mirror of
https://github.com/android/ndk-samples
synced 2025-11-06 15:35:36 +08:00
Workaround permission issue when loading NNAPI model from asset file. (#804)
This commit is contained in:
@@ -44,15 +44,8 @@ Java_com_example_android_basic_MainActivity_initModel(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
env->ReleaseStringUTFChars(_assetName, assetName);
|
env->ReleaseStringUTFChars(_assetName, assetName);
|
||||||
off_t offset, length;
|
SimpleModel* nn_model = new SimpleModel(asset);
|
||||||
int fd = AAsset_openFileDescriptor(asset, &offset, &length);
|
|
||||||
AAsset_close(asset);
|
AAsset_close(asset);
|
||||||
if (fd < 0) {
|
|
||||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
|
||||||
"Failed to open the model_data file descriptor.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
SimpleModel* nn_model = new SimpleModel(length, PROT_READ, fd, offset);
|
|
||||||
if (!nn_model->CreateCompiledModel()) {
|
if (!nn_model->CreateCompiledModel()) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
||||||
"Failed to prepare the model.");
|
"Failed to prepare the model.");
|
||||||
|
|||||||
@@ -15,41 +15,81 @@
|
|||||||
*/
|
*/
|
||||||
#include "simple_model.h"
|
#include "simple_model.h"
|
||||||
|
|
||||||
|
#include <android/asset_manager_jni.h>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#include <android/sharedmem.h>
|
#include <android/sharedmem.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Create ANeuralNetworksMemory from an asset file.
|
||||||
|
//
|
||||||
|
// Note that, at API level 30 or earlier, the NNAPI drivers may not have the permission to
|
||||||
|
// access the asset file. To work around this issue, here we will:
|
||||||
|
// 1. Allocate a large-enough shared memory to hold the model data;
|
||||||
|
// 2. Copy the asset file to the shared memory;
|
||||||
|
// 3. Create the NNAPI memory with the file descriptor of the shared memory.
|
||||||
|
ANeuralNetworksMemory *createMemoryFromAsset(AAsset *asset) {
|
||||||
|
// Allocate a large-enough shared memory to hold the model data.
|
||||||
|
off_t length = AAsset_getLength(asset);
|
||||||
|
int fd = ASharedMemory_create("model_data", length);
|
||||||
|
if (fd < 0) {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
||||||
|
"ASharedMemory_create failed with size %d", length);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the asset file to the shared memory.
|
||||||
|
void *data = mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (data == nullptr) {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to map a shared memory");
|
||||||
|
close(fd);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
AAsset_read(asset, data, length);
|
||||||
|
munmap(data, length);
|
||||||
|
|
||||||
|
// Create the NNAPI memory with the file descriptor of the shared memory.
|
||||||
|
ANeuralNetworksMemory *memory;
|
||||||
|
int status = ANeuralNetworksMemory_createFromFd(length, PROT_READ | PROT_WRITE, fd, 0,
|
||||||
|
&memory);
|
||||||
|
|
||||||
|
// It is safe to close the file descriptor here because ANeuralNetworksMemory_createFromFd
|
||||||
|
// will create a dup.
|
||||||
|
close(fd);
|
||||||
|
if (status != ANEURALNETWORKS_NO_ERROR) {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
||||||
|
"ANeuralNetworksMemory_createFromFd failed for trained weights");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SimpleModel Constructor.
|
* SimpleModel Constructor.
|
||||||
*
|
*
|
||||||
* Initialize the member variables, including the shared memory objects.
|
* Initialize the member variables, including the shared memory objects.
|
||||||
*/
|
*/
|
||||||
SimpleModel::SimpleModel(size_t size, int protect, int fd, size_t offset) :
|
SimpleModel::SimpleModel(AAsset *asset) :
|
||||||
model_(nullptr),
|
model_(nullptr),
|
||||||
compilation_(nullptr),
|
compilation_(nullptr),
|
||||||
dimLength_(TENSOR_SIZE),
|
dimLength_(TENSOR_SIZE) {
|
||||||
offset_(offset),
|
|
||||||
modelDataFd_(fd) {
|
|
||||||
tensorSize_ = dimLength_;
|
tensorSize_ = dimLength_;
|
||||||
inputTensor1_.resize(tensorSize_);
|
inputTensor1_.resize(tensorSize_);
|
||||||
|
|
||||||
// Create ANeuralNetworksMemory from a file containing the trained data.
|
// Create ANeuralNetworksMemory from a file containing the trained data.
|
||||||
int32_t status = ANeuralNetworksMemory_createFromFd(size + offset, protect, fd, 0,
|
memoryModel_ = createMemoryFromAsset(asset);
|
||||||
&memoryModel_);
|
|
||||||
if (status != ANEURALNETWORKS_NO_ERROR) {
|
|
||||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
|
||||||
"ANeuralNetworksMemory_createFromFd failed for trained weights");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create ASharedMemory to hold the data for the second input tensor and output output tensor.
|
// Create ASharedMemory to hold the data for the second input tensor and output output tensor.
|
||||||
inputTensor2Fd_ = ASharedMemory_create("input2", tensorSize_ * sizeof(float));
|
inputTensor2Fd_ = ASharedMemory_create("input2", tensorSize_ * sizeof(float));
|
||||||
outputTensorFd_ = ASharedMemory_create("output", tensorSize_ * sizeof(float));
|
outputTensorFd_ = ASharedMemory_create("output", tensorSize_ * sizeof(float));
|
||||||
|
|
||||||
// Create ANeuralNetworksMemory objects from the corresponding ASharedMemory objects.
|
// Create ANeuralNetworksMemory objects from the corresponding ASharedMemory objects.
|
||||||
status = ANeuralNetworksMemory_createFromFd(tensorSize_ * sizeof(float),
|
int status = ANeuralNetworksMemory_createFromFd(tensorSize_ * sizeof(float),
|
||||||
PROT_READ,
|
PROT_READ,
|
||||||
inputTensor2Fd_, 0,
|
inputTensor2Fd_, 0,
|
||||||
&memoryInput2_);
|
&memoryInput2_);
|
||||||
@@ -179,7 +219,7 @@ bool SimpleModel::CreateCompiledModel() {
|
|||||||
status = ANeuralNetworksModel_setOperandValueFromMemory(model_,
|
status = ANeuralNetworksModel_setOperandValueFromMemory(model_,
|
||||||
tensor0,
|
tensor0,
|
||||||
memoryModel_,
|
memoryModel_,
|
||||||
offset_,
|
0,
|
||||||
tensorSize_ * sizeof(float));
|
tensorSize_ * sizeof(float));
|
||||||
if (status != ANEURALNETWORKS_NO_ERROR) {
|
if (status != ANEURALNETWORKS_NO_ERROR) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
||||||
@@ -210,7 +250,7 @@ bool SimpleModel::CreateCompiledModel() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
status = ANeuralNetworksModel_setOperandValueFromMemory(
|
status = ANeuralNetworksModel_setOperandValueFromMemory(
|
||||||
model_, tensor2, memoryModel_, offset_ + tensorSize_ * sizeof(float),
|
model_, tensor2, memoryModel_, tensorSize_ * sizeof(float),
|
||||||
tensorSize_ * sizeof(float));
|
tensorSize_ * sizeof(float));
|
||||||
if (status != ANEURALNETWORKS_NO_ERROR) {
|
if (status != ANEURALNETWORKS_NO_ERROR) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
|
||||||
@@ -504,5 +544,4 @@ SimpleModel::~SimpleModel() {
|
|||||||
ANeuralNetworksMemory_free(memoryOutput_);
|
ANeuralNetworksMemory_free(memoryOutput_);
|
||||||
close(inputTensor2Fd_);
|
close(inputTensor2Fd_);
|
||||||
close(outputTensorFd_);
|
close(outputTensorFd_);
|
||||||
close(modelDataFd_);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#ifndef NNAPI_SIMPLE_MODEL_H
|
#ifndef NNAPI_SIMPLE_MODEL_H
|
||||||
#define NNAPI_SIMPLE_MODEL_H
|
#define NNAPI_SIMPLE_MODEL_H
|
||||||
|
|
||||||
|
#include <android/asset_manager_jni.h>
|
||||||
#include <android/NeuralNetworks.h>
|
#include <android/NeuralNetworks.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@
|
|||||||
*/
|
*/
|
||||||
class SimpleModel {
|
class SimpleModel {
|
||||||
public:
|
public:
|
||||||
explicit SimpleModel(size_t size, int protect, int fd, size_t offset);
|
explicit SimpleModel(AAsset* asset);
|
||||||
~SimpleModel();
|
~SimpleModel();
|
||||||
|
|
||||||
bool CreateCompiledModel();
|
bool CreateCompiledModel();
|
||||||
@@ -53,10 +54,8 @@ private:
|
|||||||
|
|
||||||
uint32_t dimLength_;
|
uint32_t dimLength_;
|
||||||
uint32_t tensorSize_;
|
uint32_t tensorSize_;
|
||||||
size_t offset_;
|
|
||||||
|
|
||||||
std::vector<float> inputTensor1_;
|
std::vector<float> inputTensor1_;
|
||||||
int modelDataFd_;
|
|
||||||
int inputTensor2Fd_;
|
int inputTensor2Fd_;
|
||||||
int outputTensorFd_;
|
int outputTensorFd_;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user