diff options
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( |