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