summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl6
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java3
-rw-r--r--services/core/java/com/android/server/pm/Installer.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java29
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java58
-rw-r--r--services/java/com/android/server/SystemServer.java8
6 files changed, 85 insertions, 23 deletions
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 90a1198e3132..2c6b604a9657 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -429,6 +429,12 @@ interface IPackageManager {
void performFstrimIfNeeded();
/**
+ * Ask the package manager to extract packages if needed, to save
+ * the VM unzipping the APK in memory during launch.
+ */
+ void extractPackagesIfNeeded();
+
+ /**
* Notify the package manager that a package is going to be used.
*/
void notifyPackageUse(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 06f828e4b4b7..89e89b03832c 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -93,7 +93,8 @@ public class BackgroundDexOptService extends JobService {
// skip previously failing package
continue;
}
- if (!pm.performDexOpt(pkg, /* instruction set */ null, useJitProfiles)) {
+ if (!pm.performDexOpt(pkg, /* instruction set */ null, useJitProfiles,
+ /* extractOnly */ 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/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 366edf953072..cf876ee631bf 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -47,8 +47,8 @@ public final class Installer extends SystemService {
public static final int DEXOPT_DEBUGGABLE = 1 << 3;
/** The system boot has finished */
public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
- /** Run the application with the JIT compiler */
- public static final int DEXOPT_USEJIT = 1 << 5;
+ /** Do not compile, only extract bytecode into an OAT file */
+ public static final int DEXOPT_EXTRACTONLY = 1 << 5;
/** @hide */
@IntDef(flag = true, value = {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 44b51d4f50be..482217cedfea 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -41,7 +41,7 @@ import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
-import static com.android.server.pm.Installer.DEXOPT_USEJIT;
+import static com.android.server.pm.Installer.DEXOPT_EXTRACTONLY;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -82,7 +82,7 @@ final class PackageDexOptimizer {
* {@link PackageManagerService#mInstallLock}.
*/
int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
- boolean inclDependencies, String volumeUuid, boolean useProfiles) {
+ boolean inclDependencies, String volumeUuid, boolean useProfiles, boolean extractOnly) {
ArraySet<String> done;
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
done = new ArraySet<String>();
@@ -97,7 +97,8 @@ final class PackageDexOptimizer {
mDexoptWakeLock.acquire();
}
try {
- return performDexOptLI(pkg, instructionSets, done, volumeUuid, useProfiles);
+ return performDexOptLI(pkg, instructionSets, done, volumeUuid, useProfiles,
+ extractOnly);
} finally {
if (useLock) {
mDexoptWakeLock.release();
@@ -107,7 +108,7 @@ final class PackageDexOptimizer {
}
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
- ArraySet<String> done, String volumeUuid, boolean useProfiles) {
+ ArraySet<String> done, String volumeUuid, boolean useProfiles, boolean extractOnly) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
@@ -173,12 +174,13 @@ final class PackageDexOptimizer {
Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+ pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
- + " oatDir = " + oatDir);
+ + " extractOnly=" + extractOnly + " oatDir = " + oatDir);
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
final int dexFlags =
(!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0)
| (vmSafeMode ? DEXOPT_SAFEMODE : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
+ | (extractOnly ? DEXOPT_EXTRACTONLY : 0)
| DEXOPT_BOOTCOMPLETE;
try {
mPackageManagerService.mInstaller.dexopt(path, sharedGid,
@@ -190,12 +192,14 @@ final class PackageDexOptimizer {
}
}
- // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
- // either have either succeeded dexopt, or have had getDexOptNeeded tell us
- // it isn't required. We therefore mark that this package doesn't need dexopt unless
- // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
- // it.
- pkg.mDexOptPerformed.add(dexCodeInstructionSet);
+ if (!extractOnly) {
+ // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
+ // either have either succeeded dexopt, or have had getDexOptNeeded tell us
+ // it isn't required. We therefore mark that this package doesn't need dexopt unless
+ // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
+ // it.
+ pkg.mDexOptPerformed.add(dexCodeInstructionSet);
+ }
}
// If we've gotten here, we're sure that no error occurred and that we haven't
@@ -249,7 +253,8 @@ final class PackageDexOptimizer {
// TODO: Analyze and investigate if we (should) profile libraries.
// Currently this will do a full compilation of the library.
performDexOptLI(libPkg, instructionSets, done,
- StorageManager.UUID_PRIVATE_INTERNAL, /*useProfiles*/ false);
+ StorageManager.UUID_PRIVATE_INTERNAL, /*useProfiles*/ false,
+ /* extractOnly */ false);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 26660dfc352a..b86e1dd67cc4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -34,6 +34,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.INSTALL_EXTERNAL;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
+import static android.content.pm.PackageManager.INSTALL_FAILED_DEXOPT;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
import static android.content.pm.PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID;
@@ -627,6 +628,9 @@ public class PackageManagerService extends IPackageManager.Stub {
// List of packages names to keep cached, even if they are uninstalled for all users
private List<String> mKeepUninstalledPackages;
+ private boolean mUseJitProfiles =
+ SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+
private static class IFVerificationParams {
PackageParser.Package pkg;
boolean replacing;
@@ -6624,6 +6628,23 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ @Override
+ public void extractPackagesIfNeeded() {
+ enforceSystemOrRoot("Only the system can request package extraction");
+
+ // Extract pacakges only if profile-guided compilation is enabled because
+ // otherwise BackgroundDexOptService will not dexopt them later.
+ if (mUseJitProfiles) {
+ ArraySet<String> pkgs = getOptimizablePackages();
+ if (pkgs != null) {
+ for (String pkg : pkgs) {
+ performDexOpt(pkg, null /* instructionSet */, false /* useProfiles */,
+ true /* extractOnly */);
+ }
+ }
+ }
+ }
+
private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
List<ResolveInfo> ris = null;
try {
@@ -6654,25 +6675,27 @@ public class PackageManagerService extends IPackageManager.Stub {
// TODO: this is not used nor needed. Delete it.
@Override
public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
- return performDexOptTraced(packageName, instructionSet, false);
+ return performDexOptTraced(packageName, instructionSet, false /* useProfiles */,
+ false /* extractOnly */);
}
- public boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles) {
- return performDexOptTraced(packageName, instructionSet, useProfiles);
+ public boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
+ boolean extractOnly) {
+ return performDexOptTraced(packageName, instructionSet, useProfiles, extractOnly);
}
private boolean performDexOptTraced(String packageName, String instructionSet,
- boolean useProfiles) {
+ boolean useProfiles, boolean extractOnly) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
try {
- return performDexOptInternal(packageName, instructionSet, useProfiles);
+ return performDexOptInternal(packageName, instructionSet, useProfiles, extractOnly);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private boolean performDexOptInternal(String packageName, String instructionSet,
- boolean useProfiles) {
+ boolean useProfiles, boolean extractOnly) {
PackageParser.Package p;
final String targetInstructionSet;
synchronized (mPackages) {
@@ -6694,7 +6717,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mInstallLock) {
final String[] instructionSets = new String[] { targetInstructionSet };
int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
- true /* inclDependencies */, p.volumeUuid, useProfiles);
+ true /* inclDependencies */, p.volumeUuid, useProfiles, extractOnly);
return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
}
} finally {
@@ -6739,7 +6762,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// Whoever is calling forceDexOpt wants a fully compiled package.
// Don't use profiles since that may cause compilation to be skipped.
final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
- true /* inclDependencies */, pkg.volumeUuid, false /* useProfiles */);
+ true /* inclDependencies */, pkg.volumeUuid, false /* useProfiles */,
+ false /* extractOnly */);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -12981,6 +13005,24 @@ public class PackageManagerService extends IPackageManager.Stub {
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
return;
}
+
+ // Extract package to save the VM unzipping the APK in memory during
+ // launch. Only do this if profile-guided compilation is enabled because
+ // otherwise BackgroundDexOptService will not dexopt the package later.
+ if (mUseJitProfiles) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ // Do not run PackageDexOptimizer through the local performDexOpt
+ // method because `pkg` is not in `mPackages` yet.
+ int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
+ false /* inclDependencies */, volumeUuid, false /* useProfiles */,
+ true /* extractOnly */);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
+ String msg = "Extracking package failed for " + pkgName;
+ res.setError(INSTALL_FAILED_DEXOPT, msg);
+ return;
+ }
+ }
}
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b5330e4639cd..811403187bde 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -667,6 +667,14 @@ public final class SystemServer {
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "ExtractPackagesIfNeeded");
+ try {
+ mPackageManagerService.extractPackagesIfNeeded();
+ } catch (Throwable e) {
+ reportWtf("extract packages", e);
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+
try {
ActivityManagerNative.getDefault().showBootMessage(
context.getResources().getText(