Add HIDL lifetime and protecting callback info to NN README
This CL copies information from
packages/modules/NeuralNetworks/runtime/VersionedInterfaces.cpp and
modifies the description to be more appropriate for the NN HAL utility
code.
Specific sections added to the README:
* "HIDL Interface Lifetimes across Processes"
* "Protecting Asynchronous Calls across HIDL"
Bug: 170289677
Test: mma
Change-Id: Id381895535d708b627f4746687b4d12e16560639
Merged-In: Id381895535d708b627f4746687b4d12e16560639
(cherry picked from commit 7a655bb3d4
)
This commit is contained in:
parent
4024d8f4d8
commit
aad934baa7
24 changed files with 129 additions and 5 deletions
|
@ -27,6 +27,9 @@
|
|||
#include <nnapi/hal/ProtectCallback.h>
|
||||
#include <nnapi/hal/TransferValue.h>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
|
||||
class PreparedModelCallback final : public IPreparedModelCallback,
|
||||
|
|
|
@ -32,8 +32,12 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
|
||||
// Class that adapts V1_0::IDevice to nn::IDevice.
|
||||
class Device final : public nn::IDevice {
|
||||
struct PrivateConstructorTag {};
|
||||
|
||||
|
|
|
@ -29,8 +29,12 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
|
||||
// Class that adapts V1_0::IPreparedModel to nn::IPreparedModel.
|
||||
class PreparedModel final : public nn::IPreparedModel {
|
||||
struct PrivateConstructorTag {};
|
||||
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
|
||||
#include <utility>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
|
||||
nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
|
||||
|
|
|
@ -32,8 +32,12 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_1::utils {
|
||||
|
||||
// Class that adapts V1_1::IDevice to nn::IDevice.
|
||||
class Device final : public nn::IDevice {
|
||||
struct PrivateConstructorTag {};
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_1::utils {
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
#include <nnapi/hal/ProtectCallback.h>
|
||||
#include <nnapi/hal/TransferValue.h>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
|
||||
class PreparedModelCallback final : public IPreparedModelCallback,
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
|
||||
nn::GeneralResult<std::string> initVersionString(V1_2::IDevice* device);
|
||||
|
@ -40,6 +43,7 @@ nn::GeneralResult<std::vector<nn::Extension>> initExtensions(V1_2::IDevice* devi
|
|||
nn::GeneralResult<std::pair<uint32_t, uint32_t>> initNumberOfCacheFilesNeeded(
|
||||
V1_2::IDevice* device);
|
||||
|
||||
// Class that adapts V1_2::IDevice to nn::IDevice.
|
||||
class Device final : public nn::IDevice {
|
||||
struct PrivateConstructorTag {};
|
||||
|
||||
|
|
|
@ -30,8 +30,12 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
|
||||
// Class that adapts V1_2::IPreparedModel to nn::IPreparedModel.
|
||||
class PreparedModel final : public nn::IPreparedModel {
|
||||
struct PrivateConstructorTag {};
|
||||
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
|
||||
#include <utility>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -24,8 +24,12 @@
|
|||
#include <nnapi/Types.h>
|
||||
#include <memory>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
|
||||
// Class that adapts V1_3::IBuffer to nn::IBuffer.
|
||||
class Buffer final : public nn::IBuffer {
|
||||
struct PrivateConstructorTag {};
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
#include <nnapi/hal/ProtectCallback.h>
|
||||
#include <nnapi/hal/TransferValue.h>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
|
||||
class PreparedModelCallback final : public IPreparedModelCallback,
|
||||
|
|
|
@ -32,8 +32,12 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
|
||||
// Class that adapts V1_3::IDevice to nn::IDevice.
|
||||
class Device final : public nn::IDevice {
|
||||
struct PrivateConstructorTag {};
|
||||
|
||||
|
|
|
@ -29,8 +29,12 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
|
||||
// Class that adapts V1_3::IPreparedModel to nn::IPreparedModel.
|
||||
class PreparedModel final : public nn::IPreparedModel {
|
||||
struct PrivateConstructorTag {};
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
|
||||
nn::GeneralResult<std::shared_ptr<const Buffer>> Buffer::create(
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
|
||||
#include <utility>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# NNAPI Conversions
|
||||
|
||||
`convert` fails if either the source type or the destination type is invalid, and it yields a valid
|
||||
object if the conversion succeeds. For example, let's say that an enumeration in the current
|
||||
version has fewer possible values than the "same" canonical enumeration, such as `OperationType`.
|
||||
The new value of `HARD_SWISH` (introduced in Android R / NN HAL 1.3) does not map to any valid
|
||||
existing value in `OperationType`, but an older value of `ADD` (introduced in Android OC-MR1 / NN
|
||||
HAL 1.0) is valid. This can be seen in the following model conversions:
|
||||
object if the conversion succeeds. For example, let's say that an enumeration in the current version
|
||||
has fewer possible values than the "same" canonical enumeration, such as `OperationType`. The new
|
||||
value of `HARD_SWISH` (introduced in Android R / NN HAL 1.3) does not map to any valid existing
|
||||
value in `OperationType`, but an older value of `ADD` (introduced in Android OC-MR1 / NN HAL 1.0) is
|
||||
valid. This can be seen in the following model conversions:
|
||||
|
||||
```cpp
|
||||
// Unsuccessful conversion
|
||||
|
@ -48,3 +48,50 @@ The `convert` functions operate only on types that used in a HIDL method call di
|
|||
`unvalidatedConvert` functions operate on types that are either used in a HIDL method call directly
|
||||
(i.e., not as a nested class) or used in a subsequent version of the NN HAL. Prefer using `convert`
|
||||
over `unvalidatedConvert`.
|
||||
|
||||
# HIDL Interface Lifetimes across Processes
|
||||
|
||||
Some notes about HIDL interface objects and lifetimes across processes:
|
||||
|
||||
All HIDL interface objects inherit from `IBase`, which itself inherits from `::android::RefBase`. As
|
||||
such, all HIDL interface objects are reference counted and must be owned through `::android::sp` (or
|
||||
referenced through `::android::wp`). Allocating `RefBase` objects on the stack will log errors and
|
||||
may result in crashes, and deleting a `RefBase` object through another means (e.g., "delete",
|
||||
"free", or RAII-cleanup through `std::unique_ptr` or some equivalent) will result in double-free
|
||||
and/or use-after-free undefined behavior.
|
||||
|
||||
HIDL/Binder manages the reference count of HIDL interface objects automatically across processes. If
|
||||
a process that references (but did not create) the HIDL interface object dies, HIDL/Binder ensures
|
||||
any reference count it held is properly released. (Caveat: it might be possible that HIDL/Binder
|
||||
behave strangely with `::android::wp` references.)
|
||||
|
||||
If the process which created the HIDL interface object dies, any call on this object from another
|
||||
process will result in a HIDL transport error with the code `DEAD_OBJECT`.
|
||||
|
||||
# Protecting Asynchronous Calls across HIDL
|
||||
|
||||
Some notes about asynchronous calls across HIDL:
|
||||
|
||||
For synchronous calls across HIDL, if an error occurs after the function was called but before it
|
||||
returns, HIDL will return a transport error. For example, if the message cannot be delivered to the
|
||||
server process or if the server process dies before returning a result, HIDL will return from the
|
||||
function with the appropriate transport error in the `Return<>` object, which can be queried with
|
||||
`Return<>::isOk()`, `Return<>::isDeadObject()`, `Return<>::description()`, etc.
|
||||
|
||||
However, HIDL offers no such error management in the case of asynchronous calls. By default, if the
|
||||
client launches an asynchronous task and the server fails to return a result through the callback,
|
||||
the client will be left waiting indefinitely for a result it will never receive.
|
||||
|
||||
In the NNAPI, `IDevice::prepareModel*` and `IPreparedModel::execute*` (but not
|
||||
`IPreparedModel::executeSynchronously*`) are asynchronous calls across HIDL. Specifically, these
|
||||
asynchronous functions are called with a HIDL interface callback object (`IPrepareModelCallback` for
|
||||
`IDevice::prepareModel*` and `IExecutionCallback` for `IPreparedModel::execute*`) and are expected
|
||||
to quickly return, and the results are returned at a later time through these callback objects.
|
||||
|
||||
To protect against the case when the server dies after the asynchronous task was called successfully
|
||||
but before the results could be returned, HIDL provides an object called a "`hidl_death_recipient`,"
|
||||
which can be used to detect when an interface object (and more generally, the server process) has
|
||||
died. nnapi/hal/ProtectCallback.h's `DeathHandler` uses `hidl_death_recipient`s to detect when the
|
||||
driver process has died, and `DeathHandler` will unblock any thread waiting on the results of an
|
||||
`IProtectedCallback` callback object that may otherwise not be signaled. In order for this to work,
|
||||
the `IProtectedCallback` object must have been registered via `DeathHandler::protectCallback()`.
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::utils {
|
||||
|
||||
class IProtectedCallback {
|
||||
|
|
Loading…
Reference in a new issue