Skip to content

Commit 82d1af2

Browse files
fengpeitianKottsonegithub-actions
authored
Workaround permission issue when loading NNAPI model from asset file. (#804) (#827)
Co-authored-by: Kottsone <xusongw@google.com> Co-authored-by: github-actions <github-actions@github.com>
1 parent f4574a3 commit 82d1af2

File tree

3 files changed

+60
-29
lines changed

3 files changed

+60
-29
lines changed

nn-samples/basic/src/main/cpp/nn_sample.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,8 @@ Java_com_example_android_basic_MainActivity_initModel(
4444
return 0;
4545
}
4646
env->ReleaseStringUTFChars(_assetName, assetName);
47-
off_t offset, length;
48-
int fd = AAsset_openFileDescriptor(asset, &offset, &length);
47+
SimpleModel* nn_model = new SimpleModel(asset);
4948
AAsset_close(asset);
50-
if (fd < 0) {
51-
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
52-
"Failed to open the model_data file descriptor.");
53-
return 0;
54-
}
55-
SimpleModel* nn_model = new SimpleModel(length, PROT_READ, fd, offset);
5649
if (!nn_model->CreateCompiledModel()) {
5750
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
5851
"Failed to prepare the model.");

nn-samples/basic/src/main/cpp/simple_model.cpp

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,84 @@
1515
*/
1616
#include "simple_model.h"
1717

18+
#include <android/asset_manager_jni.h>
1819
#include <android/log.h>
1920
#include <android/sharedmem.h>
2021
#include <sys/mman.h>
2122
#include <string>
2223
#include <unistd.h>
2324

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+
2472
/**
2573
* SimpleModel Constructor.
2674
*
2775
* Initialize the member variables, including the shared memory objects.
2876
*/
29-
SimpleModel::SimpleModel(size_t size, int protect, int fd, size_t offset) :
77+
SimpleModel::SimpleModel(AAsset *asset) :
3078
model_(nullptr),
3179
compilation_(nullptr),
32-
dimLength_(TENSOR_SIZE),
33-
offset_(offset),
34-
modelDataFd_(fd) {
80+
dimLength_(TENSOR_SIZE) {
3581
tensorSize_ = dimLength_;
3682
inputTensor1_.resize(tensorSize_);
3783

3884
// 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);
4686

4787
// Create ASharedMemory to hold the data for the second input tensor and output output tensor.
4888
inputTensor2Fd_ = ASharedMemory_create("input2", tensorSize_ * sizeof(float));
4989
outputTensorFd_ = ASharedMemory_create("output", tensorSize_ * sizeof(float));
5090

5191
// 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_);
5696
if (status != ANEURALNETWORKS_NO_ERROR) {
5797
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
5898
"ANeuralNetworksMemory_createFromFd failed for Input2");
@@ -179,7 +219,7 @@ bool SimpleModel::CreateCompiledModel() {
179219
status = ANeuralNetworksModel_setOperandValueFromMemory(model_,
180220
tensor0,
181221
memoryModel_,
182-
offset_,
222+
0,
183223
tensorSize_ * sizeof(float));
184224
if (status != ANEURALNETWORKS_NO_ERROR) {
185225
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
@@ -210,7 +250,7 @@ bool SimpleModel::CreateCompiledModel() {
210250
return false;
211251
}
212252
status = ANeuralNetworksModel_setOperandValueFromMemory(
213-
model_, tensor2, memoryModel_, offset_ + tensorSize_ * sizeof(float),
253+
model_, tensor2, memoryModel_, tensorSize_ * sizeof(float),
214254
tensorSize_ * sizeof(float));
215255
if (status != ANEURALNETWORKS_NO_ERROR) {
216256
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
@@ -504,5 +544,4 @@ SimpleModel::~SimpleModel() {
504544
ANeuralNetworksMemory_free(memoryOutput_);
505545
close(inputTensor2Fd_);
506546
close(outputTensorFd_);
507-
close(modelDataFd_);
508547
}

nn-samples/basic/src/main/cpp/simple_model.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef NNAPI_SIMPLE_MODEL_H
1818
#define NNAPI_SIMPLE_MODEL_H
1919

20+
#include <android/asset_manager_jni.h>
2021
#include <android/NeuralNetworks.h>
2122
#include <vector>
2223

@@ -38,7 +39,7 @@
3839
*/
3940
class SimpleModel {
4041
public:
41-
explicit SimpleModel(size_t size, int protect, int fd, size_t offset);
42+
explicit SimpleModel(AAsset* asset);
4243
~SimpleModel();
4344

4445
bool CreateCompiledModel();
@@ -53,10 +54,8 @@ class SimpleModel {
5354

5455
uint32_t dimLength_;
5556
uint32_t tensorSize_;
56-
size_t offset_;
5757

5858
std::vector<float> inputTensor1_;
59-
int modelDataFd_;
6059
int inputTensor2Fd_;
6160
int outputTensorFd_;
6261
};

0 commit comments

Comments
 (0)