1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // Provides C++ classes to more easily use the Neural Networks API.
18 // TODO(b/117845862): this should be auto generated from NeuralNetworksWrapper.h.
19 
20 #ifndef ANDROID_PACKAGES_MODULES_NEURALNETWORKS_SL_SUPPORT_LIBRARY_WRAPPER_H
21 #define ANDROID_PACKAGES_MODULES_NEURALNETWORKS_SL_SUPPORT_LIBRARY_WRAPPER_H
22 
23 #include <android-base/unique_fd.h>
24 #include <android/hardware_buffer.h>
25 #include <math.h>
26 #include <unistd.h>
27 
28 #include <algorithm>
29 #include <memory>
30 #include <optional>
31 #include <string>
32 #include <utility>
33 #include <vector>
34 
35 #include "NeuralNetworksWrapper.h"
36 #include "SupportLibrary.h"
37 
38 using namespace ::android::nn::wrapper;
39 
40 namespace android {
41 namespace nn {
42 namespace sl_wrapper {
43 
44 using ::android::nn::wrapper::Duration;
45 using ::android::nn::wrapper::OperandType;
46 using ::android::nn::wrapper::Result;
47 
48 class Memory {
49    public:
50     // Takes ownership of a ANeuralNetworksMemory
Memory(const NnApiSupportLibrary * nnapi,ANeuralNetworksMemory * memory)51     Memory(const NnApiSupportLibrary* nnapi, ANeuralNetworksMemory* memory)
52         : mNnApi(nnapi), mMemory(memory), mSize(0) {}
53 
54     // Create from a FD and may takes ownership of the fd.
55     Memory(const NnApiSupportLibrary* nnapi, size_t size, int protect, int fd, size_t offset,
56            bool ownsFd = false)
mNnApi(nnapi)57         : mNnApi(nnapi), mOwnedFd(ownsFd ? std::optional<int>{fd} : std::nullopt), mSize(size) {
58         mValid = mNnApi->getFL5()->ANeuralNetworksMemory_createFromFd(
59                          size, protect, fd, offset, &mMemory) == ANEURALNETWORKS_NO_ERROR;
60     }
61 
62     // Create from a buffer, may take ownership.
Memory(const NnApiSupportLibrary * nnapi,AHardwareBuffer * buffer,bool ownAHWB,size_t size)63     Memory(const NnApiSupportLibrary* nnapi, AHardwareBuffer* buffer, bool ownAHWB, size_t size)
64         : mNnApi(nnapi), mOwnedAHWB(ownAHWB ? buffer : nullptr), mSize(size) {
65         mValid = mNnApi->getFL5()->ANeuralNetworksMemory_createFromAHardwareBuffer(
66                          buffer, &mMemory) == ANEURALNETWORKS_NO_ERROR;
67     }
68 
69     // Create from a desc
Memory(const NnApiSupportLibrary * nnapi,ANeuralNetworksMemoryDesc * desc,size_t size)70     Memory(const NnApiSupportLibrary* nnapi, ANeuralNetworksMemoryDesc* desc, size_t size)
71         : mNnApi(nnapi), mSize(size) {
72         mValid = mNnApi->getFL5()->ANeuralNetworksMemory_createFromDesc(desc, &mMemory) ==
73                  ANEURALNETWORKS_NO_ERROR;
74     }
75 
~Memory()76     virtual ~Memory() {
77         if (mMemory) {
78             mNnApi->getFL5()->ANeuralNetworksMemory_free(mMemory);
79         }
80         if (mOwnedFd) {
81             close(*mOwnedFd);
82         }
83         if (mOwnedAHWB) {
84             AHardwareBuffer_release(mOwnedAHWB);
85         }
86     }
87 
88     // Disallow copy semantics to ensure the runtime object can only be freed
89     // once. Copy semantics could be enabled if some sort of reference counting
90     // or deep-copy system for runtime objects is added later.
91     Memory(const Memory&) = delete;
92     Memory& operator=(const Memory&) = delete;
93 
94     // Move semantics to remove access to the runtime object from the wrapper
95     // object that is being moved. This ensures the runtime object will be
96     // freed only once.
Memory(Memory && other)97     Memory(Memory&& other) { *this = std::move(other); }
98     Memory& operator=(Memory&& other) {
99         if (this != &other) {
100             if (mMemory) {
101                 mNnApi->getFL5()->ANeuralNetworksMemory_free(mMemory);
102             }
103             if (mOwnedFd) {
104                 close(*mOwnedFd);
105             }
106             if (mOwnedAHWB) {
107                 AHardwareBuffer_release(mOwnedAHWB);
108             }
109 
110             mMemory = other.mMemory;
111             mValid = other.mValid;
112             mNnApi = other.mNnApi;
113             mOwnedFd = other.mOwnedFd;
114             mOwnedAHWB = other.mOwnedAHWB;
115             other.mMemory = nullptr;
116             other.mValid = false;
117             other.mOwnedFd.reset();
118             other.mOwnedAHWB = nullptr;
119         }
120         return *this;
121     }
122 
get()123     ANeuralNetworksMemory* get() const { return mMemory; }
isValid()124     bool isValid() const { return mValid; }
getSize()125     size_t getSize() const { return mSize; }
copyTo(Memory & other)126     Result copyTo(Memory& other) {
127         return static_cast<Result>(
128                 mNnApi->getFL5()->ANeuralNetworksMemory_copy(mMemory, other.mMemory));
129     }
130 
131    private:
132     const NnApiSupportLibrary* mNnApi = nullptr;
133     ANeuralNetworksMemory* mMemory = nullptr;
134     bool mValid = true;
135     std::optional<int> mOwnedFd;
136     AHardwareBuffer* mOwnedAHWB = nullptr;
137     size_t mSize;
138 };
139 
140 class Model {
141    public:
Model(const NnApiSupportLibrary * nnapi)142     Model(const NnApiSupportLibrary* nnapi) : mNnApi(nnapi) {
143         mValid = mNnApi->getFL5()->ANeuralNetworksModel_create(&mModel) == ANEURALNETWORKS_NO_ERROR;
144     }
~Model()145     ~Model() {
146         if (mModel) {
147             mNnApi->getFL5()->ANeuralNetworksModel_free(mModel);
148         }
149     }
150 
151     // Disallow copy semantics to ensure the runtime object can only be freed
152     // once. Copy semantics could be enabled if some sort of reference counting
153     // or deep-copy system for runtime objects is added later.
154     Model(const Model&) = delete;
155     Model& operator=(const Model&) = delete;
156 
157     // Move semantics to remove access to the runtime object from the wrapper
158     // object that is being moved. This ensures the runtime object will be
159     // freed only once.
Model(Model && other)160     Model(Model&& other) { *this = std::move(other); }
161     Model& operator=(Model&& other) {
162         if (this != &other) {
163             if (mModel != nullptr) {
164                 mNnApi->getFL5()->ANeuralNetworksModel_free(mModel);
165             }
166             mNnApi = other.mNnApi;
167             mModel = other.mModel;
168             mNextOperandId = other.mNextOperandId;
169             mValid = other.mValid;
170             mRelaxed = other.mRelaxed;
171             mFinished = other.mFinished;
172             mOperands = std::move(other.mOperands);
173             mInputs = std::move(other.mInputs);
174             mOutputs = std::move(other.mOutputs);
175             other.mModel = nullptr;
176             other.mNextOperandId = 0;
177             other.mValid = false;
178             other.mRelaxed = false;
179             other.mFinished = false;
180         }
181         return *this;
182     }
183 
finish()184     Result finish() {
185         if (mValid) {
186             auto result =
187                     static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksModel_finish(mModel));
188             if (result != Result::NO_ERROR) {
189                 mValid = false;
190             }
191             mFinished = true;
192             return result;
193         } else {
194             return Result::BAD_STATE;
195         }
196     }
197 
addOperand(const OperandType * type)198     uint32_t addOperand(const OperandType* type) {
199         if (mNnApi->getFL5()->ANeuralNetworksModel_addOperand(mModel, &type->operandType) !=
200             ANEURALNETWORKS_NO_ERROR) {
201             mValid = false;
202         } else {
203             mOperands.push_back(*type);
204         }
205 
206         if (type->channelQuant) {
207             if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(
208                         mModel, mNextOperandId, &type->channelQuant.value().params) !=
209                 ANEURALNETWORKS_NO_ERROR) {
210                 mValid = false;
211             }
212         }
213 
214         return mNextOperandId++;
215     }
216 
217     template <typename T>
addConstantOperand(const OperandType * type,const T & value)218     uint32_t addConstantOperand(const OperandType* type, const T& value) {
219         static_assert(sizeof(T) <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES,
220                       "Values larger than ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES "
221                       "not supported");
222         uint32_t index = addOperand(type);
223         setOperandValue(index, &value);
224         return index;
225     }
226 
addModelOperand(const Model * value)227     uint32_t addModelOperand(const Model* value) {
228         OperandType operandType(Type::MODEL, {});
229         uint32_t operand = addOperand(&operandType);
230         setOperandValueFromModel(operand, value);
231         return operand;
232     }
233 
setOperandValue(uint32_t index,const void * buffer,size_t length)234     void setOperandValue(uint32_t index, const void* buffer, size_t length) {
235         if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandValue(mModel, index, buffer, length) !=
236             ANEURALNETWORKS_NO_ERROR) {
237             mValid = false;
238         }
239     }
240 
241     template <typename T>
setOperandValue(uint32_t index,const T * value)242     void setOperandValue(uint32_t index, const T* value) {
243         static_assert(!std::is_pointer<T>(), "No operand may have a pointer as its value");
244         return setOperandValue(index, value, sizeof(T));
245     }
246 
setOperandValueFromMemory(uint32_t index,const Memory * memory,uint32_t offset,size_t length)247     void setOperandValueFromMemory(uint32_t index, const Memory* memory, uint32_t offset,
248                                    size_t length) {
249         if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandValueFromMemory(
250                     mModel, index, memory->get(), offset, length) != ANEURALNETWORKS_NO_ERROR) {
251             mValid = false;
252         }
253     }
254 
setOperandValueFromModel(uint32_t index,const Model * value)255     void setOperandValueFromModel(uint32_t index, const Model* value) {
256         if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandValueFromModel(
257                     mModel, index, value->mModel) != ANEURALNETWORKS_NO_ERROR) {
258             mValid = false;
259         }
260     }
261 
setOperandValueFromModel(uint32_t index,ANeuralNetworksModel * value)262     void setOperandValueFromModel(uint32_t index, ANeuralNetworksModel* value) {
263         if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandValueFromModel(mModel, index, value) !=
264             ANEURALNETWORKS_NO_ERROR) {
265             mValid = false;
266         }
267     }
268 
addOperation(ANeuralNetworksOperationType type,const std::vector<uint32_t> & inputs,const std::vector<uint32_t> & outputs)269     void addOperation(ANeuralNetworksOperationType type, const std::vector<uint32_t>& inputs,
270                       const std::vector<uint32_t>& outputs) {
271         if (mNnApi->getFL5()->ANeuralNetworksModel_addOperation(
272                     mModel, type, static_cast<uint32_t>(inputs.size()), inputs.data(),
273                     static_cast<uint32_t>(outputs.size()),
274                     outputs.data()) != ANEURALNETWORKS_NO_ERROR) {
275             mValid = false;
276         }
277     }
identifyInputsAndOutputs(const std::vector<uint32_t> & inputs,const std::vector<uint32_t> & outputs)278     void identifyInputsAndOutputs(const std::vector<uint32_t>& inputs,
279                                   const std::vector<uint32_t>& outputs) {
280         if (mNnApi->getFL5()->ANeuralNetworksModel_identifyInputsAndOutputs(
281                     mModel, static_cast<uint32_t>(inputs.size()), inputs.data(),
282                     static_cast<uint32_t>(outputs.size()),
283                     outputs.data()) != ANEURALNETWORKS_NO_ERROR) {
284             mValid = false;
285         } else {
286             mInputs = inputs;
287             mOutputs = outputs;
288         }
289     }
290 
relaxComputationFloat32toFloat16(bool isRelax)291     void relaxComputationFloat32toFloat16(bool isRelax) {
292         if (mNnApi->getFL5()->ANeuralNetworksModel_relaxComputationFloat32toFloat16(
293                     mModel, isRelax) == ANEURALNETWORKS_NO_ERROR) {
294             mRelaxed = isRelax;
295         }
296     }
297 
getExtensionOperandType(const std::string & extensionName,uint16_t operandCodeWithinExtension,int32_t * type)298     void getExtensionOperandType(const std::string& extensionName,
299                                  uint16_t operandCodeWithinExtension, int32_t* type) {
300         if (mNnApi->getFL5()->ANeuralNetworksModel_getExtensionOperandType(
301                     mModel, extensionName.c_str(), operandCodeWithinExtension, type) !=
302             ANEURALNETWORKS_NO_ERROR) {
303             mValid = false;
304         }
305     }
306 
getExtensionOperationType(const std::string & extensionName,uint16_t operandCodeWithinExtension,ANeuralNetworksOperationType * type)307     void getExtensionOperationType(const std::string& extensionName,
308                                    uint16_t operandCodeWithinExtension,
309                                    ANeuralNetworksOperationType* type) {
310         if (mNnApi->getFL5()->ANeuralNetworksModel_getExtensionOperationType(
311                     mModel, extensionName.c_str(), operandCodeWithinExtension, type) !=
312             ANEURALNETWORKS_NO_ERROR) {
313             mValid = false;
314         }
315     }
316 
setOperandExtensionData(int32_t operandId,const void * data,size_t length)317     void setOperandExtensionData(int32_t operandId, const void* data, size_t length) {
318         if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandExtensionData(
319                     mModel, operandId, data, length) != ANEURALNETWORKS_NO_ERROR) {
320             mValid = false;
321         }
322     }
323 
getHandle()324     ANeuralNetworksModel* getHandle() const { return mModel; }
isValid()325     bool isValid() const { return mValid; }
isRelaxed()326     bool isRelaxed() const { return mRelaxed; }
isFinished()327     bool isFinished() const { return mFinished; }
328 
getInputs()329     const std::vector<uint32_t>& getInputs() const { return mInputs; }
getOutputs()330     const std::vector<uint32_t>& getOutputs() const { return mOutputs; }
getOperands()331     const std::vector<OperandType>& getOperands() const { return mOperands; }
332 
333    protected:
334     const NnApiSupportLibrary* mNnApi = nullptr;
335     ANeuralNetworksModel* mModel = nullptr;
336     // We keep track of the operand ID as a convenience to the caller.
337     uint32_t mNextOperandId = 0;
338     // We keep track of the operand datatypes/dimensions as a convenience to the caller.
339     std::vector<OperandType> mOperands;
340     std::vector<uint32_t> mInputs;
341     std::vector<uint32_t> mOutputs;
342     bool mValid = true;
343     bool mRelaxed = false;
344     bool mFinished = false;
345 };
346 
347 class Compilation {
348    public:
349     // On success, createForDevice(s) will return Result::NO_ERROR and the created compilation;
350     // otherwise, it will return the error code and Compilation object wrapping a nullptr handle.
createForDevice(const NnApiSupportLibrary * nnapi,const Model * model,const ANeuralNetworksDevice * device)351     static std::pair<Result, Compilation> createForDevice(const NnApiSupportLibrary* nnapi,
352                                                           const Model* model,
353                                                           const ANeuralNetworksDevice* device) {
354         return createForDevices(nnapi, model, {device});
355     }
createForDevices(const NnApiSupportLibrary * nnapi,const Model * model,const std::vector<const ANeuralNetworksDevice * > & devices)356     static std::pair<Result, Compilation> createForDevices(
357             const NnApiSupportLibrary* nnapi, const Model* model,
358             const std::vector<const ANeuralNetworksDevice*>& devices) {
359         ANeuralNetworksCompilation* compilation = nullptr;
360         const Result result =
361                 static_cast<Result>(nnapi->getFL5()->ANeuralNetworksCompilation_createForDevices(
362                         model->getHandle(), devices.empty() ? nullptr : devices.data(),
363                         devices.size(), &compilation));
364         return {result, Compilation(nnapi, compilation)};
365     }
366 
~Compilation()367     ~Compilation() { mNnApi->getFL5()->ANeuralNetworksCompilation_free(mCompilation); }
368 
369     // Disallow copy semantics to ensure the runtime object can only be freed
370     // once. Copy semantics could be enabled if some sort of reference counting
371     // or deep-copy system for runtime objects is added later.
372     Compilation(const Compilation&) = delete;
373     Compilation& operator=(const Compilation&) = delete;
374 
375     // Move semantics to remove access to the runtime object from the wrapper
376     // object that is being moved. This ensures the runtime object will be
377     // freed only once.
Compilation(Compilation && other)378     Compilation(Compilation&& other) { *this = std::move(other); }
379     Compilation& operator=(Compilation&& other) {
380         if (this != &other) {
381             mNnApi = other.mNnApi;
382             mNnApi->getFL5()->ANeuralNetworksCompilation_free(mCompilation);
383             mCompilation = other.mCompilation;
384             other.mCompilation = nullptr;
385         }
386         return *this;
387     }
388 
setPreference(ExecutePreference preference)389     Result setPreference(ExecutePreference preference) {
390         return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksCompilation_setPreference(
391                 mCompilation, static_cast<int32_t>(preference)));
392     }
393 
setPriority(ExecutePriority priority)394     Result setPriority(ExecutePriority priority) {
395         return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksCompilation_setPriority(
396                 mCompilation, static_cast<int32_t>(priority)));
397     }
398 
setTimeout(uint64_t durationNs)399     Result setTimeout(uint64_t durationNs) {
400         return static_cast<Result>(
401                 mNnApi->getFL5()->ANeuralNetworksCompilation_setTimeout(mCompilation, durationNs));
402     }
403 
setCaching(const std::string & cacheDir,const std::vector<uint8_t> & token)404     Result setCaching(const std::string& cacheDir, const std::vector<uint8_t>& token) {
405         if (token.size() != ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN) {
406             return Result::BAD_DATA;
407         }
408         return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksCompilation_setCaching(
409                 mCompilation, cacheDir.c_str(), token.data()));
410     }
411 
setCachingFromFds(const std::vector<int> & modelCacheFds,const std::vector<int> & dataCacheFds,const std::vector<uint8_t> & token)412     Result setCachingFromFds(const std::vector<int>& modelCacheFds,
413                              const std::vector<int>& dataCacheFds,
414                              const std::vector<uint8_t>& token) {
415         if (token.size() != ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN) {
416             return Result::BAD_DATA;
417         }
418         return static_cast<Result>(
419                 mNnApi->getFL5()->SL_ANeuralNetworksCompilation_setCachingFromFds(
420                         mCompilation, modelCacheFds.data(), modelCacheFds.size(),
421                         dataCacheFds.data(), dataCacheFds.size(), token.data()));
422     }
423 
setCachingFromFds(const std::vector<base::unique_fd> & modelCacheOwnedFds,const std::vector<base::unique_fd> & dataCacheOwnedFds,const std::vector<uint8_t> & token)424     Result setCachingFromFds(const std::vector<base::unique_fd>& modelCacheOwnedFds,
425                              const std::vector<base::unique_fd>& dataCacheOwnedFds,
426                              const std::vector<uint8_t>& token) {
427         std::vector<int> modelCacheFds, dataCacheFds;
428         for (const auto& fd : modelCacheOwnedFds) {
429             modelCacheFds.push_back(fd.get());
430         }
431         for (const auto& fd : dataCacheOwnedFds) {
432             dataCacheFds.push_back(fd.get());
433         }
434         return setCachingFromFds(modelCacheFds, dataCacheFds, token);
435     }
436 
finish()437     Result finish() {
438         return static_cast<Result>(
439                 mNnApi->getFL5()->ANeuralNetworksCompilation_finish(mCompilation));
440     }
441 
getPreferredMemoryAlignmentForInput(uint32_t index,uint32_t * alignment)442     Result getPreferredMemoryAlignmentForInput(uint32_t index, uint32_t* alignment) const {
443         return static_cast<Result>(
444                 mNnApi->getFL5()->ANeuralNetworksCompilation_getPreferredMemoryAlignmentForInput(
445                         mCompilation, index, alignment));
446     };
447 
getPreferredMemoryPaddingForInput(uint32_t index,uint32_t * padding)448     Result getPreferredMemoryPaddingForInput(uint32_t index, uint32_t* padding) const {
449         return static_cast<Result>(
450                 mNnApi->getFL5()->ANeuralNetworksCompilation_getPreferredMemoryPaddingForInput(
451                         mCompilation, index, padding));
452     };
453 
getPreferredMemoryAlignmentForOutput(uint32_t index,uint32_t * alignment)454     Result getPreferredMemoryAlignmentForOutput(uint32_t index, uint32_t* alignment) const {
455         return static_cast<Result>(
456                 mNnApi->getFL5()->ANeuralNetworksCompilation_getPreferredMemoryAlignmentForOutput(
457                         mCompilation, index, alignment));
458     };
459 
getPreferredMemoryPaddingForOutput(uint32_t index,uint32_t * padding)460     Result getPreferredMemoryPaddingForOutput(uint32_t index, uint32_t* padding) const {
461         return static_cast<Result>(
462                 mNnApi->getFL5()->ANeuralNetworksCompilation_getPreferredMemoryPaddingForOutput(
463                         mCompilation, index, padding));
464     };
465 
addExtensionAttribute(const std::string & extensionName,uint16_t attributeCodeWithinExtension,const std::vector<uint8_t> & extensionAttributeData)466     Result addExtensionAttribute(const std::string& extensionName,
467                                  uint16_t attributeCodeWithinExtension,
468                                  const std::vector<uint8_t>& extensionAttributeData) {
469         return static_cast<Result>(
470                 mNnApi->getFL8()->ANeuralNetworksCompilation_addExtensionAttribute(
471                         mCompilation, extensionName.c_str(), attributeCodeWithinExtension,
472                         extensionAttributeData.data(), extensionAttributeData.size()));
473     }
474 
getHandle()475     ANeuralNetworksCompilation* getHandle() const { return mCompilation; }
476 
477    protected:
478     // Takes the ownership of ANeuralNetworksCompilation.
Compilation(const NnApiSupportLibrary * nnapi,ANeuralNetworksCompilation * compilation)479     Compilation(const NnApiSupportLibrary* nnapi, ANeuralNetworksCompilation* compilation)
480         : mNnApi(nnapi), mCompilation(compilation) {}
481 
482     const NnApiSupportLibrary* mNnApi = nullptr;
483     ANeuralNetworksCompilation* mCompilation = nullptr;
484 };
485 
486 class Execution {
487    public:
Execution(const NnApiSupportLibrary * nnapi,const Compilation * compilation)488     Execution(const NnApiSupportLibrary* nnapi, const Compilation* compilation)
489         : mNnApi(nnapi), mCompilation(compilation->getHandle()) {
490         int result = mNnApi->getFL5()->ANeuralNetworksExecution_create(compilation->getHandle(),
491                                                                        &mExecution);
492         if (result != 0) {
493             // TODO Handle the error
494         }
495     }
496 
~Execution()497     ~Execution() {
498         if (mExecution) {
499             mNnApi->getFL5()->ANeuralNetworksExecution_free(mExecution);
500         }
501     }
502 
503     // Disallow copy semantics to ensure the runtime object can only be freed
504     // once. Copy semantics could be enabled if some sort of reference counting
505     // or deep-copy system for runtime objects is added later.
506     Execution(const Execution&) = delete;
507     Execution& operator=(const Execution&) = delete;
508 
509     // Move semantics to remove access to the runtime object from the wrapper
510     // object that is being moved. This ensures the runtime object will be
511     // freed only once.
Execution(Execution && other)512     Execution(Execution&& other) { *this = std::move(other); }
513     Execution& operator=(Execution&& other) {
514         if (this != &other) {
515             if (mExecution != nullptr) {
516                 mNnApi->getFL5()->ANeuralNetworksExecution_free(mExecution);
517             }
518             mNnApi = other.mNnApi;
519             mCompilation = other.mCompilation;
520             mExecution = other.mExecution;
521             other.mCompilation = nullptr;
522             other.mExecution = nullptr;
523         }
524         return *this;
525     }
526 
527     Result setInput(uint32_t index, const void* buffer, size_t length,
528                     const ANeuralNetworksOperandType* type = nullptr) {
529         return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_setInput(
530                 mExecution, index, type, buffer, length));
531     }
532 
533     template <typename T>
534     Result setInput(uint32_t index, const T* value,
535                     const ANeuralNetworksOperandType* type = nullptr) {
536         static_assert(!std::is_pointer<T>(), "No operand may have a pointer as its value");
537         return setInput(index, value, sizeof(T), type);
538     }
539 
540     Result setInputFromMemory(uint32_t index, const Memory* memory, uint32_t offset,
541                               uint32_t length, const ANeuralNetworksOperandType* type = nullptr) {
542         return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_setInputFromMemory(
543                 mExecution, index, type, memory->get(), offset, length));
544     }
545 
546     Result setOutput(uint32_t index, void* buffer, size_t length,
547                      const ANeuralNetworksOperandType* type = nullptr) {
548         return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_setOutput(
549                 mExecution, index, type, buffer, length));
550     }
551 
552     template <typename T>
553     Result setOutput(uint32_t index, T* value, const ANeuralNetworksOperandType* type = nullptr) {
554         static_assert(!std::is_pointer<T>(), "No operand may have a pointer as its value");
555         return setOutput(index, value, sizeof(T), type);
556     }
557 
558     Result setOutputFromMemory(uint32_t index, const Memory* memory, uint32_t offset,
559                                uint32_t length, const ANeuralNetworksOperandType* type = nullptr) {
560         return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_setOutputFromMemory(
561                 mExecution, index, type, memory->get(), offset, length));
562     }
563 
setLoopTimeout(uint64_t duration)564     Result setLoopTimeout(uint64_t duration) {
565         return static_cast<Result>(
566                 mNnApi->getFL5()->ANeuralNetworksExecution_setLoopTimeout(mExecution, duration));
567     }
568 
setMeasureTiming(bool measure)569     Result setMeasureTiming(bool measure) {
570         return static_cast<Result>(
571                 mNnApi->getFL5()->ANeuralNetworksExecution_setMeasureTiming(mExecution, measure));
572     }
573 
setTimeout(uint64_t duration)574     Result setTimeout(uint64_t duration) {
575         return static_cast<Result>(
576                 mNnApi->getFL5()->ANeuralNetworksExecution_setTimeout(mExecution, duration));
577     }
578 
getDuration(Duration durationCode,uint64_t * duration)579     Result getDuration(Duration durationCode, uint64_t* duration) {
580         return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_getDuration(
581                 mExecution, static_cast<int32_t>(durationCode), duration));
582     }
583 
enableInputAndOutputPadding(bool enable)584     Result enableInputAndOutputPadding(bool enable) {
585         return static_cast<Result>(
586                 mNnApi->getFL5()->ANeuralNetworksExecution_enableInputAndOutputPadding(mExecution,
587                                                                                        enable));
588     }
589 
setReusable(bool reusable)590     Result setReusable(bool reusable) {
591         return static_cast<Result>(
592                 mNnApi->getFL5()->ANeuralNetworksExecution_setReusable(mExecution, reusable));
593     }
594 
595     // By default, compute() uses the synchronous API. Either an argument or
596     // setComputeMode() can be used to change the behavior of compute() to
597     // use the burst API
598     // Returns the previous ComputeMode.
599     enum class ComputeMode { SYNC, BURST, FENCED };
setComputeMode(ComputeMode mode)600     static ComputeMode setComputeMode(ComputeMode mode) {
601         ComputeMode oldComputeMode = mComputeMode;
602         mComputeMode = mode;
603         return oldComputeMode;
604     }
getComputeMode()605     static ComputeMode getComputeMode() { return mComputeMode; }
606 
607     Result compute(ComputeMode computeMode = mComputeMode) {
608         switch (computeMode) {
609             case ComputeMode::SYNC: {
610                 return static_cast<Result>(
611                         mNnApi->getFL5()->ANeuralNetworksExecution_compute(mExecution));
612             }
613             case ComputeMode::BURST: {
614                 ANeuralNetworksBurst* burst = nullptr;
615                 Result result = static_cast<Result>(
616                         mNnApi->getFL5()->ANeuralNetworksBurst_create(mCompilation, &burst));
617                 if (result != Result::NO_ERROR) {
618                     return result;
619                 }
620                 result = static_cast<Result>(
621                         mNnApi->getFL5()->ANeuralNetworksExecution_burstCompute(mExecution, burst));
622                 mNnApi->getFL5()->ANeuralNetworksBurst_free(burst);
623                 return result;
624             }
625             case ComputeMode::FENCED: {
626                 ANeuralNetworksEvent* event = nullptr;
627                 Result result = static_cast<Result>(
628                         mNnApi->getFL5()->ANeuralNetworksExecution_startComputeWithDependencies(
629                                 mExecution, nullptr, 0, 0, &event));
630                 if (result != Result::NO_ERROR) {
631                     return result;
632                 }
633                 result = static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksEvent_wait(event));
634                 mNnApi->getFL5()->ANeuralNetworksEvent_free(event);
635                 return result;
636             }
637         }
638         return Result::BAD_DATA;
639     }
640 
startComputeWithDependencies(const std::vector<const ANeuralNetworksEvent * > & deps,uint64_t duration,Event * event)641     Result startComputeWithDependencies(const std::vector<const ANeuralNetworksEvent*>& deps,
642                                         uint64_t duration, Event* event) {
643         ANeuralNetworksEvent* ev = nullptr;
644         Result result = static_cast<Result>(
645                 NNAPI_CALL(ANeuralNetworksExecution_startComputeWithDependencies(
646                         mExecution, deps.data(), deps.size(), duration, &ev)));
647         event->set(ev);
648         return result;
649     }
650 
getOutputOperandDimensions(uint32_t index,std::vector<uint32_t> * dimensions)651     Result getOutputOperandDimensions(uint32_t index, std::vector<uint32_t>* dimensions) {
652         uint32_t rank = 0;
653         Result result =
654                 static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_getOutputOperandRank(
655                         mExecution, index, &rank));
656         dimensions->resize(rank);
657         if ((result != Result::NO_ERROR && result != Result::OUTPUT_INSUFFICIENT_SIZE) ||
658             rank == 0) {
659             return result;
660         }
661         result = static_cast<Result>(
662                 mNnApi->getFL5()->ANeuralNetworksExecution_getOutputOperandDimensions(
663                         mExecution, index, dimensions->data()));
664         return result;
665     }
666 
addExtensionAttribute(const std::string & extensionName,uint16_t attributeCodeWithinExtension,const std::vector<uint8_t> & extensionAttributeData)667     Result addExtensionAttribute(const std::string& extensionName,
668                                  uint16_t attributeCodeWithinExtension,
669                                  const std::vector<uint8_t>& extensionAttributeData) {
670         return static_cast<Result>(mNnApi->getFL8()->ANeuralNetworksExecution_addExtensionAttribute(
671                 mExecution, extensionName.c_str(), attributeCodeWithinExtension,
672                 extensionAttributeData.data(), extensionAttributeData.size()));
673     }
674 
getHandle()675     ANeuralNetworksExecution* getHandle() { return mExecution; };
676 
677    private:
678     const NnApiSupportLibrary* mNnApi = nullptr;
679     ANeuralNetworksCompilation* mCompilation = nullptr;
680     ANeuralNetworksExecution* mExecution = nullptr;
681 
682     // Initialized to ComputeMode::SYNC in TestNeuralNetworksWrapper.cpp.
683     static ComputeMode mComputeMode;
684 };
685 
686 }  // namespace sl_wrapper
687 }  // namespace nn
688 }  // namespace android
689 
690 #endif  // ANDROID_PACKAGES_MODULES_NEURALNETWORKS_SL_SUPPORT_LIBRARY_WRAPPER_H
691