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