|
15 | 15 | */
|
16 | 16 | #include "simple_model.h"
|
17 | 17 |
|
| 18 | +#include <android/asset_manager_jni.h> |
18 | 19 | #include <android/log.h>
|
19 | 20 | #include <android/sharedmem.h>
|
20 | 21 | #include <sys/mman.h>
|
21 | 22 | #include <string>
|
22 | 23 | #include <unistd.h>
|
23 | 24 |
|
| 25 | +namespace { |
| 26 | + |
| 27 | +// Create ANeuralNetworksMemory from an asset file. |
| 28 | +// |
| 29 | +// Note that, at API level 30 or earlier, the NNAPI drivers may not have the permission to |
| 30 | +// access the asset file. To work around this issue, here we will: |
| 31 | +// 1. Allocate a large-enough shared memory to hold the model data; |
| 32 | +// 2. Copy the asset file to the shared memory; |
| 33 | +// 3. Create the NNAPI memory with the file descriptor of the shared memory. |
| 34 | +ANeuralNetworksMemory *createMemoryFromAsset(AAsset *asset) { |
| 35 | + // Allocate a large-enough shared memory to hold the model data. |
| 36 | + off_t length = AAsset_getLength(asset); |
| 37 | + int fd = ASharedMemory_create("model_data", length); |
| 38 | + if (fd < 0) { |
| 39 | + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, |
| 40 | + "ASharedMemory_create failed with size %d", length); |
| 41 | + return nullptr; |
| 42 | + } |
| 43 | + |
| 44 | + // Copy the asset file to the shared memory. |
| 45 | + void *data = mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
| 46 | + if (data == nullptr) { |
| 47 | + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to map a shared memory"); |
| 48 | + close(fd); |
| 49 | + return nullptr; |
| 50 | + } |
| 51 | + AAsset_read(asset, data, length); |
| 52 | + munmap(data, length); |
| 53 | + |
| 54 | + // Create the NNAPI memory with the file descriptor of the shared memory. |
| 55 | + ANeuralNetworksMemory *memory; |
| 56 | + int status = ANeuralNetworksMemory_createFromFd(length, PROT_READ | PROT_WRITE, fd, 0, |
| 57 | + &memory); |
| 58 | + |
| 59 | + // It is safe to close the file descriptor here because ANeuralNetworksMemory_createFromFd |
| 60 | + // will create a dup. |
| 61 | + close(fd); |
| 62 | + if (status != ANEURALNETWORKS_NO_ERROR) { |
| 63 | + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, |
| 64 | + "ANeuralNetworksMemory_createFromFd failed for trained weights"); |
| 65 | + return nullptr; |
| 66 | + } |
| 67 | + return memory; |
| 68 | +} |
| 69 | + |
| 70 | +} // namespace |
| 71 | + |
24 | 72 | /**
|
25 | 73 | * SimpleModel Constructor.
|
26 | 74 | *
|
27 | 75 | * Initialize the member variables, including the shared memory objects.
|
28 | 76 | */
|
29 |
| -SimpleModel::SimpleModel(size_t size, int protect, int fd, size_t offset) : |
| 77 | +SimpleModel::SimpleModel(AAsset *asset) : |
30 | 78 | model_(nullptr),
|
31 | 79 | compilation_(nullptr),
|
32 |
| - dimLength_(TENSOR_SIZE), |
33 |
| - offset_(offset), |
34 |
| - modelDataFd_(fd) { |
| 80 | + dimLength_(TENSOR_SIZE) { |
35 | 81 | tensorSize_ = dimLength_;
|
36 | 82 | inputTensor1_.resize(tensorSize_);
|
37 | 83 |
|
38 | 84 | // Create ANeuralNetworksMemory from a file containing the trained data.
|
39 |
| - int32_t status = ANeuralNetworksMemory_createFromFd(size + offset, protect, fd, 0, |
40 |
| - &memoryModel_); |
41 |
| - if (status != ANEURALNETWORKS_NO_ERROR) { |
42 |
| - __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, |
43 |
| - "ANeuralNetworksMemory_createFromFd failed for trained weights"); |
44 |
| - return; |
45 |
| - } |
| 85 | + memoryModel_ = createMemoryFromAsset(asset); |
46 | 86 |
|
47 | 87 | // Create ASharedMemory to hold the data for the second input tensor and output output tensor.
|
48 | 88 | inputTensor2Fd_ = ASharedMemory_create("input2", tensorSize_ * sizeof(float));
|
49 | 89 | outputTensorFd_ = ASharedMemory_create("output", tensorSize_ * sizeof(float));
|
50 | 90 |
|
51 | 91 | // Create ANeuralNetworksMemory objects from the corresponding ASharedMemory objects.
|
52 |
| - status = ANeuralNetworksMemory_createFromFd(tensorSize_ * sizeof(float), |
53 |
| - PROT_READ, |
54 |
| - inputTensor2Fd_, 0, |
55 |
| - &memoryInput2_); |
| 92 | + int status = ANeuralNetworksMemory_createFromFd(tensorSize_ * sizeof(float), |
| 93 | + PROT_READ, |
| 94 | + inputTensor2Fd_, 0, |
| 95 | + &memoryInput2_); |
56 | 96 | if (status != ANEURALNETWORKS_NO_ERROR) {
|
57 | 97 | __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
58 | 98 | "ANeuralNetworksMemory_createFromFd failed for Input2");
|
@@ -179,7 +219,7 @@ bool SimpleModel::CreateCompiledModel() {
|
179 | 219 | status = ANeuralNetworksModel_setOperandValueFromMemory(model_,
|
180 | 220 | tensor0,
|
181 | 221 | memoryModel_,
|
182 |
| - offset_, |
| 222 | + 0, |
183 | 223 | tensorSize_ * sizeof(float));
|
184 | 224 | if (status != ANEURALNETWORKS_NO_ERROR) {
|
185 | 225 | __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
@@ -210,7 +250,7 @@ bool SimpleModel::CreateCompiledModel() {
|
210 | 250 | return false;
|
211 | 251 | }
|
212 | 252 | status = ANeuralNetworksModel_setOperandValueFromMemory(
|
213 |
| - model_, tensor2, memoryModel_, offset_ + tensorSize_ * sizeof(float), |
| 253 | + model_, tensor2, memoryModel_, tensorSize_ * sizeof(float), |
214 | 254 | tensorSize_ * sizeof(float));
|
215 | 255 | if (status != ANEURALNETWORKS_NO_ERROR) {
|
216 | 256 | __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
@@ -504,5 +544,4 @@ SimpleModel::~SimpleModel() {
|
504 | 544 | ANeuralNetworksMemory_free(memoryOutput_);
|
505 | 545 | close(inputTensor2Fd_);
|
506 | 546 | close(outputTensorFd_);
|
507 |
| - close(modelDataFd_); |
508 | 547 | }
|
0 commit comments