NativeLibraryHelper.java revision 8d479b0c2ddb150182bcf510876a240cb869661b
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.content; 18 19import static android.content.pm.PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS; 20import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; 21import static android.content.pm.PackageManager.NO_NATIVE_LIBRARIES; 22 23import android.content.pm.PackageManager; 24import android.content.pm.PackageParser; 25import android.content.pm.PackageParser.Package; 26import android.content.pm.PackageParser.PackageLite; 27import android.content.pm.PackageParser.PackageParserException; 28import android.util.Slog; 29 30import dalvik.system.CloseGuard; 31 32import java.io.Closeable; 33import java.io.File; 34import java.io.IOException; 35import java.util.List; 36 37/** 38 * Native libraries helper. 39 * 40 * @hide 41 */ 42public class NativeLibraryHelper { 43 private static final String TAG = "NativeHelper"; 44 45 private static final boolean DEBUG_NATIVE = false; 46 47 /** 48 * A handle to an opened package, consisting of one or more APKs. Used as 49 * input to the various NativeLibraryHelper methods. Allows us to scan and 50 * parse the APKs exactly once instead of doing it multiple times. 51 * 52 * @hide 53 */ 54 public static class Handle implements Closeable { 55 private final CloseGuard mGuard = CloseGuard.get(); 56 private volatile boolean mClosed; 57 58 final long[] apkHandles; 59 60 public static Handle create(File packageFile) throws IOException { 61 try { 62 final PackageLite lite = PackageParser.parsePackageLite(packageFile, 0); 63 return create(lite); 64 } catch (PackageParserException e) { 65 throw new IOException("Failed to parse package: " + packageFile, e); 66 } 67 } 68 69 public static Handle create(Package pkg) throws IOException { 70 return create(pkg.getAllCodePaths()); 71 } 72 73 public static Handle create(PackageLite lite) throws IOException { 74 return create(lite.getAllCodePaths()); 75 } 76 77 private static Handle create(List<String> codePaths) throws IOException { 78 final int size = codePaths.size(); 79 final long[] apkHandles = new long[size]; 80 for (int i = 0; i < size; i++) { 81 final String path = codePaths.get(i); 82 apkHandles[i] = nativeOpenApk(path); 83 if (apkHandles[i] == 0) { 84 // Unwind everything we've opened so far 85 for (int j = 0; j < i; j++) { 86 nativeClose(apkHandles[j]); 87 } 88 throw new IOException("Unable to open APK: " + path); 89 } 90 } 91 92 return new Handle(apkHandles); 93 } 94 95 Handle(long[] apkHandles) { 96 this.apkHandles = apkHandles; 97 mGuard.open("close"); 98 } 99 100 @Override 101 public void close() { 102 for (long apkHandle : apkHandles) { 103 nativeClose(apkHandle); 104 } 105 mGuard.close(); 106 mClosed = true; 107 } 108 109 @Override 110 protected void finalize() throws Throwable { 111 if (mGuard != null) { 112 mGuard.warnIfOpen(); 113 } 114 try { 115 if (!mClosed) { 116 close(); 117 } 118 } finally { 119 super.finalize(); 120 } 121 } 122 } 123 124 private static native long nativeOpenApk(String path); 125 private static native void nativeClose(long handle); 126 127 private static native long nativeSumNativeBinaries(long handle, String cpuAbi); 128 129 /** 130 * Sums the size of native binaries in an APK for a given ABI. 131 * 132 * @return size of all native binary files in bytes 133 */ 134 public static long sumNativeBinariesLI(Handle handle, String abi) { 135 long sum = 0; 136 for (long apkHandle : handle.apkHandles) { 137 sum += nativeSumNativeBinaries(apkHandle, abi); 138 } 139 return sum; 140 } 141 142 private native static int nativeCopyNativeBinaries(long handle, 143 String sharedLibraryPath, String abiToCopy); 144 145 /** 146 * Copies native binaries to a shared library directory. 147 * 148 * @param handle APK file to scan for native libraries 149 * @param sharedLibraryDir directory for libraries to be copied to 150 * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another 151 * error code from that class if not 152 */ 153 public static int copyNativeBinariesIfNeededLI(Handle handle, File sharedLibraryDir, 154 String abi) { 155 for (long apkHandle : handle.apkHandles) { 156 int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi); 157 if (res != INSTALL_SUCCEEDED) { 158 return res; 159 } 160 } 161 return INSTALL_SUCCEEDED; 162 } 163 164 /** 165 * Checks if a given APK contains native code for any of the provided 166 * {@code supportedAbis}. Returns an index into {@code supportedAbis} if a matching 167 * ABI is found, {@link PackageManager#NO_NATIVE_LIBRARIES} if the 168 * APK doesn't contain any native code, and 169 * {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match. 170 */ 171 public static int findSupportedAbi(Handle handle, String[] supportedAbis) { 172 int finalRes = NO_NATIVE_LIBRARIES; 173 for (long apkHandle : handle.apkHandles) { 174 final int res = nativeFindSupportedAbi(apkHandle, supportedAbis); 175 if (res == NO_NATIVE_LIBRARIES) { 176 // No native code, keep looking through all APKs. 177 } else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) { 178 // Found some native code, but no ABI match; update our final 179 // result if we haven't found other valid code. 180 if (finalRes < 0) { 181 finalRes = INSTALL_FAILED_NO_MATCHING_ABIS; 182 } 183 } else if (res >= 0) { 184 // Found valid native code, track the best ABI match 185 if (finalRes < 0 || res < finalRes) { 186 finalRes = res; 187 } 188 } else { 189 // Unexpected error; bail 190 return res; 191 } 192 } 193 return finalRes; 194 } 195 196 private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis); 197 198 // Convenience method to call removeNativeBinariesFromDirLI(File) 199 public static boolean removeNativeBinariesLI(String nativeLibraryPath) { 200 if (nativeLibraryPath == null) return false; 201 return removeNativeBinariesFromDirLI(new File(nativeLibraryPath)); 202 } 203 204 // Remove the native binaries of a given package. This simply 205 // gets rid of the files in the 'lib' sub-directory. 206 public static boolean removeNativeBinariesFromDirLI(File nativeLibraryDir) { 207 if (DEBUG_NATIVE) { 208 Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryDir.getPath()); 209 } 210 211 boolean deletedFiles = false; 212 213 /* 214 * Just remove any file in the directory. Since the directory is owned 215 * by the 'system' UID, the application is not supposed to have written 216 * anything there. 217 */ 218 if (nativeLibraryDir.exists()) { 219 final File[] binaries = nativeLibraryDir.listFiles(); 220 if (binaries != null) { 221 for (int nn = 0; nn < binaries.length; nn++) { 222 if (DEBUG_NATIVE) { 223 Slog.d(TAG, " Deleting " + binaries[nn].getName()); 224 } 225 226 if (!binaries[nn].delete()) { 227 Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath()); 228 } else { 229 deletedFiles = true; 230 } 231 } 232 } 233 // Do not delete 'lib' directory itself, or this will prevent 234 // installation of future updates. 235 } 236 237 return deletedFiles; 238 } 239 240 // We don't care about the other return values for now. 241 private static final int BITCODE_PRESENT = 1; 242 243 public static boolean hasRenderscriptBitcode(Handle handle) throws IOException { 244 for (long apkHandle : handle.apkHandles) { 245 final int res = hasRenderscriptBitcode(apkHandle); 246 if (res < 0) { 247 throw new IOException("Error scanning APK, code: " + res); 248 } else if (res == BITCODE_PRESENT) { 249 return true; 250 } 251 } 252 return false; 253 } 254 255 private static native int hasRenderscriptBitcode(long apkHandle); 256} 257