Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0e10434 authored by David Brazdil's avatar David Brazdil
Browse files

Extract APKs on install or OTA

ART will unzip APKs in memory during launch if an OAT file is not
present. To save the time and memory, this patch will invoke dex2oat
with '--compiler-filter=verify-at-runtime' to unzip the APK during
install or after an OTA.

Change-Id: I16583f9450ad60356123a29f7a6a649b2ab9999f
parent 88f04309
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -428,6 +428,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.
     */
+2 −1
Original line number Diff line number Diff line
@@ -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);
+2 −2
Original line number Diff line number Diff line
@@ -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 = {
+17 −12
Original line number Diff line number Diff line
@@ -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,6 +192,7 @@ final class PackageDexOptimizer {
                }
            }

            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
@@ -197,6 +200,7 @@ final class PackageDexOptimizer {
                // it.
                pkg.mDexOptPerformed.add(dexCodeInstructionSet);
            }
        }

        // If we've gotten here, we're sure that no error occurred and that we haven't
        // deferred dex-opt. We've either dex-opted one more paths or instruction sets or
@@ -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);
            }
        }
    }
+50 −8
Original line number Diff line number Diff line
@@ -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)) {
Loading