• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include "tensorflow/lite/nnapi/nnapi_implementation.h"
16 
17 #include <dlfcn.h>
18 #include <fcntl.h>
19 #include <sys/mman.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 
23 #include <algorithm>
24 #include <cstdlib>
25 
26 #include "tensorflow/lite/nnapi/NeuralNetworksTypes.h"
27 #include "tensorflow/lite/nnapi/sl/public/NeuralNetworksSupportLibraryImpl.h"
28 
29 #ifdef __ANDROID__
30 #include <sys/system_properties.h>
31 #endif  // __ANDROID__
32 
33 #define NNAPI_LOG(format, ...) fprintf(stderr, format "\n", __VA_ARGS__);
34 
35 namespace {
36 
37 #ifdef __ANDROID__
GetAndroidSdkVersion()38 int32_t GetAndroidSdkVersion() {
39   const char* sdkProp = "ro.build.version.sdk";
40   char sdkVersion[PROP_VALUE_MAX];
41   int length = __system_property_get(sdkProp, sdkVersion);
42   if (length != 0) {
43     int32_t result = 0;
44     for (int i = 0; i < length; ++i) {
45       int digit = sdkVersion[i] - '0';
46       if (digit < 0 || digit > 9) {
47         // Non-numeric SDK version, assume it's higher than expected;
48         return 0xffff;
49       }
50       result = result * 10 + digit;
51     }
52     return result;
53   }
54   return 0;
55 }
56 #endif  // __ANDROID__
57 
LoadFunction(void * handle,const char * name,bool optional)58 void* LoadFunction(void* handle, const char* name, bool optional) {
59   if (handle == nullptr) {
60     return nullptr;
61   }
62   void* fn = dlsym(handle, name);
63   if (fn == nullptr && !optional) {
64     NNAPI_LOG("nnapi error: unable to open function %s", name);
65   }
66   return fn;
67 }
68 
69 #ifndef __ANDROID__
70 // Add /dev/shm implementation of shared memory for non-Android platforms
ASharedMemory_create(const char * name,size_t size)71 int ASharedMemory_create(const char* name, size_t size) {
72   // Each call to ASharedMemory_create produces a unique memory space, hence
73   // name should be unique, otherwise two calls to create memory regions using
74   // the same 'name', will collide.
75   // Caller is responsible to provide a unique name.
76 
77   // Make sure new shared memory region is created: shm_open return an error if
78   // shm object with given name already exists (O_CREAT | O_EXCL)
79   int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0644);
80   if (fd < 0) {
81     return fd;
82   }
83   int result = ftruncate(fd, size);
84   if (result < 0) {
85     close(fd);
86     return -1;
87   }
88   return fd;
89 }
90 
91 // Determine the NnApi version from loaded entry points
CalculateAndroidSdkVersion(NnApi const & nnapi)92 uint32_t CalculateAndroidSdkVersion(NnApi const& nnapi) {
93   // Test for specific NNAPI 1.0, 1.1, 1.2 and 1.3 functions
94   bool has_10 = nnapi.ANeuralNetworksMemory_createFromFd != nullptr;
95   bool has_11 =
96       nnapi.ANeuralNetworksModel_relaxComputationFloat32toFloat16 != nullptr;
97   bool has_12 = nnapi.ANeuralNetworks_getDeviceCount != nullptr;
98   bool has_13 = nnapi.ANeuralNetworksCompilation_setTimeout != nullptr;
99   bool has_14 = nnapi.ANeuralNetworks_getRuntimeFeatureLevel != nullptr;
100 
101   uint32_t sdk_version = 0;
102   if (has_10) {
103     sdk_version = 27;
104   }
105   if (sdk_version == 27 && has_11) {
106     sdk_version = 28;
107   }
108   if (sdk_version == 28 && has_12) {
109     sdk_version = 29;
110   }
111   if (sdk_version == 29 && has_13) {
112     sdk_version = 30;
113   }
114   if (sdk_version == 30 && has_14) {
115     sdk_version = 31;
116   }
117   return sdk_version;
118 }
119 #else
120 
getASharedMemory_create()121 ASharedMemory_create_fn getASharedMemory_create() {
122   // ASharedMemory_create has different implementations in Android depending on
123   // the partition. Generally it can be loaded from libandroid.so but in vendor
124   // partition (e.g. if a HAL wants to use NNAPI) it is only accessible through
125   // libcutils.
126   void* libandroid = nullptr;
127   libandroid = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
128   if (libandroid != nullptr) {
129     return reinterpret_cast<ASharedMemory_create_fn>(
130         LoadFunction(libandroid, "ASharedMemory_create", false));
131   }
132 
133   std::string libandroid_error = dlerror();
134   void* cutils_handle = dlopen("libcutils.so", RTLD_LAZY | RTLD_LOCAL);
135   if (cutils_handle != nullptr) {
136     return reinterpret_cast<ASharedMemory_create_fn>(
137         LoadFunction(cutils_handle, "ashmem_create_region", false));
138   }
139 
140   NNAPI_LOG(
141       "nnapi error: unable to open both library %s (%s) and library %s "
142       "(%s)",
143       "libandroid.so", libandroid_error.c_str(), "libcutils.so", dlerror());
144   return nullptr;
145 }
146 
147 #endif  // __ANDROID__
148 
149 #define LOAD_FUNCTION(handle, name)         \
150   nnapi.name = reinterpret_cast<name##_fn>( \
151       LoadFunction(handle, #name, /*optional*/ false));
152 
153 #define LOAD_FUNCTION_OPTIONAL(handle, name) \
154   nnapi.name = reinterpret_cast<name##_fn>(  \
155       LoadFunction(handle, #name, /*optional*/ true));
156 
157 #define LOAD_FUNCTION_RENAME(handle, name, symbol) \
158   nnapi.name = reinterpret_cast<name##_fn>(        \
159       LoadFunction(handle, symbol, /*optional*/ false));
160 
LoadNnApi()161 const NnApi LoadNnApi() {
162   NnApi nnapi = {};
163   nnapi.android_sdk_version = 0;
164 
165 #ifdef __ANDROID__
166   nnapi.android_sdk_version = GetAndroidSdkVersion();
167   if (nnapi.android_sdk_version < 27) {
168     NNAPI_LOG("nnapi error: requires android sdk version to be at least %d",
169               27);
170     nnapi.nnapi_exists = false;
171     return nnapi;
172   }
173 #endif  // __ANDROID__
174 
175   void* libneuralnetworks = nullptr;
176   // TODO(b/123243014): change RTLD_LOCAL? Assumes there can be multiple
177   // instances of nn api RT
178   static const char nnapi_library_name[] = "libneuralnetworks.so";
179   libneuralnetworks = dlopen(nnapi_library_name, RTLD_LAZY | RTLD_LOCAL);
180 #ifdef __ANDROID__
181   // Note: If there is an problem trying to open the NNAPI library on a
182   // non-Android system, the error message is suppressed. This is to avoid
183   // showing confusing errors when running in environments that do not support
184   // NNAPI. As more platforms support NNAPI, the #ifdef logic above can be
185   // expanded.
186   if (libneuralnetworks == nullptr) {
187     const char* error = dlerror();
188     if (error) {
189       NNAPI_LOG("%s\n", error);
190     }
191     NNAPI_LOG("nnapi error: unable to open library %s", nnapi_library_name);
192   }
193 #endif  // __ANDROID__
194 
195   nnapi.nnapi_exists = libneuralnetworks != nullptr;
196 
197   // API 27 (NN 1.0) methods.
198   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksMemory_createFromFd);
199   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksMemory_free);
200   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_create);
201   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_free);
202   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_finish);
203   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_addOperand);
204   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_setOperandValue);
205   LOAD_FUNCTION_OPTIONAL(
206       libneuralnetworks,
207       ANeuralNetworksModel_setOperandSymmPerChannelQuantParams);
208   LOAD_FUNCTION(libneuralnetworks,
209                 ANeuralNetworksModel_setOperandValueFromMemory);
210   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_addOperation);
211   LOAD_FUNCTION(libneuralnetworks,
212                 ANeuralNetworksModel_identifyInputsAndOutputs);
213   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksCompilation_create);
214   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksCompilation_free);
215   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksCompilation_setPreference);
216   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksCompilation_finish);
217   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_create);
218   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_free);
219   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_setInput);
220   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_setInputFromMemory);
221   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_setOutput);
222   LOAD_FUNCTION(libneuralnetworks,
223                 ANeuralNetworksExecution_setOutputFromMemory);
224   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_startCompute);
225   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksEvent_wait);
226   LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksEvent_free);
227 
228 #ifdef __ANDROID__
229   nnapi.ASharedMemory_create = getASharedMemory_create();
230 #else
231   // Mock ASharedMemory_create only if libneuralnetworks.so was successfully
232   // loaded. This ensures identical behaviour on platforms which use this
233   // implementation, but don't have libneuralnetworks.so library, and
234   // platforms which use nnapi_implementation_disabled.cc stub.
235   if (libneuralnetworks != nullptr) {
236     nnapi.ASharedMemory_create = ASharedMemory_create;
237   }
238 #endif  // __ANDROID__
239 
240   // API 28 (NN 1.1) methods.
241   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
242                          ANeuralNetworksModel_relaxComputationFloat32toFloat16);
243 
244   // API 29 (NN 1.2) methods.
245   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworks_getDeviceCount);
246   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworks_getDevice);
247   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksDevice_getName);
248   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksDevice_getVersion);
249   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
250                          ANeuralNetworksDevice_getFeatureLevel);
251   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksDevice_getType);
252   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
253                          ANeuralNetworksModel_getSupportedOperationsForDevices);
254   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
255                          ANeuralNetworksCompilation_createForDevices);
256   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
257                          ANeuralNetworksCompilation_setCaching);
258   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksExecution_compute);
259   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
260                          ANeuralNetworksExecution_getOutputOperandRank);
261   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
262                          ANeuralNetworksExecution_getOutputOperandDimensions);
263   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksBurst_create);
264   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksBurst_free);
265   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
266                          ANeuralNetworksExecution_burstCompute);
267   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
268                          ANeuralNetworksMemory_createFromAHardwareBuffer);
269   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
270                          ANeuralNetworksExecution_setMeasureTiming);
271   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
272                          ANeuralNetworksExecution_getDuration);
273   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
274                          ANeuralNetworksDevice_getExtensionSupport);
275   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
276                          ANeuralNetworksModel_getExtensionOperandType);
277   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
278                          ANeuralNetworksModel_getExtensionOperationType);
279   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
280                          ANeuralNetworksModel_setOperandExtensionData);
281 
282   // API 30 (NNAPI 1.3) methods.
283   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
284                          ANeuralNetworksCompilation_setTimeout);
285   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
286                          ANeuralNetworksCompilation_setPriority);
287   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
288                          ANeuralNetworksExecution_setTimeout);
289   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
290                          ANeuralNetworksExecution_setLoopTimeout);
291   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksMemoryDesc_create);
292   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksMemoryDesc_free);
293   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
294                          ANeuralNetworksMemoryDesc_addInputRole);
295   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
296                          ANeuralNetworksMemoryDesc_addOutputRole);
297   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
298                          ANeuralNetworksMemoryDesc_setDimensions);
299   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksMemoryDesc_finish);
300   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
301                          ANeuralNetworksMemory_createFromDesc);
302   LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksMemory_copy);
303   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
304                          ANeuralNetworksEvent_createFromSyncFenceFd);
305   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
306                          ANeuralNetworksEvent_getSyncFenceFd);
307   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
308                          ANeuralNetworksExecution_startComputeWithDependencies);
309 
310   // API 31 methods
311   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
312                          ANeuralNetworks_getRuntimeFeatureLevel);
313   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
314                          ANeuralNetworksExecution_enableInputAndOutputPadding);
315   LOAD_FUNCTION_OPTIONAL(libneuralnetworks,
316                          ANeuralNetworksExecution_setReusable);
317 #ifndef __ANDROID__
318   // If libneuralnetworks.so is loaded, but android_sdk_version is not set,
319   // then determine android_sdk_version by testing which functions are
320   // available.
321   if (nnapi.nnapi_exists && nnapi.android_sdk_version == 0) {
322     nnapi.android_sdk_version = CalculateAndroidSdkVersion(nnapi);
323   }
324 #endif  // __ANDROID__
325   // Determin NNAPI Runtime feature level.
326   if (nnapi.ANeuralNetworks_getRuntimeFeatureLevel) {
327     nnapi.nnapi_runtime_feature_level =
328         nnapi.ANeuralNetworks_getRuntimeFeatureLevel();
329   } else {
330     nnapi.nnapi_runtime_feature_level = nnapi.android_sdk_version;
331   }
332 
333   return nnapi;
334 }
335 
336 }  // namespace
337 
CreateNnApiFromSupportLibrary(const NnApiSLDriverImplFL5 * nnapi_support_library_driver)338 std::unique_ptr<const NnApi> CreateNnApiFromSupportLibrary(
339     const NnApiSLDriverImplFL5* nnapi_support_library_driver) {
340   auto nnapi = std::make_unique<NnApi>();
341   nnapi->nnapi_exists = true;
342   nnapi->android_sdk_version = ANEURALNETWORKS_FEATURE_LEVEL_5;
343   nnapi->nnapi_runtime_feature_level =
344       nnapi_support_library_driver->base.implFeatureLevel;
345 
346 #define ASSIGN_SL_FUNCTION_TO_NNAPI(name) \
347   nnapi->name = nnapi_support_library_driver->name;
348 
349   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemory_createFromFd);
350   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemory_free);
351   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_create);
352   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_free);
353   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_finish);
354   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_addOperand);
355   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_setOperandValue);
356   ASSIGN_SL_FUNCTION_TO_NNAPI(
357       ANeuralNetworksModel_setOperandSymmPerChannelQuantParams);
358   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_setOperandValueFromMemory);
359   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_addOperation);
360   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_identifyInputsAndOutputs);
361   ASSIGN_SL_FUNCTION_TO_NNAPI(
362       ANeuralNetworksModel_relaxComputationFloat32toFloat16);
363   // ANeuralNetworksCompilation_create is not available in the support library
364   // because its clients are expected to know which accelerator they want to
365   // use. ANeuralNetworksCompilation_createForDevices is available to create
366   // compilation for specified devices.
367   nnapi->ANeuralNetworksCompilation_create = nullptr;
368   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksCompilation_free);
369   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksCompilation_setPreference);
370   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksCompilation_finish);
371   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_create);
372   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_free);
373   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_setInput);
374   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_setInputFromMemory);
375   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_setOutput);
376   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_setOutputFromMemory);
377   // Support library doesn't support regular asynchronous execution.
378   nnapi->ANeuralNetworksExecution_startCompute = nullptr;
379   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksEvent_wait);
380   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksEvent_free);
381 
382 #ifdef __ANDROID__
383   nnapi->ASharedMemory_create = getASharedMemory_create();
384 #else
385   nnapi->ASharedMemory_create = ASharedMemory_create;
386 #endif  // __ANDROID__
387 
388   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworks_getDeviceCount);
389   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworks_getDevice);
390   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksDevice_getName);
391   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksDevice_getVersion);
392   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksDevice_getFeatureLevel);
393   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksDevice_getType);
394   ASSIGN_SL_FUNCTION_TO_NNAPI(
395       ANeuralNetworksModel_getSupportedOperationsForDevices);
396   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksCompilation_createForDevices);
397   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksCompilation_setCaching);
398   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksCompilation_setTimeout);
399   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksCompilation_setPriority);
400   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_compute);
401   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_setTimeout);
402   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_setLoopTimeout);
403   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_getOutputOperandRank);
404   ASSIGN_SL_FUNCTION_TO_NNAPI(
405       ANeuralNetworksExecution_getOutputOperandDimensions);
406   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksBurst_create);
407   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksBurst_free);
408   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_burstCompute);
409   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemory_createFromAHardwareBuffer);
410   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_setMeasureTiming);
411   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_getDuration);
412   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksDevice_getExtensionSupport);
413   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_getExtensionOperandType);
414   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_getExtensionOperationType);
415   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksModel_setOperandExtensionData);
416 
417   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemoryDesc_create);
418   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemoryDesc_free);
419   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemoryDesc_addInputRole);
420   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemoryDesc_addOutputRole);
421   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemoryDesc_setDimensions);
422   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemoryDesc_finish);
423 
424   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemory_createFromDesc);
425   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksMemory_copy);
426 
427   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksEvent_createFromSyncFenceFd);
428   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksEvent_getSyncFenceFd);
429 
430   ASSIGN_SL_FUNCTION_TO_NNAPI(
431       ANeuralNetworksExecution_startComputeWithDependencies);
432   ASSIGN_SL_FUNCTION_TO_NNAPI(
433       ANeuralNetworksExecution_enableInputAndOutputPadding);
434   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworksExecution_setReusable);
435 
436   ASSIGN_SL_FUNCTION_TO_NNAPI(ANeuralNetworks_getRuntimeFeatureLevel);
437 
438   // There are several functions that are defined in the SL but are not yet used
439   // in the delegate:
440   //   * ANeuralNetworksDevice_wait
441   //   * ANeuralNetworksModel_setOperandValueFromModel
442   //   * ANeuralNetworks_getDefaultLoopTimeout
443   //   * ANeuralNetworks_getMaximumLoopTimeout
444 
445   return nnapi;
446 }
447 
NnApiImplementation()448 const NnApi* NnApiImplementation() {
449   static const NnApi nnapi = LoadNnApi();
450   return &nnapi;
451 }
452