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