1 /* 2 * Copyright (C) 2021 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.os.Trace.TRACE_TAG_DALVIK; 20 21 import static com.android.server.LocalManagerRegistry.ManagerNotFoundException; 22 import static com.android.server.pm.ApexManager.ActiveApexInfo; 23 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; 24 import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT; 25 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; 26 import static com.android.server.pm.PackageManagerService.REASON_BOOT_AFTER_MAINLINE_UPDATE; 27 import static com.android.server.pm.PackageManagerService.REASON_BOOT_AFTER_OTA; 28 import static com.android.server.pm.PackageManagerService.REASON_CMDLINE; 29 import static com.android.server.pm.PackageManagerService.REASON_FIRST_BOOT; 30 import static com.android.server.pm.PackageManagerService.STUB_SUFFIX; 31 import static com.android.server.pm.PackageManagerService.TAG; 32 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason; 33 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter; 34 import static com.android.server.pm.PackageManagerServiceUtils.REMOVE_IF_APEX_PKG; 35 import static com.android.server.pm.PackageManagerServiceUtils.REMOVE_IF_NULL_PKG; 36 import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal; 37 38 import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; 39 40 import android.annotation.NonNull; 41 import android.annotation.Nullable; 42 import android.app.AppGlobals; 43 import android.app.role.RoleManager; 44 import android.content.BroadcastReceiver; 45 import android.content.Context; 46 import android.content.Intent; 47 import android.content.IntentFilter; 48 import android.content.pm.ResolveInfo; 49 import android.content.pm.SharedLibraryInfo; 50 import android.content.pm.dex.ArtManager; 51 import android.os.Binder; 52 import android.os.RemoteException; 53 import android.os.SystemClock; 54 import android.os.SystemProperties; 55 import android.os.Trace; 56 import android.os.UserHandle; 57 import android.text.TextUtils; 58 import android.util.ArraySet; 59 import android.util.Log; 60 import android.util.Slog; 61 62 import com.android.internal.logging.MetricsLogger; 63 import com.android.internal.util.FrameworkStatsLog; 64 import com.android.internal.util.IndentingPrintWriter; 65 import com.android.server.LocalManagerRegistry; 66 import com.android.server.LocalServices; 67 import com.android.server.PinnerService; 68 import com.android.server.art.ArtManagerLocal; 69 import com.android.server.art.DexUseManagerLocal; 70 import com.android.server.art.ReasonMapping; 71 import com.android.server.art.model.ArtFlags; 72 import com.android.server.art.model.DexoptParams; 73 import com.android.server.art.model.DexoptResult; 74 import com.android.server.pm.Installer.InstallerException; 75 import com.android.server.pm.Installer.LegacyDexoptDisabledException; 76 import com.android.server.pm.PackageDexOptimizer.DexOptResult; 77 import com.android.server.pm.dex.DexManager; 78 import com.android.server.pm.dex.DexoptOptions; 79 import com.android.server.pm.pkg.AndroidPackage; 80 import com.android.server.pm.pkg.PackageState; 81 import com.android.server.pm.pkg.PackageStateInternal; 82 83 import java.io.File; 84 import java.nio.file.Path; 85 import java.nio.file.Paths; 86 import java.util.ArrayList; 87 import java.util.Collection; 88 import java.util.Collections; 89 import java.util.Comparator; 90 import java.util.HashSet; 91 import java.util.List; 92 import java.util.Set; 93 import java.util.concurrent.TimeUnit; 94 import java.util.function.Predicate; 95 96 /** 97 * Helper class for dex optimization operations in PackageManagerService. 98 */ 99 public final class DexOptHelper { 100 private static final long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000; 101 102 private static boolean sArtManagerLocalIsInitialized = false; 103 104 private final PackageManagerService mPm; 105 106 // Start time for the boot dexopt in performPackageDexOptUpgradeIfNeeded when ART Service is 107 // used, to make it available to the onDexoptDone callback. 108 private volatile long mBootDexoptStartTime; 109 DexOptHelper(PackageManagerService pm)110 DexOptHelper(PackageManagerService pm) { 111 mPm = pm; 112 } 113 114 /* 115 * Return the prebuilt profile path given a package base code path. 116 */ getPrebuildProfilePath(AndroidPackage pkg)117 private static String getPrebuildProfilePath(AndroidPackage pkg) { 118 return pkg.getBaseApkPath() + ".prof"; 119 } 120 121 /** 122 * Performs dexopt on the set of packages in {@code packages} and returns an int array 123 * containing statistics about the invocation. The array consists of three elements, 124 * which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped} 125 * and {@code numberOfPackagesFailed}. 126 */ performDexOptUpgrade(List<PackageStateInternal> packageStates, final int compilationReason, boolean bootComplete)127 public int[] performDexOptUpgrade(List<PackageStateInternal> packageStates, 128 final int compilationReason, boolean bootComplete) 129 throws LegacyDexoptDisabledException { 130 Installer.checkLegacyDexoptDisabled(); 131 int numberOfPackagesVisited = 0; 132 int numberOfPackagesOptimized = 0; 133 int numberOfPackagesSkipped = 0; 134 int numberOfPackagesFailed = 0; 135 final int numberOfPackagesToDexopt = packageStates.size(); 136 137 for (var packageState : packageStates) { 138 var pkg = packageState.getAndroidPackage(); 139 numberOfPackagesVisited++; 140 141 boolean useProfileForDexopt = false; 142 143 if ((mPm.isFirstBoot() || mPm.isDeviceUpgrading()) && packageState.isSystem()) { 144 // Copy over initial preopt profiles since we won't get any JIT samples for methods 145 // that are already compiled. 146 File profileFile = new File(getPrebuildProfilePath(pkg)); 147 // Copy profile if it exists. 148 if (profileFile.exists()) { 149 try { 150 // We could also do this lazily before calling dexopt in 151 // PackageDexOptimizer to prevent this happening on first boot. The issue 152 // is that we don't have a good way to say "do this only once". 153 if (!mPm.mInstaller.copySystemProfile(profileFile.getAbsolutePath(), 154 pkg.getUid(), pkg.getPackageName(), 155 ArtManager.getProfileName(null))) { 156 Log.e(TAG, "Installer failed to copy system profile!"); 157 } else { 158 // Disabled as this causes speed-profile compilation during first boot 159 // even if things are already compiled. 160 // useProfileForDexopt = true; 161 } 162 } catch (InstallerException | RuntimeException e) { 163 Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", 164 e); 165 } 166 } else { 167 PackageSetting disabledPs = mPm.mSettings.getDisabledSystemPkgLPr( 168 pkg.getPackageName()); 169 // Handle compressed APKs in this path. Only do this for stubs with profiles to 170 // minimize the number off apps being speed-profile compiled during first boot. 171 // The other paths will not change the filter. 172 if (disabledPs != null && disabledPs.getPkg().isStub()) { 173 // The package is the stub one, remove the stub suffix to get the normal 174 // package and APK names. 175 String systemProfilePath = getPrebuildProfilePath(disabledPs.getPkg()) 176 .replace(STUB_SUFFIX, ""); 177 profileFile = new File(systemProfilePath); 178 // If we have a profile for a compressed APK, copy it to the reference 179 // location. 180 // Note that copying the profile here will cause it to override the 181 // reference profile every OTA even though the existing reference profile 182 // may have more data. We can't copy during decompression since the 183 // directories are not set up at that point. 184 if (profileFile.exists()) { 185 try { 186 // We could also do this lazily before calling dexopt in 187 // PackageDexOptimizer to prevent this happening on first boot. The 188 // issue is that we don't have a good way to say "do this only 189 // once". 190 if (!mPm.mInstaller.copySystemProfile(profileFile.getAbsolutePath(), 191 pkg.getUid(), pkg.getPackageName(), 192 ArtManager.getProfileName(null))) { 193 Log.e(TAG, "Failed to copy system profile for stub package!"); 194 } else { 195 useProfileForDexopt = true; 196 } 197 } catch (InstallerException | RuntimeException e) { 198 Log.e(TAG, "Failed to copy profile " 199 + profileFile.getAbsolutePath() + " ", e); 200 } 201 } 202 } 203 } 204 } 205 206 if (!mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) { 207 if (DEBUG_DEXOPT) { 208 Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName()); 209 } 210 numberOfPackagesSkipped++; 211 continue; 212 } 213 214 if (DEBUG_DEXOPT) { 215 Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " 216 + numberOfPackagesToDexopt + ": " + pkg.getPackageName()); 217 } 218 219 int pkgCompilationReason = compilationReason; 220 if (useProfileForDexopt) { 221 // Use background dexopt mode to try and use the profile. Note that this does not 222 // guarantee usage of the profile. 223 pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT; 224 } 225 226 // TODO(b/251903639): Do this when ART Service is used, or remove it from here. 227 if (SystemProperties.getBoolean(mPm.PRECOMPILE_LAYOUTS, false)) { 228 mPm.mArtManagerService.compileLayouts(packageState, pkg); 229 } 230 231 int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0; 232 233 String filter = getCompilerFilterForReason(pkgCompilationReason); 234 if (isProfileGuidedCompilerFilter(filter)) { 235 // DEXOPT_CHECK_FOR_PROFILES_UPDATES used to be false to avoid merging profiles 236 // during boot which might interfere with background compilation (b/28612421). 237 // However those problems were related to the verify-profile compiler filter which 238 // doesn't exist any more, so enable it again. 239 dexoptFlags |= DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES; 240 } 241 242 if (compilationReason == REASON_FIRST_BOOT) { 243 // TODO: This doesn't cover the upgrade case, we should check for this too. 244 dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE; 245 } 246 int primaryDexOptStatus = performDexOptTraced( 247 new DexoptOptions(pkg.getPackageName(), pkgCompilationReason, filter, 248 /*splitName*/ null, dexoptFlags)); 249 250 switch (primaryDexOptStatus) { 251 case PackageDexOptimizer.DEX_OPT_PERFORMED: 252 numberOfPackagesOptimized++; 253 break; 254 case PackageDexOptimizer.DEX_OPT_SKIPPED: 255 numberOfPackagesSkipped++; 256 break; 257 case PackageDexOptimizer.DEX_OPT_CANCELLED: 258 // ignore this case 259 break; 260 case PackageDexOptimizer.DEX_OPT_FAILED: 261 numberOfPackagesFailed++; 262 break; 263 default: 264 Log.e(TAG, "Unexpected dexopt return code " + primaryDexOptStatus); 265 break; 266 } 267 } 268 269 return new int[]{numberOfPackagesOptimized, numberOfPackagesSkipped, 270 numberOfPackagesFailed}; 271 } 272 273 /** 274 * Checks if system UI package (typically "com.android.systemui") needs to be re-compiled, and 275 * compiles it if needed. 276 */ checkAndDexOptSystemUi(int reason)277 private void checkAndDexOptSystemUi(int reason) throws LegacyDexoptDisabledException { 278 Computer snapshot = mPm.snapshotComputer(); 279 String sysUiPackageName = 280 mPm.mContext.getString(com.android.internal.R.string.config_systemUi); 281 AndroidPackage pkg = snapshot.getPackage(sysUiPackageName); 282 if (pkg == null) { 283 Log.w(TAG, "System UI package " + sysUiPackageName + " is not found for dexopting"); 284 return; 285 } 286 287 String defaultCompilerFilter = getCompilerFilterForReason(reason); 288 String targetCompilerFilter = 289 SystemProperties.get("dalvik.vm.systemuicompilerfilter", defaultCompilerFilter); 290 String compilerFilter; 291 292 if (isProfileGuidedCompilerFilter(targetCompilerFilter)) { 293 compilerFilter = "verify"; 294 File profileFile = new File(getPrebuildProfilePath(pkg)); 295 296 // Copy the profile to the reference profile path if it exists. Installd can only use a 297 // profile at the reference profile path for dexopt. 298 if (profileFile.exists()) { 299 try { 300 synchronized (mPm.mInstallLock) { 301 if (mPm.mInstaller.copySystemProfile(profileFile.getAbsolutePath(), 302 pkg.getUid(), pkg.getPackageName(), 303 ArtManager.getProfileName(null))) { 304 compilerFilter = targetCompilerFilter; 305 } else { 306 Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath()); 307 } 308 } 309 } catch (InstallerException | RuntimeException e) { 310 Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath(), e); 311 } 312 } 313 } else { 314 compilerFilter = targetCompilerFilter; 315 } 316 317 performDexoptPackage(sysUiPackageName, reason, compilerFilter); 318 } 319 dexoptLauncher(int reason)320 private void dexoptLauncher(int reason) throws LegacyDexoptDisabledException { 321 Computer snapshot = mPm.snapshotComputer(); 322 RoleManager roleManager = mPm.mContext.getSystemService(RoleManager.class); 323 for (var packageName : roleManager.getRoleHolders(RoleManager.ROLE_HOME)) { 324 AndroidPackage pkg = snapshot.getPackage(packageName); 325 if (pkg == null) { 326 Log.w(TAG, "Launcher package " + packageName + " is not found for dexopting"); 327 } else { 328 performDexoptPackage(packageName, reason, "speed-profile"); 329 } 330 } 331 } 332 performDexoptPackage(@onNull String packageName, int reason, @NonNull String compilerFilter)333 private void performDexoptPackage(@NonNull String packageName, int reason, 334 @NonNull String compilerFilter) throws LegacyDexoptDisabledException { 335 Installer.checkLegacyDexoptDisabled(); 336 337 // DEXOPT_CHECK_FOR_PROFILES_UPDATES is set to replicate behaviour that will be 338 // unconditionally enabled for profile guided filters when ART Service is called instead of 339 // the legacy PackageDexOptimizer implementation. 340 int dexoptFlags = isProfileGuidedCompilerFilter(compilerFilter) 341 ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES 342 : 0; 343 344 performDexOptTraced(new DexoptOptions( 345 packageName, reason, compilerFilter, null /* splitName */, dexoptFlags)); 346 } 347 348 /** 349 * Called during startup to do any boot time dexopting. This can occasionally be time consuming 350 * (30+ seconds) and the function will block until it is complete. 351 */ performPackageDexOptUpgradeIfNeeded()352 public void performPackageDexOptUpgradeIfNeeded() { 353 PackageManagerServiceUtils.enforceSystemOrRoot( 354 "Only the system can request package update"); 355 356 int reason; 357 if (mPm.isFirstBoot()) { 358 reason = REASON_FIRST_BOOT; // First boot or factory reset. 359 } else if (mPm.isDeviceUpgrading()) { 360 reason = REASON_BOOT_AFTER_OTA; 361 } else if (hasBcpApexesChanged()) { 362 reason = REASON_BOOT_AFTER_MAINLINE_UPDATE; 363 } else { 364 return; 365 } 366 367 Log.i(TAG, 368 "Starting boot dexopt for reason " 369 + DexoptOptions.convertToArtServiceDexoptReason(reason)); 370 371 final long startTime = System.nanoTime(); 372 373 if (useArtService()) { 374 mBootDexoptStartTime = startTime; 375 getArtManagerLocal().onBoot(DexoptOptions.convertToArtServiceDexoptReason(reason), 376 null /* progressCallbackExecutor */, null /* progressCallback */); 377 } else { 378 try { 379 // System UI and the launcher are important to user experience, so we check them 380 // after a mainline update or OTA. They may need to be re-compiled in these cases. 381 checkAndDexOptSystemUi(reason); 382 dexoptLauncher(reason); 383 384 if (reason != REASON_BOOT_AFTER_OTA && reason != REASON_FIRST_BOOT) { 385 return; 386 } 387 388 final Computer snapshot = mPm.snapshotComputer(); 389 390 // TODO(b/251903639): Align this with how ART Service selects packages for boot 391 // compilation. 392 List<PackageStateInternal> pkgSettings = 393 getPackagesForDexopt(snapshot.getPackageStates().values(), mPm); 394 395 final int[] stats = 396 performDexOptUpgrade(pkgSettings, reason, false /* bootComplete */); 397 reportBootDexopt(startTime, stats[0], stats[1], stats[2]); 398 } catch (LegacyDexoptDisabledException e) { 399 throw new RuntimeException(e); 400 } 401 } 402 } 403 reportBootDexopt(long startTime, int numDexopted, int numSkipped, int numFailed)404 private void reportBootDexopt(long startTime, int numDexopted, int numSkipped, int numFailed) { 405 final int elapsedTimeSeconds = 406 (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime); 407 408 final Computer newSnapshot = mPm.snapshotComputer(); 409 410 MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_dexopted", numDexopted); 411 MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_skipped", numSkipped); 412 MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_failed", numFailed); 413 // TODO(b/251903639): getOptimizablePackages calls PackageDexOptimizer.canOptimizePackage 414 // which duplicates logic in ART Service (com.android.server.art.Utils.canDexoptPackage). 415 MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_total", 416 getOptimizablePackages(newSnapshot).size()); 417 MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds); 418 } 419 getOptimizablePackages(@onNull Computer snapshot)420 public List<String> getOptimizablePackages(@NonNull Computer snapshot) { 421 ArrayList<String> pkgs = new ArrayList<>(); 422 mPm.forEachPackageState(snapshot, packageState -> { 423 final AndroidPackage pkg = packageState.getPkg(); 424 if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) { 425 pkgs.add(packageState.getPackageName()); 426 } 427 }); 428 return pkgs; 429 } 430 performDexOpt(DexoptOptions options)431 /*package*/ boolean performDexOpt(DexoptOptions options) { 432 final Computer snapshot = mPm.snapshotComputer(); 433 if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) { 434 return false; 435 } else if (snapshot.isInstantApp(options.getPackageName(), UserHandle.getCallingUserId())) { 436 return false; 437 } 438 var pkg = snapshot.getPackage(options.getPackageName()); 439 if (pkg != null && pkg.isApex()) { 440 // skip APEX 441 return true; 442 } 443 444 @DexOptResult int dexoptStatus; 445 if (options.isDexoptOnlySecondaryDex()) { 446 if (useArtService()) { 447 dexoptStatus = performDexOptWithArtService(options, 0 /* extraFlags */); 448 } else { 449 try { 450 return mPm.getDexManager().dexoptSecondaryDex(options); 451 } catch (LegacyDexoptDisabledException e) { 452 throw new RuntimeException(e); 453 } 454 } 455 } else { 456 dexoptStatus = performDexOptWithStatus(options); 457 } 458 return dexoptStatus != PackageDexOptimizer.DEX_OPT_FAILED; 459 } 460 461 /** 462 * Perform dexopt on the given package and return one of following result: 463 * {@link PackageDexOptimizer#DEX_OPT_SKIPPED} 464 * {@link PackageDexOptimizer#DEX_OPT_PERFORMED} 465 * {@link PackageDexOptimizer#DEX_OPT_CANCELLED} 466 * {@link PackageDexOptimizer#DEX_OPT_FAILED} 467 */ 468 @DexOptResult performDexOptWithStatus(DexoptOptions options)469 /* package */ int performDexOptWithStatus(DexoptOptions options) { 470 return performDexOptTraced(options); 471 } 472 473 @DexOptResult performDexOptTraced(DexoptOptions options)474 private int performDexOptTraced(DexoptOptions options) { 475 Trace.traceBegin(TRACE_TAG_DALVIK, "dexopt"); 476 try { 477 return performDexOptInternal(options); 478 } finally { 479 Trace.traceEnd(TRACE_TAG_DALVIK); 480 } 481 } 482 483 // Run dexopt on a given package. Returns true if dexopt did not fail, i.e. 484 // if the package can now be considered up to date for the given filter. 485 @DexOptResult performDexOptInternal(DexoptOptions options)486 private int performDexOptInternal(DexoptOptions options) { 487 if (useArtService()) { 488 return performDexOptWithArtService(options, ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES); 489 } 490 491 AndroidPackage p; 492 PackageSetting pkgSetting; 493 synchronized (mPm.mLock) { 494 p = mPm.mPackages.get(options.getPackageName()); 495 pkgSetting = mPm.mSettings.getPackageLPr(options.getPackageName()); 496 if (p == null || pkgSetting == null) { 497 // Package could not be found. Report failure. 498 return PackageDexOptimizer.DEX_OPT_FAILED; 499 } 500 if (p.isApex()) { 501 // APEX needs no dexopt 502 return PackageDexOptimizer.DEX_OPT_SKIPPED; 503 } 504 mPm.getPackageUsage().maybeWriteAsync(mPm.mSettings.getPackagesLocked()); 505 mPm.mCompilerStats.maybeWriteAsync(); 506 } 507 final long callingId = Binder.clearCallingIdentity(); 508 try { 509 return performDexOptInternalWithDependenciesLI(p, pkgSetting, options); 510 } catch (LegacyDexoptDisabledException e) { 511 throw new RuntimeException(e); 512 } finally { 513 Binder.restoreCallingIdentity(callingId); 514 } 515 } 516 517 /** 518 * Performs dexopt on the given package using ART Service. May only be called when ART Service 519 * is enabled, i.e. when {@link useArtService} returns true. 520 */ 521 @DexOptResult performDexOptWithArtService(DexoptOptions options, int extraFlags)522 private int performDexOptWithArtService(DexoptOptions options, 523 /*@DexoptFlags*/ int extraFlags) { 524 try (PackageManagerLocal.FilteredSnapshot snapshot = 525 getPackageManagerLocal().withFilteredSnapshot()) { 526 PackageState ops = snapshot.getPackageState(options.getPackageName()); 527 if (ops == null) { 528 return PackageDexOptimizer.DEX_OPT_FAILED; 529 } 530 AndroidPackage oap = ops.getAndroidPackage(); 531 if (oap == null) { 532 return PackageDexOptimizer.DEX_OPT_FAILED; 533 } 534 DexoptParams params = options.convertToDexoptParams(extraFlags); 535 DexoptResult result = 536 getArtManagerLocal().dexoptPackage(snapshot, options.getPackageName(), params); 537 return convertToDexOptResult(result); 538 } 539 } 540 541 @DexOptResult performDexOptInternalWithDependenciesLI( AndroidPackage p, @NonNull PackageStateInternal pkgSetting, DexoptOptions options)542 private int performDexOptInternalWithDependenciesLI( 543 AndroidPackage p, @NonNull PackageStateInternal pkgSetting, DexoptOptions options) 544 throws LegacyDexoptDisabledException { 545 if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) { 546 // This needs to be done in odrefresh in early boot, for security reasons. 547 throw new IllegalArgumentException("Cannot dexopt the system server"); 548 } 549 550 // Select the dex optimizer based on the force parameter. 551 // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to 552 // allocate an object here. 553 PackageDexOptimizer pdo = options.isForce() 554 ? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPm.mPackageDexOptimizer) 555 : mPm.mPackageDexOptimizer; 556 557 // Dexopt all dependencies first. Note: we ignore the return value and march on 558 // on errors. 559 // Note that we are going to call performDexOpt on those libraries as many times as 560 // they are referenced in packages. When we do a batch of performDexOpt (for example 561 // at boot, or background job), the passed 'targetCompilerFilter' stays the same, 562 // and the first package that uses the library will dexopt it. The 563 // others will see that the compiled code for the library is up to date. 564 Collection<SharedLibraryInfo> deps = SharedLibraryUtils.findSharedLibraries(pkgSetting); 565 final String[] instructionSets = getAppDexInstructionSets( 566 pkgSetting.getPrimaryCpuAbi(), 567 pkgSetting.getSecondaryCpuAbi()); 568 if (!deps.isEmpty()) { 569 DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(), 570 options.getCompilationReason(), options.getCompilerFilter(), 571 options.getSplitName(), 572 options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY); 573 for (SharedLibraryInfo info : deps) { 574 Computer snapshot = mPm.snapshotComputer(); 575 AndroidPackage depPackage = snapshot.getPackage(info.getPackageName()); 576 PackageStateInternal depPackageStateInternal = 577 snapshot.getPackageStateInternal(info.getPackageName()); 578 if (depPackage != null && depPackageStateInternal != null) { 579 // TODO: Analyze and investigate if we (should) profile libraries. 580 pdo.performDexOpt(depPackage, depPackageStateInternal, instructionSets, 581 mPm.getOrCreateCompilerPackageStats(depPackage), 582 mPm.getDexManager().getPackageUseInfoOrDefault( 583 depPackage.getPackageName()), libraryOptions); 584 } else { 585 // TODO(ngeoffray): Support dexopting system shared libraries. 586 } 587 } 588 } 589 590 return pdo.performDexOpt(p, pkgSetting, instructionSets, 591 mPm.getOrCreateCompilerPackageStats(p), 592 mPm.getDexManager().getPackageUseInfoOrDefault(p.getPackageName()), options); 593 } 594 595 /** @deprecated For legacy shell command only. */ 596 @Deprecated forceDexOpt(@onNull Computer snapshot, String packageName)597 public void forceDexOpt(@NonNull Computer snapshot, String packageName) 598 throws LegacyDexoptDisabledException { 599 PackageManagerServiceUtils.enforceSystemOrRoot("forceDexOpt"); 600 601 final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); 602 final AndroidPackage pkg = packageState == null ? null : packageState.getPkg(); 603 if (packageState == null || pkg == null) { 604 throw new IllegalArgumentException("Unknown package: " + packageName); 605 } 606 if (pkg.isApex()) { 607 throw new IllegalArgumentException("Can't dexopt APEX package: " + packageName); 608 } 609 610 Trace.traceBegin(TRACE_TAG_DALVIK, "dexopt"); 611 612 // Whoever is calling forceDexOpt wants a compiled package. 613 // Don't use profiles since that may cause compilation to be skipped. 614 DexoptOptions options = new DexoptOptions(packageName, REASON_CMDLINE, 615 getDefaultCompilerFilter(), null /* splitName */, 616 DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE); 617 618 @DexOptResult int res = performDexOptInternalWithDependenciesLI(pkg, packageState, options); 619 620 Trace.traceEnd(TRACE_TAG_DALVIK); 621 if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) { 622 throw new IllegalStateException("Failed to dexopt: " + res); 623 } 624 } 625 performDexOptMode(@onNull Computer snapshot, String packageName, String targetCompilerFilter, boolean force, boolean bootComplete, String splitName)626 public boolean performDexOptMode(@NonNull Computer snapshot, String packageName, 627 String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) { 628 if (!PackageManagerServiceUtils.isSystemOrRootOrShell() 629 && !isCallerInstallerForPackage(snapshot, packageName)) { 630 throw new SecurityException("performDexOptMode"); 631 } 632 633 int flags = (force ? DexoptOptions.DEXOPT_FORCE : 0) 634 | (bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0); 635 636 if (isProfileGuidedCompilerFilter(targetCompilerFilter)) { 637 // Set this flag whenever the filter is profile guided, to align with ART Service 638 // behavior. 639 flags |= DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES; 640 } 641 642 return performDexOpt(new DexoptOptions(packageName, REASON_CMDLINE, 643 targetCompilerFilter, splitName, flags)); 644 } 645 isCallerInstallerForPackage(@onNull Computer snapshot, String packageName)646 private boolean isCallerInstallerForPackage(@NonNull Computer snapshot, String packageName) { 647 final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); 648 if (packageState == null) { 649 return false; 650 } 651 final InstallSource installSource = packageState.getInstallSource(); 652 653 final PackageStateInternal installerPackageState = 654 snapshot.getPackageStateInternal(installSource.mInstallerPackageName); 655 if (installerPackageState == null) { 656 return false; 657 } 658 final AndroidPackage installerPkg = installerPackageState.getPkg(); 659 return installerPkg.getUid() == Binder.getCallingUid(); 660 } 661 performDexOptSecondary( String packageName, String compilerFilter, boolean force)662 public boolean performDexOptSecondary( 663 String packageName, String compilerFilter, boolean force) { 664 int flags = DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX 665 | DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES 666 | DexoptOptions.DEXOPT_BOOT_COMPLETE 667 | (force ? DexoptOptions.DEXOPT_FORCE : 0); 668 return performDexOpt(new DexoptOptions(packageName, REASON_CMDLINE, 669 compilerFilter, null /* splitName */, flags)); 670 } 671 672 // Sort apps by importance for dexopt ordering. Important apps are given 673 // more priority in case the device runs out of space. getPackagesForDexopt( Collection<? extends PackageStateInternal> packages, PackageManagerService packageManagerService)674 public static List<PackageStateInternal> getPackagesForDexopt( 675 Collection<? extends PackageStateInternal> packages, 676 PackageManagerService packageManagerService) { 677 return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT); 678 } 679 getPackagesForDexopt( Collection<? extends PackageStateInternal> pkgSettings, PackageManagerService packageManagerService, boolean debug)680 public static List<PackageStateInternal> getPackagesForDexopt( 681 Collection<? extends PackageStateInternal> pkgSettings, 682 PackageManagerService packageManagerService, 683 boolean debug) { 684 List<PackageStateInternal> result = new ArrayList<>(); 685 ArrayList<PackageStateInternal> remainingPkgSettings = new ArrayList<>(pkgSettings); 686 687 // First, remove all settings without available packages 688 remainingPkgSettings.removeIf(REMOVE_IF_NULL_PKG); 689 remainingPkgSettings.removeIf(REMOVE_IF_APEX_PKG); 690 691 ArrayList<PackageStateInternal> sortTemp = new ArrayList<>(remainingPkgSettings.size()); 692 693 final Computer snapshot = packageManagerService.snapshotComputer(); 694 695 // Give priority to core apps. 696 applyPackageFilter(snapshot, pkgSetting -> pkgSetting.getPkg().isCoreApp(), result, 697 remainingPkgSettings, sortTemp, packageManagerService); 698 699 // Give priority to system apps that listen for pre boot complete. 700 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); 701 final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM); 702 applyPackageFilter(snapshot, pkgSetting -> pkgNames.contains(pkgSetting.getPackageName()), result, 703 remainingPkgSettings, sortTemp, packageManagerService); 704 705 // Give priority to apps used by other apps. 706 DexManager dexManager = packageManagerService.getDexManager(); 707 applyPackageFilter(snapshot, pkgSetting -> 708 dexManager.getPackageUseInfoOrDefault(pkgSetting.getPackageName()) 709 .isAnyCodePathUsedByOtherApps(), 710 result, remainingPkgSettings, sortTemp, packageManagerService); 711 712 // Filter out packages that aren't recently used, add all remaining apps. 713 // TODO: add a property to control this? 714 Predicate<PackageStateInternal> remainingPredicate; 715 if (!remainingPkgSettings.isEmpty() 716 && packageManagerService.isHistoricalPackageUsageAvailable()) { 717 if (debug) { 718 Log.i(TAG, "Looking at historical package use"); 719 } 720 // Get the package that was used last. 721 PackageStateInternal lastUsed = Collections.max(remainingPkgSettings, 722 Comparator.comparingLong( 723 pkgSetting -> pkgSetting.getTransientState() 724 .getLatestForegroundPackageUseTimeInMills())); 725 if (debug) { 726 Log.i(TAG, "Taking package " + lastUsed.getPackageName() 727 + " as reference in time use"); 728 } 729 long estimatedPreviousSystemUseTime = lastUsed.getTransientState() 730 .getLatestForegroundPackageUseTimeInMills(); 731 // Be defensive if for some reason package usage has bogus data. 732 if (estimatedPreviousSystemUseTime != 0) { 733 final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS; 734 remainingPredicate = pkgSetting -> pkgSetting.getTransientState() 735 .getLatestForegroundPackageUseTimeInMills() >= cutoffTime; 736 } else { 737 // No meaningful historical info. Take all. 738 remainingPredicate = pkgSetting -> true; 739 } 740 sortPackagesByUsageDate(remainingPkgSettings, packageManagerService); 741 } else { 742 // No historical info. Take all. 743 remainingPredicate = pkgSetting -> true; 744 } 745 applyPackageFilter(snapshot, remainingPredicate, result, remainingPkgSettings, sortTemp, 746 packageManagerService); 747 748 // Make sure the system server isn't in the result, because it can never be dexopted here. 749 result.removeIf(pkgSetting -> PLATFORM_PACKAGE_NAME.equals(pkgSetting.getPackageName())); 750 751 if (debug) { 752 Log.i(TAG, "Packages to be dexopted: " + packagesToString(result)); 753 Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgSettings)); 754 } 755 756 return result; 757 } 758 759 // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the 760 // package will be removed from {@code packages} and added to {@code result} with its 761 // dependencies. If usage data is available, the positive packages will be sorted by usage 762 // data (with {@code sortTemp} as temporary storage). applyPackageFilter(@onNull Computer snapshot, Predicate<PackageStateInternal> filter, Collection<PackageStateInternal> result, Collection<PackageStateInternal> packages, @NonNull List<PackageStateInternal> sortTemp, PackageManagerService packageManagerService)763 private static void applyPackageFilter(@NonNull Computer snapshot, 764 Predicate<PackageStateInternal> filter, 765 Collection<PackageStateInternal> result, 766 Collection<PackageStateInternal> packages, 767 @NonNull List<PackageStateInternal> sortTemp, 768 PackageManagerService packageManagerService) { 769 for (PackageStateInternal pkgSetting : packages) { 770 if (filter.test(pkgSetting)) { 771 sortTemp.add(pkgSetting); 772 } 773 } 774 775 sortPackagesByUsageDate(sortTemp, packageManagerService); 776 packages.removeAll(sortTemp); 777 778 for (PackageStateInternal pkgSetting : sortTemp) { 779 result.add(pkgSetting); 780 781 List<PackageStateInternal> deps = snapshot.findSharedNonSystemLibraries(pkgSetting); 782 if (!deps.isEmpty()) { 783 deps.removeAll(result); 784 result.addAll(deps); 785 packages.removeAll(deps); 786 } 787 } 788 789 sortTemp.clear(); 790 } 791 792 // Sort a list of apps by their last usage, most recently used apps first. The order of 793 // packages without usage data is undefined (but they will be sorted after the packages 794 // that do have usage data). sortPackagesByUsageDate(List<PackageStateInternal> pkgSettings, PackageManagerService packageManagerService)795 private static void sortPackagesByUsageDate(List<PackageStateInternal> pkgSettings, 796 PackageManagerService packageManagerService) { 797 if (!packageManagerService.isHistoricalPackageUsageAvailable()) { 798 return; 799 } 800 801 Collections.sort(pkgSettings, (pkgSetting1, pkgSetting2) -> 802 Long.compare( 803 pkgSetting2.getTransientState().getLatestForegroundPackageUseTimeInMills(), 804 pkgSetting1.getTransientState().getLatestForegroundPackageUseTimeInMills()) 805 ); 806 } 807 getPackageNamesForIntent(Intent intent, int userId)808 private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) { 809 List<ResolveInfo> ris = null; 810 try { 811 ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId) 812 .getList(); 813 } catch (RemoteException e) { 814 } 815 ArraySet<String> pkgNames = new ArraySet<String>(); 816 if (ris != null) { 817 for (ResolveInfo ri : ris) { 818 pkgNames.add(ri.activityInfo.packageName); 819 } 820 } 821 return pkgNames; 822 } 823 packagesToString(List<PackageStateInternal> pkgSettings)824 public static String packagesToString(List<PackageStateInternal> pkgSettings) { 825 StringBuilder sb = new StringBuilder(); 826 for (int index = 0; index < pkgSettings.size(); index++) { 827 if (sb.length() > 0) { 828 sb.append(", "); 829 } 830 sb.append(pkgSettings.get(index).getPackageName()); 831 } 832 return sb.toString(); 833 } 834 835 /** 836 * Requests that files preopted on a secondary system partition be copied to the data partition 837 * if possible. Note that the actual copying of the files is accomplished by init for security 838 * reasons. This simply requests that the copy takes place and awaits confirmation of its 839 * completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy. 840 */ requestCopyPreoptedFiles()841 public static void requestCopyPreoptedFiles() { 842 final int WAIT_TIME_MS = 100; 843 final String CP_PREOPT_PROPERTY = "sys.cppreopt"; 844 if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) { 845 SystemProperties.set(CP_PREOPT_PROPERTY, "requested"); 846 // We will wait for up to 100 seconds. 847 final long timeStart = SystemClock.uptimeMillis(); 848 final long timeEnd = timeStart + 100 * 1000; 849 long timeNow = timeStart; 850 while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) { 851 try { 852 Thread.sleep(WAIT_TIME_MS); 853 } catch (InterruptedException e) { 854 // Do nothing 855 } 856 timeNow = SystemClock.uptimeMillis(); 857 if (timeNow > timeEnd) { 858 SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out"); 859 Slog.wtf(TAG, "cppreopt did not finish!"); 860 break; 861 } 862 } 863 864 Slog.i(TAG, "cppreopts took " + (timeNow - timeStart) + " ms"); 865 } 866 } 867 controlDexOptBlocking(boolean block)868 /*package*/ void controlDexOptBlocking(boolean block) throws LegacyDexoptDisabledException { 869 mPm.mPackageDexOptimizer.controlDexOptBlocking(block); 870 } 871 872 /** 873 * Dumps the dexopt state for the given package, or all packages if it is null. 874 */ dumpDexoptState( @onNull IndentingPrintWriter ipw, @Nullable String packageName)875 public static void dumpDexoptState( 876 @NonNull IndentingPrintWriter ipw, @Nullable String packageName) { 877 try (PackageManagerLocal.FilteredSnapshot snapshot = 878 getPackageManagerLocal().withFilteredSnapshot()) { 879 if (packageName != null) { 880 try { 881 DexOptHelper.getArtManagerLocal().dumpPackage(ipw, snapshot, packageName); 882 } catch (IllegalArgumentException e) { 883 // Package isn't found, but that should only happen due to race. 884 ipw.println(e); 885 } 886 } else { 887 DexOptHelper.getArtManagerLocal().dump(ipw, snapshot); 888 } 889 } 890 } 891 892 /** 893 * Returns the module names of the APEXes that contribute to bootclasspath. 894 */ getBcpApexes()895 private static List<String> getBcpApexes() { 896 String bcp = System.getenv("BOOTCLASSPATH"); 897 if (TextUtils.isEmpty(bcp)) { 898 Log.e(TAG, "Unable to get BOOTCLASSPATH"); 899 return List.of(); 900 } 901 902 ArrayList<String> bcpApexes = new ArrayList<>(); 903 for (String pathStr : bcp.split(":")) { 904 Path path = Paths.get(pathStr); 905 // Check if the path is in the format of `/apex/<apex-module-name>/...` and extract the 906 // apex module name from the path. 907 if (path.getNameCount() >= 2 && path.getName(0).toString().equals("apex")) { 908 bcpApexes.add(path.getName(1).toString()); 909 } 910 } 911 912 return bcpApexes; 913 } 914 915 /** 916 * Returns true of any of the APEXes that contribute to bootclasspath has changed during this 917 * boot. 918 */ hasBcpApexesChanged()919 private static boolean hasBcpApexesChanged() { 920 Set<String> bcpApexes = new HashSet<>(getBcpApexes()); 921 ApexManager apexManager = ApexManager.getInstance(); 922 for (ActiveApexInfo apexInfo : apexManager.getActiveApexInfos()) { 923 if (bcpApexes.contains(apexInfo.apexModuleName) && apexInfo.activeApexChanged) { 924 return true; 925 } 926 } 927 return false; 928 } 929 930 /** 931 * Returns true if ART Service should be used for package optimization. 932 */ useArtService()933 public static boolean useArtService() { 934 return SystemProperties.getBoolean("dalvik.vm.useartservice", false); 935 } 936 937 /** 938 * Returns {@link DexUseManagerLocal} if ART Service should be used for package optimization. 939 */ getDexUseManagerLocal()940 public static @Nullable DexUseManagerLocal getDexUseManagerLocal() { 941 if (!useArtService()) { 942 return null; 943 } 944 try { 945 return LocalManagerRegistry.getManagerOrThrow(DexUseManagerLocal.class); 946 } catch (ManagerNotFoundException e) { 947 throw new RuntimeException(e); 948 } 949 } 950 951 private class DexoptDoneHandler implements ArtManagerLocal.DexoptDoneCallback { 952 /** 953 * Called after every package dexopt operation done by {@link ArtManagerLocal} (when ART 954 * Service is in use). 955 */ 956 @Override onDexoptDone(@onNull DexoptResult result)957 public void onDexoptDone(@NonNull DexoptResult result) { 958 switch (result.getReason()) { 959 case ReasonMapping.REASON_FIRST_BOOT: 960 case ReasonMapping.REASON_BOOT_AFTER_OTA: 961 case ReasonMapping.REASON_BOOT_AFTER_MAINLINE_UPDATE: 962 int numDexopted = 0; 963 int numSkipped = 0; 964 int numFailed = 0; 965 for (DexoptResult.PackageDexoptResult pkgRes : 966 result.getPackageDexoptResults()) { 967 switch (pkgRes.getStatus()) { 968 case DexoptResult.DEXOPT_PERFORMED: 969 numDexopted += 1; 970 break; 971 case DexoptResult.DEXOPT_SKIPPED: 972 numSkipped += 1; 973 break; 974 case DexoptResult.DEXOPT_FAILED: 975 numFailed += 1; 976 break; 977 } 978 } 979 980 reportBootDexopt(mBootDexoptStartTime, numDexopted, numSkipped, numFailed); 981 break; 982 } 983 984 for (DexoptResult.PackageDexoptResult pkgRes : result.getPackageDexoptResults()) { 985 CompilerStats.PackageStats stats = 986 mPm.getOrCreateCompilerPackageStats(pkgRes.getPackageName()); 987 for (DexoptResult.DexContainerFileDexoptResult dexRes : 988 pkgRes.getDexContainerFileDexoptResults()) { 989 stats.setCompileTime( 990 dexRes.getDexContainerFile(), dexRes.getDex2oatWallTimeMillis()); 991 } 992 } 993 994 synchronized (mPm.mLock) { 995 mPm.getPackageUsage().maybeWriteAsync(mPm.mSettings.getPackagesLocked()); 996 mPm.mCompilerStats.maybeWriteAsync(); 997 } 998 999 if (result.getReason().equals(ReasonMapping.REASON_INACTIVE)) { 1000 for (DexoptResult.PackageDexoptResult pkgRes : result.getPackageDexoptResults()) { 1001 if (pkgRes.getStatus() == DexoptResult.DEXOPT_PERFORMED) { 1002 long pkgSizeBytes = 0; 1003 long pkgSizeBeforeBytes = 0; 1004 for (DexoptResult.DexContainerFileDexoptResult dexRes : 1005 pkgRes.getDexContainerFileDexoptResults()) { 1006 long dexContainerSize = new File(dexRes.getDexContainerFile()).length(); 1007 pkgSizeBytes += dexRes.getSizeBytes() + dexContainerSize; 1008 pkgSizeBeforeBytes += dexRes.getSizeBeforeBytes() + dexContainerSize; 1009 } 1010 FrameworkStatsLog.write(FrameworkStatsLog.APP_DOWNGRADED, 1011 pkgRes.getPackageName(), pkgSizeBeforeBytes, pkgSizeBytes, 1012 false /* aggressive */); 1013 } 1014 } 1015 } 1016 1017 var updatedPackages = new ArraySet<String>(); 1018 for (DexoptResult.PackageDexoptResult pkgRes : result.getPackageDexoptResults()) { 1019 if (pkgRes.hasUpdatedArtifacts()) { 1020 updatedPackages.add(pkgRes.getPackageName()); 1021 } 1022 } 1023 if (!updatedPackages.isEmpty()) { 1024 LocalServices.getService(PinnerService.class) 1025 .update(updatedPackages, false /* force */); 1026 } 1027 } 1028 } 1029 1030 /** 1031 * Initializes {@link ArtManagerLocal} before {@link getArtManagerLocal} is called. 1032 */ initializeArtManagerLocal( @onNull Context systemContext, @NonNull PackageManagerService pm)1033 public static void initializeArtManagerLocal( 1034 @NonNull Context systemContext, @NonNull PackageManagerService pm) { 1035 if (!useArtService()) { 1036 return; 1037 } 1038 1039 ArtManagerLocal artManager = new ArtManagerLocal(systemContext); 1040 artManager.addDexoptDoneCallback(false /* onlyIncludeUpdates */, Runnable::run, 1041 pm.getDexOptHelper().new DexoptDoneHandler()); 1042 LocalManagerRegistry.addManager(ArtManagerLocal.class, artManager); 1043 sArtManagerLocalIsInitialized = true; 1044 1045 // Schedule the background job when boot is complete. This decouples us from when 1046 // JobSchedulerService is initialized. 1047 systemContext.registerReceiver(new BroadcastReceiver() { 1048 @Override 1049 public void onReceive(Context context, Intent intent) { 1050 context.unregisterReceiver(this); 1051 artManager.scheduleBackgroundDexoptJob(); 1052 } 1053 }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 1054 } 1055 1056 /** 1057 * Returns true if an {@link ArtManagerLocal} instance has been created. 1058 * 1059 * Avoid this function if at all possible, because it may hide initialization order problems. 1060 */ artManagerLocalIsInitialized()1061 public static boolean artManagerLocalIsInitialized() { 1062 return sArtManagerLocalIsInitialized; 1063 } 1064 1065 /** 1066 * Returns the registered {@link ArtManagerLocal} instance, or else throws an unchecked error. 1067 */ getArtManagerLocal()1068 public static @NonNull ArtManagerLocal getArtManagerLocal() { 1069 try { 1070 return LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class); 1071 } catch (ManagerNotFoundException e) { 1072 throw new RuntimeException(e); 1073 } 1074 } 1075 1076 /** 1077 * Converts an ART Service {@link DexoptResult} to {@link DexOptResult}. 1078 * 1079 * For interfacing {@link ArtManagerLocal} with legacy dex optimization code in PackageManager. 1080 */ 1081 @DexOptResult convertToDexOptResult(DexoptResult result)1082 private static int convertToDexOptResult(DexoptResult result) { 1083 /*@DexoptResultStatus*/ int status = result.getFinalStatus(); 1084 switch (status) { 1085 case DexoptResult.DEXOPT_SKIPPED: 1086 return PackageDexOptimizer.DEX_OPT_SKIPPED; 1087 case DexoptResult.DEXOPT_FAILED: 1088 return PackageDexOptimizer.DEX_OPT_FAILED; 1089 case DexoptResult.DEXOPT_PERFORMED: 1090 return PackageDexOptimizer.DEX_OPT_PERFORMED; 1091 case DexoptResult.DEXOPT_CANCELLED: 1092 return PackageDexOptimizer.DEX_OPT_CANCELLED; 1093 default: 1094 throw new IllegalArgumentException("DexoptResult for " 1095 + result.getPackageDexoptResults().get(0).getPackageName() 1096 + " has unsupported status " + status); 1097 } 1098 } 1099 } 1100