From aad934baa7894472c5b1e177fb101ce0b2f61f51 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Sun, 13 Dec 2020 23:06:06 -0800 Subject: [PATCH] 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 7a655bb3d4752e0c373ad3fdbcf4508eb7050afc) --- .../utils/include/nnapi/hal/1.0/Callbacks.h | 3 + .../1.0/utils/include/nnapi/hal/1.0/Device.h | 4 ++ .../include/nnapi/hal/1.0/PreparedModel.h | 4 ++ neuralnetworks/1.0/utils/src/Callbacks.cpp | 3 + neuralnetworks/1.0/utils/src/Device.cpp | 3 + .../1.0/utils/src/PreparedModel.cpp | 3 + .../1.1/utils/include/nnapi/hal/1.1/Device.h | 4 ++ neuralnetworks/1.1/utils/src/Device.cpp | 3 + .../utils/include/nnapi/hal/1.2/Callbacks.h | 3 + .../1.2/utils/include/nnapi/hal/1.2/Device.h | 4 ++ .../include/nnapi/hal/1.2/PreparedModel.h | 4 ++ neuralnetworks/1.2/utils/src/Callbacks.cpp | 3 + neuralnetworks/1.2/utils/src/Device.cpp | 3 + .../1.2/utils/src/PreparedModel.cpp | 3 + .../1.3/utils/include/nnapi/hal/1.3/Buffer.h | 4 ++ .../utils/include/nnapi/hal/1.3/Callbacks.h | 3 + .../1.3/utils/include/nnapi/hal/1.3/Device.h | 4 ++ .../include/nnapi/hal/1.3/PreparedModel.h | 4 ++ neuralnetworks/1.3/utils/src/Buffer.cpp | 3 + neuralnetworks/1.3/utils/src/Callbacks.cpp | 3 + neuralnetworks/1.3/utils/src/Device.cpp | 3 + .../1.3/utils/src/PreparedModel.cpp | 3 + neuralnetworks/utils/README.md | 57 +++++++++++++++++-- .../include/nnapi/hal/ProtectCallback.h | 3 + 24 files changed, 129 insertions(+), 5 deletions(-) diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.h index 65b75e5d82..2e00fcecf3 100644 --- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.h +++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.h @@ -27,6 +27,9 @@ #include #include +// 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, diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h index ee103bacf5..db3b2ad44f 100644 --- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h +++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h @@ -32,8 +32,12 @@ #include #include +// 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 {}; diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h index 198cbc8e81..2de182871d 100644 --- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h +++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h @@ -29,8 +29,12 @@ #include #include +// 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 {}; diff --git a/neuralnetworks/1.0/utils/src/Callbacks.cpp b/neuralnetworks/1.0/utils/src/Callbacks.cpp index b1259c3c56..a0bdb3cd99 100644 --- a/neuralnetworks/1.0/utils/src/Callbacks.cpp +++ b/neuralnetworks/1.0/utils/src/Callbacks.cpp @@ -32,6 +32,9 @@ #include +// 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 { diff --git a/neuralnetworks/1.0/utils/src/Device.cpp b/neuralnetworks/1.0/utils/src/Device.cpp index 285c515c20..83e0015689 100644 --- a/neuralnetworks/1.0/utils/src/Device.cpp +++ b/neuralnetworks/1.0/utils/src/Device.cpp @@ -38,6 +38,9 @@ #include #include +// 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 { diff --git a/neuralnetworks/1.0/utils/src/PreparedModel.cpp b/neuralnetworks/1.0/utils/src/PreparedModel.cpp index add827567e..c1dd1d9e70 100644 --- a/neuralnetworks/1.0/utils/src/PreparedModel.cpp +++ b/neuralnetworks/1.0/utils/src/PreparedModel.cpp @@ -34,6 +34,9 @@ #include #include +// 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> PreparedModel::create( diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h index c1e95fe1a5..5e224b5018 100644 --- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h +++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h @@ -32,8 +32,12 @@ #include #include +// 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 {}; diff --git a/neuralnetworks/1.1/utils/src/Device.cpp b/neuralnetworks/1.1/utils/src/Device.cpp index f73d3f8253..b57c7f4c54 100644 --- a/neuralnetworks/1.1/utils/src/Device.cpp +++ b/neuralnetworks/1.1/utils/src/Device.cpp @@ -39,6 +39,9 @@ #include #include +// 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 { diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h index bc7d92ac83..1162bc33b3 100644 --- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h +++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h @@ -31,6 +31,9 @@ #include #include +// 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, diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h index a68830d86e..79c3b041ad 100644 --- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h +++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h @@ -32,6 +32,9 @@ #include #include +// 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 initVersionString(V1_2::IDevice* device); @@ -40,6 +43,7 @@ nn::GeneralResult> initExtensions(V1_2::IDevice* devi nn::GeneralResult> initNumberOfCacheFilesNeeded( V1_2::IDevice* device); +// Class that adapts V1_2::IDevice to nn::IDevice. class Device final : public nn::IDevice { struct PrivateConstructorTag {}; diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h index 53bd4d12ef..8ed5ca7f97 100644 --- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h +++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h @@ -30,8 +30,12 @@ #include #include +// 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 {}; diff --git a/neuralnetworks/1.2/utils/src/Callbacks.cpp b/neuralnetworks/1.2/utils/src/Callbacks.cpp index 39f88c2c5e..ab3e0ca879 100644 --- a/neuralnetworks/1.2/utils/src/Callbacks.cpp +++ b/neuralnetworks/1.2/utils/src/Callbacks.cpp @@ -36,6 +36,9 @@ #include +// 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 { diff --git a/neuralnetworks/1.2/utils/src/Device.cpp b/neuralnetworks/1.2/utils/src/Device.cpp index 0061065f0b..6cca841aba 100644 --- a/neuralnetworks/1.2/utils/src/Device.cpp +++ b/neuralnetworks/1.2/utils/src/Device.cpp @@ -41,6 +41,9 @@ #include #include +// 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 { diff --git a/neuralnetworks/1.2/utils/src/PreparedModel.cpp b/neuralnetworks/1.2/utils/src/PreparedModel.cpp index 32c2651950..b422cedefa 100644 --- a/neuralnetworks/1.2/utils/src/PreparedModel.cpp +++ b/neuralnetworks/1.2/utils/src/PreparedModel.cpp @@ -37,6 +37,9 @@ #include #include +// 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 { diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h index 637179de33..fda79c88c1 100644 --- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h +++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h @@ -24,8 +24,12 @@ #include #include +// 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 {}; diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h index d46b111701..cb2a56a2e2 100644 --- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h +++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h @@ -34,6 +34,9 @@ #include #include +// 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, diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h index 0f5234bd26..84f606a357 100644 --- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h +++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h @@ -32,8 +32,12 @@ #include #include +// 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 {}; diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h index 09360eceb8..c4ba483463 100644 --- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h +++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h @@ -29,8 +29,12 @@ #include #include +// 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 {}; diff --git a/neuralnetworks/1.3/utils/src/Buffer.cpp b/neuralnetworks/1.3/utils/src/Buffer.cpp index ffdeccdf62..4ef54a2c93 100644 --- a/neuralnetworks/1.3/utils/src/Buffer.cpp +++ b/neuralnetworks/1.3/utils/src/Buffer.cpp @@ -33,6 +33,9 @@ #include #include +// 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> Buffer::create( diff --git a/neuralnetworks/1.3/utils/src/Callbacks.cpp b/neuralnetworks/1.3/utils/src/Callbacks.cpp index e3c6074549..17c20fba68 100644 --- a/neuralnetworks/1.3/utils/src/Callbacks.cpp +++ b/neuralnetworks/1.3/utils/src/Callbacks.cpp @@ -39,6 +39,9 @@ #include +// 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 { diff --git a/neuralnetworks/1.3/utils/src/Device.cpp b/neuralnetworks/1.3/utils/src/Device.cpp index 82837bac73..60564985de 100644 --- a/neuralnetworks/1.3/utils/src/Device.cpp +++ b/neuralnetworks/1.3/utils/src/Device.cpp @@ -47,6 +47,9 @@ #include #include +// 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 { diff --git a/neuralnetworks/1.3/utils/src/PreparedModel.cpp b/neuralnetworks/1.3/utils/src/PreparedModel.cpp index 124a8db263..0bae95de87 100644 --- a/neuralnetworks/1.3/utils/src/PreparedModel.cpp +++ b/neuralnetworks/1.3/utils/src/PreparedModel.cpp @@ -39,6 +39,9 @@ #include #include +// 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 { diff --git a/neuralnetworks/utils/README.md b/neuralnetworks/utils/README.md index 0dee103811..45ca0b442f 100644 --- a/neuralnetworks/utils/README.md +++ b/neuralnetworks/utils/README.md @@ -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()`. diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h b/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h index 85bd6137ee..c9218857ac 100644 --- a/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h +++ b/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h @@ -28,6 +28,9 @@ #include #include +// 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 {