1 /* 2 * Copyright (C) 2015 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.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; 20 21 import static com.android.server.pm.DexOptHelper.useArtService; 22 import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; 23 import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; 24 import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS; 25 import static com.android.server.pm.Installer.DEXOPT_FORCE; 26 import static com.android.server.pm.Installer.DEXOPT_FOR_RESTORE; 27 import static com.android.server.pm.Installer.DEXOPT_GENERATE_APP_IMAGE; 28 import static com.android.server.pm.Installer.DEXOPT_GENERATE_COMPACT_DEX; 29 import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB; 30 import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED; 31 import static com.android.server.pm.Installer.DEXOPT_PUBLIC; 32 import static com.android.server.pm.Installer.DEXOPT_SECONDARY_DEX; 33 import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE; 34 import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE; 35 import static com.android.server.pm.Installer.PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES; 36 import static com.android.server.pm.Installer.PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; 37 import static com.android.server.pm.Installer.PROFILE_ANALYSIS_OPTIMIZE; 38 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; 39 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; 40 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; 41 import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT; 42 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReasonName; 43 44 import static dalvik.system.DexFile.getSafeModeCompilerFilter; 45 import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; 46 47 import android.annotation.IntDef; 48 import android.annotation.NonNull; 49 import android.annotation.Nullable; 50 import android.content.ContentResolver; 51 import android.content.Context; 52 import android.content.pm.ApplicationInfo; 53 import android.content.pm.SharedLibraryInfo; 54 import android.content.pm.dex.ArtManager; 55 import android.content.pm.dex.DexMetadataHelper; 56 import android.os.FileUtils; 57 import android.os.PowerManager; 58 import android.os.SystemClock; 59 import android.os.SystemProperties; 60 import android.os.Trace; 61 import android.os.UserHandle; 62 import android.os.WorkSource; 63 import android.util.Log; 64 import android.util.Slog; 65 import android.util.SparseArray; 66 67 import com.android.internal.annotations.GuardedBy; 68 import com.android.internal.annotations.VisibleForTesting; 69 import com.android.internal.content.F2fsUtils; 70 import com.android.internal.util.IndentingPrintWriter; 71 import com.android.server.LocalServices; 72 import com.android.server.apphibernation.AppHibernationManagerInternal; 73 import com.android.server.pm.Installer.InstallerException; 74 import com.android.server.pm.Installer.LegacyDexoptDisabledException; 75 import com.android.server.pm.dex.ArtManagerService; 76 import com.android.server.pm.dex.ArtStatsLogUtils; 77 import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger; 78 import com.android.server.pm.dex.DexoptOptions; 79 import com.android.server.pm.dex.DexoptUtils; 80 import com.android.server.pm.dex.PackageDexUsage; 81 import com.android.server.pm.parsing.pkg.AndroidPackageUtils; 82 import com.android.server.pm.pkg.AndroidPackage; 83 import com.android.server.pm.pkg.PackageState; 84 import com.android.server.pm.pkg.PackageStateInternal; 85 86 import dalvik.system.DexFile; 87 88 import java.io.File; 89 import java.io.IOException; 90 import java.lang.annotation.Retention; 91 import java.lang.annotation.RetentionPolicy; 92 import java.util.ArrayList; 93 import java.util.Arrays; 94 import java.util.List; 95 import java.util.Map; 96 import java.util.Random; 97 98 /** 99 * Helper class for running dexopt command on packages. 100 */ 101 public class PackageDexOptimizer { 102 private static final String TAG = "PackageDexOptimizer"; 103 static final String OAT_DIR_NAME = "oat"; 104 // TODO b/19550105 Remove error codes and use exceptions 105 /** No need to run dexopt and it was skipped */ 106 public static final int DEX_OPT_SKIPPED = 0; 107 /** Dexopt was completed */ 108 public static final int DEX_OPT_PERFORMED = 1; 109 /** 110 * Cancelled while running it. This is not an error case as cancel was requested 111 * from the client. 112 */ 113 public static final int DEX_OPT_CANCELLED = 2; 114 /** Failed to run dexopt */ 115 public static final int DEX_OPT_FAILED = -1; 116 117 @IntDef(prefix = {"DEX_OPT_"}, value = { 118 DEX_OPT_SKIPPED, 119 DEX_OPT_PERFORMED, 120 DEX_OPT_CANCELLED, 121 DEX_OPT_FAILED, 122 }) 123 @Retention(RetentionPolicy.SOURCE) 124 public @interface DexOptResult { 125 } 126 127 // One minute over PM WATCHDOG_TIMEOUT 128 private static final long WAKELOCK_TIMEOUT_MS = WATCHDOG_TIMEOUT + 1000 * 60; 129 130 private final Object mInstallLock; 131 132 /** 133 * This should be accessed only through {@link #getInstallerLI()} with {@link #mInstallLock} 134 * or {@link #getInstallerWithoutLock()} without the lock. Check both methods for further 135 * details on when to use each of them. 136 */ 137 private final Installer mInstaller; 138 139 @GuardedBy("mInstallLock") 140 private final PowerManager.WakeLock mDexoptWakeLock; 141 private volatile boolean mSystemReady; 142 143 private final ArtStatsLogger mArtStatsLogger = new ArtStatsLogger(); 144 private final Injector mInjector; 145 146 147 private final Context mContext; 148 private static final Random sRandom = new Random(); 149 PackageDexOptimizer(Installer installer, Object installLock, Context context, String wakeLockTag)150 PackageDexOptimizer(Installer installer, Object installLock, Context context, 151 String wakeLockTag) { 152 this(new Injector() { 153 @Override 154 public AppHibernationManagerInternal getAppHibernationManagerInternal() { 155 return LocalServices.getService(AppHibernationManagerInternal.class); 156 } 157 158 @Override 159 public PowerManager getPowerManager(Context context) { 160 return context.getSystemService(PowerManager.class); 161 } 162 }, installer, installLock, context, wakeLockTag); 163 } 164 PackageDexOptimizer(PackageDexOptimizer from)165 protected PackageDexOptimizer(PackageDexOptimizer from) { 166 this.mContext = from.mContext; 167 this.mInstaller = from.mInstaller; 168 this.mInstallLock = from.mInstallLock; 169 this.mDexoptWakeLock = from.mDexoptWakeLock; 170 this.mSystemReady = from.mSystemReady; 171 this.mInjector = from.mInjector; 172 } 173 174 @VisibleForTesting PackageDexOptimizer(@onNull Injector injector, Installer installer, Object installLock, Context context, String wakeLockTag)175 PackageDexOptimizer(@NonNull Injector injector, Installer installer, Object installLock, 176 Context context, String wakeLockTag) { 177 this.mContext = context; 178 this.mInstaller = installer; 179 this.mInstallLock = installLock; 180 181 PowerManager powerManager = injector.getPowerManager(context); 182 mDexoptWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag); 183 mInjector = injector; 184 } 185 canOptimizePackage(@onNull AndroidPackage pkg)186 boolean canOptimizePackage(@NonNull AndroidPackage pkg) { 187 // The system package has to be optimized during early boot by odrefresh instead. 188 if (PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName())) { 189 return false; 190 } 191 192 // We do not dexopt a package with no code. 193 if (!pkg.isDeclaredHavingCode()) { 194 return false; 195 } 196 197 // We do not dexopt APEX packages. 198 if (pkg.isApex()) { 199 return false; 200 } 201 202 // We do not dexopt unused packages. 203 // It's possible for this to be called before app hibernation service is ready due to 204 // an OTA dexopt. In this case, we ignore the hibernation check here. This is fine since 205 // a hibernating app should have no artifacts to copy in the first place. 206 AppHibernationManagerInternal ahm = mInjector.getAppHibernationManagerInternal(); 207 if (ahm != null 208 && ahm.isHibernatingGlobally(pkg.getPackageName()) 209 && ahm.isOatArtifactDeletionEnabled()) { 210 return false; 211 } 212 213 return true; 214 } 215 216 /** 217 * Performs dexopt on all code paths and libraries of the specified package for specified 218 * instruction sets. 219 * 220 * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are 221 * synchronized on {@link #mInstallLock}. 222 */ 223 @DexOptResult performDexOpt(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting, String[] instructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options)224 int performDexOpt(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting, 225 String[] instructionSets, CompilerStats.PackageStats packageStats, 226 PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) 227 throws LegacyDexoptDisabledException { 228 if (PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName())) { 229 throw new IllegalArgumentException( 230 "System server dexopting should be done via odrefresh"); 231 } 232 if (pkg.getUid() == -1) { 233 throw new IllegalArgumentException("Dexopt for " + pkg.getPackageName() 234 + " has invalid uid."); 235 } 236 if (!canOptimizePackage(pkg)) { 237 return DEX_OPT_SKIPPED; 238 } 239 synchronized (mInstallLock) { 240 final long acquireTime = acquireWakeLockLI(pkg.getUid()); 241 try { 242 return performDexOptLI(pkg, pkgSetting, instructionSets, 243 packageStats, packageUseInfo, options); 244 } finally { 245 releaseWakeLockLI(acquireTime); 246 } 247 } 248 } 249 250 /** 251 * Cancels currently running dex optimization. 252 */ controlDexOptBlocking(boolean block)253 void controlDexOptBlocking(boolean block) throws LegacyDexoptDisabledException { 254 // This method should not hold mInstallLock as cancelling should be possible while 255 // the lock is held by other thread running performDexOpt. 256 getInstallerWithoutLock().controlDexOptBlocking(block); 257 } 258 259 /** 260 * Performs dexopt on all code paths of the given package. 261 * It assumes the install lock is held. 262 */ 263 @GuardedBy("mInstallLock") 264 @DexOptResult performDexOptLI(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting, String[] targetInstructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options)265 private int performDexOptLI(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting, 266 String[] targetInstructionSets, CompilerStats.PackageStats packageStats, 267 PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) 268 throws LegacyDexoptDisabledException { 269 // ClassLoader only refers non-native (jar) shared libraries and must ignore 270 // native (so) shared libraries. See also LoadedApk#createSharedLibraryLoader(). 271 final List<SharedLibraryInfo> sharedLibraries = pkgSetting.getTransientState() 272 .getNonNativeUsesLibraryInfos(); 273 final String[] instructionSets = targetInstructionSets != null ? 274 targetInstructionSets : getAppDexInstructionSets( 275 pkgSetting.getPrimaryCpuAbi(), 276 pkgSetting.getSecondaryCpuAbi()); 277 final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); 278 final List<String> paths = AndroidPackageUtils.getAllCodePaths(pkg); 279 280 int sharedGid = UserHandle.getSharedAppGid(pkg.getUid()); 281 if (sharedGid == -1) { 282 Slog.wtf(TAG, "Well this is awkward; package " + pkg.getPackageName() + " had UID " 283 + pkg.getUid(), new Throwable()); 284 sharedGid = android.os.Process.NOBODY_UID; 285 } 286 287 // Get the class loader context dependencies. 288 // For each code path in the package, this array contains the class loader context that 289 // needs to be passed to dexopt in order to ensure correct optimizations. 290 boolean[] pathsWithCode = new boolean[paths.size()]; 291 pathsWithCode[0] = pkg.isDeclaredHavingCode(); 292 for (int i = 1; i < paths.size(); i++) { 293 pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0; 294 } 295 String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts( 296 pkg, sharedLibraries, pathsWithCode); 297 298 // Validity check that we do not call dexopt with inconsistent data. 299 if (paths.size() != classLoaderContexts.length) { 300 String[] splitCodePaths = pkg.getSplitCodePaths(); 301 throw new IllegalStateException("Inconsistent information " 302 + "between AndroidPackage and its ApplicationInfo. " 303 + "pkg.getAllCodePaths=" + paths 304 + " pkg.getBaseCodePath=" + pkg.getBaseApkPath() 305 + " pkg.getSplitCodePaths=" 306 + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths))); 307 } 308 309 int result = DEX_OPT_SKIPPED; 310 for (int i = 0; i < paths.size(); i++) { 311 // Skip paths that have no code. 312 if (!pathsWithCode[i]) { 313 continue; 314 } 315 if (classLoaderContexts[i] == null) { 316 throw new IllegalStateException("Inconsistent information in the " 317 + "package structure. A split is marked to contain code " 318 + "but has no dependency listed. Index=" + i + " path=" + paths.get(i)); 319 } 320 321 // Append shared libraries with split dependencies for this split. 322 String path = paths.get(i); 323 if (options.getSplitName() != null) { 324 // We are asked to compile only a specific split. Check that the current path is 325 // what we are looking for. 326 if (!options.getSplitName().equals(new File(path).getName())) { 327 continue; 328 } 329 } 330 331 String profileName = ArtManager.getProfileName( 332 i == 0 ? null : pkg.getSplitNames()[i - 1]); 333 334 final boolean isUsedByOtherApps; 335 if (options.isDexoptAsSharedLibrary()) { 336 isUsedByOtherApps = true; 337 } else if (useArtService()) { 338 // We get here when collecting dexopt commands in OTA preopt, even when ART Service 339 // is in use. packageUseInfo isn't useful in that case since the legacy dex use 340 // database hasn't been updated. So we'd have to query ART Service instead, but it 341 // doesn't provide that API. Just cop-out and bypass the cloud profile handling. 342 // That means such apps will get preopted wrong, and we'll leave it to a later 343 // background dexopt after reboot instead. 344 isUsedByOtherApps = false; 345 } else { 346 isUsedByOtherApps = packageUseInfo.isUsedByOtherApps(path); 347 } 348 349 String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter()); 350 // If the app is used by other apps, we must not use the existing profile because it 351 // may contain user data, unless the profile is newly created on install. 352 final boolean useCloudProfile = isProfileGuidedCompilerFilter(compilerFilter) 353 && isUsedByOtherApps 354 && options.getCompilationReason() != PackageManagerService.REASON_INSTALL; 355 356 String dexMetadataPath = null; 357 if (options.isDexoptInstallWithDexMetadata() || useCloudProfile) { 358 File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path)); 359 dexMetadataPath = dexMetadataFile == null 360 ? null : dexMetadataFile.getAbsolutePath(); 361 } 362 363 // If we don't have to check for profiles updates assume 364 // PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to 365 // profiles. 366 int profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; 367 if (options.isCheckForProfileUpdates()) { 368 profileAnalysisResult = 369 analyseProfiles(pkg, sharedGid, profileName, compilerFilter); 370 } 371 String cloudProfileName = null; 372 try { 373 if (useCloudProfile) { 374 cloudProfileName = "cloud-" + profileName; 375 if (prepareCloudProfile(pkg, cloudProfileName, path, dexMetadataPath)) { 376 profileName = cloudProfileName; 377 } else { 378 // Fall back to use the shared filter. 379 compilerFilter = 380 PackageManagerServiceCompilerMapping.getCompilerFilterForReason( 381 PackageManagerService.REASON_SHARED); 382 profileName = null; 383 } 384 385 // We still run `analyseProfiles` even if `useCloudProfile` is true because it 386 // merges profiles into the reference profile, which a system API 387 // `ArtManager.snapshotRuntimeProfile` takes snapshots from. However, we don't 388 // want the result to affect the decision of whether dexopt is needed. 389 profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; 390 } 391 392 // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct 393 // flags. 394 final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, 395 useCloudProfile, options); 396 397 for (String dexCodeIsa : dexCodeInstructionSets) { 398 int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter, 399 profileAnalysisResult, classLoaderContexts[i], dexoptFlags, sharedGid, 400 packageStats, options.isDowngrade(), profileName, dexMetadataPath, 401 options.getCompilationReason()); 402 // OTAPreopt doesn't have stats so don't report in that case. 403 if (packageStats != null) { 404 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "dex2oat-metrics"); 405 try { 406 long sessionId = sRandom.nextLong(); 407 ArtStatsLogUtils.writeStatsLog( 408 mArtStatsLogger, 409 sessionId, 410 compilerFilter, 411 pkg.getUid(), 412 packageStats.getCompileTime(path), 413 dexMetadataPath, 414 options.getCompilationReason(), 415 newResult, 416 ArtStatsLogUtils.getApkType(path, pkg.getBaseApkPath(), 417 pkg.getSplitCodePaths()), 418 dexCodeIsa, 419 path); 420 } finally { 421 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 422 } 423 } 424 425 // Should stop the operation immediately. 426 if (newResult == DEX_OPT_CANCELLED) { 427 // Even for the cancellation, return failed if has failed. 428 if (result == DEX_OPT_FAILED) { 429 return result; 430 } 431 return newResult; 432 } 433 // The end result is: 434 // - FAILED if any path failed, 435 // - PERFORMED if at least one path needed compilation, 436 // - SKIPPED when all paths are up to date 437 if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) { 438 result = newResult; 439 } 440 } 441 } finally { 442 if (cloudProfileName != null) { 443 try { 444 mInstaller.deleteReferenceProfile(pkg.getPackageName(), cloudProfileName); 445 } catch (InstallerException e) { 446 Slog.w(TAG, "Failed to cleanup cloud profile", e); 447 } 448 } 449 } 450 } 451 return result; 452 } 453 454 /** 455 * Creates a profile with the name {@code profileName} from the dex metadata file at {@code 456 * dexMetadataPath} for the dex file at {@code path} belonging to the package {@code pkg}. 457 * 458 * @return true on success, or false otherwise. 459 */ 460 @GuardedBy("mInstallLock") prepareCloudProfile(AndroidPackage pkg, String profileName, String path, @Nullable String dexMetadataPath)461 private boolean prepareCloudProfile(AndroidPackage pkg, String profileName, String path, 462 @Nullable String dexMetadataPath) throws LegacyDexoptDisabledException { 463 if (dexMetadataPath != null) { 464 if (mInstaller.isIsolated()) { 465 // If the installer is isolated, the two calls to it below will return immediately, 466 // so this only short-circuits that a bit. We need to do it to avoid the 467 // LegacyDexoptDisabledException getting thrown first, when we get here during OTA 468 // preopt and ART Service is enabled. 469 return true; 470 } 471 472 try { 473 // Make sure we don't keep any existing contents. 474 mInstaller.deleteReferenceProfile(pkg.getPackageName(), profileName); 475 476 final int appId = UserHandle.getAppId(pkg.getUid()); 477 mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL, appId, 478 profileName, path, dexMetadataPath); 479 return true; 480 } catch (InstallerException e) { 481 Slog.w(TAG, "Failed to prepare cloud profile", e); 482 return false; 483 } 484 } else { 485 return false; 486 } 487 } 488 489 /** 490 * Performs dexopt on the {@code path} belonging to the package {@code pkg}. 491 * 492 * @return 493 * DEX_OPT_FAILED if there was any exception during dexopt 494 * DEX_OPT_PERFORMED if dexopt was performed successfully on the given path. 495 * DEX_OPT_SKIPPED if the path does not need to be deopt-ed. 496 */ 497 @GuardedBy("mInstallLock") 498 @DexOptResult dexOptPath(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting, String path, String isa, String compilerFilter, int profileAnalysisResult, String classLoaderContext, int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade, String profileName, String dexMetadataPath, int compilationReason)499 private int dexOptPath(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting, 500 String path, String isa, String compilerFilter, int profileAnalysisResult, 501 String classLoaderContext, int dexoptFlags, int uid, 502 CompilerStats.PackageStats packageStats, boolean downgrade, String profileName, 503 String dexMetadataPath, int compilationReason) throws LegacyDexoptDisabledException { 504 String oatDir = getPackageOatDirIfSupported(pkgSetting, pkg); 505 506 int dexoptNeeded = getDexoptNeeded(pkg.getPackageName(), path, isa, compilerFilter, 507 classLoaderContext, profileAnalysisResult, downgrade, dexoptFlags, oatDir); 508 if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) { 509 return DEX_OPT_SKIPPED; 510 } 511 512 Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path 513 + " pkg=" + pkg.getPackageName() + " isa=" + isa 514 + " dexoptFlags=" + printDexoptFlags(dexoptFlags) 515 + " targetFilter=" + compilerFilter + " oatDir=" + oatDir 516 + " classLoaderContext=" + classLoaderContext); 517 518 try { 519 long startTime = System.currentTimeMillis(); 520 521 // TODO: Consider adding 2 different APIs for primary and secondary dexopt. 522 // installd only uses downgrade flag for secondary dex files and ignores it for 523 // primary dex files. 524 String seInfo = pkgSetting.getSeInfo(); 525 boolean completed = getInstallerLI().dexopt(path, uid, pkg.getPackageName(), isa, 526 dexoptNeeded, oatDir, dexoptFlags, compilerFilter, pkg.getVolumeUuid(), 527 classLoaderContext, seInfo, /* downgrade= */ false , 528 pkg.getTargetSdkVersion(), profileName, dexMetadataPath, 529 getAugmentedReasonName(compilationReason, dexMetadataPath != null)); 530 if (!completed) { 531 return DEX_OPT_CANCELLED; 532 } 533 if (packageStats != null) { 534 long endTime = System.currentTimeMillis(); 535 packageStats.setCompileTime(path, (int)(endTime - startTime)); 536 } 537 if (oatDir != null) { 538 // Release odex/vdex compressed blocks to save user space. 539 // Compression support will be checked in F2fsUtils. 540 // The system app may be dexed, oatDir may be null, skip this situation. 541 final ContentResolver resolver = mContext.getContentResolver(); 542 F2fsUtils.releaseCompressedBlocks(resolver, new File(oatDir)); 543 } 544 return DEX_OPT_PERFORMED; 545 } catch (InstallerException e) { 546 Slog.w(TAG, "Failed to dexopt", e); 547 return DEX_OPT_FAILED; 548 } 549 } 550 getAugmentedReasonName(int compilationReason, boolean useDexMetadata)551 private String getAugmentedReasonName(int compilationReason, boolean useDexMetadata) { 552 String annotation = useDexMetadata 553 ? ArtManagerService.DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : ""; 554 return getReasonName(compilationReason) + annotation; 555 } 556 557 /** 558 * Performs dexopt on the secondary dex {@code path} belonging to the app {@code info}. 559 * 560 * @return 561 * DEX_OPT_FAILED if there was any exception during dexopt 562 * DEX_OPT_PERFORMED if dexopt was performed successfully on the given path. 563 * NOTE that DEX_OPT_PERFORMED for secondary dex files includes the case when the dex file 564 * didn't need an update. That's because at the moment we don't get more than success/failure 565 * from installd. 566 * 567 * TODO(calin): Consider adding return codes to installd dexopt invocation (rather than 568 * throwing exceptions). Or maybe make a separate call to installd to get DexOptNeeded, though 569 * that seems wasteful. 570 */ 571 @DexOptResult dexOptSecondaryDexPath(ApplicationInfo info, String path, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options)572 public int dexOptSecondaryDexPath(ApplicationInfo info, String path, 573 PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) 574 throws LegacyDexoptDisabledException { 575 if (info.uid == -1) { 576 throw new IllegalArgumentException("Dexopt for path " + path + " has invalid uid."); 577 } 578 synchronized (mInstallLock) { 579 final long acquireTime = acquireWakeLockLI(info.uid); 580 try { 581 return dexOptSecondaryDexPathLI(info, path, dexUseInfo, options); 582 } finally { 583 releaseWakeLockLI(acquireTime); 584 } 585 } 586 } 587 588 @GuardedBy("mInstallLock") acquireWakeLockLI(final int uid)589 private long acquireWakeLockLI(final int uid) { 590 // During boot the system doesn't need to instantiate and obtain a wake lock. 591 // PowerManager might not be ready, but that doesn't mean that we can't proceed with 592 // dexopt. 593 if (!mSystemReady) { 594 return -1; 595 } 596 mDexoptWakeLock.setWorkSource(new WorkSource(uid)); 597 mDexoptWakeLock.acquire(WAKELOCK_TIMEOUT_MS); 598 return SystemClock.elapsedRealtime(); 599 } 600 601 @GuardedBy("mInstallLock") releaseWakeLockLI(final long acquireTime)602 private void releaseWakeLockLI(final long acquireTime) { 603 if (acquireTime < 0) { 604 return; 605 } 606 try { 607 if (mDexoptWakeLock.isHeld()) { 608 mDexoptWakeLock.release(); 609 } 610 final long duration = SystemClock.elapsedRealtime() - acquireTime; 611 if (duration >= WAKELOCK_TIMEOUT_MS) { 612 Slog.wtf(TAG, "WakeLock " + mDexoptWakeLock.getTag() 613 + " time out. Operation took " + duration + " ms. Thread: " 614 + Thread.currentThread().getName()); 615 } 616 } catch (RuntimeException e) { 617 Slog.wtf(TAG, "Error while releasing " + mDexoptWakeLock.getTag() + " lock", e); 618 } 619 } 620 621 @GuardedBy("mInstallLock") 622 @DexOptResult dexOptSecondaryDexPathLI(ApplicationInfo info, String path, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options)623 private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, 624 PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) 625 throws LegacyDexoptDisabledException { 626 String compilerFilter = getRealCompilerFilter(info, options.getCompilerFilter(), 627 dexUseInfo.isUsedByOtherApps()); 628 // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags. 629 // Secondary dex files are currently not compiled at boot. 630 int dexoptFlags = getDexFlags(info, compilerFilter, options) | DEXOPT_SECONDARY_DEX; 631 // Check the app storage and add the appropriate flags. 632 if (info.deviceProtectedDataDir != null && 633 FileUtils.contains(info.deviceProtectedDataDir, path)) { 634 dexoptFlags |= DEXOPT_STORAGE_DE; 635 } else if (info.credentialProtectedDataDir != null && 636 FileUtils.contains(info.credentialProtectedDataDir, path)) { 637 dexoptFlags |= DEXOPT_STORAGE_CE; 638 } else { 639 Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName); 640 return DEX_OPT_FAILED; 641 } 642 String classLoaderContext = null; 643 if (dexUseInfo.isUnsupportedClassLoaderContext() 644 || dexUseInfo.isVariableClassLoaderContext()) { 645 // If we have an unknown (not yet set), or a variable class loader chain. Just verify 646 // the dex file. 647 compilerFilter = "verify"; 648 } else { 649 classLoaderContext = dexUseInfo.getClassLoaderContext(); 650 } 651 652 int reason = options.getCompilationReason(); 653 Log.d(TAG, "Running dexopt on: " + path 654 + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas() 655 + " reason=" + getReasonName(reason) 656 + " dexoptFlags=" + printDexoptFlags(dexoptFlags) 657 + " target-filter=" + compilerFilter 658 + " class-loader-context=" + classLoaderContext); 659 660 try { 661 for (String isa : dexUseInfo.getLoaderIsas()) { 662 // Reuse the same dexopt path as for the primary apks. We don't need all the 663 // arguments as some (dexopNeeded and oatDir) will be computed by installd because 664 // system server cannot read untrusted app content. 665 // TODO(calin): maybe add a separate call. 666 boolean completed = getInstallerLI().dexopt(path, info.uid, info.packageName, 667 isa, /* dexoptNeeded= */ 0, 668 /* outputPath= */ null, dexoptFlags, 669 compilerFilter, info.volumeUuid, classLoaderContext, info.seInfo, 670 options.isDowngrade(), info.targetSdkVersion, /* profileName= */ null, 671 /* dexMetadataPath= */ null, getReasonName(reason)); 672 if (!completed) { 673 return DEX_OPT_CANCELLED; 674 } 675 } 676 677 return DEX_OPT_PERFORMED; 678 } catch (InstallerException e) { 679 Slog.w(TAG, "Failed to dexopt", e); 680 return DEX_OPT_FAILED; 681 } 682 } 683 684 /** 685 * Adjust the given dexopt-needed value. Can be overridden to influence the decision to 686 * optimize or not (and in what way). 687 */ adjustDexoptNeeded(int dexoptNeeded)688 protected int adjustDexoptNeeded(int dexoptNeeded) { 689 return dexoptNeeded; 690 } 691 692 /** 693 * Adjust the given dexopt flags that will be passed to the installer. 694 */ adjustDexoptFlags(int dexoptFlags)695 protected int adjustDexoptFlags(int dexoptFlags) { 696 return dexoptFlags; 697 } 698 699 /** 700 * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}. 701 */ dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg, PackageStateInternal pkgSetting, PackageDexUsage.PackageUseInfo useInfo)702 void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg, 703 PackageStateInternal pkgSetting, PackageDexUsage.PackageUseInfo useInfo) 704 throws LegacyDexoptDisabledException { 705 final String[] instructionSets = getAppDexInstructionSets(pkgSetting.getPrimaryCpuAbi(), 706 pkgSetting.getSecondaryCpuAbi()); 707 final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); 708 709 final List<String> paths = AndroidPackageUtils.getAllCodePathsExcludingResourceOnly(pkg); 710 711 for (String path : paths) { 712 pw.println("path: " + path); 713 pw.increaseIndent(); 714 715 for (String isa : dexCodeInstructionSets) { 716 try { 717 DexFile.OptimizationInfo info = DexFile.getDexFileOptimizationInfo(path, isa); 718 pw.println(isa + ": [status=" + info.getStatus() 719 +"] [reason=" + info.getReason() + "]"); 720 } catch (IOException ioe) { 721 pw.println(isa + ": [Exception]: " + ioe.getMessage()); 722 } 723 } 724 725 if (useInfo.isUsedByOtherApps(path)) { 726 pw.println("used by other apps: " + useInfo.getLoadingPackages(path)); 727 } 728 729 Map<String, PackageDexUsage.DexUseInfo> dexUseInfoMap = useInfo.getDexUseInfoMap(); 730 731 if (!dexUseInfoMap.isEmpty()) { 732 pw.println("known secondary dex files:"); 733 pw.increaseIndent(); 734 for (Map.Entry<String, PackageDexUsage.DexUseInfo> e : dexUseInfoMap.entrySet()) { 735 String dex = e.getKey(); 736 PackageDexUsage.DexUseInfo dexUseInfo = e.getValue(); 737 pw.println(dex); 738 pw.increaseIndent(); 739 // TODO(calin): get the status of the oat file (needs installd call) 740 pw.println("class loader context: " + dexUseInfo.getClassLoaderContext()); 741 if (dexUseInfo.isUsedByOtherApps()) { 742 pw.println("used by other apps: " + dexUseInfo.getLoadingPackages()); 743 } 744 pw.decreaseIndent(); 745 } 746 pw.decreaseIndent(); 747 } 748 pw.decreaseIndent(); 749 } 750 } 751 752 /** 753 * Returns the compiler filter that should be used to optimize the secondary dex. 754 * The target filter will be updated if the package code is used by other apps 755 * or if it has the safe mode flag set. 756 */ getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter, boolean isUsedByOtherApps)757 private String getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter, 758 boolean isUsedByOtherApps) { 759 if (info.isEmbeddedDexUsed()) { 760 // Downgrade optimizing filters to "verify", but don't upgrade lower filters. 761 return DexFile.isOptimizedCompilerFilter(targetCompilerFilter) ? "verify" 762 : targetCompilerFilter; 763 } 764 765 // We force vmSafeMode on debuggable apps as well: 766 // - the runtime ignores their compiled code 767 // - they generally have lots of methods that could make the compiler used run 768 // out of memory (b/130828957) 769 // Note that forcing the compiler filter here applies to all compilations (even if they 770 // are done via adb shell commands). That's ok because right now the runtime will ignore 771 // the compiled code anyway. The alternative would have been to update either 772 // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages 773 // but that would have the downside of possibly producing a big odex files which would 774 // be ignored anyway. 775 boolean vmSafeModeOrDebuggable = ((info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0) 776 || ((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0); 777 778 if (vmSafeModeOrDebuggable) { 779 return getSafeModeCompilerFilter(targetCompilerFilter); 780 } 781 782 if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) { 783 // If the dex files is used by other apps, apply the shared filter. 784 return PackageManagerServiceCompilerMapping.getCompilerFilterForReason( 785 PackageManagerService.REASON_SHARED); 786 } 787 788 return targetCompilerFilter; 789 } 790 791 /** 792 * Returns the compiler filter that should be used to optimize the primary dex. 793 * The target filter will be updated if the package has the safe mode flag set. Note that this 794 * method does NOT take other app use into account. The caller should be responsible for 795 * handling the case where the package code is used by other apps. 796 */ getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter)797 private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter) { 798 if (pkg.isUseEmbeddedDex()) { 799 // Downgrade optimizing filters to "verify", but don't upgrade lower filters. 800 return DexFile.isOptimizedCompilerFilter(targetCompilerFilter) ? "verify" 801 : targetCompilerFilter; 802 } 803 804 // We force vmSafeMode on debuggable apps as well: 805 // - the runtime ignores their compiled code 806 // - they generally have lots of methods that could make the compiler used run 807 // out of memory (b/130828957) 808 // Note that forcing the compiler filter here applies to all compilations (even if they 809 // are done via adb shell commands). That's ok because right now the runtime will ignore 810 // the compiled code anyway. The alternative would have been to update either 811 // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages 812 // but that would have the downside of possibly producing a big odex files which would 813 // be ignored anyway. 814 boolean vmSafeModeOrDebuggable = pkg.isVmSafeMode() || pkg.isDebuggable(); 815 816 if (vmSafeModeOrDebuggable) { 817 return getSafeModeCompilerFilter(targetCompilerFilter); 818 } 819 820 return targetCompilerFilter; 821 } 822 isAppImageEnabled()823 private boolean isAppImageEnabled() { 824 return SystemProperties.get("dalvik.vm.appimageformat", "").length() > 0; 825 } 826 getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options)827 private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) { 828 return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0, 829 info.getHiddenApiEnforcementPolicy(), info.splitDependencies, 830 info.requestsIsolatedSplitLoading(), compilerFilter, false /* useCloudProfile */, 831 options); 832 } 833 getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting, String compilerFilter, boolean useCloudProfile, DexoptOptions options)834 private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting, 835 String compilerFilter, boolean useCloudProfile, DexoptOptions options) { 836 return getDexFlags(pkg.isDebuggable(), 837 AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting), 838 pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter, 839 useCloudProfile, options); 840 } 841 842 /** 843 * Computes the dex flags that needs to be pass to installd for the given package and compiler 844 * filter. 845 */ getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy, SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading, String compilerFilter, boolean useCloudProfile, DexoptOptions options)846 private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy, 847 SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading, 848 String compilerFilter, boolean useCloudProfile, DexoptOptions options) { 849 // Profile guide compiled oat files should not be public unles they are based 850 // on profiles from dex metadata archives. 851 // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that 852 // the user does not have an existing profile. 853 // The flag useCloudProfile applies only when the cloud profile should be used. 854 boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter); 855 boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata() 856 || useCloudProfile; 857 int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; 858 // Some apps are executed with restrictions on hidden API usage. If this app is one 859 // of them, pass a flag to dexopt to enable the same restrictions during compilation. 860 // TODO we should pass the actual flag value to dexopt, rather than assuming denylist 861 // TODO(b/135203078): This flag is no longer set as part of AndroidPackage 862 // and may not be preserved 863 int hiddenApiFlag = hiddenApiEnforcementPolicy == HIDDEN_API_ENFORCEMENT_DISABLED 864 ? 0 865 : DEXOPT_ENABLE_HIDDEN_API_CHECKS; 866 // Avoid generating CompactDex for modes that are latency critical. 867 final int compilationReason = options.getCompilationReason(); 868 boolean generateCompactDex = true; 869 switch (compilationReason) { 870 case PackageManagerService.REASON_FIRST_BOOT: 871 case PackageManagerService.REASON_BOOT_AFTER_OTA: 872 case PackageManagerService.REASON_POST_BOOT: 873 case PackageManagerService.REASON_INSTALL: 874 generateCompactDex = false; 875 } 876 // Use app images only if it is enabled and we are compiling 877 // profile-guided (so the app image doesn't conservatively contain all classes). 878 // If the app didn't request for the splits to be loaded in isolation or if it does not 879 // declare inter-split dependencies, then all the splits will be loaded in the base 880 // apk class loader (in the order of their definition, otherwise disable app images 881 // because they are unsupported for multiple class loaders. b/7269679 882 boolean generateAppImage = isProfileGuidedFilter && (splitDependencies == null || 883 !requestsIsolatedSplitLoading) && isAppImageEnabled(); 884 int dexFlags = 885 (isPublic ? DEXOPT_PUBLIC : 0) 886 | (debuggable ? DEXOPT_DEBUGGABLE : 0) 887 | profileFlag 888 | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0) 889 | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0) 890 | (generateCompactDex ? DEXOPT_GENERATE_COMPACT_DEX : 0) 891 | (generateAppImage ? DEXOPT_GENERATE_APP_IMAGE : 0) 892 | (options.isDexoptInstallForRestore() ? DEXOPT_FOR_RESTORE : 0) 893 | hiddenApiFlag; 894 return adjustDexoptFlags(dexFlags); 895 } 896 897 /** 898 * Assesses if there's a need to perform dexopt on {@code path} for the given 899 * configuration (isa, compiler filter, profile). 900 */ 901 @GuardedBy("mInstallLock") getDexoptNeeded(String packageName, String path, String isa, String compilerFilter, String classLoaderContext, int profileAnalysisResult, boolean downgrade, int dexoptFlags, String oatDir)902 private int getDexoptNeeded(String packageName, String path, String isa, String compilerFilter, 903 String classLoaderContext, int profileAnalysisResult, boolean downgrade, 904 int dexoptFlags, String oatDir) throws LegacyDexoptDisabledException { 905 // Allow calls from OtaDexoptService even when ART Service is in use. The installer is 906 // isolated in that case so later calls to it won't call into installd anyway. 907 if (!mInstaller.isIsolated()) { 908 Installer.checkLegacyDexoptDisabled(); 909 } 910 911 final boolean shouldBePublic = (dexoptFlags & DEXOPT_PUBLIC) != 0; 912 final boolean isProfileGuidedFilter = (dexoptFlags & DEXOPT_PROFILE_GUIDED) != 0; 913 boolean newProfile = profileAnalysisResult == PROFILE_ANALYSIS_OPTIMIZE; 914 915 if (!newProfile && isProfileGuidedFilter && shouldBePublic 916 && isOdexPrivate(packageName, path, isa, oatDir)) { 917 // The profile that will be used is a cloud profile, while the profile used previously 918 // is a user profile. Typically, this happens after an app starts being used by other 919 // apps. 920 newProfile = true; 921 } 922 923 int dexoptNeeded; 924 try { 925 // A profile guided optimizations with an empty profile is essentially 'verify' and 926 // dex2oat already makes this transformation. However DexFile.getDexOptNeeded() cannot 927 // check the profiles because system server does not have access to them. 928 // As such, we rely on the previous profile analysis (done with dexoptanalyzer) and 929 // manually adjust the actual filter before checking. 930 // 931 // TODO: ideally. we'd move this check in dexoptanalyzer, but that's a large change, 932 // and in the interim we can still improve things here. 933 String actualCompilerFilter = compilerFilter; 934 if (compilerFilterDependsOnProfiles(compilerFilter) 935 && profileAnalysisResult == PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES) { 936 actualCompilerFilter = "verify"; 937 } 938 dexoptNeeded = DexFile.getDexOptNeeded(path, isa, actualCompilerFilter, 939 classLoaderContext, newProfile, downgrade); 940 } catch (IOException ioe) { 941 Slog.w(TAG, "IOException reading apk: " + path, ioe); 942 return DEX_OPT_FAILED; 943 } catch (RuntimeException e) { 944 Slog.wtf(TAG, "Unexpected exception when calling dexoptNeeded on " + path, e); 945 return DEX_OPT_FAILED; 946 } 947 return adjustDexoptNeeded(dexoptNeeded); 948 } 949 950 /** Returns true if the compiler filter depends on profiles (e.g speed-profile). */ compilerFilterDependsOnProfiles(String compilerFilter)951 private boolean compilerFilterDependsOnProfiles(String compilerFilter) { 952 return compilerFilter.endsWith("-profile"); 953 } 954 955 /** Returns true if the current artifacts of the app are private to the app itself. */ 956 @GuardedBy("mInstallLock") isOdexPrivate(String packageName, String path, String isa, String oatDir)957 private boolean isOdexPrivate(String packageName, String path, String isa, String oatDir) 958 throws LegacyDexoptDisabledException { 959 try { 960 return mInstaller.getOdexVisibility(packageName, path, isa, oatDir) 961 == Installer.ODEX_IS_PRIVATE; 962 } catch (InstallerException e) { 963 Slog.w(TAG, "Failed to get odex visibility for " + path, e); 964 return false; 965 } 966 } 967 968 /** 969 * Checks if there is an update on the profile information of the {@code pkg}. 970 * If the compiler filter is not profile guided the method returns a safe default: 971 * PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA. 972 * 973 * Note that this is a "destructive" operation with side effects. Under the hood the 974 * current profile and the reference profile will be merged and subsequent calls 975 * may return a different result. 976 */ analyseProfiles(AndroidPackage pkg, int uid, String profileName, String compilerFilter)977 private int analyseProfiles(AndroidPackage pkg, int uid, String profileName, 978 String compilerFilter) throws LegacyDexoptDisabledException { 979 Installer.checkLegacyDexoptDisabled(); 980 981 // Check if we are allowed to merge and if the compiler filter is profile guided. 982 if (!isProfileGuidedCompilerFilter(compilerFilter)) { 983 return PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; 984 } 985 // Merge profiles. It returns whether or not there was an updated in the profile info. 986 try { 987 synchronized (mInstallLock) { 988 return getInstallerLI().mergeProfiles(uid, pkg.getPackageName(), profileName); 989 } 990 } catch (InstallerException e) { 991 Slog.w(TAG, "Failed to merge profiles", e); 992 // We don't need to optimize if we failed to merge. 993 return PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; 994 } 995 } 996 997 /** 998 * Gets oat dir for the specified package if needed and supported. 999 * In certain cases oat directory 1000 * <strong>cannot</strong> be created: 1001 * <ul> 1002 * <li>{@code pkg} is a system app, which is not updated.</li> 1003 * <li>Package location is not a directory, i.e. monolithic install.</li> 1004 * </ul> 1005 * 1006 * @return Absolute path to the oat directory or null, if oat directories 1007 * not needed or unsupported for the package. 1008 */ 1009 @Nullable getPackageOatDirIfSupported(@onNull PackageState packageState, @NonNull AndroidPackage pkg)1010 private String getPackageOatDirIfSupported(@NonNull PackageState packageState, 1011 @NonNull AndroidPackage pkg) { 1012 if (!AndroidPackageUtils.canHaveOatDir(packageState, pkg)) { 1013 return null; 1014 } 1015 File codePath = new File(pkg.getPath()); 1016 if (!codePath.isDirectory()) { 1017 return null; 1018 } 1019 return getOatDir(codePath).getAbsolutePath(); 1020 } 1021 1022 /** Returns the oat dir for the given code path */ getOatDir(File codePath)1023 public static File getOatDir(File codePath) { 1024 return new File(codePath, OAT_DIR_NAME); 1025 } 1026 systemReady()1027 void systemReady() { 1028 mSystemReady = true; 1029 } 1030 printDexoptFlags(int flags)1031 private String printDexoptFlags(int flags) { 1032 ArrayList<String> flagsList = new ArrayList<>(); 1033 1034 if ((flags & DEXOPT_BOOTCOMPLETE) == DEXOPT_BOOTCOMPLETE) { 1035 flagsList.add("boot_complete"); 1036 } 1037 if ((flags & DEXOPT_DEBUGGABLE) == DEXOPT_DEBUGGABLE) { 1038 flagsList.add("debuggable"); 1039 } 1040 if ((flags & DEXOPT_PROFILE_GUIDED) == DEXOPT_PROFILE_GUIDED) { 1041 flagsList.add("profile_guided"); 1042 } 1043 if ((flags & DEXOPT_PUBLIC) == DEXOPT_PUBLIC) { 1044 flagsList.add("public"); 1045 } 1046 if ((flags & DEXOPT_SECONDARY_DEX) == DEXOPT_SECONDARY_DEX) { 1047 flagsList.add("secondary"); 1048 } 1049 if ((flags & DEXOPT_FORCE) == DEXOPT_FORCE) { 1050 flagsList.add("force"); 1051 } 1052 if ((flags & DEXOPT_STORAGE_CE) == DEXOPT_STORAGE_CE) { 1053 flagsList.add("storage_ce"); 1054 } 1055 if ((flags & DEXOPT_STORAGE_DE) == DEXOPT_STORAGE_DE) { 1056 flagsList.add("storage_de"); 1057 } 1058 if ((flags & DEXOPT_IDLE_BACKGROUND_JOB) == DEXOPT_IDLE_BACKGROUND_JOB) { 1059 flagsList.add("idle_background_job"); 1060 } 1061 if ((flags & DEXOPT_ENABLE_HIDDEN_API_CHECKS) == DEXOPT_ENABLE_HIDDEN_API_CHECKS) { 1062 flagsList.add("enable_hidden_api_checks"); 1063 } 1064 1065 return String.join(",", flagsList); 1066 } 1067 1068 /** 1069 * A specialized PackageDexOptimizer that overrides already-installed checks, forcing a 1070 * dexopt path. 1071 */ 1072 public static class ForcedUpdatePackageDexOptimizer extends PackageDexOptimizer { 1073 ForcedUpdatePackageDexOptimizer(Installer installer, Object installLock, Context context, String wakeLockTag)1074 public ForcedUpdatePackageDexOptimizer(Installer installer, Object installLock, 1075 Context context, String wakeLockTag) { 1076 super(installer, installLock, context, wakeLockTag); 1077 } 1078 ForcedUpdatePackageDexOptimizer(PackageDexOptimizer from)1079 public ForcedUpdatePackageDexOptimizer(PackageDexOptimizer from) { 1080 super(from); 1081 } 1082 1083 @Override adjustDexoptNeeded(int dexoptNeeded)1084 protected int adjustDexoptNeeded(int dexoptNeeded) { 1085 if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) { 1086 // Ensure compilation by pretending a compiler filter change on the 1087 // apk/odex location (the reason for the '-'. A positive value means 1088 // the 'oat' location). 1089 return -DexFile.DEX2OAT_FOR_FILTER; 1090 } 1091 return dexoptNeeded; 1092 } 1093 1094 @Override adjustDexoptFlags(int flags)1095 protected int adjustDexoptFlags(int flags) { 1096 // Add DEXOPT_FORCE flag to signal installd that it should force compilation 1097 // and discard dexoptanalyzer result. 1098 return flags | DEXOPT_FORCE; 1099 } 1100 } 1101 1102 /** 1103 * Returns {@link #mInstaller} with {@link #mInstallLock}. This should be used for all 1104 * {@link #mInstaller} access unless {@link #getInstallerWithoutLock()} is allowed. 1105 */ 1106 @GuardedBy("mInstallLock") getInstallerLI()1107 private Installer getInstallerLI() { 1108 return mInstaller; 1109 } 1110 1111 /** 1112 * Returns {@link #mInstaller} without lock. This should be used only inside 1113 * {@link #controlDexOptBlocking(boolean)}. 1114 */ getInstallerWithoutLock()1115 private Installer getInstallerWithoutLock() { 1116 return mInstaller; 1117 } 1118 1119 /** 1120 * Injector for {@link PackageDexOptimizer} dependencies 1121 */ 1122 interface Injector { getAppHibernationManagerInternal()1123 AppHibernationManagerInternal getAppHibernationManagerInternal(); 1124 getPowerManager(Context context)1125 PowerManager getPowerManager(Context context); 1126 } 1127 } 1128