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