Merge "Extract DSP NNAPI SL libraries to disk"
diff --git a/Android.mk b/Android.mk
index 51797d8..1e64c39 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,7 +36,7 @@
endif
LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/nn/benchmark)
-LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni $(SL_LIBS)
+LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni libsupport_library_jni $(SL_LIBS)
# need fread_unlocked in version 28
LOCAL_SDK_VERSION := 28
@@ -71,7 +71,7 @@
LOCAL_COMPATIBILITY_SUITE += device-tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni librandom_graph_test_jni $(SL_LIBS)
+LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni libsupport_library_jni librandom_graph_test_jni $(SL_LIBS)
# need fread_unlocked in version 28
LOCAL_SDK_VERSION := 28
diff --git a/crashtest/Android.mk b/crashtest/Android.mk
index 8b93d8b..29aa86e 100644
--- a/crashtest/Android.mk
+++ b/crashtest/Android.mk
@@ -32,7 +32,7 @@
$(call all-java-files-under, ../src/com/android/nn/crashtest/core) \
../src/com/android/nn/benchmark/app/AcceleratorSpecificTestSupport.java
-LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni
+LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni libsupport_library_jni
LOCAL_SDK_VERSION := 27
LOCAL_ASSET_DIR := $(LOCAL_PATH)/../../models/assets
diff --git a/dogfood/Android.mk b/dogfood/Android.mk
index 52d4633..6cd07d8 100644
--- a/dogfood/Android.mk
+++ b/dogfood/Android.mk
@@ -29,7 +29,7 @@
$(call all-java-files-under, ../src/com/android/nn/benchmark/evaluators) \
$(call all-java-files-under, ../src/com/android/nn/benchmark/imageprocessors) \
$(call all-java-files-under, ../src/com/android/nn/benchmark/util)
-LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni
+LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni libsupport_library_jni
LOCAL_SDK_VERSION := 28
LOCAL_ASSET_DIR := $(LOCAL_PATH)/../../models/assets
diff --git a/jni/Android.bp b/jni/Android.bp
index 0be00ec..1dc575c 100644
--- a/jni/Android.bp
+++ b/jni/Android.bp
@@ -97,3 +97,31 @@
keep_symbols: true,
},
}
+
+cc_library {
+ name: "libsupport_library_jni",
+ sdk_version: "current",
+ min_sdk_version: "29",
+ srcs: [
+ "support_library_jni.cpp",
+ ],
+ header_libs: [
+ "flatbuffer_headers",
+ "jni_headers",
+ "tensorflow_headers",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libtflite_static",
+ ],
+ cflags: [
+ "-Wno-sign-compare",
+ "-Wno-unused-parameter",
+ ],
+ stl: "libc++_static",
+ strip: {
+ keep_symbols: true,
+ },
+}
\ No newline at end of file
diff --git a/jni/benchmark_jni.cpp b/jni/benchmark_jni.cpp
index 075aeb2..c4f114a 100644
--- a/jni/benchmark_jni.cpp
+++ b/jni/benchmark_jni.cpp
@@ -26,9 +26,6 @@
#include <android/log.h>
#include <android/sharedmem.h>
#include <sys/mman.h>
-#include "tensorflow/lite/nnapi/nnapi_implementation.h"
-
-#define LOG_TAG "NN_BENCHMARK"
extern "C" JNIEXPORT jboolean JNICALL
Java_com_android_nn_benchmark_core_NNTestBase_hasNnApiDevice(
@@ -104,30 +101,7 @@
return (jlong)(uintptr_t)handle;
}
-// This method loads the NNAPI SL from the given path.
-// Is called by a synchronized method in NNTestBase that will cache the
-// result. We expect this to be called only once per JVM and the handle
-// to be released when the JVM is shut down.
-extern "C" JNIEXPORT jlong JNICALL
-Java_com_android_nn_benchmark_core_NNTestBase_loadNnApiSlHandle(
- JNIEnv *env, jobject /* clazz */, jstring _nnapiSlDriverPath) {
- if (_nnapiSlDriverPath != NULL) {
- const char *nnapiSlDriverPath =
- env->GetStringUTFChars(_nnapiSlDriverPath, NULL);
- std::unique_ptr<const tflite::nnapi::NnApiSupportLibrary> tmp =
- tflite::nnapi::loadNnApiSupportLibrary(nnapiSlDriverPath);
- if (!tmp) {
- __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
- "Failed to load NNAPI SL driver from '%s'",
- nnapiSlDriverPath);
- return false;
- }
- __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Loaded NNAPI SL");
- return (jlong)(uintptr_t)tmp.release();
- }
- return 0l;
-}
extern "C"
JNIEXPORT void
diff --git a/jni/support_library_jni.cpp b/jni/support_library_jni.cpp
new file mode 100644
index 0000000..a8eb1cf
--- /dev/null
+++ b/jni/support_library_jni.cpp
@@ -0,0 +1,55 @@
+/**
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "run_tflite.h"
+
+#include <jni.h>
+#include <string>
+#include <iomanip>
+#include <sstream>
+#include <fcntl.h>
+
+#include <android/log.h>
+
+#include "tensorflow/lite/nnapi/nnapi_implementation.h"
+
+#define LOG_TAG "NN_BENCHMARK"
+
+
+// This method loads the NNAPI SL from the given path.
+// Is called by a synchronized method in NNTestBase that will cache the
+// result. We expect this to be called only once per JVM and the handle
+// to be released when the JVM is shut down.
+extern "C" JNIEXPORT jlong JNICALL
+Java_com_android_nn_benchmark_core_sl_SupportLibraryDriverHandler_loadNnApiSlHandle(
+ JNIEnv *env, jobject /* clazz */, jstring _nnapiSlDriverPath) {
+ if (_nnapiSlDriverPath != NULL) {
+ const char *nnapiSlDriverPath =
+ env->GetStringUTFChars(_nnapiSlDriverPath, NULL);
+ std::unique_ptr<const tflite::nnapi::NnApiSupportLibrary> tmp =
+ tflite::nnapi::loadNnApiSupportLibrary(nnapiSlDriverPath);
+ if (!tmp) {
+ __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+ "Failed to load NNAPI SL driver from '%s'",
+ nnapiSlDriverPath);
+ return false;
+ }
+ __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Loaded NNAPI SL");
+ return (jlong)(uintptr_t)tmp.release();
+ }
+
+ return 0l;
+}
\ No newline at end of file
diff --git a/sl_prebuilt/assets/dsp_loaded_libraries.txt b/sl_prebuilt/assets/dsp_loaded_libraries.txt
new file mode 100644
index 0000000..6c11b96
--- /dev/null
+++ b/sl_prebuilt/assets/dsp_loaded_libraries.txt
@@ -0,0 +1 @@
+libhexagon_nn_skel.so
\ No newline at end of file
diff --git a/src/com/android/nn/benchmark/core/NNTestBase.java b/src/com/android/nn/benchmark/core/NNTestBase.java
index f8454f0..31feea3 100644
--- a/src/com/android/nn/benchmark/core/NNTestBase.java
+++ b/src/com/android/nn/benchmark/core/NNTestBase.java
@@ -20,13 +20,17 @@
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Build;
+import android.system.Os;
+import android.system.ErrnoException;
import android.util.Log;
import android.util.Pair;
import android.widget.TextView;
import androidx.test.InstrumentationRegistry;
+import com.android.nn.benchmark.core.sl.QualcommSupportLibraryDriverHandler;
+import com.android.nn.benchmark.core.sl.SupportLibraryDriverHandler;
import java.io.BufferedReader;
import java.io.File;
-import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -37,7 +41,6 @@
import java.util.List;
import java.util.Optional;
import java.util.Random;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import dalvik.system.BaseDexClassLoader;
import android.content.res.AssetFileDescriptor;
@@ -49,8 +52,6 @@
public class NNTestBase implements AutoCloseable {
protected static final String TAG = "NN_TESTBASE";
- private static final String NNAPI_SL_LIBRARIES_LIST_ASSET_PATH = "sl_prebuilt_filelist.txt";
-
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("nnbenchmark_jni");
@@ -68,103 +69,6 @@
public static native boolean getAcceleratorNames(List<String> resultList);
public static native boolean hasNnApiDevice(String nnApiDeviceName);
- private static native long loadNnApiSlHandle(String nnApiSlPath);
-
- private static long nnapiSlHandle = 0;
- public static synchronized long getOrLoadNnApiSlHandle(Context context, boolean extractNnApiSupportLibrary)
- throws IOException {
- if (nnapiSlHandle == 0) {
- Log.i(TAG, "Initializing NNAPI SL.");
-
- String nnSupportLibFilePath = null;
- Log.i(TAG, "Preparing NNAPI SL");
- if (extractNnApiSupportLibrary) {
- nnSupportLibFilePath = extractAllAndGetNnApiSlPath(context, NNAPI_SL_LIB_NAME);
- } else {
- nnSupportLibFilePath = getNnApiSlPathFromApkLibraries(context, NNAPI_SL_LIB_NAME);
- }
-
- if (nnSupportLibFilePath != null) {
- nnapiSlHandle = loadNnApiSlHandle(nnSupportLibFilePath);
- if (nnapiSlHandle == 0) {
- Log.e(TAG, String
- .format("Unable load NNAPI SL from '%s'.", nnSupportLibFilePath));
- } else {
- Log.i(TAG, String
- .format("Successfully loaded NNAPI SL from '%s'.", nnSupportLibFilePath));
- }
- } else {
- Log.e(TAG, String
- .format("Unable to find NNAPI SL entry point '%s' in embedded libraries path.",
- NNAPI_SL_LIB_NAME));
- }
- }
- return nnapiSlHandle;
- }
-
- private static InputStream getInputStreamFromApk(String apkPath, String filePath) throws IOException {
- Log.i(TAG, String.format("Getting input stream from APK '%s' and file '%s'.", apkPath, filePath));
-
- JarFile jarFile = new JarFile(apkPath);
- JarEntry jarEntry = jarFile.getJarEntry(filePath);
- return jarFile.getInputStream(jarEntry);
- }
-
- private static String extractAllAndGetNnApiSlPath(Context context, String entryPointName)
- throws IOException {
- try {
- BufferedReader slLibraryListReader
- = new BufferedReader(
- new InputStreamReader(
- context.getAssets().open(NNAPI_SL_LIBRARIES_LIST_ASSET_PATH)));
- String result = null;
- final String nnLibTargetFolder = context.getCodeCacheDir().toString();
- for (final String libraryFile : slLibraryListReader.lines().collect(Collectors.toList())) {
- String sourcePath = getNnApiSlPathFromApkLibraries(context, libraryFile);
- if (sourcePath == null) {
- Log.w(TAG, String.format("Unable to find SL library '%s' to extract assuming is not part of this chipset distribution.", libraryFile));
- continue;
- }
-
- String[] apkAndLibraryPaths = sourcePath.split("!");
- if (apkAndLibraryPaths.length != 2) {
- Log.e(TAG, String.format("Unable to extract %s.", sourcePath));
- return null;
- }
-
- File targetPath = new File(nnLibTargetFolder, libraryFile);
- try(InputStream in = getInputStreamFromApk(apkAndLibraryPaths[0],
- // Removing leading '/'
- apkAndLibraryPaths[1].substring(1));
- OutputStream out = new FileOutputStream(targetPath)
- ) {
- copyFull(in, out);
- }
-
- Log.i(TAG, String.format("Copied '%s' to '%s'.", sourcePath, targetPath));
-
- if (libraryFile.equals(entryPointName)) {
- result = targetPath.getAbsolutePath();
- }
- }
- return result;
- } catch (IOException e) {
- Log.e(TAG, "Unable to find list of SL libraries under assets.", e);
- throw e;
- }
- }
-
- private static String getNnApiSlPathFromApkLibraries(Context context, String resourceName) {
- BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) context.getClassLoader();
- // Removing the "lib" prefix and ".so" suffix.
- String libShortName = resourceName.substring(3, resourceName.length() - 3);
- String result = dexClassLoader.findLibrary(libShortName);
- if (result != null) {
- return result;
- }
- return dexClassLoader.findLibrary(resourceName);
- }
-
private synchronized native long initModel(
String modelFileName,
int tfliteBackend,
@@ -220,8 +124,6 @@
/** Collect only 1 benchmark result every 10 **/
public static final int FLAG_SAMPLE_BENCHMARK_RESULTS = 1 << 2;
- private static final String NNAPI_SL_LIB_NAME = "libnnapi_sl_driver.so";
-
protected Context mContext;
protected TextView mText;
private final String mModelName;
@@ -323,14 +225,16 @@
mContext = ipcxt;
long nnApiLibHandle = 0;
if (mUseNnApiSupportLibrary) {
- nnApiLibHandle = getOrLoadNnApiSlHandle(mContext, mExtractNnApiSupportLibrary);
+ // TODO: support different drivers providers maybe with a flag
+ QualcommSupportLibraryDriverHandler qcSlhandler = new QualcommSupportLibraryDriverHandler();
+ nnApiLibHandle = qcSlhandler.getOrLoadNnApiSlHandle(mContext, mExtractNnApiSupportLibrary);
if (nnApiLibHandle == 0) {
Log.e(TAG, String
.format("Unable to find NNAPI SL entry point '%s' in embedded libraries path.",
- NNAPI_SL_LIB_NAME));
+ SupportLibraryDriverHandler.NNAPI_SL_LIB_NAME));
throw new NnApiDelegationFailure(String
.format("Unable to find NNAPI SL entry point '%s' in embedded libraries path.",
- NNAPI_SL_LIB_NAME));
+ SupportLibraryDriverHandler.NNAPI_SL_LIB_NAME));
}
}
if (mTemporaryModelFilePath != null) {
@@ -577,7 +481,7 @@
}
}
- private static void copyFull(InputStream in, OutputStream out) throws IOException {
+ public static void copyFull(InputStream in, OutputStream out) throws IOException {
byte[] byteBuffer = new byte[1024];
int readBytes = -1;
while ((readBytes = in.read(byteBuffer)) != -1) {
diff --git a/src/com/android/nn/benchmark/core/sl/QualcommSupportLibraryDriverHandler.java b/src/com/android/nn/benchmark/core/sl/QualcommSupportLibraryDriverHandler.java
new file mode 100644
index 0000000..3edaef1
--- /dev/null
+++ b/src/com/android/nn/benchmark/core/sl/QualcommSupportLibraryDriverHandler.java
@@ -0,0 +1,67 @@
+package com.android.nn.benchmark.core.sl;
+
+import android.content.Context;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class QualcommSupportLibraryDriverHandler extends SupportLibraryDriverHandler {
+ private static final String NNAPI_DSP_SL_LIBRARIES_ASSET_PATH = "dsp_loaded_libraries.txt";
+ private static final String DSP_LOAD_PATH_ENV_VAR = "ADSP_LIBRARY_PATH";
+
+ @Override
+ public void prepareDriver(Context context, String nnSupportLibFilePath) throws IOException {
+ boolean isApkPath = nnSupportLibFilePath.contains("apk!");
+
+ String dspLibsFolder = null;
+ Log.i(TAG, "Preparing NNAPI SL");
+ if (isApkPath) {
+ dspLibsFolder = extractDSPLibraries(context);
+ } else {
+ dspLibsFolder = new File(nnSupportLibFilePath).getParent();
+ }
+
+ if (dspLibsFolder != null) {
+ try {
+ Os.setenv(DSP_LOAD_PATH_ENV_VAR, dspLibsFolder, /*overwrite=*/true);
+ Log.i(TAG, String.format("Overwritten system env variable %s with %s",
+ DSP_LOAD_PATH_ENV_VAR, dspLibsFolder));
+ } catch (ErrnoException errnoException) {
+ throw new IOException(String.format("Unable to overwrite system env variable %s with %s",
+ DSP_LOAD_PATH_ENV_VAR, dspLibsFolder), errnoException);
+ }
+ }
+ }
+
+ private String extractDSPLibraries(Context context)
+ throws IOException {
+ try {
+ BufferedReader slLibraryListReader
+ = new BufferedReader(
+ new InputStreamReader(
+ context.getAssets().open(NNAPI_DSP_SL_LIBRARIES_ASSET_PATH)));
+ final String nnLibTargetFolder = context.getCodeCacheDir().toString();
+ final List<String> libsToExtract = slLibraryListReader.lines().collect(Collectors.toList());
+ if (libsToExtract.isEmpty()) {
+ Log.i(TAG, "No SL library to extract.");
+ return null;
+ }
+ for (final String libraryFile : libsToExtract) {
+ if (!extractNnApiSlLibTo(context, libraryFile, nnLibTargetFolder)) {
+ throw new FileNotFoundException(String.format("Unable to extract file %s", libraryFile));
+ }
+ }
+ return nnLibTargetFolder;
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to find list of SL libraries to extract from APK under assets.", e);
+ throw e;
+ }
+ }
+}
diff --git a/src/com/android/nn/benchmark/core/sl/SupportLibraryDriverHandler.java b/src/com/android/nn/benchmark/core/sl/SupportLibraryDriverHandler.java
new file mode 100644
index 0000000..5c2f232
--- /dev/null
+++ b/src/com/android/nn/benchmark/core/sl/SupportLibraryDriverHandler.java
@@ -0,0 +1,147 @@
+package com.android.nn.benchmark.core.sl;
+
+import android.content.Context;
+import android.util.Log;
+import com.android.nn.benchmark.core.NNTestBase;
+import dalvik.system.BaseDexClassLoader;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+
+/**
+ * Abstracts the initialization required to enable a NNAPI Support Library for a given vendor.
+ **/
+public abstract class SupportLibraryDriverHandler {
+
+ static {
+ System.loadLibrary("support_library_jni");
+ }
+
+ protected static final String TAG = "NN_TESTBASE";
+
+ private static final String NNAPI_SL_LIBRARIES_LIST_ASSET_PATH = "sl_prebuilt_filelist.txt";
+ public static final String NNAPI_SL_LIB_NAME = "libnnapi_sl_driver.so";
+
+ private static native long loadNnApiSlHandle(String nnApiSlPath);
+
+ // Guarded by this
+ private static long nnapiSlHandle = 0;
+
+ public synchronized long getOrLoadNnApiSlHandle(Context context, boolean extractNnApiSupportLibrary)
+ throws IOException {
+ if (nnapiSlHandle == 0) {
+ Log.i(TAG, "Initializing NNAPI SL.");
+
+ String nnSupportLibFilePath = null;
+ Log.i(TAG, "Preparing NNAPI SL");
+ if (extractNnApiSupportLibrary) {
+ nnSupportLibFilePath = extractAllAndGetNnApiSlPath(context, NNAPI_SL_LIB_NAME);
+ } else {
+ nnSupportLibFilePath = getNnApiSlPathFromApkLibraries(context, NNAPI_SL_LIB_NAME);
+ }
+
+ prepareDriver(context, nnSupportLibFilePath);
+
+ if (nnSupportLibFilePath != null) {
+ nnapiSlHandle = loadNnApiSlHandle(nnSupportLibFilePath);
+ if (nnapiSlHandle == 0) {
+ Log.e(TAG, String
+ .format("Unable load NNAPI SL from '%s'.", nnSupportLibFilePath));
+ } else {
+ Log.i(TAG, String
+ .format("Successfully loaded NNAPI SL from '%s'.", nnSupportLibFilePath));
+ }
+ } else {
+ Log.e(TAG, String
+ .format("Unable to find NNAPI SL entry point '%s' in embedded libraries path.",
+ NNAPI_SL_LIB_NAME));
+ }
+ }
+ return nnapiSlHandle;
+ }
+
+ private static InputStream getInputStreamFromApk(String apkPath, String filePath) throws IOException {
+ Log.i(TAG, String.format("Getting input stream from APK '%s' and file '%s'.", apkPath, filePath));
+
+ JarFile jarFile = new JarFile(apkPath);
+ JarEntry jarEntry = jarFile.getJarEntry(filePath);
+ return jarFile.getInputStream(jarEntry);
+ }
+
+ private static String extractAllAndGetNnApiSlPath(Context context, String entryPointName)
+ throws IOException {
+ try {
+ BufferedReader slLibraryListReader
+ = new BufferedReader(
+ new InputStreamReader(
+ context.getAssets().open(NNAPI_SL_LIBRARIES_LIST_ASSET_PATH)));
+ String result = null;
+ final String nnLibTargetFolder = context.getCodeCacheDir().toString();
+ for (final String libraryFile : slLibraryListReader.lines().collect(Collectors.toList())) {
+ try {
+ boolean copied = extractNnApiSlLibTo(context, libraryFile, nnLibTargetFolder);
+ if (copied && libraryFile.equals(entryPointName)) {
+ result = new File(nnLibTargetFolder, libraryFile).getAbsolutePath();
+ }
+ } catch (FileNotFoundException unableToExtractFile) {
+ return null;
+ }
+ }
+ return result;
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to find list of SL libraries under assets.", e);
+ throw e;
+ }
+ }
+
+ protected static boolean extractNnApiSlLibTo(Context context, String libraryFile, String targetFolder)
+ throws IOException {
+ String sourcePath = getNnApiSlPathFromApkLibraries(context, libraryFile);
+ if (sourcePath == null) {
+ Log.w(TAG, String.format("Unable to find SL library '%s' to extract assuming is not part of this chipset distribution.", libraryFile));
+ return false;
+ }
+
+ String[] apkAndLibraryPaths = sourcePath.split("!");
+ if (apkAndLibraryPaths.length != 2) {
+ final String errorMsg = String.format("Unable to extract %s.", sourcePath);
+ Log.e(TAG, errorMsg);
+ throw new FileNotFoundException(errorMsg);
+ }
+
+ File targetPath = new File(targetFolder, libraryFile);
+ try(InputStream in = getInputStreamFromApk(apkAndLibraryPaths[0],
+ // Removing leading '/'
+ apkAndLibraryPaths[1].substring(1));
+ OutputStream out = new FileOutputStream(targetPath)
+ ) {
+ NNTestBase.copyFull(in, out);
+ }
+
+ Log.i(TAG, String.format("Copied '%s' to '%s'.", sourcePath, targetPath));
+
+ return true;
+ }
+
+ private static String getNnApiSlPathFromApkLibraries(Context context, String resourceName) {
+ BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) context.getClassLoader();
+ // Removing the "lib" prefix and ".so" suffix.
+ String libShortName = resourceName.substring(3, resourceName.length() - 3);
+ String result = dexClassLoader.findLibrary(libShortName);
+ if (result != null) {
+ return result;
+ }
+ return dexClassLoader.findLibrary(resourceName);
+ }
+
+ // Vendor-specifi preparation steps
+ protected abstract void prepareDriver(Context context, String nnSupportLibFilePath) throws IOException;
+}