1*4d7e907cSAndroid Build Coastguard Worker# NNAPI Conversions 2*4d7e907cSAndroid Build Coastguard Worker 3*4d7e907cSAndroid Build Coastguard Worker`convert` fails if either the source type or the destination type is invalid, and it yields a valid 4*4d7e907cSAndroid Build Coastguard Workerobject if the conversion succeeds. For example, let's say that an enumeration in the current version 5*4d7e907cSAndroid Build Coastguard Workerhas fewer possible values than the "same" canonical enumeration, such as `OperationType`. The new 6*4d7e907cSAndroid Build Coastguard Workervalue of `HARD_SWISH` (introduced in Android R / NN HAL 1.3) does not map to any valid existing 7*4d7e907cSAndroid Build Coastguard Workervalue in `OperationType`, but an older value of `ADD` (introduced in Android OC-MR1 / NN HAL 1.0) is 8*4d7e907cSAndroid Build Coastguard Workervalid. This can be seen in the following model conversions: 9*4d7e907cSAndroid Build Coastguard Worker 10*4d7e907cSAndroid Build Coastguard Worker```cpp 11*4d7e907cSAndroid Build Coastguard Worker// Unsuccessful conversion 12*4d7e907cSAndroid Build Coastguard Workerconst nn::Model canonicalModel = createModelWhichHasV1_3Operations(); 13*4d7e907cSAndroid Build Coastguard Workerconst nn::Result<V1_0::Model> maybeVersionedModel = V1_0::utils::convert(canonicalModel); 14*4d7e907cSAndroid Build Coastguard WorkerEXPECT_FALSE(maybeVersionedModel.has_value()); 15*4d7e907cSAndroid Build Coastguard Worker``` 16*4d7e907cSAndroid Build Coastguard Worker```cpp 17*4d7e907cSAndroid Build Coastguard Worker// Successful conversion 18*4d7e907cSAndroid Build Coastguard Workerconst nn::Model canonicalModel = createModelWhichHasOnlyV1_0Operations(); 19*4d7e907cSAndroid Build Coastguard Workerconst nn::Result<V1_0::Model> maybeVersionedModel = V1_0::utils::convert(canonicalModel); 20*4d7e907cSAndroid Build Coastguard WorkerASSERT_TRUE(maybeVersionedModel.has_value()); 21*4d7e907cSAndroid Build Coastguard Workerconst V1_0::Model& versionedModel = maybeVersionedModel.value(); 22*4d7e907cSAndroid Build Coastguard WorkerEXPECT_TRUE(V1_0::utils::valid(versionedModel)); 23*4d7e907cSAndroid Build Coastguard Worker``` 24*4d7e907cSAndroid Build Coastguard Worker 25*4d7e907cSAndroid Build Coastguard Worker`V1_X::utils::convert` does not guarantee that all information is preserved. For example, In the 26*4d7e907cSAndroid Build Coastguard Workercase of `nn::ErrorStatus`, the new value of `MISSED_DEADLINE_TRANSIENT` can be represented by the 27*4d7e907cSAndroid Build Coastguard Workerexisting value of `V1_0::GENERAL_FAILURE`: 28*4d7e907cSAndroid Build Coastguard Worker 29*4d7e907cSAndroid Build Coastguard Worker```cpp 30*4d7e907cSAndroid Build Coastguard Worker// Lossy Canonical -> HAL -> Canonical conversion 31*4d7e907cSAndroid Build Coastguard Workerconst nn::ErrorStatus canonicalBefore = nn::ErrorStatus::MISSED_DEADLINE_TRANSIENT; 32*4d7e907cSAndroid Build Coastguard Workerconst V1_0::ErrorStatus versioned = V1_0::utils::convert(canonicalBefore).value(); 33*4d7e907cSAndroid Build Coastguard Workerconst nn::ErrorStatus canonicalAfter = nn::convert(versioned).value(); 34*4d7e907cSAndroid Build Coastguard WorkerEXPECT_NE(canonicalBefore, canonicalAfter); 35*4d7e907cSAndroid Build Coastguard Worker``` 36*4d7e907cSAndroid Build Coastguard Worker 37*4d7e907cSAndroid Build Coastguard WorkerHowever, `nn::convert` is guaranteed to preserve all information: 38*4d7e907cSAndroid Build Coastguard Worker 39*4d7e907cSAndroid Build Coastguard Worker```cpp 40*4d7e907cSAndroid Build Coastguard Worker// Lossless HAL -> Canonical -> HAL conversion 41*4d7e907cSAndroid Build Coastguard Workerconst V1_0::ErrorStatus versionedBefore = V1_0::ErrorStatus::GENERAL_FAILURE; 42*4d7e907cSAndroid Build Coastguard Workerconst nn::ErrorStatus canonical = nn::convert(versionedBefore).value(); 43*4d7e907cSAndroid Build Coastguard Workerconst V1_0::ErrorStatus versionedAfter = V1_0::utils::convert(canonical).value(); 44*4d7e907cSAndroid Build Coastguard WorkerEXPECT_EQ(versionedBefore, versionedAfter); 45*4d7e907cSAndroid Build Coastguard Worker``` 46*4d7e907cSAndroid Build Coastguard Worker 47*4d7e907cSAndroid Build Coastguard WorkerThe `convert` functions operate only on types that are used in a HIDL method call directly. The 48*4d7e907cSAndroid Build Coastguard Worker`unvalidatedConvert` functions operate on types that are either used in a HIDL method call directly 49*4d7e907cSAndroid Build Coastguard Worker(i.e., not as a nested class) or used in a subsequent version of the NN HAL. Prefer using `convert` 50*4d7e907cSAndroid Build Coastguard Workerover `unvalidatedConvert`. 51*4d7e907cSAndroid Build Coastguard Worker 52*4d7e907cSAndroid Build Coastguard Worker# Interface Lifetimes across Processes 53*4d7e907cSAndroid Build Coastguard Worker 54*4d7e907cSAndroid Build Coastguard Worker## HIDL 55*4d7e907cSAndroid Build Coastguard Worker 56*4d7e907cSAndroid Build Coastguard WorkerSome notes about HIDL interface objects and lifetimes across processes: 57*4d7e907cSAndroid Build Coastguard Worker 58*4d7e907cSAndroid Build Coastguard WorkerAll HIDL interface objects inherit from `IBase`, which itself inherits from `::android::RefBase`. As 59*4d7e907cSAndroid Build Coastguard Workersuch, all HIDL interface objects are reference counted and must be owned through `::android::sp` (or 60*4d7e907cSAndroid Build Coastguard Workerreferenced through `::android::wp`). Allocating `RefBase` objects on the stack will log errors and 61*4d7e907cSAndroid Build Coastguard Workermay result in crashes, and deleting a `RefBase` object through another means (e.g., "delete", 62*4d7e907cSAndroid Build Coastguard Worker"free", or RAII-cleanup through `std::unique_ptr` or some equivalent) will result in double-free 63*4d7e907cSAndroid Build Coastguard Workerand/or use-after-free undefined behavior. 64*4d7e907cSAndroid Build Coastguard Worker 65*4d7e907cSAndroid Build Coastguard WorkerHIDL/Binder manages the reference count of HIDL interface objects automatically across processes. If 66*4d7e907cSAndroid Build Coastguard Workera process that references (but did not create) the HIDL interface object dies, HIDL/Binder ensures 67*4d7e907cSAndroid Build Coastguard Workerany reference count it held is properly released. (Caveat: it might be possible that HIDL/Binder 68*4d7e907cSAndroid Build Coastguard Workerbehave strangely with `::android::wp` references.) 69*4d7e907cSAndroid Build Coastguard Worker 70*4d7e907cSAndroid Build Coastguard WorkerIf the process which created the HIDL interface object dies, any call on this object from another 71*4d7e907cSAndroid Build Coastguard Workerprocess will result in a HIDL transport error with the code `DEAD_OBJECT`. 72*4d7e907cSAndroid Build Coastguard Worker 73*4d7e907cSAndroid Build Coastguard Worker## AIDL 74*4d7e907cSAndroid Build Coastguard Worker 75*4d7e907cSAndroid Build Coastguard WorkerWe use NDK backend for AIDL interfaces. Handling of lifetimes is generally the same with the 76*4d7e907cSAndroid Build Coastguard Workerfollowing differences: 77*4d7e907cSAndroid Build Coastguard Worker* Interfaces inherit from `ndk::ICInterface`, which inherits from `ndk::SharedRefBase`. The latter 78*4d7e907cSAndroid Build Coastguard Worker is an analog of `::android::RefBase` using `std::shared_ptr` for reference counting. 79*4d7e907cSAndroid Build Coastguard Worker* AIDL calls return `ndk::ScopedAStatus` which wraps fields of types `binder_status_t` and 80*4d7e907cSAndroid Build Coastguard Worker `binder_exception_t`. In case the call is made on a dead object, the call will return 81*4d7e907cSAndroid Build Coastguard Worker `ndk::ScopedAStatus` with exception `EX_TRANSACTION_FAILED` and binder status 82*4d7e907cSAndroid Build Coastguard Worker `STATUS_DEAD_OBJECT`. 83*4d7e907cSAndroid Build Coastguard Worker 84*4d7e907cSAndroid Build Coastguard Worker# Protecting Asynchronous Calls 85*4d7e907cSAndroid Build Coastguard Worker 86*4d7e907cSAndroid Build Coastguard Worker## Across HIDL 87*4d7e907cSAndroid Build Coastguard Worker 88*4d7e907cSAndroid Build Coastguard WorkerSome notes about asynchronous calls across HIDL: 89*4d7e907cSAndroid Build Coastguard Worker 90*4d7e907cSAndroid Build Coastguard WorkerFor synchronous calls across HIDL, if an error occurs after the function was called but before it 91*4d7e907cSAndroid Build Coastguard Workerreturns, HIDL will return a transport error. For example, if the message cannot be delivered to the 92*4d7e907cSAndroid Build Coastguard Workerserver process or if the server process dies before returning a result, HIDL will return from the 93*4d7e907cSAndroid Build Coastguard Workerfunction with the appropriate transport error in the `Return<>` object, which can be queried with 94*4d7e907cSAndroid Build Coastguard Worker`Return<>::isOk()`, `Return<>::isDeadObject()`, `Return<>::description()`, etc. 95*4d7e907cSAndroid Build Coastguard Worker 96*4d7e907cSAndroid Build Coastguard WorkerHowever, HIDL offers no such error management in the case of asynchronous calls. By default, if the 97*4d7e907cSAndroid Build Coastguard Workerclient launches an asynchronous task and the server fails to return a result through the callback, 98*4d7e907cSAndroid Build Coastguard Workerthe client will be left waiting indefinitely for a result it will never receive. 99*4d7e907cSAndroid Build Coastguard Worker 100*4d7e907cSAndroid Build Coastguard WorkerIn the NNAPI, `IDevice::prepareModel*` and `IPreparedModel::execute*` (but not 101*4d7e907cSAndroid Build Coastguard Worker`IPreparedModel::executeSynchronously*`) are asynchronous calls across HIDL. Specifically, these 102*4d7e907cSAndroid Build Coastguard Workerasynchronous functions are called with a HIDL interface callback object (`IPrepareModelCallback` for 103*4d7e907cSAndroid Build Coastguard Worker`IDevice::prepareModel*` and `IExecutionCallback` for `IPreparedModel::execute*`) and are expected 104*4d7e907cSAndroid Build Coastguard Workerto quickly return, and the results are returned at a later time through these callback objects. 105*4d7e907cSAndroid Build Coastguard Worker 106*4d7e907cSAndroid Build Coastguard WorkerTo protect against the case when the server dies after the asynchronous task was called successfully 107*4d7e907cSAndroid Build Coastguard Workerbut before the results could be returned, HIDL provides an object called a "`hidl_death_recipient`," 108*4d7e907cSAndroid Build Coastguard Workerwhich can be used to detect when an interface object (and more generally, the server process) has 109*4d7e907cSAndroid Build Coastguard Workerdied. nnapi/hal/ProtectCallback.h's `DeathHandler` uses `hidl_death_recipient`s to detect when the 110*4d7e907cSAndroid Build Coastguard Workerdriver process has died, and `DeathHandler` will unblock any thread waiting on the results of an 111*4d7e907cSAndroid Build Coastguard Worker`IProtectedCallback` callback object that may otherwise not be signaled. In order for this to work, 112*4d7e907cSAndroid Build Coastguard Workerthe `IProtectedCallback` object must have been registered via `DeathHandler::protectCallback()`. 113*4d7e907cSAndroid Build Coastguard Worker 114*4d7e907cSAndroid Build Coastguard Worker## Across AIDL 115*4d7e907cSAndroid Build Coastguard Worker 116*4d7e907cSAndroid Build Coastguard WorkerWe use NDK backend for AIDL interfaces. Handling of asynchronous calls is generally the same with 117*4d7e907cSAndroid Build Coastguard Workerthe following differences: 118*4d7e907cSAndroid Build Coastguard Worker* AIDL calls return `ndk::ScopedAStatus` which wraps fields of types `binder_status_t` and 119*4d7e907cSAndroid Build Coastguard Worker `binder_exception_t`. In case the call is made on a dead object, the call will return 120*4d7e907cSAndroid Build Coastguard Worker `ndk::ScopedAStatus` with exception `EX_TRANSACTION_FAILED` and binder status 121*4d7e907cSAndroid Build Coastguard Worker `STATUS_DEAD_OBJECT`. 122*4d7e907cSAndroid Build Coastguard Worker* AIDL interface doesn't contain asynchronous `IPreparedModel::execute`. 123*4d7e907cSAndroid Build Coastguard Worker* Service death is handled using `AIBinder_DeathRecipient` object which is linked to an interface 124*4d7e907cSAndroid Build Coastguard Worker object using `AIBinder_linkToDeath`. nnapi/hal/aidl/ProtectCallback.h provides `DeathHandler` 125*4d7e907cSAndroid Build Coastguard Worker object that is a direct analog of HIDL `DeathHandler`, only using libbinder_ndk objects for 126*4d7e907cSAndroid Build Coastguard Worker implementation. 127