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 17 package com.android.internal.content; 18 19 import static android.content.pm.PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS; 20 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; 21 import static android.content.pm.PackageManager.NO_NATIVE_LIBRARIES; 22 import static android.system.OsConstants.S_IRGRP; 23 import static android.system.OsConstants.S_IROTH; 24 import static android.system.OsConstants.S_IRWXU; 25 import static android.system.OsConstants.S_IXGRP; 26 import static android.system.OsConstants.S_IXOTH; 27 28 import android.content.Context; 29 import android.content.pm.ApplicationInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.parsing.ApkLiteParseUtils; 32 import android.content.pm.parsing.PackageLite; 33 import android.content.pm.parsing.result.ParseResult; 34 import android.content.pm.parsing.result.ParseTypeImpl; 35 import android.os.Build; 36 import android.os.IBinder; 37 import android.os.SELinux; 38 import android.os.ServiceManager; 39 import android.os.incremental.IIncrementalService; 40 import android.os.incremental.IncrementalManager; 41 import android.os.incremental.IncrementalStorage; 42 import android.system.ErrnoException; 43 import android.system.Os; 44 import android.util.Slog; 45 46 import dalvik.system.CloseGuard; 47 import dalvik.system.VMRuntime; 48 49 import java.io.Closeable; 50 import java.io.File; 51 import java.io.FileDescriptor; 52 import java.io.IOException; 53 import java.nio.file.Path; 54 import java.util.List; 55 56 /** 57 * Native libraries helper. 58 * 59 * @hide 60 */ 61 public class NativeLibraryHelper { 62 private static final String TAG = "NativeHelper"; 63 private static final boolean DEBUG_NATIVE = false; 64 65 public static final String LIB_DIR_NAME = "lib"; 66 public static final String LIB64_DIR_NAME = "lib64"; 67 68 // Special value for indicating that the cpuAbiOverride must be clear. 69 public static final String CLEAR_ABI_OVERRIDE = "-"; 70 71 /** 72 * A handle to an opened package, consisting of one or more APKs. Used as 73 * input to the various NativeLibraryHelper methods. Allows us to scan and 74 * parse the APKs exactly once instead of doing it multiple times. 75 * 76 * @hide 77 */ 78 public static class Handle implements Closeable { 79 private final CloseGuard mGuard = CloseGuard.get(); 80 private volatile boolean mClosed; 81 82 final String[] apkPaths; 83 final long[] apkHandles; 84 final boolean multiArch; 85 final boolean extractNativeLibs; 86 final boolean debuggable; 87 88 final boolean pageSizeCompatDisabled; 89 create(File packageFile)90 public static Handle create(File packageFile) throws IOException { 91 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 92 final ParseResult<PackageLite> ret = ApkLiteParseUtils.parsePackageLite(input.reset(), 93 packageFile, /* flags */ 0); 94 if (ret.isError()) { 95 throw new IOException("Failed to parse package: " + packageFile, 96 ret.getException()); 97 } 98 return create(ret.getResult()); 99 } 100 create(PackageLite lite)101 public static Handle create(PackageLite lite) throws IOException { 102 boolean isPageSizeCompatDisabled = lite.getPageSizeCompat() 103 == ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_DISABLED; 104 return create(lite.getAllApkPaths(), lite.isMultiArch(), lite.isExtractNativeLibs(), 105 lite.isDebuggable(), isPageSizeCompatDisabled); 106 } 107 create(List<String> codePaths, boolean multiArch, boolean extractNativeLibs, boolean debuggable, boolean isPageSizeCompatDisabled)108 public static Handle create(List<String> codePaths, boolean multiArch, 109 boolean extractNativeLibs, boolean debuggable, boolean isPageSizeCompatDisabled) 110 throws IOException { 111 final int size = codePaths.size(); 112 final String[] apkPaths = new String[size]; 113 final long[] apkHandles = new long[size]; 114 for (int i = 0; i < size; i++) { 115 final String path = codePaths.get(i); 116 apkPaths[i] = path; 117 apkHandles[i] = nativeOpenApk(path); 118 if (apkHandles[i] == 0) { 119 // Unwind everything we've opened so far 120 for (int j = 0; j < i; j++) { 121 nativeClose(apkHandles[j]); 122 } 123 throw new IOException("Unable to open APK: " + path); 124 } 125 } 126 127 return new Handle(apkPaths, apkHandles, multiArch, extractNativeLibs, debuggable, 128 isPageSizeCompatDisabled); 129 } 130 createFd(PackageLite lite, FileDescriptor fd)131 public static Handle createFd(PackageLite lite, FileDescriptor fd) throws IOException { 132 final long[] apkHandles = new long[1]; 133 final String path = lite.getBaseApkPath(); 134 apkHandles[0] = nativeOpenApkFd(fd, path); 135 if (apkHandles[0] == 0) { 136 throw new IOException("Unable to open APK " + path + " from fd " + fd); 137 } 138 139 boolean isPageSizeCompatDisabled = lite.getPageSizeCompat() 140 == ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_DISABLED; 141 142 return new Handle(new String[]{path}, apkHandles, lite.isMultiArch(), 143 lite.isExtractNativeLibs(), lite.isDebuggable(), isPageSizeCompatDisabled); 144 } 145 Handle(String[] apkPaths, long[] apkHandles, boolean multiArch, boolean extractNativeLibs, boolean debuggable, boolean isPageSizeCompatDisabled)146 Handle(String[] apkPaths, long[] apkHandles, boolean multiArch, 147 boolean extractNativeLibs, boolean debuggable, boolean isPageSizeCompatDisabled) { 148 this.apkPaths = apkPaths; 149 this.apkHandles = apkHandles; 150 this.multiArch = multiArch; 151 this.extractNativeLibs = extractNativeLibs; 152 this.debuggable = debuggable; 153 this.pageSizeCompatDisabled = isPageSizeCompatDisabled; 154 mGuard.open("close"); 155 } 156 157 @Override close()158 public void close() { 159 for (long apkHandle : apkHandles) { 160 nativeClose(apkHandle); 161 } 162 mGuard.close(); 163 mClosed = true; 164 } 165 166 @Override finalize()167 protected void finalize() throws Throwable { 168 if (mGuard != null) { 169 mGuard.warnIfOpen(); 170 } 171 try { 172 if (!mClosed) { 173 close(); 174 } 175 } finally { 176 super.finalize(); 177 } 178 } 179 } 180 nativeOpenApk(String path)181 private static native long nativeOpenApk(String path); nativeOpenApkFd(FileDescriptor fd, String debugPath)182 private static native long nativeOpenApkFd(FileDescriptor fd, String debugPath); nativeClose(long handle)183 private static native void nativeClose(long handle); 184 nativeSumNativeBinaries(long handle, String cpuAbi)185 private static native long nativeSumNativeBinaries(long handle, String cpuAbi); 186 nativeCopyNativeBinaries(long handle, String sharedLibraryPath, String abiToCopy, boolean extractNativeLibs, boolean debuggable, boolean pageSizeCompatDisabled)187 private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath, 188 String abiToCopy, boolean extractNativeLibs, boolean debuggable, 189 boolean pageSizeCompatDisabled); 190 nativeCheckAlignment( long handle, String sharedLibraryPath, String abi, boolean extractNativeLibs, boolean debuggable)191 private static native int nativeCheckAlignment( 192 long handle, 193 String sharedLibraryPath, 194 String abi, 195 boolean extractNativeLibs, 196 boolean debuggable); 197 sumNativeBinaries(Handle handle, String abi)198 private static long sumNativeBinaries(Handle handle, String abi) { 199 long sum = 0; 200 for (long apkHandle : handle.apkHandles) { 201 sum += nativeSumNativeBinaries(apkHandle, abi); 202 } 203 return sum; 204 } 205 206 /** 207 * Copies native binaries to a shared library directory. 208 * 209 * @param handle APK file to scan for native libraries 210 * @param sharedLibraryDir directory for libraries to be copied to 211 * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another 212 * error code from that class if not 213 */ copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi)214 public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) { 215 for (long apkHandle : handle.apkHandles) { 216 int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi, 217 handle.extractNativeLibs, handle.debuggable, handle.pageSizeCompatDisabled); 218 if (res != INSTALL_SUCCEEDED) { 219 return res; 220 } 221 } 222 return INSTALL_SUCCEEDED; 223 } 224 225 /** 226 * Checks if a given APK contains native code for any of the provided 227 * {@code supportedAbis}. Returns an index into {@code supportedAbis} if a matching 228 * ABI is found, {@link PackageManager#NO_NATIVE_LIBRARIES} if the 229 * APK doesn't contain any native code, and 230 * {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match. 231 */ findSupportedAbi(Handle handle, String[] supportedAbis)232 public static int findSupportedAbi(Handle handle, String[] supportedAbis) { 233 int finalRes = NO_NATIVE_LIBRARIES; 234 for (long apkHandle : handle.apkHandles) { 235 final int res = nativeFindSupportedAbi(apkHandle, supportedAbis); 236 if (res == NO_NATIVE_LIBRARIES) { 237 // No native code, keep looking through all APKs. 238 } else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) { 239 // Found some native code, but no ABI match; update our final 240 // result if we haven't found other valid code. 241 if (finalRes < 0) { 242 finalRes = INSTALL_FAILED_NO_MATCHING_ABIS; 243 } 244 } else if (res >= 0) { 245 // Found valid native code, track the best ABI match 246 if (finalRes < 0 || res < finalRes) { 247 finalRes = res; 248 } 249 } else { 250 // Unexpected error; bail 251 return res; 252 } 253 } 254 return finalRes; 255 } 256 nativeFindSupportedAbi(long handle, String[] supportedAbis)257 private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis); 258 259 // Convenience method to call removeNativeBinariesFromDirLI(File) removeNativeBinariesLI(String nativeLibraryPath)260 public static void removeNativeBinariesLI(String nativeLibraryPath) { 261 if (nativeLibraryPath == null) return; 262 removeNativeBinariesFromDirLI(new File(nativeLibraryPath), false /* delete root dir */); 263 } 264 265 /** 266 * Remove the native binaries of a given package. This deletes the files 267 */ removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir)268 public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, 269 boolean deleteRootDir) { 270 if (DEBUG_NATIVE) { 271 Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryRoot.getPath()); 272 } 273 274 /* 275 * Just remove any file in the directory. Since the directory is owned 276 * by the 'system' UID, the application is not supposed to have written 277 * anything there. 278 */ 279 if (nativeLibraryRoot.exists()) { 280 final File[] files = nativeLibraryRoot.listFiles(); 281 if (files != null) { 282 for (int nn = 0; nn < files.length; nn++) { 283 if (DEBUG_NATIVE) { 284 Slog.d(TAG, " Deleting " + files[nn].getName()); 285 } 286 287 if (files[nn].isDirectory()) { 288 removeNativeBinariesFromDirLI(files[nn], true /* delete root dir */); 289 } else if (!files[nn].delete()) { 290 Slog.w(TAG, "Could not delete native binary: " + files[nn].getPath()); 291 } 292 } 293 } 294 // Do not delete 'lib' directory itself, unless we're specifically 295 // asked to or this will prevent installation of future updates. 296 if (deleteRootDir) { 297 if (!nativeLibraryRoot.delete()) { 298 Slog.w(TAG, "Could not delete native binary directory: " + 299 nativeLibraryRoot.getPath()); 300 } 301 } 302 } 303 } 304 305 /** 306 * @hide 307 */ createNativeLibrarySubdir(File path)308 public static void createNativeLibrarySubdir(File path) throws IOException { 309 if (!path.isDirectory()) { 310 path.delete(); 311 312 if (!path.mkdir()) { 313 throw new IOException("Cannot create " + path.getPath()); 314 } 315 316 try { 317 Os.chmod(path.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 318 } catch (ErrnoException e) { 319 throw new IOException("Cannot chmod native library directory " 320 + path.getPath(), e); 321 } 322 } else if (!SELinux.restorecon(path)) { 323 throw new IOException("Cannot set SELinux context for " + path.getPath()); 324 } 325 } 326 sumNativeBinariesForSupportedAbi(Handle handle, String[] abiList)327 private static long sumNativeBinariesForSupportedAbi(Handle handle, String[] abiList) { 328 int abi = findSupportedAbi(handle, abiList); 329 if (abi >= 0) { 330 return sumNativeBinaries(handle, abiList[abi]); 331 } else { 332 return 0; 333 } 334 } 335 copyNativeBinariesForSupportedAbi(Handle handle, File libraryRoot, String[] abiList, boolean useIsaSubdir, boolean isIncremental)336 public static int copyNativeBinariesForSupportedAbi(Handle handle, File libraryRoot, 337 String[] abiList, boolean useIsaSubdir, boolean isIncremental) throws IOException { 338 /* 339 * If this is an internal application or our nativeLibraryPath points to 340 * the app-lib directory, unpack the libraries if necessary. 341 */ 342 int abi = findSupportedAbi(handle, abiList); 343 if (abi < 0) { 344 return abi; 345 } 346 347 /* 348 * If we have a matching instruction set, construct a subdir under the native 349 * library root that corresponds to this instruction set. 350 */ 351 final String supportedAbi = abiList[abi]; 352 final String instructionSet = VMRuntime.getInstructionSet(supportedAbi); 353 final File subDir; 354 if (useIsaSubdir) { 355 subDir = new File(libraryRoot, instructionSet); 356 } else { 357 subDir = libraryRoot; 358 } 359 360 if (isIncremental) { 361 int res = 362 incrementalConfigureNativeBinariesForSupportedAbi(handle, subDir, supportedAbi); 363 if (res != PackageManager.INSTALL_SUCCEEDED) { 364 // TODO(b/133435829): the caller of this function expects that we return the index 365 // to the supported ABI. However, any non-negative integer can be a valid index. 366 // We should fix this function and make sure it doesn't accidentally return an error 367 // code that can also be a valid index. 368 return res; 369 } 370 return abi; 371 } 372 373 // For non-incremental, use regular extraction and copy 374 createNativeLibrarySubdir(libraryRoot); 375 if (subDir != libraryRoot) { 376 createNativeLibrarySubdir(subDir); 377 } 378 379 // Even if extractNativeLibs is false, we still need to check if the native libs in the APK 380 // are valid. This is done in the native code. 381 int copyRet = copyNativeBinaries(handle, subDir, supportedAbi); 382 if (copyRet != PackageManager.INSTALL_SUCCEEDED) { 383 return copyRet; 384 } 385 386 return abi; 387 } 388 copyNativeBinariesWithOverride(Handle handle, File libraryRoot, String abiOverride, boolean isIncremental)389 public static int copyNativeBinariesWithOverride(Handle handle, File libraryRoot, 390 String abiOverride, boolean isIncremental) { 391 try { 392 if (handle.multiArch) { 393 // Warn if we've set an abiOverride for multi-lib packages.. 394 // By definition, we need to copy both 32 and 64 bit libraries for 395 // such packages. 396 if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) { 397 Slog.w(TAG, "Ignoring abiOverride for multi arch application."); 398 } 399 400 int copyRet = PackageManager.NO_NATIVE_LIBRARIES; 401 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { 402 copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, 403 Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */, 404 isIncremental); 405 if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && 406 copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { 407 Slog.w(TAG, "Failure copying 32 bit native libraries; copyRet=" +copyRet); 408 return copyRet; 409 } 410 } 411 412 if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { 413 copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, 414 Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */, 415 isIncremental); 416 if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && 417 copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { 418 Slog.w(TAG, "Failure copying 64 bit native libraries; copyRet=" +copyRet); 419 return copyRet; 420 } 421 } 422 } else { 423 String cpuAbiOverride = null; 424 if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) { 425 cpuAbiOverride = null; 426 } else if (abiOverride != null) { 427 cpuAbiOverride = abiOverride; 428 } 429 430 String[] abiList = (cpuAbiOverride != null) ? 431 new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; 432 if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null && 433 hasRenderscriptBitcode(handle)) { 434 abiList = Build.SUPPORTED_32_BIT_ABIS; 435 } 436 437 int copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, abiList, 438 true /* use isa specific subdirs */, isIncremental); 439 if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { 440 Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]"); 441 return copyRet; 442 } 443 } 444 445 return PackageManager.INSTALL_SUCCEEDED; 446 } catch (IOException e) { 447 Slog.e(TAG, "Copying native libraries failed", e); 448 return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; 449 } 450 } 451 452 /** 453 * Checks alignment of APK and native libraries for 16KB device 454 * 455 * @param handle APK file to scan for native libraries 456 * @param libraryRoot directory for libraries 457 * @param abiOverride abiOverride for package 458 * @return {@link Modes from ApplicationInfo.PageSizeAppCompat} if successful or error code 459 * which suggests undefined mode 460 */ 461 @ApplicationInfo.PageSizeAppCompatFlags checkAlignmentForCompatMode( Handle handle, String libraryRoot, boolean nativeLibraryRootRequiresIsa, String abiOverride)462 public static int checkAlignmentForCompatMode( 463 Handle handle, 464 String libraryRoot, 465 boolean nativeLibraryRootRequiresIsa, 466 String abiOverride) { 467 // Keep the code below in sync with copyNativeBinariesForSupportedAbi 468 int abi = findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS); 469 if (abi < 0) { 470 return ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR; 471 } 472 473 final String supportedAbi = Build.SUPPORTED_64_BIT_ABIS[abi]; 474 final String instructionSet = VMRuntime.getInstructionSet(supportedAbi); 475 String subDir = libraryRoot; 476 if (nativeLibraryRootRequiresIsa) { 477 subDir += "/" + instructionSet; 478 } 479 480 int mode = ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED; 481 for (long apkHandle : handle.apkHandles) { 482 int res = 483 nativeCheckAlignment( 484 apkHandle, 485 subDir, 486 Build.SUPPORTED_64_BIT_ABIS[abi], 487 handle.extractNativeLibs, 488 handle.debuggable); 489 if (res == ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR) { 490 return res; 491 } 492 mode |= res; 493 } 494 return mode; 495 } 496 sumNativeBinariesWithOverride(Handle handle, String abiOverride)497 public static long sumNativeBinariesWithOverride(Handle handle, String abiOverride) 498 throws IOException { 499 long sum = 0; 500 if (handle.multiArch) { 501 // Warn if we've set an abiOverride for multi-lib packages.. 502 // By definition, we need to copy both 32 and 64 bit libraries for 503 // such packages. 504 if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) { 505 Slog.w(TAG, "Ignoring abiOverride for multi arch application."); 506 } 507 508 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { 509 sum += sumNativeBinariesForSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS); 510 } 511 512 if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { 513 sum += sumNativeBinariesForSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS); 514 } 515 } else { 516 String cpuAbiOverride = null; 517 if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) { 518 cpuAbiOverride = null; 519 } else if (abiOverride != null) { 520 cpuAbiOverride = abiOverride; 521 } 522 523 String[] abiList = (cpuAbiOverride != null) ? 524 new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; 525 if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null && 526 hasRenderscriptBitcode(handle)) { 527 abiList = Build.SUPPORTED_32_BIT_ABIS; 528 } 529 530 sum += sumNativeBinariesForSupportedAbi(handle, abiList); 531 } 532 return sum; 533 } 534 535 /** 536 * Configure the native library files managed by Incremental Service. Makes sure Incremental 537 * Service will create native library directories and set up native library binary files in the 538 * same structure as they are in non-incremental installations. 539 * 540 * @param handle The Handle object that contains all apk paths. 541 * @param libSubDir The target directory to put the native library files, e.g., lib/ or lib/arm 542 * @param abi The abi that is supported by the current device. 543 * @return Integer code if installation succeeds or fails. 544 */ incrementalConfigureNativeBinariesForSupportedAbi(Handle handle, File libSubDir, String abi)545 private static int incrementalConfigureNativeBinariesForSupportedAbi(Handle handle, 546 File libSubDir, String abi) { 547 final String[] apkPaths = handle.apkPaths; 548 if (apkPaths == null || apkPaths.length == 0) { 549 Slog.e(TAG, "No apks to extract native libraries from."); 550 return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; 551 } 552 553 final IBinder incrementalService = ServiceManager.getService(Context.INCREMENTAL_SERVICE); 554 if (incrementalService == null) { 555 //TODO(b/133435829): add incremental specific error codes 556 return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; 557 } 558 final IncrementalManager incrementalManager = new IncrementalManager( 559 IIncrementalService.Stub.asInterface(incrementalService)); 560 final File apkParent = new File(apkPaths[0]).getParentFile(); 561 IncrementalStorage incrementalStorage = 562 incrementalManager.openStorage(apkParent.getAbsolutePath()); 563 if (incrementalStorage == null) { 564 Slog.e(TAG, "Failed to find incremental storage"); 565 return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; 566 } 567 568 String libRelativeDir = getRelativePath(apkParent, libSubDir); 569 if (libRelativeDir == null) { 570 return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; 571 } 572 573 for (int i = 0; i < apkPaths.length; i++) { 574 if (!incrementalStorage.configureNativeBinaries(apkPaths[i], libRelativeDir, abi, 575 handle.extractNativeLibs)) { 576 return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; 577 } 578 } 579 return PackageManager.INSTALL_SUCCEEDED; 580 } 581 getRelativePath(File base, File target)582 private static String getRelativePath(File base, File target) { 583 try { 584 final Path basePath = base.toPath(); 585 final Path targetPath = target.toPath(); 586 final Path relativePath = basePath.relativize(targetPath); 587 if (relativePath.toString().isEmpty()) { 588 return ""; 589 } 590 return relativePath.toString(); 591 } catch (IllegalArgumentException ex) { 592 Slog.e(TAG, "Failed to find relative path between: " + base.getAbsolutePath() 593 + " and: " + target.getAbsolutePath()); 594 return null; 595 } 596 } 597 598 // We don't care about the other return values for now. 599 private static final int BITCODE_PRESENT = 1; 600 hasRenderscriptBitcode(long apkHandle)601 private static native int hasRenderscriptBitcode(long apkHandle); 602 hasRenderscriptBitcode(Handle handle)603 public static boolean hasRenderscriptBitcode(Handle handle) throws IOException { 604 for (long apkHandle : handle.apkHandles) { 605 final int res = hasRenderscriptBitcode(apkHandle); 606 if (res < 0) { 607 throw new IOException("Error scanning APK, code: " + res); 608 } else if (res == BITCODE_PRESENT) { 609 return true; 610 } 611 } 612 return false; 613 } 614 } 615