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:
Michael Butler 2020-12-13 23:06:06 -08:00
parent 4024d8f4d8
commit aad934baa7
24 changed files with 129 additions and 5 deletions

View file

@ -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,

View file

@ -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 {};

View file

@ -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 {};

View file

@ -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 {

View file

@ -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 {

View file

@ -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(

View file

@ -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 {};

View file

@ -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 {

View file

@ -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,

View file

@ -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 {};

View file

@ -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 {};

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {};

View file

@ -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,

View file

@ -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 {};

View file

@ -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 {};

View file

@ -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(

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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()`.

View file

@ -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 {