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 android.annotation.Nullable; 20 import android.content.Context; 21 import android.content.pm.ApplicationInfo; 22 import android.content.pm.PackageParser; 23 import android.os.FileUtils; 24 import android.os.PowerManager; 25 import android.os.SystemClock; 26 import android.os.UserHandle; 27 import android.os.WorkSource; 28 import android.util.Log; 29 import android.util.Slog; 30 31 import com.android.internal.annotations.GuardedBy; 32 import com.android.internal.util.IndentingPrintWriter; 33 import com.android.server.pm.Installer.InstallerException; 34 import com.android.server.pm.dex.DexManager; 35 import com.android.server.pm.dex.DexoptOptions; 36 import com.android.server.pm.dex.DexoptUtils; 37 import com.android.server.pm.dex.PackageDexUsage; 38 39 import java.io.File; 40 import java.io.IOException; 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.List; 44 import java.util.Map; 45 46 import dalvik.system.DexFile; 47 48 import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; 49 import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; 50 import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED; 51 import static com.android.server.pm.Installer.DEXOPT_PUBLIC; 52 import static com.android.server.pm.Installer.DEXOPT_SECONDARY_DEX; 53 import static com.android.server.pm.Installer.DEXOPT_FORCE; 54 import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE; 55 import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE; 56 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; 57 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; 58 59 import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT; 60 61 import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter; 62 import static dalvik.system.DexFile.getSafeModeCompilerFilter; 63 import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; 64 65 /** 66 * Helper class for running dexopt command on packages. 67 */ 68 public class PackageDexOptimizer { 69 private static final String TAG = "PackageManager.DexOptimizer"; 70 static final String OAT_DIR_NAME = "oat"; 71 // TODO b/19550105 Remove error codes and use exceptions 72 public static final int DEX_OPT_SKIPPED = 0; 73 public static final int DEX_OPT_PERFORMED = 1; 74 public static final int DEX_OPT_FAILED = -1; 75 // One minute over PM WATCHDOG_TIMEOUT 76 private static final long WAKELOCK_TIMEOUT_MS = WATCHDOG_TIMEOUT + 1000 * 60; 77 78 /** Special library name that skips shared libraries check during compilation. */ 79 public static final String SKIP_SHARED_LIBRARY_CHECK = "&"; 80 81 @GuardedBy("mInstallLock") 82 private final Installer mInstaller; 83 private final Object mInstallLock; 84 85 @GuardedBy("mInstallLock") 86 private final PowerManager.WakeLock mDexoptWakeLock; 87 private volatile boolean mSystemReady; 88 PackageDexOptimizer(Installer installer, Object installLock, Context context, String wakeLockTag)89 PackageDexOptimizer(Installer installer, Object installLock, Context context, 90 String wakeLockTag) { 91 this.mInstaller = installer; 92 this.mInstallLock = installLock; 93 94 PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 95 mDexoptWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag); 96 } 97 PackageDexOptimizer(PackageDexOptimizer from)98 protected PackageDexOptimizer(PackageDexOptimizer from) { 99 this.mInstaller = from.mInstaller; 100 this.mInstallLock = from.mInstallLock; 101 this.mDexoptWakeLock = from.mDexoptWakeLock; 102 this.mSystemReady = from.mSystemReady; 103 } 104 canOptimizePackage(PackageParser.Package pkg)105 static boolean canOptimizePackage(PackageParser.Package pkg) { 106 return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0; 107 } 108 109 /** 110 * Performs dexopt on all code paths and libraries of the specified package for specified 111 * instruction sets. 112 * 113 * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are 114 * synchronized on {@link #mInstallLock}. 115 */ performDexOpt(PackageParser.Package pkg, String[] sharedLibraries, String[] instructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options)116 int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries, 117 String[] instructionSets, CompilerStats.PackageStats packageStats, 118 PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { 119 if (!canOptimizePackage(pkg)) { 120 return DEX_OPT_SKIPPED; 121 } 122 synchronized (mInstallLock) { 123 final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid); 124 try { 125 return performDexOptLI(pkg, sharedLibraries, instructionSets, 126 packageStats, packageUseInfo, options); 127 } finally { 128 releaseWakeLockLI(acquireTime); 129 } 130 } 131 } 132 133 /** 134 * Performs dexopt on all code paths of the given package. 135 * It assumes the install lock is held. 136 */ 137 @GuardedBy("mInstallLock") performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries, String[] targetInstructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options)138 private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries, 139 String[] targetInstructionSets, CompilerStats.PackageStats packageStats, 140 PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { 141 final String[] instructionSets = targetInstructionSets != null ? 142 targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo); 143 final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); 144 final List<String> paths = pkg.getAllCodePaths(); 145 final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); 146 147 // Get the class loader context dependencies. 148 // For each code path in the package, this array contains the class loader context that 149 // needs to be passed to dexopt in order to ensure correct optimizations. 150 boolean[] pathsWithCode = new boolean[paths.size()]; 151 pathsWithCode[0] = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0; 152 for (int i = 1; i < paths.size(); i++) { 153 pathsWithCode[i] = (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0; 154 } 155 String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts( 156 pkg.applicationInfo, sharedLibraries, pathsWithCode); 157 158 // Sanity check that we do not call dexopt with inconsistent data. 159 if (paths.size() != classLoaderContexts.length) { 160 String[] splitCodePaths = pkg.applicationInfo.getSplitCodePaths(); 161 throw new IllegalStateException("Inconsistent information " 162 + "between PackageParser.Package and its ApplicationInfo. " 163 + "pkg.getAllCodePaths=" + paths 164 + " pkg.applicationInfo.getBaseCodePath=" + pkg.applicationInfo.getBaseCodePath() 165 + " pkg.applicationInfo.getSplitCodePaths=" 166 + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths))); 167 } 168 169 int result = DEX_OPT_SKIPPED; 170 for (int i = 0; i < paths.size(); i++) { 171 // Skip paths that have no code. 172 if (!pathsWithCode[i]) { 173 continue; 174 } 175 if (classLoaderContexts[i] == null) { 176 throw new IllegalStateException("Inconsistent information in the " 177 + "package structure. A split is marked to contain code " 178 + "but has no dependency listed. Index=" + i + " path=" + paths.get(i)); 179 } 180 181 // Append shared libraries with split dependencies for this split. 182 String path = paths.get(i); 183 if (options.getSplitName() != null) { 184 // We are asked to compile only a specific split. Check that the current path is 185 // what we are looking for. 186 if (!options.getSplitName().equals(new File(path).getName())) { 187 continue; 188 } 189 } 190 191 final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary() 192 || packageUseInfo.isUsedByOtherApps(path); 193 final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo, 194 options.getCompilerFilter(), isUsedByOtherApps); 195 final boolean profileUpdated = options.isCheckForProfileUpdates() && 196 isProfileUpdated(pkg, sharedGid, compilerFilter); 197 198 // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct 199 // flags. 200 final int dexoptFlags = getDexFlags(pkg, compilerFilter, options.isBootComplete()); 201 202 for (String dexCodeIsa : dexCodeInstructionSets) { 203 int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, 204 profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid, 205 packageStats, options.isDowngrade()); 206 // The end result is: 207 // - FAILED if any path failed, 208 // - PERFORMED if at least one path needed compilation, 209 // - SKIPPED when all paths are up to date 210 if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) { 211 result = newResult; 212 } 213 } 214 } 215 return result; 216 } 217 218 /** 219 * Performs dexopt on the {@code path} belonging to the package {@code pkg}. 220 * 221 * @return 222 * DEX_OPT_FAILED if there was any exception during dexopt 223 * DEX_OPT_PERFORMED if dexopt was performed successfully on the given path. 224 * DEX_OPT_SKIPPED if the path does not need to be deopt-ed. 225 */ 226 @GuardedBy("mInstallLock") dexOptPath(PackageParser.Package pkg, String path, String isa, String compilerFilter, boolean profileUpdated, String sharedLibrariesPath, int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade)227 private int dexOptPath(PackageParser.Package pkg, String path, String isa, 228 String compilerFilter, boolean profileUpdated, String sharedLibrariesPath, 229 int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade) { 230 int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, profileUpdated, downgrade); 231 if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) { 232 return DEX_OPT_SKIPPED; 233 } 234 235 // TODO(calin): there's no need to try to create the oat dir over and over again, 236 // especially since it involve an extra installd call. We should create 237 // if (if supported) on the fly during the dexopt call. 238 String oatDir = createOatDirIfSupported(pkg, isa); 239 240 Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path 241 + " pkg=" + pkg.applicationInfo.packageName + " isa=" + isa 242 + " dexoptFlags=" + printDexoptFlags(dexoptFlags) 243 + " target-filter=" + compilerFilter + " oatDir=" + oatDir 244 + " sharedLibraries=" + sharedLibrariesPath); 245 246 try { 247 long startTime = System.currentTimeMillis(); 248 249 // TODO: Consider adding 2 different APIs for primary and secondary dexopt. 250 // installd only uses downgrade flag for secondary dex files and ignores it for 251 // primary dex files. 252 mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags, 253 compilerFilter, pkg.volumeUuid, sharedLibrariesPath, pkg.applicationInfo.seInfo, 254 false /* downgrade*/); 255 256 if (packageStats != null) { 257 long endTime = System.currentTimeMillis(); 258 packageStats.setCompileTime(path, (int)(endTime - startTime)); 259 } 260 return DEX_OPT_PERFORMED; 261 } catch (InstallerException e) { 262 Slog.w(TAG, "Failed to dexopt", e); 263 return DEX_OPT_FAILED; 264 } 265 } 266 267 /** 268 * Performs dexopt on the secondary dex {@code path} belonging to the app {@code info}. 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 * NOTE that DEX_OPT_PERFORMED for secondary dex files includes the case when the dex file 274 * didn't need an update. That's because at the moment we don't get more than success/failure 275 * from installd. 276 * 277 * TODO(calin): Consider adding return codes to installd dexopt invocation (rather than 278 * throwing exceptions). Or maybe make a separate call to installd to get DexOptNeeded, though 279 * that seems wasteful. 280 */ dexOptSecondaryDexPath(ApplicationInfo info, String path, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options)281 public int dexOptSecondaryDexPath(ApplicationInfo info, String path, 282 PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) { 283 synchronized (mInstallLock) { 284 final long acquireTime = acquireWakeLockLI(info.uid); 285 try { 286 return dexOptSecondaryDexPathLI(info, path, dexUseInfo, options); 287 } finally { 288 releaseWakeLockLI(acquireTime); 289 } 290 } 291 } 292 293 @GuardedBy("mInstallLock") acquireWakeLockLI(final int uid)294 private long acquireWakeLockLI(final int uid) { 295 // During boot the system doesn't need to instantiate and obtain a wake lock. 296 // PowerManager might not be ready, but that doesn't mean that we can't proceed with 297 // dexopt. 298 if (!mSystemReady) { 299 return -1; 300 } 301 mDexoptWakeLock.setWorkSource(new WorkSource(uid)); 302 mDexoptWakeLock.acquire(WAKELOCK_TIMEOUT_MS); 303 return SystemClock.elapsedRealtime(); 304 } 305 306 @GuardedBy("mInstallLock") releaseWakeLockLI(final long acquireTime)307 private void releaseWakeLockLI(final long acquireTime) { 308 if (acquireTime < 0) { 309 return; 310 } 311 try { 312 if (mDexoptWakeLock.isHeld()) { 313 mDexoptWakeLock.release(); 314 } 315 final long duration = SystemClock.elapsedRealtime() - acquireTime; 316 if (duration >= WAKELOCK_TIMEOUT_MS) { 317 Slog.wtf(TAG, "WakeLock " + mDexoptWakeLock.getTag() 318 + " time out. Operation took " + duration + " ms. Thread: " 319 + Thread.currentThread().getName()); 320 } 321 } catch (Exception e) { 322 Slog.wtf(TAG, "Error while releasing " + mDexoptWakeLock.getTag() + " lock", e); 323 } 324 } 325 326 @GuardedBy("mInstallLock") dexOptSecondaryDexPathLI(ApplicationInfo info, String path, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options)327 private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, 328 PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) { 329 if (options.isDexoptOnlySharedDex() && !dexUseInfo.isUsedByOtherApps()) { 330 // We are asked to optimize only the dex files used by other apps and this is not 331 // on of them: skip it. 332 return DEX_OPT_SKIPPED; 333 } 334 335 String compilerFilter = getRealCompilerFilter(info, options.getCompilerFilter(), 336 dexUseInfo.isUsedByOtherApps()); 337 // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags. 338 // Secondary dex files are currently not compiled at boot. 339 int dexoptFlags = getDexFlags(info, compilerFilter, /* bootComplete */ true) 340 | DEXOPT_SECONDARY_DEX; 341 // Check the app storage and add the appropriate flags. 342 if (info.deviceProtectedDataDir != null && 343 FileUtils.contains(info.deviceProtectedDataDir, path)) { 344 dexoptFlags |= DEXOPT_STORAGE_DE; 345 } else if (info.credentialProtectedDataDir != null && 346 FileUtils.contains(info.credentialProtectedDataDir, path)) { 347 dexoptFlags |= DEXOPT_STORAGE_CE; 348 } else { 349 Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName); 350 return DEX_OPT_FAILED; 351 } 352 Log.d(TAG, "Running dexopt on: " + path 353 + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas() 354 + " dexoptFlags=" + printDexoptFlags(dexoptFlags) 355 + " target-filter=" + compilerFilter); 356 357 // TODO(calin): b/64530081 b/66984396. Use SKIP_SHARED_LIBRARY_CHECK for the context 358 // (instead of dexUseInfo.getClassLoaderContext()) in order to compile secondary dex files 359 // in isolation (and avoid to extract/verify the main apk if it's in the class path). 360 // Note this trades correctness for performance since the resulting slow down is 361 // unacceptable in some cases until b/64530081 is fixed. 362 String classLoaderContext = SKIP_SHARED_LIBRARY_CHECK; 363 364 try { 365 for (String isa : dexUseInfo.getLoaderIsas()) { 366 // Reuse the same dexopt path as for the primary apks. We don't need all the 367 // arguments as some (dexopNeeded and oatDir) will be computed by installd because 368 // system server cannot read untrusted app content. 369 // TODO(calin): maybe add a separate call. 370 mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0, 371 /*oatDir*/ null, dexoptFlags, 372 compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser, 373 options.isDowngrade()); 374 } 375 376 return DEX_OPT_PERFORMED; 377 } catch (InstallerException e) { 378 Slog.w(TAG, "Failed to dexopt", e); 379 return DEX_OPT_FAILED; 380 } 381 } 382 383 /** 384 * Adjust the given dexopt-needed value. Can be overridden to influence the decision to 385 * optimize or not (and in what way). 386 */ adjustDexoptNeeded(int dexoptNeeded)387 protected int adjustDexoptNeeded(int dexoptNeeded) { 388 return dexoptNeeded; 389 } 390 391 /** 392 * Adjust the given dexopt flags that will be passed to the installer. 393 */ adjustDexoptFlags(int dexoptFlags)394 protected int adjustDexoptFlags(int dexoptFlags) { 395 return dexoptFlags; 396 } 397 398 /** 399 * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}. 400 */ dumpDexoptState(IndentingPrintWriter pw, PackageParser.Package pkg, PackageDexUsage.PackageUseInfo useInfo)401 void dumpDexoptState(IndentingPrintWriter pw, PackageParser.Package pkg, 402 PackageDexUsage.PackageUseInfo useInfo) { 403 final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo); 404 final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); 405 406 final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); 407 408 for (String path : paths) { 409 pw.println("path: " + path); 410 pw.increaseIndent(); 411 412 for (String isa : dexCodeInstructionSets) { 413 String status = null; 414 try { 415 status = DexFile.getDexFileStatus(path, isa); 416 } catch (IOException ioe) { 417 status = "[Exception]: " + ioe.getMessage(); 418 } 419 pw.println(isa + ": " + status); 420 } 421 422 if (useInfo.isUsedByOtherApps(path)) { 423 pw.println("used by other apps: " + useInfo.getLoadingPackages(path)); 424 } 425 426 Map<String, PackageDexUsage.DexUseInfo> dexUseInfoMap = useInfo.getDexUseInfoMap(); 427 428 if (!dexUseInfoMap.isEmpty()) { 429 pw.println("known secondary dex files:"); 430 pw.increaseIndent(); 431 for (Map.Entry<String, PackageDexUsage.DexUseInfo> e : dexUseInfoMap.entrySet()) { 432 String dex = e.getKey(); 433 PackageDexUsage.DexUseInfo dexUseInfo = e.getValue(); 434 pw.println(dex); 435 pw.increaseIndent(); 436 // TODO(calin): get the status of the oat file (needs installd call) 437 pw.println("class loader context: " + dexUseInfo.getClassLoaderContext()); 438 if (dexUseInfo.isUsedByOtherApps()) { 439 pw.println("used by other apps: " + dexUseInfo.getLoadingPackages()); 440 } 441 pw.decreaseIndent(); 442 } 443 pw.decreaseIndent(); 444 } 445 pw.decreaseIndent(); 446 } 447 } 448 449 /** 450 * Returns the compiler filter that should be used to optimize the package code. 451 * The target filter will be updated if the package code is used by other apps 452 * or if it has the safe mode flag set. 453 */ getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter, boolean isUsedByOtherApps)454 private String getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter, 455 boolean isUsedByOtherApps) { 456 int flags = info.flags; 457 boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0; 458 if (vmSafeMode) { 459 return getSafeModeCompilerFilter(targetCompilerFilter); 460 } 461 462 if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) { 463 // If the dex files is used by other apps, apply the shared filter. 464 return PackageManagerServiceCompilerMapping.getCompilerFilterForReason( 465 PackageManagerService.REASON_SHARED); 466 } 467 468 return targetCompilerFilter; 469 } 470 471 /** 472 * Computes the dex flags that needs to be pass to installd for the given package and compiler 473 * filter. 474 */ getDexFlags(PackageParser.Package pkg, String compilerFilter, boolean bootComplete)475 private int getDexFlags(PackageParser.Package pkg, String compilerFilter, 476 boolean bootComplete) { 477 return getDexFlags(pkg.applicationInfo, compilerFilter, bootComplete); 478 } 479 getDexFlags(ApplicationInfo info, String compilerFilter, boolean bootComplete)480 private int getDexFlags(ApplicationInfo info, String compilerFilter, boolean bootComplete) { 481 int flags = info.flags; 482 boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; 483 // Profile guide compiled oat files should not be public. 484 boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter); 485 boolean isPublic = !info.isForwardLocked() && !isProfileGuidedFilter; 486 int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; 487 int dexFlags = 488 (isPublic ? DEXOPT_PUBLIC : 0) 489 | (debuggable ? DEXOPT_DEBUGGABLE : 0) 490 | profileFlag 491 | (bootComplete ? DEXOPT_BOOTCOMPLETE : 0); 492 return adjustDexoptFlags(dexFlags); 493 } 494 495 /** 496 * Assesses if there's a need to perform dexopt on {@code path} for the given 497 * configuration (isa, compiler filter, profile). 498 */ getDexoptNeeded(String path, String isa, String compilerFilter, boolean newProfile, boolean downgrade)499 private int getDexoptNeeded(String path, String isa, String compilerFilter, 500 boolean newProfile, boolean downgrade) { 501 int dexoptNeeded; 502 try { 503 dexoptNeeded = DexFile.getDexOptNeeded(path, isa, compilerFilter, newProfile, 504 downgrade); 505 } catch (IOException ioe) { 506 Slog.w(TAG, "IOException reading apk: " + path, ioe); 507 return DEX_OPT_FAILED; 508 } 509 return adjustDexoptNeeded(dexoptNeeded); 510 } 511 512 /** 513 * Checks if there is an update on the profile information of the {@code pkg}. 514 * If the compiler filter is not profile guided the method returns false. 515 * 516 * Note that this is a "destructive" operation with side effects. Under the hood the 517 * current profile and the reference profile will be merged and subsequent calls 518 * may return a different result. 519 */ isProfileUpdated(PackageParser.Package pkg, int uid, String compilerFilter)520 private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String compilerFilter) { 521 // Check if we are allowed to merge and if the compiler filter is profile guided. 522 if (!isProfileGuidedCompilerFilter(compilerFilter)) { 523 return false; 524 } 525 // Merge profiles. It returns whether or not there was an updated in the profile info. 526 try { 527 return mInstaller.mergeProfiles(uid, pkg.packageName); 528 } catch (InstallerException e) { 529 Slog.w(TAG, "Failed to merge profiles", e); 530 } 531 return false; 532 } 533 534 /** 535 * Creates oat dir for the specified package if needed and supported. 536 * In certain cases oat directory 537 * <strong>cannot</strong> be created: 538 * <ul> 539 * <li>{@code pkg} is a system app, which is not updated.</li> 540 * <li>Package location is not a directory, i.e. monolithic install.</li> 541 * </ul> 542 * 543 * @return Absolute path to the oat directory or null, if oat directory 544 * cannot be created. 545 */ 546 @Nullable createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet)547 private String createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet) { 548 if (!pkg.canHaveOatDir()) { 549 return null; 550 } 551 File codePath = new File(pkg.codePath); 552 if (codePath.isDirectory()) { 553 // TODO(calin): why do we create this only if the codePath is a directory? (i.e for 554 // cluster packages). It seems that the logic for the folder creation is 555 // split between installd and here. 556 File oatDir = getOatDir(codePath); 557 try { 558 mInstaller.createOatDir(oatDir.getAbsolutePath(), dexInstructionSet); 559 } catch (InstallerException e) { 560 Slog.w(TAG, "Failed to create oat dir", e); 561 return null; 562 } 563 return oatDir.getAbsolutePath(); 564 } 565 return null; 566 } 567 getOatDir(File codePath)568 static File getOatDir(File codePath) { 569 return new File(codePath, OAT_DIR_NAME); 570 } 571 systemReady()572 void systemReady() { 573 mSystemReady = true; 574 } 575 printDexoptFlags(int flags)576 private String printDexoptFlags(int flags) { 577 ArrayList<String> flagsList = new ArrayList<>(); 578 579 if ((flags & DEXOPT_BOOTCOMPLETE) == DEXOPT_BOOTCOMPLETE) { 580 flagsList.add("boot_complete"); 581 } 582 if ((flags & DEXOPT_DEBUGGABLE) == DEXOPT_DEBUGGABLE) { 583 flagsList.add("debuggable"); 584 } 585 if ((flags & DEXOPT_PROFILE_GUIDED) == DEXOPT_PROFILE_GUIDED) { 586 flagsList.add("profile_guided"); 587 } 588 if ((flags & DEXOPT_PUBLIC) == DEXOPT_PUBLIC) { 589 flagsList.add("public"); 590 } 591 if ((flags & DEXOPT_SECONDARY_DEX) == DEXOPT_SECONDARY_DEX) { 592 flagsList.add("secondary"); 593 } 594 if ((flags & DEXOPT_FORCE) == DEXOPT_FORCE) { 595 flagsList.add("force"); 596 } 597 if ((flags & DEXOPT_STORAGE_CE) == DEXOPT_STORAGE_CE) { 598 flagsList.add("storage_ce"); 599 } 600 if ((flags & DEXOPT_STORAGE_DE) == DEXOPT_STORAGE_DE) { 601 flagsList.add("storage_de"); 602 } 603 604 return String.join(",", flagsList); 605 } 606 607 /** 608 * A specialized PackageDexOptimizer that overrides already-installed checks, forcing a 609 * dexopt path. 610 */ 611 public static class ForcedUpdatePackageDexOptimizer extends PackageDexOptimizer { 612 ForcedUpdatePackageDexOptimizer(Installer installer, Object installLock, Context context, String wakeLockTag)613 public ForcedUpdatePackageDexOptimizer(Installer installer, Object installLock, 614 Context context, String wakeLockTag) { 615 super(installer, installLock, context, wakeLockTag); 616 } 617 ForcedUpdatePackageDexOptimizer(PackageDexOptimizer from)618 public ForcedUpdatePackageDexOptimizer(PackageDexOptimizer from) { 619 super(from); 620 } 621 622 @Override adjustDexoptNeeded(int dexoptNeeded)623 protected int adjustDexoptNeeded(int dexoptNeeded) { 624 if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) { 625 // Ensure compilation by pretending a compiler filter change on the 626 // apk/odex location (the reason for the '-'. A positive value means 627 // the 'oat' location). 628 return -DexFile.DEX2OAT_FOR_FILTER; 629 } 630 return dexoptNeeded; 631 } 632 633 @Override adjustDexoptFlags(int flags)634 protected int adjustDexoptFlags(int flags) { 635 // Add DEXOPT_FORCE flag to signal installd that it should force compilation 636 // and discard dexoptanalyzer result. 637 return flags | DEXOPT_FORCE; 638 } 639 } 640 } 641