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.InstructionSets.getAppDexInstructionSets; 35 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; 36 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; 37 import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT; 38 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReasonName; 39 40 import static dalvik.system.DexFile.getSafeModeCompilerFilter; 41 import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; 42 43 import android.annotation.NonNull; 44 import android.annotation.Nullable; 45 import android.content.Context; 46 import android.content.pm.ApplicationInfo; 47 import android.content.pm.SharedLibraryInfo; 48 import android.content.pm.dex.ArtManager; 49 import android.content.pm.dex.DexMetadataHelper; 50 import android.os.FileUtils; 51 import android.os.PowerManager; 52 import android.os.SystemClock; 53 import android.os.SystemProperties; 54 import android.os.UserHandle; 55 import android.os.WorkSource; 56 import android.os.storage.StorageManager; 57 import android.util.Log; 58 import android.util.Slog; 59 import android.util.SparseArray; 60 61 import com.android.internal.annotations.GuardedBy; 62 import com.android.internal.util.IndentingPrintWriter; 63 import com.android.server.pm.Installer.InstallerException; 64 import com.android.server.pm.dex.ArtManagerService; 65 import com.android.server.pm.dex.DexManager; 66 import com.android.server.pm.dex.DexoptOptions; 67 import com.android.server.pm.dex.DexoptUtils; 68 import com.android.server.pm.dex.PackageDexUsage; 69 import com.android.server.pm.parsing.pkg.AndroidPackage; 70 import com.android.server.pm.parsing.pkg.AndroidPackageUtils; 71 72 import dalvik.system.DexFile; 73 74 import java.io.File; 75 import java.io.IOException; 76 import java.util.ArrayList; 77 import java.util.Arrays; 78 import java.util.List; 79 import java.util.Map; 80 81 /** 82 * Helper class for running dexopt command on packages. 83 */ 84 public class PackageDexOptimizer { 85 private static final String TAG = "PackageDexOptimizer"; 86 static final String OAT_DIR_NAME = "oat"; 87 // TODO b/19550105 Remove error codes and use exceptions 88 public static final int DEX_OPT_SKIPPED = 0; 89 public static final int DEX_OPT_PERFORMED = 1; 90 public static final int DEX_OPT_FAILED = -1; 91 // One minute over PM WATCHDOG_TIMEOUT 92 private static final long WAKELOCK_TIMEOUT_MS = WATCHDOG_TIMEOUT + 1000 * 60; 93 94 @GuardedBy("mInstallLock") 95 private final Installer mInstaller; 96 private final Object mInstallLock; 97 98 @GuardedBy("mInstallLock") 99 private final PowerManager.WakeLock mDexoptWakeLock; 100 private volatile boolean mSystemReady; 101 PackageDexOptimizer(Installer installer, Object installLock, Context context, String wakeLockTag)102 PackageDexOptimizer(Installer installer, Object installLock, Context context, 103 String wakeLockTag) { 104 this.mInstaller = installer; 105 this.mInstallLock = installLock; 106 107 PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 108 mDexoptWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag); 109 } 110 PackageDexOptimizer(PackageDexOptimizer from)111 protected PackageDexOptimizer(PackageDexOptimizer from) { 112 this.mInstaller = from.mInstaller; 113 this.mInstallLock = from.mInstallLock; 114 this.mDexoptWakeLock = from.mDexoptWakeLock; 115 this.mSystemReady = from.mSystemReady; 116 } 117 canOptimizePackage(AndroidPackage pkg)118 static boolean canOptimizePackage(AndroidPackage pkg) { 119 // We do not dexopt a package with no code. 120 // Note that the system package is marked as having no code, however we can 121 // still optimize it via dexoptSystemServerPath. 122 if (!PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName()) && !pkg.isHasCode()) { 123 return false; 124 } 125 126 return true; 127 } 128 129 /** 130 * Performs dexopt on all code paths and libraries of the specified package for specified 131 * instruction sets. 132 * 133 * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are 134 * synchronized on {@link #mInstallLock}. 135 */ performDexOpt(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String[] instructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options)136 int performDexOpt(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, 137 String[] instructionSets, CompilerStats.PackageStats packageStats, 138 PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { 139 if (PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName())) { 140 throw new IllegalArgumentException("System server dexopting should be done via " 141 + " DexManager and PackageDexOptimizer#dexoptSystemServerPath"); 142 } 143 if (pkg.getUid() == -1) { 144 throw new IllegalArgumentException("Dexopt for " + pkg.getPackageName() 145 + " has invalid uid."); 146 } 147 if (!canOptimizePackage(pkg)) { 148 return DEX_OPT_SKIPPED; 149 } 150 synchronized (mInstallLock) { 151 final long acquireTime = acquireWakeLockLI(pkg.getUid()); 152 try { 153 return performDexOptLI(pkg, pkgSetting, instructionSets, 154 packageStats, packageUseInfo, options); 155 } finally { 156 releaseWakeLockLI(acquireTime); 157 } 158 } 159 } 160 161 /** 162 * Performs dexopt on all code paths of the given package. 163 * It assumes the install lock is held. 164 */ 165 @GuardedBy("mInstallLock") performDexOptLI(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String[] targetInstructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options)166 private int performDexOptLI(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, 167 String[] targetInstructionSets, CompilerStats.PackageStats packageStats, 168 PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { 169 final List<SharedLibraryInfo> sharedLibraries = pkgSetting.getPkgState() 170 .getUsesLibraryInfos(); 171 final String[] instructionSets = targetInstructionSets != null ? 172 targetInstructionSets : getAppDexInstructionSets( 173 AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), 174 AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting)); 175 final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); 176 final List<String> paths = AndroidPackageUtils.getAllCodePaths(pkg); 177 178 int sharedGid = UserHandle.getSharedAppGid(pkg.getUid()); 179 if (sharedGid == -1) { 180 Slog.wtf(TAG, "Well this is awkward; package " + pkg.getPackageName() + " had UID " 181 + pkg.getUid(), new Throwable()); 182 sharedGid = android.os.Process.NOBODY_UID; 183 } 184 185 // Get the class loader context dependencies. 186 // For each code path in the package, this array contains the class loader context that 187 // needs to be passed to dexopt in order to ensure correct optimizations. 188 boolean[] pathsWithCode = new boolean[paths.size()]; 189 pathsWithCode[0] = pkg.isHasCode(); 190 for (int i = 1; i < paths.size(); i++) { 191 pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0; 192 } 193 String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts( 194 pkg, sharedLibraries, pathsWithCode); 195 196 // Sanity check that we do not call dexopt with inconsistent data. 197 if (paths.size() != classLoaderContexts.length) { 198 String[] splitCodePaths = pkg.getSplitCodePaths(); 199 throw new IllegalStateException("Inconsistent information " 200 + "between PackageParser.Package and its ApplicationInfo. " 201 + "pkg.getAllCodePaths=" + paths 202 + " pkg.getBaseCodePath=" + pkg.getBaseCodePath() 203 + " pkg.getSplitCodePaths=" 204 + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths))); 205 } 206 207 int result = DEX_OPT_SKIPPED; 208 for (int i = 0; i < paths.size(); i++) { 209 // Skip paths that have no code. 210 if (!pathsWithCode[i]) { 211 continue; 212 } 213 if (classLoaderContexts[i] == null) { 214 throw new IllegalStateException("Inconsistent information in the " 215 + "package structure. A split is marked to contain code " 216 + "but has no dependency listed. Index=" + i + " path=" + paths.get(i)); 217 } 218 219 // Append shared libraries with split dependencies for this split. 220 String path = paths.get(i); 221 if (options.getSplitName() != null) { 222 // We are asked to compile only a specific split. Check that the current path is 223 // what we are looking for. 224 if (!options.getSplitName().equals(new File(path).getName())) { 225 continue; 226 } 227 } 228 229 String profileName = ArtManager.getProfileName( 230 i == 0 ? null : pkg.getSplitNames()[i - 1]); 231 232 String dexMetadataPath = null; 233 if (options.isDexoptInstallWithDexMetadata()) { 234 File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path)); 235 dexMetadataPath = dexMetadataFile == null 236 ? null : dexMetadataFile.getAbsolutePath(); 237 } 238 239 final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary() 240 || packageUseInfo.isUsedByOtherApps(path); 241 final String compilerFilter = getRealCompilerFilter(pkg, 242 options.getCompilerFilter(), isUsedByOtherApps); 243 final boolean profileUpdated = options.isCheckForProfileUpdates() && 244 isProfileUpdated(pkg, sharedGid, profileName, compilerFilter); 245 246 // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct 247 // flags. 248 final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, options); 249 250 for (String dexCodeIsa : dexCodeInstructionSets) { 251 int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter, 252 profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid, 253 packageStats, options.isDowngrade(), profileName, dexMetadataPath, 254 options.getCompilationReason()); 255 // The end result is: 256 // - FAILED if any path failed, 257 // - PERFORMED if at least one path needed compilation, 258 // - SKIPPED when all paths are up to date 259 if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) { 260 result = newResult; 261 } 262 } 263 } 264 return result; 265 } 266 267 /** 268 * Performs dexopt on the {@code path} belonging to the package {@code pkg}. 269 * 270 * @return 271 * DEX_OPT_FAILED if there was any exception during dexopt 272 * DEX_OPT_PERFORMED if dexopt was performed successfully on the given path. 273 * DEX_OPT_SKIPPED if the path does not need to be deopt-ed. 274 */ 275 @GuardedBy("mInstallLock") dexOptPath(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String path, String isa, String compilerFilter, boolean profileUpdated, String classLoaderContext, int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade, String profileName, String dexMetadataPath, int compilationReason)276 private int dexOptPath(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String path, 277 String isa, String compilerFilter, boolean profileUpdated, String classLoaderContext, 278 int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade, 279 String profileName, String dexMetadataPath, int compilationReason) { 280 int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext, 281 profileUpdated, downgrade); 282 if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) { 283 return DEX_OPT_SKIPPED; 284 } 285 286 String oatDir = getPackageOatDirIfSupported(pkg, 287 pkgSetting.getPkgState().isUpdatedSystemApp()); 288 289 Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path 290 + " pkg=" + pkg.getPackageName() + " isa=" + isa 291 + " dexoptFlags=" + printDexoptFlags(dexoptFlags) 292 + " targetFilter=" + compilerFilter + " oatDir=" + oatDir 293 + " classLoaderContext=" + classLoaderContext); 294 295 try { 296 long startTime = System.currentTimeMillis(); 297 298 // TODO: Consider adding 2 different APIs for primary and secondary dexopt. 299 // installd only uses downgrade flag for secondary dex files and ignores it for 300 // primary dex files. 301 String seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting); 302 mInstaller.dexopt(path, uid, pkg.getPackageName(), isa, dexoptNeeded, oatDir, 303 dexoptFlags, compilerFilter, pkg.getVolumeUuid(), classLoaderContext, 304 seInfo, false /* downgrade*/, pkg.getTargetSdkVersion(), 305 profileName, dexMetadataPath, 306 getAugmentedReasonName(compilationReason, dexMetadataPath != null)); 307 308 if (packageStats != null) { 309 long endTime = System.currentTimeMillis(); 310 packageStats.setCompileTime(path, (int)(endTime - startTime)); 311 } 312 return DEX_OPT_PERFORMED; 313 } catch (InstallerException e) { 314 Slog.w(TAG, "Failed to dexopt", e); 315 return DEX_OPT_FAILED; 316 } 317 } 318 319 /** 320 * Perform dexopt (if needed) on a system server code path). 321 */ dexoptSystemServerPath( String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options)322 public int dexoptSystemServerPath( 323 String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) { 324 int dexoptFlags = DEXOPT_PUBLIC 325 | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0) 326 | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0); 327 328 int result = DEX_OPT_SKIPPED; 329 for (String isa : dexUseInfo.getLoaderIsas()) { 330 int dexoptNeeded = getDexoptNeeded( 331 dexPath, 332 isa, 333 options.getCompilerFilter(), 334 dexUseInfo.getClassLoaderContext(), 335 /* newProfile= */false, 336 /* downgrade= */ false); 337 338 if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) { 339 continue; 340 } 341 try { 342 mInstaller.dexopt( 343 dexPath, 344 android.os.Process.SYSTEM_UID, 345 /* packageName= */ "android", 346 isa, 347 dexoptNeeded, 348 /* oatDir= */ null, 349 dexoptFlags, 350 options.getCompilerFilter(), 351 StorageManager.UUID_PRIVATE_INTERNAL, 352 dexUseInfo.getClassLoaderContext(), 353 /* seInfo= */ null, 354 /* downgrade= */ false , 355 /* targetSdk= */ 0, 356 /* profileName */ null, 357 /* dexMetadataPath */ null, 358 getReasonName(options.getCompilationReason())); 359 } catch (InstallerException e) { 360 Slog.w(TAG, "Failed to dexopt", e); 361 return DEX_OPT_FAILED; 362 } 363 result = DEX_OPT_PERFORMED; 364 } 365 return result; 366 } 367 getAugmentedReasonName(int compilationReason, boolean useDexMetadata)368 private String getAugmentedReasonName(int compilationReason, boolean useDexMetadata) { 369 String annotation = useDexMetadata 370 ? ArtManagerService.DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : ""; 371 return getReasonName(compilationReason) + annotation; 372 } 373 374 /** 375 * Performs dexopt on the secondary dex {@code path} belonging to the app {@code info}. 376 * 377 * @return 378 * DEX_OPT_FAILED if there was any exception during dexopt 379 * DEX_OPT_PERFORMED if dexopt was performed successfully on the given path. 380 * NOTE that DEX_OPT_PERFORMED for secondary dex files includes the case when the dex file 381 * didn't need an update. That's because at the moment we don't get more than success/failure 382 * from installd. 383 * 384 * TODO(calin): Consider adding return codes to installd dexopt invocation (rather than 385 * throwing exceptions). Or maybe make a separate call to installd to get DexOptNeeded, though 386 * that seems wasteful. 387 */ dexOptSecondaryDexPath(ApplicationInfo info, String path, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options)388 public int dexOptSecondaryDexPath(ApplicationInfo info, String path, 389 PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) { 390 if (info.uid == -1) { 391 throw new IllegalArgumentException("Dexopt for path " + path + " has invalid uid."); 392 } 393 synchronized (mInstallLock) { 394 final long acquireTime = acquireWakeLockLI(info.uid); 395 try { 396 return dexOptSecondaryDexPathLI(info, path, dexUseInfo, options); 397 } finally { 398 releaseWakeLockLI(acquireTime); 399 } 400 } 401 } 402 403 @GuardedBy("mInstallLock") acquireWakeLockLI(final int uid)404 private long acquireWakeLockLI(final int uid) { 405 // During boot the system doesn't need to instantiate and obtain a wake lock. 406 // PowerManager might not be ready, but that doesn't mean that we can't proceed with 407 // dexopt. 408 if (!mSystemReady) { 409 return -1; 410 } 411 mDexoptWakeLock.setWorkSource(new WorkSource(uid)); 412 mDexoptWakeLock.acquire(WAKELOCK_TIMEOUT_MS); 413 return SystemClock.elapsedRealtime(); 414 } 415 416 @GuardedBy("mInstallLock") releaseWakeLockLI(final long acquireTime)417 private void releaseWakeLockLI(final long acquireTime) { 418 if (acquireTime < 0) { 419 return; 420 } 421 try { 422 if (mDexoptWakeLock.isHeld()) { 423 mDexoptWakeLock.release(); 424 } 425 final long duration = SystemClock.elapsedRealtime() - acquireTime; 426 if (duration >= WAKELOCK_TIMEOUT_MS) { 427 Slog.wtf(TAG, "WakeLock " + mDexoptWakeLock.getTag() 428 + " time out. Operation took " + duration + " ms. Thread: " 429 + Thread.currentThread().getName()); 430 } 431 } catch (Exception e) { 432 Slog.wtf(TAG, "Error while releasing " + mDexoptWakeLock.getTag() + " lock", e); 433 } 434 } 435 436 @GuardedBy("mInstallLock") dexOptSecondaryDexPathLI(ApplicationInfo info, String path, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options)437 private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, 438 PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) { 439 if (options.isDexoptOnlySharedDex() && !dexUseInfo.isUsedByOtherApps()) { 440 // We are asked to optimize only the dex files used by other apps and this is not 441 // on of them: skip it. 442 return DEX_OPT_SKIPPED; 443 } 444 445 String compilerFilter = getRealCompilerFilter(info, options.getCompilerFilter(), 446 dexUseInfo.isUsedByOtherApps()); 447 // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags. 448 // Secondary dex files are currently not compiled at boot. 449 int dexoptFlags = getDexFlags(info, compilerFilter, options) | DEXOPT_SECONDARY_DEX; 450 // Check the app storage and add the appropriate flags. 451 if (info.deviceProtectedDataDir != null && 452 FileUtils.contains(info.deviceProtectedDataDir, path)) { 453 dexoptFlags |= DEXOPT_STORAGE_DE; 454 } else if (info.credentialProtectedDataDir != null && 455 FileUtils.contains(info.credentialProtectedDataDir, path)) { 456 dexoptFlags |= DEXOPT_STORAGE_CE; 457 } else { 458 Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName); 459 return DEX_OPT_FAILED; 460 } 461 String classLoaderContext = null; 462 if (dexUseInfo.isUnsupportedClassLoaderContext() 463 || dexUseInfo.isVariableClassLoaderContext()) { 464 // If we have an unknown (not yet set), or a variable class loader chain. Just extract 465 // the dex file. 466 compilerFilter = "extract"; 467 } else { 468 classLoaderContext = dexUseInfo.getClassLoaderContext(); 469 } 470 471 int reason = options.getCompilationReason(); 472 Log.d(TAG, "Running dexopt on: " + path 473 + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas() 474 + " reason=" + getReasonName(reason) 475 + " dexoptFlags=" + printDexoptFlags(dexoptFlags) 476 + " target-filter=" + compilerFilter 477 + " class-loader-context=" + classLoaderContext); 478 479 try { 480 for (String isa : dexUseInfo.getLoaderIsas()) { 481 // Reuse the same dexopt path as for the primary apks. We don't need all the 482 // arguments as some (dexopNeeded and oatDir) will be computed by installd because 483 // system server cannot read untrusted app content. 484 // TODO(calin): maybe add a separate call. 485 mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0, 486 /*oatDir*/ null, dexoptFlags, 487 compilerFilter, info.volumeUuid, classLoaderContext, info.seInfo, 488 options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null, 489 /*dexMetadataPath*/ null, getReasonName(reason)); 490 } 491 492 return DEX_OPT_PERFORMED; 493 } catch (InstallerException e) { 494 Slog.w(TAG, "Failed to dexopt", e); 495 return DEX_OPT_FAILED; 496 } 497 } 498 499 /** 500 * Adjust the given dexopt-needed value. Can be overridden to influence the decision to 501 * optimize or not (and in what way). 502 */ adjustDexoptNeeded(int dexoptNeeded)503 protected int adjustDexoptNeeded(int dexoptNeeded) { 504 return dexoptNeeded; 505 } 506 507 /** 508 * Adjust the given dexopt flags that will be passed to the installer. 509 */ adjustDexoptFlags(int dexoptFlags)510 protected int adjustDexoptFlags(int dexoptFlags) { 511 return dexoptFlags; 512 } 513 514 /** 515 * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}. 516 */ dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg, PackageSetting pkgSetting, PackageDexUsage.PackageUseInfo useInfo)517 void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg, PackageSetting pkgSetting, 518 PackageDexUsage.PackageUseInfo useInfo) { 519 final String[] instructionSets = getAppDexInstructionSets( 520 AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), 521 AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting)); 522 final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); 523 524 final List<String> paths = AndroidPackageUtils.getAllCodePathsExcludingResourceOnly(pkg); 525 526 for (String path : paths) { 527 pw.println("path: " + path); 528 pw.increaseIndent(); 529 530 for (String isa : dexCodeInstructionSets) { 531 try { 532 DexFile.OptimizationInfo info = DexFile.getDexFileOptimizationInfo(path, isa); 533 pw.println(isa + ": [status=" + info.getStatus() 534 +"] [reason=" + info.getReason() + "]"); 535 } catch (IOException ioe) { 536 pw.println(isa + ": [Exception]: " + ioe.getMessage()); 537 } 538 } 539 540 if (useInfo.isUsedByOtherApps(path)) { 541 pw.println("used by other apps: " + useInfo.getLoadingPackages(path)); 542 } 543 544 Map<String, PackageDexUsage.DexUseInfo> dexUseInfoMap = useInfo.getDexUseInfoMap(); 545 546 if (!dexUseInfoMap.isEmpty()) { 547 pw.println("known secondary dex files:"); 548 pw.increaseIndent(); 549 for (Map.Entry<String, PackageDexUsage.DexUseInfo> e : dexUseInfoMap.entrySet()) { 550 String dex = e.getKey(); 551 PackageDexUsage.DexUseInfo dexUseInfo = e.getValue(); 552 pw.println(dex); 553 pw.increaseIndent(); 554 // TODO(calin): get the status of the oat file (needs installd call) 555 pw.println("class loader context: " + dexUseInfo.getClassLoaderContext()); 556 if (dexUseInfo.isUsedByOtherApps()) { 557 pw.println("used by other apps: " + dexUseInfo.getLoadingPackages()); 558 } 559 pw.decreaseIndent(); 560 } 561 pw.decreaseIndent(); 562 } 563 pw.decreaseIndent(); 564 } 565 } 566 567 /** 568 * Returns the compiler filter that should be used to optimize the package code. 569 * The target filter will be updated if the package code is used by other apps 570 * or if it has the safe mode flag set. 571 */ getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter, boolean isUsedByOtherApps)572 private String getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter, 573 boolean isUsedByOtherApps) { 574 // When an app or priv app is configured to run out of box, only verify it. 575 if (info.isEmbeddedDexUsed() 576 || (info.isPrivilegedApp() 577 && DexManager.isPackageSelectedToRunOob(info.packageName))) { 578 return "verify"; 579 } 580 581 // We force vmSafeMode on debuggable apps as well: 582 // - the runtime ignores their compiled code 583 // - they generally have lots of methods that could make the compiler used run 584 // out of memory (b/130828957) 585 // Note that forcing the compiler filter here applies to all compilations (even if they 586 // are done via adb shell commands). That's ok because right now the runtime will ignore 587 // the compiled code anyway. The alternative would have been to update either 588 // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages 589 // but that would have the downside of possibly producing a big odex files which would 590 // be ignored anyway. 591 boolean vmSafeModeOrDebuggable = ((info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0) 592 || ((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0); 593 594 if (vmSafeModeOrDebuggable) { 595 return getSafeModeCompilerFilter(targetCompilerFilter); 596 } 597 598 if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) { 599 // If the dex files is used by other apps, apply the shared filter. 600 return PackageManagerServiceCompilerMapping.getCompilerFilterForReason( 601 PackageManagerService.REASON_SHARED); 602 } 603 604 return targetCompilerFilter; 605 } 606 607 /** 608 * Returns the compiler filter that should be used to optimize the package code. 609 * The target filter will be updated if the package code is used by other apps 610 * or if it has the safe mode flag set. 611 */ getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter, boolean isUsedByOtherApps)612 private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter, 613 boolean isUsedByOtherApps) { 614 // When an app or priv app is configured to run out of box, only verify it. 615 if (pkg.isUseEmbeddedDex() 616 || (pkg.isPrivileged() 617 && DexManager.isPackageSelectedToRunOob(pkg.getPackageName()))) { 618 return "verify"; 619 } 620 621 // We force vmSafeMode on debuggable apps as well: 622 // - the runtime ignores their compiled code 623 // - they generally have lots of methods that could make the compiler used run 624 // out of memory (b/130828957) 625 // Note that forcing the compiler filter here applies to all compilations (even if they 626 // are done via adb shell commands). That's ok because right now the runtime will ignore 627 // the compiled code anyway. The alternative would have been to update either 628 // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages 629 // but that would have the downside of possibly producing a big odex files which would 630 // be ignored anyway. 631 boolean vmSafeModeOrDebuggable = pkg.isVmSafeMode() || pkg.isDebuggable(); 632 633 if (vmSafeModeOrDebuggable) { 634 return getSafeModeCompilerFilter(targetCompilerFilter); 635 } 636 637 if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) { 638 // If the dex files is used by other apps, apply the shared filter. 639 return PackageManagerServiceCompilerMapping.getCompilerFilterForReason( 640 PackageManagerService.REASON_SHARED); 641 } 642 643 return targetCompilerFilter; 644 } 645 isAppImageEnabled()646 private boolean isAppImageEnabled() { 647 return SystemProperties.get("dalvik.vm.appimageformat", "").length() > 0; 648 } 649 getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options)650 private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) { 651 return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0, 652 info.getHiddenApiEnforcementPolicy(), info.splitDependencies, 653 info.requestsIsolatedSplitLoading(), compilerFilter, options); 654 } getDexFlags(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String compilerFilter, DexoptOptions options)655 private int getDexFlags(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, 656 String compilerFilter, DexoptOptions options) { 657 return getDexFlags(pkg.isDebuggable(), 658 AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting), 659 pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter, 660 options); 661 } 662 663 /** 664 * Computes the dex flags that needs to be pass to installd for the given package and compiler 665 * filter. 666 */ getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy, SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading, String compilerFilter, DexoptOptions options)667 private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy, 668 SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading, 669 String compilerFilter, DexoptOptions options) { 670 // Profile guide compiled oat files should not be public unles they are based 671 // on profiles from dex metadata archives. 672 // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that 673 // the user does not have an existing profile. 674 boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter); 675 boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata(); 676 int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; 677 // Some apps are executed with restrictions on hidden API usage. If this app is one 678 // of them, pass a flag to dexopt to enable the same restrictions during compilation. 679 // TODO we should pass the actual flag value to dexopt, rather than assuming blacklist 680 // TODO(b/135203078): This flag is no longer set as part of AndroidPackage 681 // and may not be preserved 682 int hiddenApiFlag = hiddenApiEnforcementPolicy == HIDDEN_API_ENFORCEMENT_DISABLED 683 ? 0 684 : DEXOPT_ENABLE_HIDDEN_API_CHECKS; 685 // Avoid generating CompactDex for modes that are latency critical. 686 final int compilationReason = options.getCompilationReason(); 687 boolean generateCompactDex = true; 688 switch (compilationReason) { 689 case PackageManagerService.REASON_FIRST_BOOT: 690 case PackageManagerService.REASON_BOOT: 691 case PackageManagerService.REASON_INSTALL: 692 generateCompactDex = false; 693 } 694 // Use app images only if it is enabled and we are compiling 695 // profile-guided (so the app image doesn't conservatively contain all classes). 696 // If the app didn't request for the splits to be loaded in isolation or if it does not 697 // declare inter-split dependencies, then all the splits will be loaded in the base 698 // apk class loader (in the order of their definition, otherwise disable app images 699 // because they are unsupported for multiple class loaders. b/7269679 700 boolean generateAppImage = isProfileGuidedFilter && (splitDependencies == null || 701 !requestsIsolatedSplitLoading) && isAppImageEnabled(); 702 int dexFlags = 703 (isPublic ? DEXOPT_PUBLIC : 0) 704 | (debuggable ? DEXOPT_DEBUGGABLE : 0) 705 | profileFlag 706 | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0) 707 | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0) 708 | (generateCompactDex ? DEXOPT_GENERATE_COMPACT_DEX : 0) 709 | (generateAppImage ? DEXOPT_GENERATE_APP_IMAGE : 0) 710 | (options.isDexoptInstallForRestore() ? DEXOPT_FOR_RESTORE : 0) 711 | hiddenApiFlag; 712 return adjustDexoptFlags(dexFlags); 713 } 714 715 /** 716 * Assesses if there's a need to perform dexopt on {@code path} for the given 717 * configuration (isa, compiler filter, profile). 718 */ getDexoptNeeded(String path, String isa, String compilerFilter, String classLoaderContext, boolean newProfile, boolean downgrade)719 private int getDexoptNeeded(String path, String isa, String compilerFilter, 720 String classLoaderContext, boolean newProfile, boolean downgrade) { 721 int dexoptNeeded; 722 try { 723 dexoptNeeded = DexFile.getDexOptNeeded(path, isa, compilerFilter, classLoaderContext, 724 newProfile, downgrade); 725 } catch (IOException ioe) { 726 Slog.w(TAG, "IOException reading apk: " + path, ioe); 727 return DEX_OPT_FAILED; 728 } catch (Exception e) { 729 Slog.wtf(TAG, "Unexpected exception when calling dexoptNeeded on " + path, e); 730 return DEX_OPT_FAILED; 731 } 732 return adjustDexoptNeeded(dexoptNeeded); 733 } 734 735 /** 736 * Checks if there is an update on the profile information of the {@code pkg}. 737 * If the compiler filter is not profile guided the method returns false. 738 * 739 * Note that this is a "destructive" operation with side effects. Under the hood the 740 * current profile and the reference profile will be merged and subsequent calls 741 * may return a different result. 742 */ isProfileUpdated(AndroidPackage pkg, int uid, String profileName, String compilerFilter)743 private boolean isProfileUpdated(AndroidPackage pkg, int uid, String profileName, 744 String compilerFilter) { 745 // Check if we are allowed to merge and if the compiler filter is profile guided. 746 if (!isProfileGuidedCompilerFilter(compilerFilter)) { 747 return false; 748 } 749 // Merge profiles. It returns whether or not there was an updated in the profile info. 750 try { 751 return mInstaller.mergeProfiles(uid, pkg.getPackageName(), profileName); 752 } catch (InstallerException e) { 753 Slog.w(TAG, "Failed to merge profiles", e); 754 } 755 return false; 756 } 757 758 /** 759 * Gets oat dir for the specified package if needed and supported. 760 * In certain cases oat directory 761 * <strong>cannot</strong> be created: 762 * <ul> 763 * <li>{@code pkg} is a system app, which is not updated.</li> 764 * <li>Package location is not a directory, i.e. monolithic install.</li> 765 * </ul> 766 * 767 * @return Absolute path to the oat directory or null, if oat directories 768 * not needed or unsupported for the package. 769 */ 770 @Nullable getPackageOatDirIfSupported(AndroidPackage pkg, boolean isUpdatedSystemApp)771 private String getPackageOatDirIfSupported(AndroidPackage pkg, boolean isUpdatedSystemApp) { 772 if (!AndroidPackageUtils.canHaveOatDir(pkg, isUpdatedSystemApp)) { 773 return null; 774 } 775 File codePath = new File(pkg.getCodePath()); 776 if (!codePath.isDirectory()) { 777 return null; 778 } 779 return getOatDir(codePath).getAbsolutePath(); 780 } 781 getOatDir(File codePath)782 static File getOatDir(File codePath) { 783 return new File(codePath, OAT_DIR_NAME); 784 } 785 systemReady()786 void systemReady() { 787 mSystemReady = true; 788 } 789 printDexoptFlags(int flags)790 private String printDexoptFlags(int flags) { 791 ArrayList<String> flagsList = new ArrayList<>(); 792 793 if ((flags & DEXOPT_BOOTCOMPLETE) == DEXOPT_BOOTCOMPLETE) { 794 flagsList.add("boot_complete"); 795 } 796 if ((flags & DEXOPT_DEBUGGABLE) == DEXOPT_DEBUGGABLE) { 797 flagsList.add("debuggable"); 798 } 799 if ((flags & DEXOPT_PROFILE_GUIDED) == DEXOPT_PROFILE_GUIDED) { 800 flagsList.add("profile_guided"); 801 } 802 if ((flags & DEXOPT_PUBLIC) == DEXOPT_PUBLIC) { 803 flagsList.add("public"); 804 } 805 if ((flags & DEXOPT_SECONDARY_DEX) == DEXOPT_SECONDARY_DEX) { 806 flagsList.add("secondary"); 807 } 808 if ((flags & DEXOPT_FORCE) == DEXOPT_FORCE) { 809 flagsList.add("force"); 810 } 811 if ((flags & DEXOPT_STORAGE_CE) == DEXOPT_STORAGE_CE) { 812 flagsList.add("storage_ce"); 813 } 814 if ((flags & DEXOPT_STORAGE_DE) == DEXOPT_STORAGE_DE) { 815 flagsList.add("storage_de"); 816 } 817 if ((flags & DEXOPT_IDLE_BACKGROUND_JOB) == DEXOPT_IDLE_BACKGROUND_JOB) { 818 flagsList.add("idle_background_job"); 819 } 820 if ((flags & DEXOPT_ENABLE_HIDDEN_API_CHECKS) == DEXOPT_ENABLE_HIDDEN_API_CHECKS) { 821 flagsList.add("enable_hidden_api_checks"); 822 } 823 824 return String.join(",", flagsList); 825 } 826 827 /** 828 * A specialized PackageDexOptimizer that overrides already-installed checks, forcing a 829 * dexopt path. 830 */ 831 public static class ForcedUpdatePackageDexOptimizer extends PackageDexOptimizer { 832 ForcedUpdatePackageDexOptimizer(Installer installer, Object installLock, Context context, String wakeLockTag)833 public ForcedUpdatePackageDexOptimizer(Installer installer, Object installLock, 834 Context context, String wakeLockTag) { 835 super(installer, installLock, context, wakeLockTag); 836 } 837 ForcedUpdatePackageDexOptimizer(PackageDexOptimizer from)838 public ForcedUpdatePackageDexOptimizer(PackageDexOptimizer from) { 839 super(from); 840 } 841 842 @Override adjustDexoptNeeded(int dexoptNeeded)843 protected int adjustDexoptNeeded(int dexoptNeeded) { 844 if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) { 845 // Ensure compilation by pretending a compiler filter change on the 846 // apk/odex location (the reason for the '-'. A positive value means 847 // the 'oat' location). 848 return -DexFile.DEX2OAT_FOR_FILTER; 849 } 850 return dexoptNeeded; 851 } 852 853 @Override adjustDexoptFlags(int flags)854 protected int adjustDexoptFlags(int flags) { 855 // Add DEXOPT_FORCE flag to signal installd that it should force compilation 856 // and discard dexoptanalyzer result. 857 return flags | DEXOPT_FORCE; 858 } 859 } 860 } 861