diff options
author | Andreas Gampe <agampe@google.com> | 2016-07-28 16:54:41 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2016-09-06 10:44:00 -0700 |
commit | 14186731f98d326239922d093371d1e63b8c22a5 (patch) | |
tree | 5fb535d4b45d3548bd6dc3539205b533ae58838f | |
parent | 7e619a912cf6a53ede7d7eea67f8bc8ed1158e24 (diff) | |
download | base-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.java | 189 |
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."); } |