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

Commit 7218363a authored by Calin Juravle's avatar Calin Juravle
Browse files

Compile secondary dex files in DexManager

Add logic for secondary dex compilation in DexManager. Also, extend the
`cmd package compile` command with '--secondary-dex' option which will
compile all used secondary dex files for the given package.

Test: flash & boot,
      cmd package compile --secondary-dex -f -m speed
com.google.android.gms
Bug: 32871170

(cherry picked from commit c22c30ed)

Change-Id: I3cf26edbfb5e9f3683e608bb2a596e1ab5682bd4

Merged-In: Ia2b95cb70d26c4ead5cb650047641b0881ca84ae
parent fcd672fc
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -482,6 +482,7 @@ interface IPackageManager {
     */
    boolean performDexOpt(String packageName, boolean checkProfiles,
            int compileReason, boolean force);

    /**
     * Ask the package manager to perform a dex-opt with the given compiler filter.
     *
@@ -491,6 +492,16 @@ interface IPackageManager {
    boolean performDexOptMode(String packageName, boolean checkProfiles,
            String targetCompilerFilter, boolean force);

    /**
     * Ask the package manager to perform a dex-opt with the given compiler filter on the
     * secondary dex files belonging to the given package.
     *
     * Note: exposed only for the shell command to allow moving packages explicitly to a
     *       definite state.
     */
    boolean performDexOptSecondary(String packageName,
            String targetCompilerFilter, boolean force);

    /**
     * Ask the package manager to dump profiles associated with a package.
     */
+8 −0
Original line number Diff line number Diff line
@@ -50,6 +50,14 @@ public class Installer extends SystemService {
    public static final int DEXOPT_BOOTCOMPLETE   = 1 << 4;
    /** Hint that the dexopt type is profile-guided. */
    public static final int DEXOPT_PROFILE_GUIDED = 1 << 5;
    /** The compilation is for a secondary dex file. */
    public static final int DEXOPT_SECONDARY_DEX  = 1 << 6;
    /** Ignore the result of dexoptNeeded and force compilation. */
    public static final int DEXOPT_FORCE          = 1 << 7;
    /** Indicates that the dex file passed to dexopt in on CE storage. */
    public static final int DEXOPT_STORAGE_CE     = 1 << 8;
    /** Indicates that the dex file passed to dexopt in on DE storage. */
    public static final int DEXOPT_STORAGE_DE     = 1 << 9;

    // NOTE: keep in sync with installd
    public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
+119 −10
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.pm;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageParser;
import android.os.Environment;
import android.os.PowerManager;
@@ -35,6 +36,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import dalvik.system.DexFile;

@@ -43,6 +45,10 @@ import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
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_SECONDARY_DEX;
import static com.android.server.pm.Installer.DEXOPT_FORCE;
import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE;
import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;

@@ -52,13 +58,13 @@ import static dalvik.system.DexFile.isProfileGuidedCompilerFilter;
/**
 * Helper class for running dexopt command on packages.
 */
class PackageDexOptimizer {
public class PackageDexOptimizer {
    private static final String TAG = "PackageManager.DexOptimizer";
    static final String OAT_DIR_NAME = "oat";
    // TODO b/19550105 Remove error codes and use exceptions
    static final int DEX_OPT_SKIPPED = 0;
    static final int DEX_OPT_PERFORMED = 1;
    static final int DEX_OPT_FAILED = -1;
    public static final int DEX_OPT_SKIPPED = 0;
    public static final int DEX_OPT_PERFORMED = 1;
    public static final int DEX_OPT_FAILED = -1;

    private final Installer mInstaller;
    private final Object mInstallLock;
@@ -100,6 +106,9 @@ class PackageDexOptimizer {
            return DEX_OPT_SKIPPED;
        }
        synchronized (mInstallLock) {
            // During boot the system doesn't need to instantiate and obtain a wake lock.
            // PowerManager might not be ready, but that doesn't mean that we can't proceed with
            // dexopt.
            final boolean useLock = mSystemReady;
            if (useLock) {
                mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
@@ -130,9 +139,11 @@ class PackageDexOptimizer {
        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);

        final String compilerFilter = getRealCompilerFilter(pkg, targetCompilerFilter);
        final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
                targetCompilerFilter, isUsedByOtherApps(pkg));
        final boolean profileUpdated = checkForProfileUpdates &&
                isProfileUpdated(pkg, sharedGid, compilerFilter);

        // TODO(calin,jeffhao): shared library paths should be adjusted to include previous code
        // paths (b/34169257).
        final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
@@ -200,6 +211,79 @@ class PackageDexOptimizer {
        }
    }

    /**
     * Performs dexopt on the secondary dex {@code path} belonging to the app {@code info}.
     *
     * @return
     *      DEX_OPT_FAILED if there was any exception during dexopt
     *      DEX_OPT_PERFORMED if dexopt was performed successfully on the given path.
     * NOTE that DEX_OPT_PERFORMED for secondary dex files includes the case when the dex file
     * didn't need an update. That's because at the moment we don't get more than success/failure
     * from installd.
     *
     * TODO(calin): Consider adding return codes to installd dexopt invocation (rather than
     * throwing exceptions). Or maybe make a separate call to installd to get DexOptNeeded, though
     * that seems wasteful.
     */
    public int dexOptSecondaryDexPath(ApplicationInfo info, String path, Set<String> isas,
            String compilerFilter, boolean isUsedByOtherApps) {
        synchronized (mInstallLock) {
            // During boot the system doesn't need to instantiate and obtain a wake lock.
            // PowerManager might not be ready, but that doesn't mean that we can't proceed with
            // dexopt.
            final boolean useLock = mSystemReady;
            if (useLock) {
                mDexoptWakeLock.setWorkSource(new WorkSource(info.uid));
                mDexoptWakeLock.acquire();
            }
            try {
                return dexOptSecondaryDexPathLI(info, path, isas, compilerFilter,
                        isUsedByOtherApps);
            } finally {
                if (useLock) {
                    mDexoptWakeLock.release();
                }
            }
        }
    }

    @GuardedBy("mInstallLock")
    private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, Set<String> isas,
            String compilerFilter, boolean isUsedByOtherApps) {
        int dexoptFlags = getDexFlags(info, compilerFilter) | DEXOPT_SECONDARY_DEX;
        // Check the app storage and add the appropriate flags.
        if (info.dataDir.equals(info.deviceProtectedDataDir)) {
            dexoptFlags |= DEXOPT_STORAGE_DE;
        } else if (info.dataDir.equals(info.credentialProtectedDataDir)) {
            dexoptFlags |= DEXOPT_STORAGE_CE;
        } else {
            Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName);
            return DEX_OPT_FAILED;
        }
        compilerFilter = getRealCompilerFilter(info, compilerFilter, isUsedByOtherApps);
        Log.d(TAG, "Running dexopt on: " + path
                + " pkg=" + info.packageName + " isa=" + isas
                + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
                + " target-filter=" + compilerFilter);

        try {
            for (String isa : isas) {
                // Reuse the same dexopt path as for the primary apks. We don't need all the
                // arguments as some (dexopNeeded and oatDir) will be computed by installd because
                // system server cannot read untrusted app content.
                // TODO(calin): maybe add a separate call.
                mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
                        /*oatDir*/ null, dexoptFlags,
                        compilerFilter, info.volumeUuid, /*sharedLibrariesPath*/ null);
            }

            return DEX_OPT_PERFORMED;
        } catch (InstallerException e) {
            Slog.w(TAG, "Failed to dexopt", e);
            return DEX_OPT_FAILED;
        }
    }

    /**
     * Adjust the given dexopt-needed value. Can be overridden to influence the decision to
     * optimize or not (and in what way).
@@ -246,8 +330,9 @@ class PackageDexOptimizer {
     * The target filter will be updated if the package code is used by other apps
     * or if it has the safe mode flag set.
     */
    private String getRealCompilerFilter(PackageParser.Package pkg, String targetCompilerFilter) {
        int flags = pkg.applicationInfo.flags;
    private String getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter,
            boolean isUsedByOtherApps) {
        int flags = info.flags;
        boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
        if (vmSafeMode) {
            // For the compilation, it doesn't really matter what we return here because installd
@@ -259,7 +344,7 @@ class PackageDexOptimizer {
            return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
        }

        if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps(pkg)) {
        if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
            // If the dex files is used by other apps, we cannot use profile-guided compilation.
            return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
        }
@@ -272,12 +357,16 @@ class PackageDexOptimizer {
     * filter.
     */
    private int getDexFlags(PackageParser.Package pkg, String compilerFilter) {
        int flags = pkg.applicationInfo.flags;
        return getDexFlags(pkg.applicationInfo, compilerFilter);
    }

    private int getDexFlags(ApplicationInfo info, String compilerFilter) {
        int flags = info.flags;
        boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
        boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
        // Profile guide compiled oat files should not be public.
        boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
        boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
        boolean isPublic = !info.isForwardLocked() && !isProfileGuidedFilter;
        int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
        int dexFlags =
                (isPublic ? DEXOPT_PUBLIC : 0)
@@ -437,6 +526,19 @@ class PackageDexOptimizer {
        if ((flags & DEXOPT_SAFEMODE) == DEXOPT_SAFEMODE) {
            flagsList.add("safemode");
        }
        if ((flags & DEXOPT_SECONDARY_DEX) == DEXOPT_SECONDARY_DEX) {
            flagsList.add("secondary");
        }
        if ((flags & DEXOPT_FORCE) == DEXOPT_FORCE) {
            flagsList.add("force");
        }
        if ((flags & DEXOPT_STORAGE_CE) == DEXOPT_STORAGE_CE) {
            flagsList.add("storage_ce");
        }
        if ((flags & DEXOPT_STORAGE_DE) == DEXOPT_STORAGE_DE) {
            flagsList.add("storage_de");
        }

        return String.join(",", flagsList);
    }

@@ -461,5 +563,12 @@ class PackageDexOptimizer {
            // TODO: The return value is wrong when patchoat is needed.
            return DexFile.DEX2OAT_FROM_SCRATCH;
        }

        @Override
        protected int adjustDexoptFlags(int flags) {
            // Add DEXOPT_FORCE flag to signal installd that it should force compilation
            // and discard dexoptanalyzer result.
            return flags | DEXOPT_FORCE;
        }
    }
}
+10 −1
Original line number Diff line number Diff line
@@ -2133,7 +2133,7 @@ public class PackageManagerService extends IPackageManager.Stub {
        mInstaller = installer;
        mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
                "*dexopt*");
        mDexManager = new DexManager();
        mDexManager = new DexManager(this, mPackageDexOptimizer);
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
        mOnPermissionChangeListeners = new OnPermissionChangeListeners(
@@ -7508,6 +7508,15 @@ public class PackageManagerService extends IPackageManager.Stub {
                targetCompilerFilter, getOrCreateCompilerPackageStats(p));
    }
    // Performs dexopt on the used secondary dex files belonging to the given package.
    // Returns true if all dex files were process successfully (which could mean either dexopt or
    // skip). Returns false if any of the files caused errors.
    @Override
    public boolean performDexOptSecondary(String packageName, String compilerFilter,
            boolean force) {
        return mDexManager.dexoptSecondaryDex(packageName, compilerFilter, force);
    }
    Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
        if (p.usesLibraries != null || p.usesOptionalLibraries != null) {
            ArrayList<PackageParser.Package> retValue = new ArrayList<>();
+1 −1
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ import dalvik.system.DexFile;
/**
 * Manage (retrieve) mappings from compilation reason to compilation filter.
 */
class PackageManagerServiceCompilerMapping {
public class PackageManagerServiceCompilerMapping {
    // Names for compilation reasons.
    static final String REASON_STRINGS[] = {
            "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "nsys-library", "shared-apk",
Loading