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