Merge "Merge \"Frameworks/base: Add new flow to OtaDexoptService\" into nyc-mr1-dev am: d06f87399b" into nyc-mr1-dev-plus-aosp
This commit is contained in:
committed by
Android (Google) Code Review
commit
8299d7156e
@@ -50,6 +50,13 @@ interface IOtaDexopt {
|
||||
/**
|
||||
* Optimize the next package. Note: this command is synchronous, that is, only returns after
|
||||
* the package has been dexopted (or dexopting failed).
|
||||
*
|
||||
* Note: this will be removed after a transition period. Use nextDexoptCommand instead.
|
||||
*/
|
||||
void dexoptNextPackage();
|
||||
|
||||
/**
|
||||
* Get the optimization parameters for the next package.
|
||||
*/
|
||||
String nextDexoptCommand();
|
||||
}
|
||||
|
||||
@@ -61,6 +61,13 @@ public final class Installer extends SystemService {
|
||||
mInstaller = new InstallerConnection();
|
||||
}
|
||||
|
||||
// Package-private installer that accepts a custom InstallerConnection. Used for
|
||||
// OtaDexoptService.
|
||||
Installer(Context context, InstallerConnection connection) {
|
||||
super(context);
|
||||
mInstaller = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Yell loudly if someone tries making future calls while holding a lock on
|
||||
* the given object.
|
||||
|
||||
@@ -32,10 +32,12 @@ import android.os.storage.StorageManager;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.os.InstallerConnection;
|
||||
import com.android.internal.os.InstallerConnection.InstallerException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -49,21 +51,28 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
private final static boolean DEBUG_DEXOPT = true;
|
||||
|
||||
private final Context mContext;
|
||||
private final PackageDexOptimizer mPackageDexOptimizer;
|
||||
private final PackageManagerService mPackageManagerService;
|
||||
|
||||
// TODO: Evaluate the need for WeakReferences here.
|
||||
|
||||
/**
|
||||
* The list of packages to dexopt.
|
||||
*/
|
||||
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 int completeSize;
|
||||
|
||||
public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
|
||||
this.mContext = context;
|
||||
this.mPackageManagerService = packageManagerService;
|
||||
|
||||
// Use the package manager install and install lock here for the OTA dex optimizer.
|
||||
mPackageDexOptimizer = new OTADexoptPackageDexOptimizer(packageManagerService.mInstaller,
|
||||
packageManagerService.mInstallLock, context);
|
||||
|
||||
// Now it's time to check whether we need to move any A/B artifacts.
|
||||
moveAbArtifacts(packageManagerService.mInstaller);
|
||||
}
|
||||
@@ -93,6 +102,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
mPackageManagerService.mPackages.values(), mPackageManagerService);
|
||||
}
|
||||
completeSize = mDexoptPackages.size();
|
||||
mCommandsForCurrentPackage = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,6 +111,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
Log.i(TAG, "Cleaning up OTA Dexopt state.");
|
||||
}
|
||||
mDexoptPackages = null;
|
||||
mCommandsForCurrentPackage = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,15 +120,109 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
throw new IllegalStateException("done() called before prepare()");
|
||||
}
|
||||
|
||||
return mDexoptPackages.isEmpty();
|
||||
return mDexoptPackages.isEmpty() && (mCommandsForCurrentPackage == null);
|
||||
}
|
||||
|
||||
@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.
|
||||
if (completeSize == 0) {
|
||||
return 1f;
|
||||
}
|
||||
return (completeSize - mDexoptPackages.size()) / ((float)completeSize);
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String nextDexoptCommand() throws RemoteException {
|
||||
if (mDexoptPackages == 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.");
|
||||
}
|
||||
|
||||
// Generate the next mPackageDexopts state. Ignore errors, this loop is strongly
|
||||
// monotonically increasing, anyways.
|
||||
generatePackageDexopts(nextPackage);
|
||||
|
||||
// Invariant check: mPackageDexopts is null or not empty.
|
||||
if (mCommandsForCurrentPackage != null && mCommandsForCurrentPackage.isEmpty()) {
|
||||
cleanup();
|
||||
throw new IllegalStateException("mPackageDexopts empty for " + nextPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private synchronized boolean generatePackageDexopts(PackageParser.Package nextPackage) {
|
||||
// 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 false;
|
||||
}
|
||||
|
||||
// Use our custom connection that just collects the commands.
|
||||
RecordingInstallerConnection collectingConnection = new RecordingInstallerConnection();
|
||||
Installer collectingInstaller = new Installer(mContext, collectingConnection);
|
||||
|
||||
// Use the package manager install and install lock here for the OTA dex optimizer.
|
||||
PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
|
||||
collectingInstaller, mPackageManagerService.mInstallLock, mContext);
|
||||
optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles,
|
||||
null /* ISAs */, false /* checkProfiles */,
|
||||
getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA));
|
||||
|
||||
mCommandsForCurrentPackage = collectingConnection.commands;
|
||||
if (mCommandsForCurrentPackage.isEmpty()) {
|
||||
mCommandsForCurrentPackage = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,8 +257,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
mPackageDexOptimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles,
|
||||
null /* ISAs */, false /* checkProfiles */,
|
||||
PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
|
||||
mPackageManagerService.mInstaller, mPackageManagerService.mInstallLock, mContext);
|
||||
optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles, null /* ISAs */,
|
||||
false /* checkProfiles */,
|
||||
getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA));
|
||||
}
|
||||
|
||||
@@ -218,4 +325,40 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class RecordingInstallerConnection extends InstallerConnection {
|
||||
public List<String> commands = new ArrayList<String>(1);
|
||||
|
||||
@Override
|
||||
public void setWarnIfHeld(Object warnIfHeld) {
|
||||
throw new IllegalStateException("Should not reach here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String transact(String cmd) {
|
||||
commands.add(cmd);
|
||||
return "0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
|
||||
throw new IllegalStateException("Should not reach here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dumpProfiles(String gid, String packageName, String codePaths)
|
||||
throws InstallerException {
|
||||
throw new IllegalStateException("Should not reach here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
throw new IllegalStateException("Should not reach here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForConnection() {
|
||||
throw new IllegalStateException("Should not reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ class OtaDexoptShellCommand extends ShellCommand {
|
||||
return runOtaDone();
|
||||
case "step":
|
||||
return runOtaStep();
|
||||
case "next":
|
||||
return runOtaNext();
|
||||
case "progress":
|
||||
return runOtaProgress();
|
||||
default:
|
||||
@@ -83,6 +85,11 @@ class OtaDexoptShellCommand extends ShellCommand {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int runOtaNext() throws RemoteException {
|
||||
getOutPrintWriter().println(mInterface.nextDexoptCommand());
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int runOtaProgress() throws RemoteException {
|
||||
final float progress = mInterface.getProgress();
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
@@ -103,6 +110,8 @@ class OtaDexoptShellCommand extends ShellCommand {
|
||||
pw.println(" Replies whether the OTA is complete or not.");
|
||||
pw.println(" step");
|
||||
pw.println(" OTA dexopt the next package.");
|
||||
pw.println(" next");
|
||||
pw.println(" Get parameters for OTA dexopt of the next package.");
|
||||
pw.println(" cleanup");
|
||||
pw.println(" Clean up internal states. Ends an OTA session.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user