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