// Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
// behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
// trade-off worth doing to save boot time work.
- pm.performDexOpt(pkg,
+ int result = pm.performDexOptWithStatus(pkg,
/* checkProfiles */ false,
PackageManagerService.REASON_BOOT,
- /* force */ false);
+ /* force */ false,
+ /* bootComplete */ true);
+ if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+ updatedPackages.add(pkg);
+ }
}
+ notifyPinService(updatedPackages);
// Ran to completion, so we abandon our timeslice and do not reschedule.
jobFinished(jobParams, /* reschedule */ false);
}
// Optimize package if needed. Note that there can be no race between
// concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
- boolean success = is_for_primary_dex
- ? pm.performDexOpt(pkg,
- /* checkProfiles */ true,
- PackageManagerService.REASON_BACKGROUND_DEXOPT,
- /* force */ false,
- /* bootComplete */ true)
- : pm.performDexOptSecondary(pkg,
- PackageManagerService.REASON_BACKGROUND_DEXOPT,
- /* force */ false);
+ boolean success;
+ if (is_for_primary_dex) {
+ int result = pm.performDexOptWithStatus(pkg,
+ /* checkProfiles */ true,
+ PackageManagerService.REASON_BACKGROUND_DEXOPT,
- /* force */ false);
++ /* force */ false,
++ /* bootComplete */ true);
+ success = result != PackageDexOptimizer.DEX_OPT_FAILED;
+ if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+ updatedPackages.add(pkg);
+ }
+ } else {
+ success = pm.performDexOptSecondary(pkg,
+ PackageManagerService.REASON_BACKGROUND_DEXOPT,
+ /* force */ false);
+ }
if (success) {
// Dexopt succeeded, remove package from the list of failing ones.
synchronized (failedPackageNames) {
return DEX_OPT_SKIPPED;
}
synchronized (mInstallLock) {
- // During boot the system doesn't need to instantiate and obtain a wake lock.
- // PowerManager might not be ready, but that doesn't mean that we can't proceed with
- // dexopt.
- final boolean useLock = mSystemReady;
- if (useLock) {
- mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
- mDexoptWakeLock.acquire();
- }
+ final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid);
try {
return performDexOptLI(pkg, sharedLibraries, instructionSets, checkProfiles,
- targetCompilationFilter, packageStats, isUsedByOtherApps);
+ targetCompilationFilter, packageStats, isUsedByOtherApps, bootComplete);
} finally {
- if (useLock) {
- mDexoptWakeLock.release();
- }
+ releaseWakeLockLI(acquireTime);
}
}
}
final boolean profileUpdated = checkForProfileUpdates &&
isProfileUpdated(pkg, sharedGid, compilerFilter);
- // TODO(calin,jeffhao): shared library paths should be adjusted to include previous code
- // paths (b/34169257).
- String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
+ final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
- final int dexoptFlags = getDexFlags(pkg, compilerFilter);
+ final int dexoptFlags = getDexFlags(pkg, compilerFilter, bootComplete);
+ // Get the dependencies of each split in the package. For each code path in the package,
+ // this array contains the relative paths of each split it depends on, separated by colons.
+ String[] splitDependencies = getSplitDependencies(pkg);
int result = DEX_OPT_SKIPPED;
- // TODO: Iterate based on dependency hierarchy (currently alphabetically by name)
- // (b/37480811).
- String basePathCheck = null;
- for (String path : paths) {
+ for (int i = 0; i < paths.size(); i++) {
+ // Skip paths that have no code.
+ if ((i == 0 && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) ||
+ (i != 0 && (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) == 0)) {
+ continue;
+ }
+ // Append shared libraries with split dependencies for this split.
+ String path = paths.get(i);
+ String sharedLibrariesPathWithSplits;
+ if (sharedLibrariesPath != null && splitDependencies[i] != null) {
+ sharedLibrariesPathWithSplits = sharedLibrariesPath + ":" + splitDependencies[i];
+ } else {
+ sharedLibrariesPathWithSplits =
+ splitDependencies[i] != null ? splitDependencies[i] : sharedLibrariesPath;
+ }
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated,
- sharedLibrariesPath, dexoptFlags, sharedGid, packageStats);
+ sharedLibrariesPathWithSplits, dexoptFlags, sharedGid, packageStats);
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
@GuardedBy("mInstallLock")
private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, Set<String> isas,
String compilerFilter, boolean isUsedByOtherApps) {
- int dexoptFlags = getDexFlags(info, compilerFilter) | DEXOPT_SECONDARY_DEX;
+ compilerFilter = getRealCompilerFilter(info, compilerFilter, isUsedByOtherApps);
+ // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
+ // Secondary dex files are currently not compiled at boot.
+ int dexoptFlags = getDexFlags(info, compilerFilter, /* bootComplete */ true)
+ | DEXOPT_SECONDARY_DEX;
// Check the app storage and add the appropriate flags.
- if (info.dataDir.equals(info.deviceProtectedDataDir)) {
+ if (info.deviceProtectedDataDir != null &&
+ FileUtils.contains(info.deviceProtectedDataDir, path)) {
dexoptFlags |= DEXOPT_STORAGE_DE;
- } else if (info.dataDir.equals(info.credentialProtectedDataDir)) {
+ } else if (info.credentialProtectedDataDir != null &&
+ FileUtils.contains(info.credentialProtectedDataDir, path)) {
dexoptFlags |= DEXOPT_STORAGE_CE;
} else {
Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName);
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
// can downgrade to reader
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "write settings");
mSettings.writeLPr();
-
- // Perform dexopt on all apps that mark themselves as coreApps. We do this pretty
- // early on (before the package manager declares itself as early) because other
- // components in the system server might ask for package contexts for these apps.
- //
- // Note that "onlyCore" in this context means the system is encrypted or encrypting
- // (i.e, that the data partition is unavailable).
- if ((isFirstBoot() || isUpgrade() || VMRuntime.didPruneDalvikCache()) && !onlyCore) {
- long start = System.nanoTime();
- List<PackageParser.Package> coreApps = new ArrayList<>();
- for (PackageParser.Package pkg : mPackages.values()) {
- if (pkg.coreApp) {
- coreApps.add(pkg);
- }
- }
-
- int[] stats = performDexOptUpgrade(coreApps, false,
- getCompilerFilterForReason(REASON_CORE_APP), /* bootComplete */ false);
-
- final int elapsedTimeSeconds =
- (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start);
- MetricsLogger.histogram(mContext, "opt_coreapps_time_s", elapsedTimeSeconds);
-
- if (DEBUG_DEXOPT) {
- Slog.i(TAG, "Dex-opt core apps took : " + elapsedTimeSeconds + " seconds (" +
- stats[0] + ", " + stats[1] + ", " + stats[2] + ")");
- }
-
-
- // TODO: Should we log these stats to tron too ?
- // MetricsLogger.histogram(mContext, "opt_coreapps_num_dexopted", stats[0]);
- // MetricsLogger.histogram(mContext, "opt_coreapps_num_skipped", stats[1]);
- // MetricsLogger.histogram(mContext, "opt_coreapps_num_failed", stats[2]);
- // MetricsLogger.histogram(mContext, "opt_coreapps_num_total", coreApps.size());
- }
-
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
@Override
public boolean performDexOpt(String packageName,
- boolean checkProfiles, int compileReason, boolean force) {
- return performDexOptWithStatus(packageName, checkProfiles, compileReason, force) !=
- PackageDexOptimizer.DEX_OPT_FAILED;
+ boolean checkProfiles, int compileReason, boolean force, boolean bootComplete) {
- int dexOptStatus = performDexOptTraced(packageName, checkProfiles,
++ int dexoptStatus = performDexOptWithStatus(
++ packageName, checkProfiles, compileReason, force, bootComplete);
++ return dexoptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
+ }
+
+ /**
+ * Perform dexopt on the given package and return one of following result:
+ * {@link PackageDexOptimizer#DEX_OPT_SKIPPED}
+ * {@link PackageDexOptimizer#DEX_OPT_PERFORMED}
+ * {@link PackageDexOptimizer#DEX_OPT_FAILED}
+ */
+ /* package */ int performDexOptWithStatus(String packageName,
- boolean checkProfiles, int compileReason, boolean force) {
++ boolean checkProfiles, int compileReason, boolean force, boolean bootComplete) {
+ return performDexOptTraced(packageName, checkProfiles,
- getCompilerFilterForReason(compileReason), force);
+ getCompilerFilterForReason(compileReason), force, bootComplete);
- return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
}
@Override
public boolean performDexOptMode(String packageName,
- boolean checkProfiles, String targetCompilerFilter, boolean force) {
+ boolean checkProfiles, String targetCompilerFilter, boolean force,
+ boolean bootComplete) {
+ if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return false;
+ }
int dexOptStatus = performDexOptTraced(packageName, checkProfiles,
- targetCompilerFilter, force);
+ targetCompilerFilter, force, bootComplete);
return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
}
if (!deps.isEmpty()) {
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
- // Currently this will do a full compilation of the library by default.
pdo.performDexOpt(depPackage, null /* sharedLibraries */, instructionSets,
false /* checkProfiles */,
- getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY),
+ targetCompilerFilter,
getOrCreateCompilerPackageStats(depPackage),
- true /* isUsedByOtherApps */);
- mDexManager.isUsedByOtherApps(p.packageName),
++ true /* isUsedByOtherApps */,
+ bootComplete);
}
}
return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets, checkProfiles,
synchronized (mInstallLock) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- // Whoever is calling forceDexOpt wants a fully compiled package.
+ // Whoever is calling forceDexOpt wants a compiled package.
// Don't use profiles since that may cause compilation to be skipped.
final int res = performDexOptInternalWithDependenciesLI(pkg,
- false /* checkProfiles */, getCompilerFilterForReason(REASON_FORCED_DEXOPT),
+ false /* checkProfiles */, getDefaultCompilerFilter(),
- true /* force */);
+ true /* force */,
+ true /* bootComplete */);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
// Shared libraries for the package need to be updated.
synchronized (mPackages) {
try {
- updateSharedLibrariesLPw(pkg, null);
+ updateSharedLibrariesLPr(pkg, null);
} catch (PackageManagerException e) {
- Slog.e(TAG, "updateSharedLibrariesLPw failed: " + e.getMessage());
+ Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
}
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- // Do not run PackageDexOptimizer through the local performDexOpt
- // method because `pkg` may not be in `mPackages` yet.
- //
- // Also, don't fail application installs if the dexopt step fails.
- mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
- null /* instructionSets */, false /* checkProfiles */,
- getCompilerFilterForReason(REASON_INSTALL),
- getOrCreateCompilerPackageStats(pkg),
- mDexManager.isUsedByOtherApps(pkg.packageName),
- true /* bootComplete */);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+ // dexopt can take some time to complete, so, for instant apps, we skip this
+ // step during installation. Instead, we'll take extra time the first time the
+ // instant app starts. It's preferred to do it this way to provide continuous
+ // progress to the user instead of mysteriously blocking somewhere in the
+ // middle of running an instant app.
+ if (!instantApp) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ // Do not run PackageDexOptimizer through the local performDexOpt
+ // method because `pkg` may not be in `mPackages` yet.
+ //
+ // Also, don't fail application installs if the dexopt step fails.
+ mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+ null /* instructionSets */, false /* checkProfiles */,
+ getCompilerFilterForReason(REASON_INSTALL),
+ getOrCreateCompilerPackageStats(pkg),
- mDexManager.isUsedByOtherApps(pkg.packageName));
++ mDexManager.isUsedByOtherApps(pkg.packageName),
++ true /* bootComplete */);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
// Notify BackgroundDexOptService that the package has been changed.
// If this is an update of a package which used to fail to compile,