Add 'package compile' shell command
Bug: 26707406
Change-Id: I554969c9f3b3153179370d3d23a88fa7e8693885
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 2c6b604..593fe2a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -452,6 +452,9 @@
*/
boolean performDexOptIfNeeded(String packageName, String instructionSet);
+ boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
+ boolean extractOnly, boolean force);
+
void forceDexOpt(String packageName);
/**
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 89e89b0..0eacd13 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -94,7 +94,7 @@
continue;
}
if (!pm.performDexOpt(pkg, /* instruction set */ null, useJitProfiles,
- /* extractOnly */ false)) {
+ /* extractOnly */ false, /* force */ false)) {
// there was a problem running dexopt,
// remember this so we do not keep retrying.
sFailedPackageNames.add(pkg);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4d66e10..fe0f141 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -81,7 +81,7 @@
* {@link PackageManagerService#mInstallLock}.
*/
int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
- boolean inclDependencies, boolean useProfiles, boolean extractOnly) {
+ boolean inclDependencies, boolean useProfiles, boolean extractOnly, boolean force) {
ArraySet<String> done;
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
done = new ArraySet<String>();
@@ -97,7 +97,7 @@
}
try {
return performDexOptLI(pkg, instructionSets, done, useProfiles,
- extractOnly);
+ extractOnly, force);
} finally {
if (useLock) {
mDexoptWakeLock.release();
@@ -107,7 +107,7 @@
}
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
- ArraySet<String> done, boolean useProfiles, boolean extractOnly) {
+ ArraySet<String> done, boolean useProfiles, boolean extractOnly, boolean force) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
@@ -128,34 +128,38 @@
final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ if (useProfiles) {
+ // If we do a profile guided compilation then we might recompile
+ // the same package if more profile information is available.
+ force = true;
+ }
+
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
boolean performedDexOpt = false;
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- if (!useProfiles && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
- // Skip only if we do not use profiles since they might trigger a recompilation.
+ if (!force && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
continue;
}
for (String path : paths) {
int dexoptNeeded;
- try {
- dexoptNeeded = DexFile.getDexOptNeeded(path, pkg.packageName,
- dexCodeInstructionSet, /* defer */false);
- } catch (IOException ioe) {
- Slog.w(TAG, "IOException reading apk: " + path, ioe);
- return DEX_OPT_FAILED;
+
+ if (force) {
+ dexoptNeeded = DexFile.DEX2OAT_NEEDED;
+ } else {
+ try {
+ dexoptNeeded = DexFile.getDexOptNeeded(path, pkg.packageName,
+ dexCodeInstructionSet, /* defer */false);
+ } catch (IOException ioe) {
+ Slog.w(TAG, "IOException reading apk: " + path, ioe);
+ return DEX_OPT_FAILED;
+ }
}
if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
- if (useProfiles) {
- // If we do a profile guided compilation then we might recompile the same
- // package if more profile information is available.
- dexoptNeeded = DexFile.DEX2OAT_NEEDED;
- } else {
- // No dexopt needed and we don't use profiles. Nothing to do.
- continue;
- }
+ // No dexopt needed and we don't use profiles. Nothing to do.
+ continue;
}
final String dexoptType;
String oatDir = null;
@@ -252,7 +256,7 @@
// TODO: Analyze and investigate if we (should) profile libraries.
// Currently this will do a full compilation of the library.
performDexOptLI(libPkg, instructionSets, done, /*useProfiles*/ false,
- /* extractOnly */ false);
+ /* extractOnly */ false, /* force */ false);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 05ef8dcd..f94a66e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6633,7 +6633,7 @@
if (pkgs != null) {
for (String pkg : pkgs) {
performDexOpt(pkg, null /* instructionSet */, false /* useProfiles */,
- true /* extractOnly */);
+ true /* extractOnly */, false /* force */);
}
}
}
@@ -6670,26 +6670,28 @@
@Override
public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
return performDexOptTraced(packageName, instructionSet, false /* useProfiles */,
- false /* extractOnly */);
+ false /* extractOnly */, false /* force */);
}
+ @Override
public boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
- boolean extractOnly) {
- return performDexOptTraced(packageName, instructionSet, useProfiles, extractOnly);
+ boolean extractOnly, boolean force) {
+ return performDexOptTraced(packageName, instructionSet, useProfiles, extractOnly, force);
}
private boolean performDexOptTraced(String packageName, String instructionSet,
- boolean useProfiles, boolean extractOnly) {
+ boolean useProfiles, boolean extractOnly, boolean force) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
try {
- return performDexOptInternal(packageName, instructionSet, useProfiles, extractOnly);
+ return performDexOptInternal(packageName, instructionSet, useProfiles, extractOnly,
+ force);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private boolean performDexOptInternal(String packageName, String instructionSet,
- boolean useProfiles, boolean extractOnly) {
+ boolean useProfiles, boolean extractOnly, boolean force) {
PackageParser.Package p;
final String targetInstructionSet;
synchronized (mPackages) {
@@ -6701,7 +6703,7 @@
targetInstructionSet = instructionSet != null ? instructionSet :
getPrimaryInstructionSet(p.applicationInfo);
- if (!useProfiles && p.mDexOptPerformed.contains(targetInstructionSet)) {
+ if (!force && !useProfiles && p.mDexOptPerformed.contains(targetInstructionSet)) {
// Skip only if we do not use profiles since they might trigger a recompilation.
return false;
}
@@ -6711,7 +6713,7 @@
synchronized (mInstallLock) {
final String[] instructionSets = new String[] { targetInstructionSet };
int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
- true /* inclDependencies */, useProfiles, extractOnly);
+ true /* inclDependencies */, useProfiles, extractOnly, force);
return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
}
} finally {
@@ -6757,7 +6759,7 @@
// Don't use profiles since that may cause compilation to be skipped.
final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
true /* inclDependencies */, false /* useProfiles */,
- false /* extractOnly */);
+ false /* extractOnly */, true /* force */);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -13025,7 +13027,7 @@
// method because `pkg` is not in `mPackages` yet.
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
false /* inclDependencies */, false /* useProfiles */,
- true /* extractOnly */);
+ true /* extractOnly */, false /* force */);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
String msg = "Extracking package failed for " + pkgName;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 43e4b84..d8845d8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -44,6 +44,7 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ShellCommand;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.PrintWriterPrinter;
@@ -96,6 +97,8 @@
return runInstallCreate();
case "install-write":
return runInstallWrite();
+ case "compile":
+ return runCompile();
case "list":
return runList();
case "uninstall":
@@ -227,6 +230,67 @@
return doWriteSession(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
}
+ private int runCompile() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ boolean useJitProfiles = false;
+ boolean extractOnly = false;
+ boolean forceCompilation = false;
+ String compilationMode = "default";
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-m":
+ compilationMode = getNextArgRequired();
+ break;
+ case "-f":
+ forceCompilation = true;
+ break;
+ default:
+ pw.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+
+ switch (compilationMode) {
+ case "default":
+ useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+ extractOnly = false;
+ break;
+ case "all":
+ useJitProfiles = false;
+ extractOnly = false;
+ break;
+ case "profile":
+ useJitProfiles = true;
+ extractOnly = false;
+ break;
+ case "extract":
+ useJitProfiles = false;
+ extractOnly = true;
+ break;
+ default:
+ pw.println("Error: Unknown compilation mode: " + compilationMode);
+ return 1;
+ }
+
+ String packageName = getNextArg();
+ if (packageName == null) {
+ pw.println("Error: package name not specified");
+ return 1;
+ }
+
+ boolean success = mInterface.performDexOpt(packageName, null /* instructionSet */,
+ useJitProfiles, extractOnly, forceCompilation);
+ if (success) {
+ pw.println("Success");
+ return 0;
+ } else {
+ pw.println("Failure: package " + packageName + " could not be compiled");
+ return 1;
+ }
+ }
+
private int runList() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final String type = getNextArg();
@@ -1069,6 +1133,12 @@
pw.println(" help");
pw.println(" Print this help text.");
pw.println("");
+ pw.println(" compile [-m MODE] [-f] TARGET-PACKAGE");
+ pw.println(" Trigger compilation of TARGET-PACKAGE.");
+ pw.println(" Options:");
+ pw.println(" -m: select compilation mode");
+ pw.println(" MODE can be one of \"default\", \"all\", \"profile\", and \"extract\"");
+ pw.println(" -f: force compilation even if not needed");
pw.println(" list features");
pw.println(" Prints all features of the system.");
pw.println(" list instrumentation [-f] [TARGET-PACKAGE]");