1# NNAPI vendor extensions 2 3In Android Q, Neural Networks API introduced vendor extensions -- a better, 4more structured alternative to the OEM operation and data types. 5An extension is a collection of vendor-defined operations and data types. 6A driver can provide custom hardware-accelerated operations via NNAPI 1.2+ 7by supporting corresponding vendor extensions. 8 9Note that extensions do not modify behavior of existing operations. 10 11This document explains how to create and use extensions. 12 13## Extensions usage allowlist 14 15Vendor extensions can only be used by explicitly specified Android apps and 16native binaries on the /product, /vendor, /odm, and /data partitions. It's not possible to 17specify an app or a native binary located on the /system partition. 18 19The allowlist is stored in `/vendor/etc/nnapi_extensions_app_allowlist`, and contains 20a list of Android apps and binaries permitted to use NNAPI vendor extensions. 21Each line of the file contains a new entry. If an entry is prefixed by '/', 22then it's a native binary path (e.g. '/data/foo'). If not, it's a name of an Android 23app package (e.g. 'com.foo.bar'). 24 25Allowlist is enforced from the NNAPI runtime shared library. It protects 26against accidental usage, but not against deliberate circumvention by directly 27using the NNAPI driver HAL interface. 28 29## Vendor extension definition 30 31The vendor is expected to create and maintain a header file with the 32extension definition. A complete example is provided in 33`test_vendor/fibonacci/FibonacciExtension.h`. 34 35Each extension must have a unique name that starts with the reverse domain name 36of the vendor: 37```c 38const char MY_EXTENSION_NAME[] = "com.example.my_extension"; 39``` 40 41This name acts as a namespace for operations and data types. 42NNAPI uses this name to distinguish between extensions. 43 44Operations and data types are declared in a way similar to 45`../runtime/include/NeuralNetworks.h`: 46```c 47enum { 48 /** 49 * A custom scalar type. 50 */ 51 MY_SCALAR = 0, 52 53 /** 54 * A custom tensor type. 55 * 56 * Attached to this tensor is {@link MyTensorParams}. 57 */ 58 MY_TENSOR = 1, 59}; 60 61enum { 62 /** 63 * Computes my function. 64 * 65 * Inputs: 66 * * 0: A scalar of {@link MY_SCALAR}. 67 * 68 * Outputs: 69 * * 0: A tensor of {@link MY_TENSOR}. 70 */ 71 MY_FUNCTION = 0, 72}; 73``` 74 75An extension operation may use any operand types, including non-extension 76operand types and operand types from other extensions. In the latter case, 77the driver must support those other extensions in order to support the 78extension. 79 80Extensions may also declare custom structures to accompany extension operands: 81```c 82/** 83 * Quantization parameters for {@link MY_TENSOR}. 84 */ 85typedef struct MyTensorParams { 86 double scale; 87 int64_t zeroPoint; 88} MyTensorParams; 89``` 90 91## Using extensions in NNAPI clients 92 93Runtime extension support is provided by 94`../runtime/include/NeuralNetworksExtensions.h` (C API) and 95`../runtime/include/NeuralNetworksWrapperExtensions.h` (C++ API). 96This section provides an overview of the former. 97 98Use `ANeuralNetworksDevice_getExtensionSupport` to check whether a device 99supports an extension: 100```c 101bool isExtensionSupported; 102CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, MY_EXTENSION_NAME, 103 &isExtensionSupported), 104 ANEURALNETWORKS_NO_ERROR); 105if (isExtensionSupported) { 106 // The device supports the extension. 107 ... 108} 109``` 110 111To build a model with an extension operand, use 112`ANeuralNetworksModel_getExtensionOperandType` to obtain the operand type. 113Then call `ANeuralNetworksModel_addOperand` as usual: 114```c 115int32_t type; 116CHECK_EQ(ANeuralNetworksModel_getExtensionOperandType(model, MY_EXTENSION_NAME, MY_TENSOR, &type), 117 ANEURALNETWORKS_NO_ERROR); 118ANeuralNetworksOperandType operandType{ 119 .type = type, 120 .dimensionCount = dimensionCount, 121 .dimensions = dimensions, 122}; 123CHECK_EQ(ANeuralNetworksModel_addOperand(model, &operandType), ANEURALNETWORKS_NO_ERROR); 124``` 125 126Optionally, use `ANeuralNetworksModel_setOperandExtensionData` to 127associate additional data with an extension operand. 128```c 129MyTensorParams params{ 130 .scale = 0.5, 131 .zeroPoint = 128, 132}; 133CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, ¶ms, sizeof(params)), 134 ANEURALNETWORKS_NO_ERROR); 135``` 136 137To build a model with an extension operation, use 138`ANeuralNetworksModel_getExtensionOperationType` to obtain the operation type. 139Then call `ANeuralNetworksModel_addOperation` as usual: 140```c 141ANeuralNetworksOperationType type; 142CHECK_EQ(ANeuralNetworksModel_getExtensionOperationType(model, MY_EXTENSION_NAME, MY_FUNCTION, 143 &type), 144 ANEURALNETWORKS_NO_ERROR); 145CHECK_EQ(ANeuralNetworksModel_addOperation(model, type, inputCount, inputs, outputCount, outputs), 146 ANEURALNETWORKS_NO_ERROR); 147``` 148 149## Adding extension support to an NNAPI driver 150 151The driver reports supported extensions via the 152`IDevice::getSupportedExtensions()` method. 153For each supported extension, the returned list must contain an entry 154describing it: 155```c++ 156Extension { 157 .name = MY_EXTENSION_NAME, 158 .operandTypes = { 159 { 160 .type = MY_SCALAR, 161 .isTensor = false, 162 .byteSize = 8, 163 }, 164 { 165 .type = MY_TENSOR, 166 .isTensor = true, 167 .byteSize = 8, 168 }, 169 }, 170} 171``` 172 173When handling operation and operand types, the driver must check the 174`Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX` high bits of the type. 175These bits constitute the extension _prefix_. A zero prefix means no extension, 176whereas a non-zero prefix maps uniquely within a model to an extension name via 177`model.extensionNameToPrefix`. 178The low `Model::ExtensionTypeEncoding::LOW_BITS_TYPE` bits of the type 179correspond to the type within the extension. 180 181The driver must validate extension operations and data types, as the NNAPI 182runtime does not know how to validate particular extension operations and data 183types. 184 185Extension operands may have associated data in `operand.extraParams.extension`, 186which the runtime treats as a raw data blob of arbitrary size. 187