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