1 package com.android.nn.benchmark.core.sl;
2 
3 import android.content.Context;
4 import android.util.Log;
5 import com.android.nn.benchmark.core.NNTestBase;
6 import dalvik.system.BaseDexClassLoader;
7 import java.io.BufferedReader;
8 import java.io.File;
9 import java.io.FileNotFoundException;
10 import java.io.FileOutputStream;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.InputStreamReader;
14 import java.io.OutputStream;
15 import java.util.jar.JarEntry;
16 import java.util.jar.JarFile;
17 import java.util.stream.Collectors;
18 
19 /**
20  * Abstracts the initialization required to enable a NNAPI Support Library for a given vendor.
21  **/
22 public abstract class SupportLibraryDriverHandler {
23 
24   static {
25     System.loadLibrary("support_library_jni");
26   }
27 
28   protected static final String TAG = "NN_TESTBASE";
29 
30   private static final String NNAPI_SL_LIBRARIES_LIST_ASSET_PATH = "sl_prebuilt_filelist.txt";
31   public static final String NNAPI_SL_LIB_NAME = "libnnapi_sl_driver.so";
32 
loadNnApiSlHandle(String nnApiSlPath)33   private static native long loadNnApiSlHandle(String nnApiSlPath);
34 
35   // Guarded by this
36   private static long nnapiSlHandle = 0;
37 
getOrLoadNnApiSlHandle(Context context, boolean extractNnApiSupportLibrary)38   public synchronized long getOrLoadNnApiSlHandle(Context context, boolean extractNnApiSupportLibrary)
39       throws IOException {
40     if (nnapiSlHandle == 0) {
41       Log.i(TAG, "Initializing NNAPI SL.");
42 
43       String nnSupportLibFilePath = null;
44       Log.i(TAG, "Preparing NNAPI SL");
45       if (extractNnApiSupportLibrary) {
46         nnSupportLibFilePath = extractAllAndGetNnApiSlPath(context, NNAPI_SL_LIB_NAME);
47       } else {
48         nnSupportLibFilePath = getNnApiSlPathFromApkLibraries(context, NNAPI_SL_LIB_NAME);
49       }
50 
51       prepareDriver(context, nnSupportLibFilePath);
52 
53       if (nnSupportLibFilePath != null) {
54         nnapiSlHandle = loadNnApiSlHandle(nnSupportLibFilePath);
55         if (nnapiSlHandle == 0) {
56           Log.e(TAG, String
57               .format("Unable load NNAPI SL from '%s'.", nnSupportLibFilePath));
58         } else {
59           Log.i(TAG, String
60               .format("Successfully loaded NNAPI SL from '%s'.", nnSupportLibFilePath));
61         }
62       } else {
63         Log.e(TAG, String
64             .format("Unable to find NNAPI SL entry point '%s' in embedded libraries path.",
65                 NNAPI_SL_LIB_NAME));
66       }
67     }
68     return nnapiSlHandle;
69   }
70 
getInputStreamFromApk(String apkPath, String filePath)71   private static InputStream getInputStreamFromApk(String apkPath, String filePath) throws IOException {
72     Log.i(TAG, String.format("Getting input stream from APK '%s' and file '%s'.", apkPath, filePath));
73 
74     JarFile jarFile = new JarFile(apkPath);
75     JarEntry jarEntry = jarFile.getJarEntry(filePath);
76     return jarFile.getInputStream(jarEntry);
77   }
78 
extractAllAndGetNnApiSlPath(Context context, String entryPointName)79   private static String extractAllAndGetNnApiSlPath(Context context, String entryPointName)
80       throws IOException {
81     try {
82       BufferedReader slLibraryListReader
83           = new BufferedReader(
84           new InputStreamReader(
85               context.getAssets().open(NNAPI_SL_LIBRARIES_LIST_ASSET_PATH)));
86       String result = null;
87       final String nnLibTargetFolder = context.getCodeCacheDir().toString();
88       for (final String libraryFile : slLibraryListReader.lines().collect(Collectors.toList())) {
89         try {
90           boolean copied = extractNnApiSlLibTo(context, libraryFile, nnLibTargetFolder);
91           if (copied && libraryFile.equals(entryPointName)) {
92             result = new File(nnLibTargetFolder, libraryFile).getAbsolutePath();
93           }
94         } catch (FileNotFoundException unableToExtractFile) {
95           return null;
96         }
97       }
98       return result;
99     } catch (IOException e) {
100       Log.e(TAG, "Unable to find list of SL libraries under assets.", e);
101       throw e;
102     }
103   }
104 
extractNnApiSlLibTo(Context context, String libraryFile, String targetFolder)105   protected static boolean extractNnApiSlLibTo(Context context, String libraryFile, String targetFolder)
106       throws IOException {
107     String sourcePath = getNnApiSlPathFromApkLibraries(context, libraryFile);
108     if (sourcePath == null) {
109       Log.w(TAG, String.format("Unable to find SL library '%s' to extract assuming is not part of this chipset distribution.", libraryFile));
110       return false;
111     }
112 
113     String[] apkAndLibraryPaths = sourcePath.split("!");
114     if (apkAndLibraryPaths.length != 2) {
115       final String errorMsg = String.format("Unable to extract %s.", sourcePath);
116       Log.e(TAG, errorMsg);
117       throw new FileNotFoundException(errorMsg);
118     }
119 
120     File targetPath = new File(targetFolder, libraryFile);
121     try(InputStream in = getInputStreamFromApk(apkAndLibraryPaths[0],
122         // Removing leading '/'
123         apkAndLibraryPaths[1].substring(1));
124         OutputStream out = new FileOutputStream(targetPath)
125     ) {
126       NNTestBase.copyFull(in, out);
127     }
128 
129     Log.i(TAG, String.format("Copied '%s' to '%s'.", sourcePath, targetPath));
130 
131     return true;
132   }
133 
getNnApiSlPathFromApkLibraries(Context context, String resourceName)134   private static String getNnApiSlPathFromApkLibraries(Context context, String resourceName) {
135     BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) context.getClassLoader();
136     // Removing the "lib" prefix and ".so" suffix.
137     String libShortName = resourceName.substring(3, resourceName.length() - 3);
138     String result = dexClassLoader.findLibrary(libShortName);
139     if (result != null) {
140       return result;
141     }
142     return dexClassLoader.findLibrary(resourceName);
143   }
144 
145   // Vendor-specifi preparation steps
prepareDriver(Context context, String nnSupportLibFilePath)146   protected abstract void prepareDriver(Context context, String nnSupportLibFilePath) throws IOException;
147 }
148