1 /* 2 * Copyright (C) 2019 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.server.pm; 18 19 import static android.content.pm.PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE; 20 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; 21 import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile; 22 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; 23 import static android.os.incremental.IncrementalManager.isIncrementalPath; 24 25 import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME; 26 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; 27 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; 28 import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet; 29 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.content.pm.Flags; 33 import android.content.pm.PackageManager; 34 import android.os.Build; 35 import android.os.Environment; 36 import android.os.FileUtils; 37 import android.os.SystemProperties; 38 import android.os.Trace; 39 import android.text.TextUtils; 40 import android.util.ArraySet; 41 import android.util.Pair; 42 import android.util.Slog; 43 44 import com.android.internal.content.NativeLibraryHelper; 45 import com.android.internal.util.ArrayUtils; 46 import com.android.server.pm.parsing.pkg.AndroidPackageUtils; 47 import com.android.server.pm.pkg.AndroidPackage; 48 import com.android.server.pm.pkg.PackageStateInternal; 49 50 import dalvik.system.VMRuntime; 51 52 import libcore.io.IoUtils; 53 54 import java.io.File; 55 import java.io.IOException; 56 import java.util.ArrayList; 57 import java.util.List; 58 59 final class PackageAbiHelperImpl implements PackageAbiHelper { 60 61 @Nullable 62 private static String[] sNativelySupported32BitAbis = null; 63 @Nullable 64 private static String[] sNativelySupported64BitAbis = null; 65 calculateBundledApkRoot(final String codePathString)66 private static String calculateBundledApkRoot(final String codePathString) { 67 final File codePath = new File(codePathString); 68 final File codeRoot; 69 if (FileUtils.contains(Environment.getRootDirectory(), codePath)) { 70 codeRoot = Environment.getRootDirectory(); 71 } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) { 72 codeRoot = Environment.getOemDirectory(); 73 } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) { 74 codeRoot = Environment.getVendorDirectory(); 75 } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) { 76 codeRoot = Environment.getOdmDirectory(); 77 } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) { 78 codeRoot = Environment.getProductDirectory(); 79 } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) { 80 codeRoot = Environment.getSystemExtDirectory(); 81 } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) { 82 codeRoot = Environment.getOdmDirectory(); 83 } else if (FileUtils.contains(Environment.getApexDirectory(), codePath)) { 84 String fullPath = codePath.getAbsolutePath(); 85 String[] parts = fullPath.split(File.separator); 86 if (parts.length > 2) { 87 codeRoot = new File(parts[1] + File.separator + parts[2]); 88 } else { 89 Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath); 90 codeRoot = Environment.getApexDirectory(); 91 } 92 } else { 93 // Unrecognized code path; take its top real segment as the apk root: 94 // e.g. /something/app/blah.apk => /something 95 try { 96 File f = codePath.getCanonicalFile(); 97 File parent = f.getParentFile(); // non-null because codePath is a file 98 File tmp; 99 while ((tmp = parent.getParentFile()) != null) { 100 f = parent; 101 parent = tmp; 102 } 103 codeRoot = f; 104 Slog.w(PackageManagerService.TAG, "Unrecognized code path " 105 + codePath + " - using " + codeRoot); 106 } catch (IOException e) { 107 // Can't canonicalize the code path -- shenanigans? 108 Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath); 109 return Environment.getRootDirectory().getPath(); 110 } 111 } 112 return codeRoot.getPath(); 113 } 114 115 // Utility method that returns the relative package path with respect 116 // to the installation directory. Like say for /data/data/com.test-1.apk 117 // string com.test-1 is returned. deriveCodePathName(String codePath)118 private static String deriveCodePathName(String codePath) { 119 if (codePath == null) { 120 return null; 121 } 122 final File codeFile = new File(codePath); 123 final String name = codeFile.getName(); 124 if (codeFile.isDirectory()) { 125 return name; 126 } else if (name.endsWith(".apk") || name.endsWith(".tmp")) { 127 final int lastDot = name.lastIndexOf('.'); 128 return name.substring(0, lastDot); 129 } else { 130 Slog.w(PackageManagerService.TAG, "Odd, " + codePath + " doesn't look like an APK"); 131 return null; 132 } 133 } 134 maybeThrowExceptionForMultiArchCopy(String message, int copyRet, boolean forceMatch)135 private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet, 136 boolean forceMatch) throws PackageManagerException { 137 if (copyRet < 0) { 138 if (copyRet != PackageManager.NO_NATIVE_LIBRARIES 139 && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { 140 throw new PackageManagerException(copyRet, message); 141 } 142 143 if (forceMatch && copyRet == PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { 144 throw new PackageManagerException( 145 PackageManager.INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS, 146 "The multiArch app's native libs don't support all the natively" 147 + " supported ABIs of the device."); 148 } 149 } 150 } 151 152 @Override deriveNativeLibraryPaths(AndroidPackage pkg, boolean isSystemApp, boolean isUpdatedSystemApp, File appLib32InstallDir)153 public NativeLibraryPaths deriveNativeLibraryPaths(AndroidPackage pkg, boolean isSystemApp, 154 boolean isUpdatedSystemApp, File appLib32InstallDir) { 155 // Trying to derive the paths, thus need the raw ABI info from the parsed package, and the 156 // current state in PackageSetting is irrelevant. 157 return deriveNativeLibraryPaths(new Abis(AndroidPackageUtils.getRawPrimaryCpuAbi(pkg), 158 AndroidPackageUtils.getRawSecondaryCpuAbi(pkg)), appLib32InstallDir, pkg.getPath(), 159 pkg.getBaseApkPath(), isSystemApp, isUpdatedSystemApp); 160 } 161 deriveNativeLibraryPaths(final Abis abis, final File appLib32InstallDir, final String codePath, final String sourceDir, final boolean isSystemApp, final boolean isUpdatedSystemApp)162 private static NativeLibraryPaths deriveNativeLibraryPaths(final Abis abis, 163 final File appLib32InstallDir, final String codePath, final String sourceDir, 164 final boolean isSystemApp, final boolean isUpdatedSystemApp) { 165 final File codeFile = new File(codePath); 166 final boolean bundledApp = isSystemApp && !isUpdatedSystemApp; 167 168 final String nativeLibraryRootDir; 169 final boolean nativeLibraryRootRequiresIsa; 170 final String nativeLibraryDir; 171 final String secondaryNativeLibraryDir; 172 173 if (isApkFile(codeFile)) { 174 // Monolithic install 175 if (bundledApp) { 176 // If "/system/lib64/apkname" exists, assume that is the per-package 177 // native library directory to use; otherwise use "/system/lib/apkname". 178 final String apkRoot = calculateBundledApkRoot(sourceDir); 179 final boolean is64Bit = VMRuntime.is64BitInstructionSet( 180 getPrimaryInstructionSet(abis)); 181 182 // This is a bundled system app so choose the path based on the ABI. 183 // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this 184 // is just the default path. 185 final String apkName = deriveCodePathName(codePath); 186 final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME; 187 nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir, 188 apkName).getAbsolutePath(); 189 190 if (abis.secondary != null) { 191 final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME; 192 secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot), 193 secondaryLibDir, apkName).getAbsolutePath(); 194 } else { 195 secondaryNativeLibraryDir = null; 196 } 197 } else { 198 final String apkName = deriveCodePathName(codePath); 199 nativeLibraryRootDir = new File(appLib32InstallDir, apkName) 200 .getAbsolutePath(); 201 secondaryNativeLibraryDir = null; 202 } 203 204 nativeLibraryRootRequiresIsa = false; 205 nativeLibraryDir = nativeLibraryRootDir; 206 } else { 207 // Cluster install 208 nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath(); 209 nativeLibraryRootRequiresIsa = true; 210 211 nativeLibraryDir = new File(nativeLibraryRootDir, 212 getPrimaryInstructionSet(abis)).getAbsolutePath(); 213 214 if (abis.secondary != null) { 215 secondaryNativeLibraryDir = new File(nativeLibraryRootDir, 216 VMRuntime.getInstructionSet(abis.secondary)).getAbsolutePath(); 217 } else { 218 secondaryNativeLibraryDir = null; 219 } 220 } 221 return new NativeLibraryPaths(nativeLibraryRootDir, nativeLibraryRootRequiresIsa, 222 nativeLibraryDir, secondaryNativeLibraryDir); 223 } 224 225 @Override getBundledAppAbis(AndroidPackage pkg)226 public Abis getBundledAppAbis(AndroidPackage pkg) { 227 final String apkName = deriveCodePathName(pkg.getPath()); 228 229 // If "/system/lib64/apkname" exists, assume that is the per-package 230 // native library directory to use; otherwise use "/system/lib/apkname". 231 final String apkRoot = calculateBundledApkRoot(pkg.getBaseApkPath()); 232 final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName); 233 return abis; 234 } 235 236 /** 237 * Deduces the ABI of a bundled app and sets the relevant fields on the 238 * parsed pkg object. 239 * 240 * @param apkRoot the root of the installed apk, something like {@code /system} or 241 * {@code /oem} under which system libraries are installed. 242 * @param apkName the name of the installed package. 243 */ getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName)244 private Abis getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName) { 245 final File codeFile = new File(pkg.getPath()); 246 247 final boolean has64BitLibs; 248 final boolean has32BitLibs; 249 250 final String primaryCpuAbi; 251 final String secondaryCpuAbi; 252 if (isApkFile(codeFile)) { 253 // Monolithic install 254 has64BitLibs = 255 (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists(); 256 has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists(); 257 } else { 258 // Cluster install 259 final File rootDir = new File(codeFile, LIB_DIR_NAME); 260 if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS) 261 && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) { 262 final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]); 263 has64BitLibs = (new File(rootDir, isa)).exists(); 264 } else { 265 has64BitLibs = false; 266 } 267 if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS) 268 && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) { 269 final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]); 270 has32BitLibs = (new File(rootDir, isa)).exists(); 271 } else { 272 has32BitLibs = false; 273 } 274 } 275 276 if (has64BitLibs && !has32BitLibs) { 277 // The package has 64 bit libs, but not 32 bit libs. Its primary 278 // ABI should be 64 bit. We can safely assume here that the bundled 279 // native libraries correspond to the most preferred ABI in the list. 280 281 primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0]; 282 secondaryCpuAbi = null; 283 } else if (has32BitLibs && !has64BitLibs) { 284 // The package has 32 bit libs but not 64 bit libs. Its primary 285 // ABI should be 32 bit. 286 287 primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0]; 288 secondaryCpuAbi = null; 289 } else if (has32BitLibs && has64BitLibs) { 290 // The application has both 64 and 32 bit bundled libraries. We check 291 // here that the app declares multiArch support, and warn if it doesn't. 292 // 293 // We will be lenient here and record both ABIs. The primary will be the 294 // ABI that's higher on the list, i.e, a device that's configured to prefer 295 // 64 bit apps will see a 64 bit primary ABI, 296 297 if (!pkg.isMultiArch()) { 298 Slog.e(PackageManagerService.TAG, 299 "Package " + pkg + " has multiple bundled libs, but is not multiarch."); 300 } 301 302 if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) { 303 primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0]; 304 secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0]; 305 } else { 306 primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0]; 307 secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0]; 308 } 309 } else { 310 primaryCpuAbi = null; 311 secondaryCpuAbi = null; 312 } 313 return new Abis(primaryCpuAbi, secondaryCpuAbi); 314 } 315 316 @NonNull getNativelySupportedAbis(@onNull String[] supportedAbis)317 private static String[] getNativelySupportedAbis(@NonNull String[] supportedAbis) { 318 List<String> nativelySupportedAbis = new ArrayList<>(); 319 for (int i = 0; i < supportedAbis.length; i++) { 320 final String currentAbi = supportedAbis[i]; 321 // In presence of a native bridge this means the Abi is emulated. 322 final String currentIsa = VMRuntime.getInstructionSet(currentAbi); 323 if (TextUtils.isEmpty(SystemProperties.get("ro.dalvik.vm.isa." + currentIsa))) { 324 nativelySupportedAbis.add(currentAbi); 325 } 326 } 327 return nativelySupportedAbis.toArray(new String[0]); 328 } 329 getNativelySupported32BitAbis()330 private static String[] getNativelySupported32BitAbis() { 331 if (sNativelySupported32BitAbis != null) { 332 return sNativelySupported32BitAbis; 333 } 334 335 sNativelySupported32BitAbis = getNativelySupportedAbis(Build.SUPPORTED_32_BIT_ABIS); 336 return sNativelySupported32BitAbis; 337 } 338 getNativelySupported64BitAbis()339 private static String[] getNativelySupported64BitAbis() { 340 if (sNativelySupported64BitAbis != null) { 341 return sNativelySupported64BitAbis; 342 } 343 344 sNativelySupported64BitAbis = getNativelySupportedAbis(Build.SUPPORTED_64_BIT_ABIS); 345 return sNativelySupported64BitAbis; 346 } 347 348 @Override 349 @SuppressWarnings("AndroidFrameworkCompatChange") // the check is before the apk is installed derivePackageAbi(AndroidPackage pkg, boolean isSystemApp, boolean isUpdatedSystemApp, String cpuAbiOverride, File appLib32InstallDir)350 public Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, boolean isSystemApp, 351 boolean isUpdatedSystemApp, String cpuAbiOverride, File appLib32InstallDir) 352 throws PackageManagerException { 353 // Give ourselves some initial paths; we'll come back for another 354 // pass once we've determined ABI below. 355 String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(pkg); 356 String pkgRawSecondaryCpuAbi = AndroidPackageUtils.getRawSecondaryCpuAbi(pkg); 357 final NativeLibraryPaths initialLibraryPaths = deriveNativeLibraryPaths( 358 new Abis(pkgRawPrimaryCpuAbi, pkgRawSecondaryCpuAbi), 359 appLib32InstallDir, pkg.getPath(), 360 pkg.getBaseApkPath(), isSystemApp, 361 isUpdatedSystemApp); 362 363 final boolean extractLibs = shouldExtractLibs(pkg, isSystemApp, isUpdatedSystemApp); 364 365 final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir; 366 final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa; 367 final boolean onIncremental = isIncrementalPath(pkg.getPath()); 368 369 String primaryCpuAbi = null; 370 String secondaryCpuAbi = null; 371 372 NativeLibraryHelper.Handle handle = null; 373 try { 374 handle = AndroidPackageUtils.createNativeLibraryHandle(pkg); 375 // TODO(multiArch): This can be null for apps that didn't go through the 376 // usual installation process. We can calculate it again, like we 377 // do during install time. 378 // 379 // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally 380 // unnecessary. 381 final File nativeLibraryRoot = new File(nativeLibraryRootStr); 382 383 // Null out the abis so that they can be recalculated. 384 primaryCpuAbi = null; 385 secondaryCpuAbi = null; 386 if (pkg.isMultiArch()) { 387 // Force the match for these cases 388 // 1. pkg.getTargetSdkVersion >= Build.VERSION_CODES.VANILLA_ICE_CREAM 389 // 2. cpuAbiOverride is null. If it is non-null, it is set via shell for testing 390 final boolean forceMatch = Flags.forceMultiArchNativeLibsMatch() 391 && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.VANILLA_ICE_CREAM 392 && cpuAbiOverride == null; 393 394 String[] supported32BitAbis = forceMatch ? getNativelySupported32BitAbis() 395 : Build.SUPPORTED_32_BIT_ABIS; 396 String[] supported64BitAbis = forceMatch ? getNativelySupported64BitAbis() 397 : Build.SUPPORTED_64_BIT_ABIS; 398 399 final boolean systemSupports32BitAbi = supported32BitAbis.length > 0; 400 final boolean systemSupports64BitAbi = supported64BitAbis.length > 0; 401 402 int abi32 = PackageManager.NO_NATIVE_LIBRARIES; 403 int abi64 = PackageManager.NO_NATIVE_LIBRARIES; 404 if (systemSupports32BitAbi) { 405 if (extractLibs) { 406 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries"); 407 abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, 408 nativeLibraryRoot, supported32BitAbis, 409 useIsaSpecificSubdirs, onIncremental); 410 } else { 411 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi"); 412 abi32 = NativeLibraryHelper.findSupportedAbi( 413 handle, supported32BitAbis); 414 } 415 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 416 } 417 418 // Shared library native code should be in the APK zip aligned 419 if (abi32 >= 0 && AndroidPackageUtils.isLibrary(pkg) && extractLibs) { 420 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 421 "Shared library native lib extraction not supported"); 422 } 423 424 maybeThrowExceptionForMultiArchCopy( 425 "Error unpackaging 32 bit native libs for multiarch app.", abi32, 426 forceMatch && systemSupports32BitAbi); 427 428 if (systemSupports64BitAbi) { 429 if (extractLibs) { 430 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries"); 431 abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, 432 nativeLibraryRoot, supported64BitAbis, 433 useIsaSpecificSubdirs, onIncremental); 434 } else { 435 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi"); 436 abi64 = NativeLibraryHelper.findSupportedAbi( 437 handle, supported64BitAbis); 438 } 439 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 440 } 441 442 maybeThrowExceptionForMultiArchCopy( 443 "Error unpackaging 64 bit native libs for multiarch app.", abi64, 444 forceMatch && systemSupports64BitAbi); 445 446 if (abi64 >= 0) { 447 // Shared library native libs should be in the APK zip aligned 448 if (extractLibs && AndroidPackageUtils.isLibrary(pkg)) { 449 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 450 "Shared library native lib extraction not supported"); 451 } 452 primaryCpuAbi = supported64BitAbis[abi64]; 453 } 454 455 if (abi32 >= 0) { 456 final String abi = supported32BitAbis[abi32]; 457 if (abi64 >= 0) { 458 if (pkg.is32BitAbiPreferred()) { 459 secondaryCpuAbi = primaryCpuAbi; 460 primaryCpuAbi = abi; 461 } else { 462 secondaryCpuAbi = abi; 463 } 464 } else { 465 primaryCpuAbi = abi; 466 } 467 } 468 } else { 469 String[] abiList = (cpuAbiOverride != null) 470 ? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS; 471 472 // If an app that contains RenderScript has target API level < 21, it needs to run 473 // with 32-bit ABI, and its APK file will contain a ".bc" file. 474 // If an app that contains RenderScript has target API level >= 21, it can run with 475 // either 32-bit or 64-bit ABI, and its APK file will not contain a ".bc" file. 476 // Therefore, on a device that supports both 32-bit and 64-bit ABIs, we scan the app 477 // APK to see if it has a ".bc" file. If so, we will run it with 32-bit ABI. 478 // However, if the device only supports 64-bit ABI but does not support 32-bit ABI, 479 // we will fail the installation for such an app because it won't be able to run. 480 boolean needsRenderScriptOverride = false; 481 // No need to check if the device only supports 32-bit 482 if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null 483 && NativeLibraryHelper.hasRenderscriptBitcode(handle)) { 484 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { 485 abiList = Build.SUPPORTED_32_BIT_ABIS; 486 needsRenderScriptOverride = true; 487 } else { 488 throw new PackageManagerException( 489 INSTALL_FAILED_CPU_ABI_INCOMPATIBLE, 490 "Apps that contain RenderScript with target API level < 21 are not " 491 + "supported on 64-bit only platforms"); 492 } 493 } 494 495 final int copyRet; 496 if (extractLibs) { 497 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries"); 498 copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, 499 nativeLibraryRoot, abiList, useIsaSpecificSubdirs, onIncremental); 500 } else { 501 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi"); 502 copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList); 503 } 504 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 505 506 if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { 507 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 508 "Error unpackaging native libs for app, errorCode=" + copyRet); 509 } 510 511 if (copyRet >= 0) { 512 // Shared libraries that have native libs must be multi-architecture 513 if (AndroidPackageUtils.isLibrary(pkg)) { 514 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 515 "Shared library with native libs must be multiarch"); 516 } 517 primaryCpuAbi = abiList[copyRet]; 518 } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES 519 && cpuAbiOverride != null) { 520 primaryCpuAbi = cpuAbiOverride; 521 } else if (needsRenderScriptOverride) { 522 primaryCpuAbi = abiList[0]; 523 } 524 } 525 } catch (IOException ioe) { 526 Slog.e(PackageManagerService.TAG, "Unable to get canonical file " + ioe.toString()); 527 } finally { 528 IoUtils.closeQuietly(handle); 529 } 530 531 // Now that we've calculated the ABIs and determined if it's an internal app, 532 // we will go ahead and populate the nativeLibraryPath. 533 534 final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi); 535 return new Pair<>(abis, 536 deriveNativeLibraryPaths(abis, appLib32InstallDir, 537 pkg.getPath(), pkg.getBaseApkPath(), isSystemApp, 538 isUpdatedSystemApp)); 539 } 540 shouldExtractLibs(AndroidPackage pkg, boolean isSystemApp, boolean isUpdatedSystemApp)541 private boolean shouldExtractLibs(AndroidPackage pkg, boolean isSystemApp, 542 boolean isUpdatedSystemApp) { 543 // We shouldn't extract libs if the package is a library or if extractNativeLibs=false 544 boolean extractLibs = !AndroidPackageUtils.isLibrary(pkg) 545 && pkg.isExtractNativeLibrariesRequested(); 546 // We shouldn't attempt to extract libs from system app when it was not updated. 547 if (isSystemApp && !isUpdatedSystemApp) { 548 extractLibs = false; 549 } 550 return extractLibs; 551 } 552 553 /** 554 * Adjusts ABIs for a set of packages belonging to a shared user so that they all match. 555 * i.e, so that all packages can be run inside a single process if required. 556 * 557 * Optionally, callers can pass in a parsed package via {@code newPackage} in which case 558 * this function will either try and make the ABI for all packages in 559 * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of 560 * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This 561 * variant is used when installing or updating a package that belongs to a shared user. 562 * 563 * NOTE: We currently only match for the primary CPU abi string. Matching the secondary 564 * adds unnecessary complexity. 565 */ 566 @Override 567 @Nullable getAdjustedAbiForSharedUser( ArraySet<? extends PackageStateInternal> packagesForUser, AndroidPackage scannedPackage)568 public String getAdjustedAbiForSharedUser( 569 ArraySet<? extends PackageStateInternal> packagesForUser, 570 AndroidPackage scannedPackage) { 571 String requiredInstructionSet = null; 572 if (scannedPackage != null) { 573 String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage); 574 if (pkgRawPrimaryCpuAbi != null) { 575 requiredInstructionSet = VMRuntime.getInstructionSet(pkgRawPrimaryCpuAbi); 576 } 577 } 578 579 PackageStateInternal requirer = null; 580 for (PackageStateInternal ps : packagesForUser) { 581 // If packagesForUser contains scannedPackage, we skip it. This will happen 582 // when scannedPackage is an update of an existing package. Without this check, 583 // we will never be able to change the ABI of any package belonging to a shared 584 // user, even if it's compatible with other packages. 585 if (scannedPackage != null && scannedPackage.getPackageName().equals( 586 ps.getPackageName())) { 587 continue; 588 } 589 if (ps.getPrimaryCpuAbiLegacy() == null) { 590 continue; 591 } 592 593 final String instructionSet = 594 VMRuntime.getInstructionSet(ps.getPrimaryCpuAbiLegacy()); 595 if (requiredInstructionSet != null && !requiredInstructionSet.equals(instructionSet)) { 596 // We have a mismatch between instruction sets (say arm vs arm64) warn about 597 // this but there's not much we can do. 598 String errorMessage = "Instruction set mismatch, " 599 + ((requirer == null) ? "[caller]" : requirer) 600 + " requires " + requiredInstructionSet + " whereas " + ps 601 + " requires " + instructionSet; 602 Slog.w(PackageManagerService.TAG, errorMessage); 603 } 604 605 if (requiredInstructionSet == null) { 606 requiredInstructionSet = instructionSet; 607 requirer = ps; 608 } 609 } 610 611 if (requiredInstructionSet == null) { 612 return null; 613 } 614 final String adjustedAbi; 615 if (requirer != null) { 616 // requirer != null implies that either scannedPackage was null or that 617 // scannedPackage did not require an ABI, in which case we have to adjust 618 // scannedPackage to match the ABI of the set (which is the same as 619 // requirer's ABI) 620 adjustedAbi = requirer.getPrimaryCpuAbiLegacy(); 621 } else { 622 // requirer == null implies that we're updating all ABIs in the set to 623 // match scannedPackage. 624 adjustedAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage); 625 } 626 return adjustedAbi; 627 } 628 } 629