summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2016-07-28 16:54:41 -0700
committerAndreas Gampe <agampe@google.com>2016-09-06 10:44:00 -0700
commit14186731f98d326239922d093371d1e63b8c22a5 (patch)
tree5fb535d4b45d3548bd6dc3539205b533ae58838f
parent7e619a912cf6a53ede7d7eea67f8bc8ed1158e24 (diff)
downloadbase-14186731f98d326239922d093371d1e63b8c22a5.tar.gz
OtaDexoptService: Run dexopt on all apps
To avoid work after reboot, dexopt all apps. However, unimportant apps are optimized with the first-boot reason (which is usually interpret-only) for space reasons. Bug: 30468718 Change-Id: Ia05d879957388967c69f9380e50d8a9834afe07d (cherry picked from commit 115514b236ebe7cb3c90892891954b8c7ba69335)
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java189
1 files changed, 64 insertions, 125 deletions
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 77c69c905036..c5f3cfd3bc7e 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -56,16 +56,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
// TODO: Evaluate the need for WeakReferences here.
/**
- * The list of packages to dexopt.
+ * The list of dexopt invocations for all work.
*/
- private List<PackageParser.Package> mDexoptPackages;
-
- /**
- * The list of dexopt invocations for the current package (which will no longer be in
- * mDexoptPackages). This can be more than one as a package may have multiple code paths,
- * e.g., in the split-APK case.
- */
- private List<String> mCommandsForCurrentPackage;
+ private List<String> mDexoptCommands;
private int completeSize;
@@ -94,15 +87,43 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
@Override
public synchronized void prepare() throws RemoteException {
- if (mDexoptPackages != null) {
+ if (mDexoptCommands != null) {
throw new IllegalStateException("already called prepare()");
}
synchronized (mPackageManagerService.mPackages) {
- mDexoptPackages = PackageManagerServiceUtils.getPackagesForDexopt(
+ // Important: the packages we need to run with ab-ota compiler-reason.
+ List<PackageParser.Package> important = PackageManagerServiceUtils.getPackagesForDexopt(
mPackageManagerService.mPackages.values(), mPackageManagerService);
+ // Others: we should optimize this with the (first-)boot compiler-reason.
+ List<PackageParser.Package> others =
+ new ArrayList<>(mPackageManagerService.mPackages.values());
+ others.removeAll(important);
+
+ // Pre-size the array list by over-allocating by a factor of 1.5.
+ mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2);
+
+ for (PackageParser.Package p : important) {
+ // Make sure that core apps are optimized according to their own "reason".
+ // If the core apps are not preopted in the B OTA, and REASON_AB_OTA is not speed
+ // (by default is speed-profile) they will be interepreted/JITed. This in itself is
+ // not a problem as we will end up doing profile guided compilation. However, some
+ // core apps may be loaded by system server which doesn't JIT and we need to make
+ // sure we don't interpret-only
+ int compilationReason = p.coreApp
+ ? PackageManagerService.REASON_CORE_APP
+ : PackageManagerService.REASON_AB_OTA;
+ mDexoptCommands.addAll(generatePackageDexopts(p, compilationReason));
+ }
+ for (PackageParser.Package p : others) {
+ // We assume here that there are no core apps left.
+ if (p.coreApp) {
+ throw new IllegalStateException("Found a core app that's not important");
+ }
+ mDexoptCommands.addAll(
+ generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT));
+ }
}
- completeSize = mDexoptPackages.size();
- mCommandsForCurrentPackage = null;
+ completeSize = mDexoptCommands.size();
}
@Override
@@ -110,87 +131,52 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Cleaning up OTA Dexopt state.");
}
- mDexoptPackages = null;
- mCommandsForCurrentPackage = null;
+ mDexoptCommands = null;
}
@Override
public synchronized boolean isDone() throws RemoteException {
- if (mDexoptPackages == null) {
+ if (mDexoptCommands == null) {
throw new IllegalStateException("done() called before prepare()");
}
- return mDexoptPackages.isEmpty() && (mCommandsForCurrentPackage == null);
+ return mDexoptCommands.isEmpty();
}
@Override
public synchronized float getProgress() throws RemoteException {
- // We approximate by number of packages here. We could track all compiles, if we
- // generated them ahead of time. Right now we're trying to conserve memory.
+ // Approximate the progress by the amount of already completed commands.
if (completeSize == 0) {
return 1f;
}
- int packagesLeft = mDexoptPackages.size() + (mCommandsForCurrentPackage != null ? 1 : 0);
- return (completeSize - packagesLeft) / ((float)completeSize);
- }
-
- /**
- * Return the next dexopt command for the current package. Enforces the invariant
- */
- private String getNextPackageDexopt() {
- if (mCommandsForCurrentPackage != null) {
- String next = mCommandsForCurrentPackage.remove(0);
- if (mCommandsForCurrentPackage.isEmpty()) {
- mCommandsForCurrentPackage = null;
- }
- return next;
- }
- return null;
+ int commandsLeft = mDexoptCommands.size();
+ return (completeSize - commandsLeft) / ((float)completeSize);
}
@Override
public synchronized String nextDexoptCommand() throws RemoteException {
- if (mDexoptPackages == null) {
+ if (mDexoptCommands == null) {
throw new IllegalStateException("dexoptNextPackage() called before prepare()");
}
- // Get the next command.
- for (;;) {
- // Check whether there's one for the current package.
- String next = getNextPackageDexopt();
- if (next != null) {
- return next;
- }
-
- // Move to the next package, if possible.
- if (mDexoptPackages.isEmpty()) {
- return "Nothing to do";
- }
-
- PackageParser.Package nextPackage = mDexoptPackages.remove(0);
-
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Processing " + nextPackage.packageName + " for OTA dexopt.");
- }
+ if (mDexoptCommands.isEmpty()) {
+ return "(all done)";
+ }
- // Generate the next mPackageDexopts state. Ignore errors, this loop is strongly
- // monotonically increasing, anyways.
- generatePackageDexopts(nextPackage);
+ String next = mDexoptCommands.remove(0);
- // Invariant check: mPackageDexopts is null or not empty.
- if (mCommandsForCurrentPackage != null && mCommandsForCurrentPackage.isEmpty()) {
- cleanup();
- throw new IllegalStateException("mPackageDexopts empty for " + nextPackage);
- }
+ if (IsFreeSpaceAvailable()) {
+ return next;
+ } else {
+ mDexoptCommands.clear();
+ return "(no free space)";
}
}
/**
- * Generate all dexopt commands for the given package and place them into mPackageDexopts.
- * Returns true on success, false in an error situation like low disk space.
+ * Check for low space. Returns true if there's space left.
*/
- private synchronized boolean generatePackageDexopts(PackageParser.Package nextPackage) {
- // Check for low space.
+ private boolean IsFreeSpaceAvailable() {
// TODO: If apps are not installed in the internal /data partition, we should compare
// against that storage's free capacity.
File dataDir = Environment.getDataDirectory();
@@ -200,12 +186,14 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
throw new IllegalStateException("Invalid low memory threshold");
}
long usableSpace = dataDir.getUsableSpace();
- if (usableSpace < lowThreshold) {
- Log.w(TAG, "Not running dexopt on " + nextPackage.packageName + " due to low memory: " +
- usableSpace);
- return false;
- }
+ return (usableSpace >= lowThreshold);
+ }
+ /**
+ * Generate all dexopt commands for the given package.
+ */
+ private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg,
+ int compilationReason) {
// Use our custom connection that just collects the commands.
RecordingInstallerConnection collectingConnection = new RecordingInstallerConnection();
Installer collectingInstaller = new Installer(mContext, collectingConnection);
@@ -213,71 +201,22 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
// Use the package manager install and install lock here for the OTA dex optimizer.
PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
collectingInstaller, mPackageManagerService.mInstallLock, mContext);
- // Make sure that core apps are optimized according to their own "reason".
- // If the core apps are not preopted in the B OTA, and REASON_AB_OTA is not speed
- // (by default is speed-profile) they will be interepreted/JITed. This in itself is not a
- // problem as we will end up doing profile guided compilation. However, some core apps may
- // be loaded by system server which doesn't JIT and we need to make sure we don't
- // interpret-only
- int compilationReason = nextPackage.coreApp
- ? PackageManagerService.REASON_CORE_APP
- : PackageManagerService.REASON_AB_OTA;
-
- optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles,
+
+ optimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null /* ISAs */, false /* checkProfiles */,
getCompilerFilterForReason(compilationReason),
null /* CompilerStats.PackageStats */);
- mCommandsForCurrentPackage = collectingConnection.commands;
- if (mCommandsForCurrentPackage.isEmpty()) {
- mCommandsForCurrentPackage = null;
- }
-
- return true;
+ return collectingConnection.commands;
}
@Override
public synchronized void dexoptNextPackage() throws RemoteException {
- if (mDexoptPackages == null) {
- throw new IllegalStateException("dexoptNextPackage() called before prepare()");
- }
- if (mDexoptPackages.isEmpty()) {
- // Tolerate repeated calls.
- return;
- }
-
- PackageParser.Package nextPackage = mDexoptPackages.remove(0);
-
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Processing " + nextPackage.packageName + " for OTA dexopt.");
- }
-
- // Check for low space.
- // TODO: If apps are not installed in the internal /data partition, we should compare
- // against that storage's free capacity.
- File dataDir = Environment.getDataDirectory();
- @SuppressWarnings("deprecation")
- long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
- if (lowThreshold == 0) {
- throw new IllegalStateException("Invalid low memory threshold");
- }
- long usableSpace = dataDir.getUsableSpace();
- if (usableSpace < lowThreshold) {
- Log.w(TAG, "Not running dexopt on " + nextPackage.packageName + " due to low memory: " +
- usableSpace);
- return;
- }
-
- PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
- mPackageManagerService.mInstaller, mPackageManagerService.mInstallLock, mContext);
- optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles, null /* ISAs */,
- false /* checkProfiles */,
- getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA),
- mPackageManagerService.getOrCreateCompilerPackageStats(nextPackage));
+ throw new UnsupportedOperationException();
}
private void moveAbArtifacts(Installer installer) {
- if (mDexoptPackages != null) {
+ if (mDexoptCommands != null) {
throw new IllegalStateException("Should not be ota-dexopting when trying to move.");
}