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

Commit 9e88c533 authored by Calin Juravle's avatar Calin Juravle Committed by Gerrit Code Review
Browse files

Merge changes from topic 'secondary-dex'

* changes:
  Fix typo in dexopt.secondary system property
  Save package dex usage info after secondary dex reconciliation
  Compile secondary dex files during background dexopt job
  Add a shell command to force the background dexopt job
  A bit more refactoring in BackgroundDexOptService
  [PM] Clean up logic for secondary dex oat files
  Compile secondary dex files in DexManager
  Notify DexManager about new package installs
parents 603fb2ef ad014af0
Loading
Loading
Loading
Loading
+23 −0
Original line number Original line Diff line number Diff line
@@ -482,6 +482,7 @@ interface IPackageManager {
     */
     */
    boolean performDexOpt(String packageName, boolean checkProfiles,
    boolean performDexOpt(String packageName, boolean checkProfiles,
            int compileReason, boolean force);
            int compileReason, boolean force);

    /**
    /**
     * Ask the package manager to perform a dex-opt with the given compiler filter.
     * 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,
    boolean performDexOptMode(String packageName, boolean checkProfiles,
            String targetCompilerFilter, boolean force);
            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.
     * Ask the package manager to dump profiles associated with a package.
     */
     */
@@ -498,6 +509,18 @@ interface IPackageManager {


    void forceDexOpt(String packageName);
    void forceDexOpt(String packageName);


    /**
     * Execute the background dexopt job immediately.
     */
    boolean runBackgroundDexoptJob();

    /**
     * Reconcile the information we have about the secondary dex files belonging to
     * {@code packagName} and the actual dex files. For all dex files that were
     * deleted, update the internal records and delete the generated oat files.
     */
    void reconcileSecondaryDexFiles(String packageName);

    /**
    /**
     * Update status of external media on the package manager to scan and
     * Update status of external media on the package manager to scan and
     * install packages installed on the external media. Like say the
     * install packages installed on the external media. Like say the
+121 −41
Original line number Original line Diff line number Diff line
@@ -30,10 +30,13 @@ import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.BatteryManager;
import android.os.Environment;
import android.os.Environment;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.storage.StorageManager;
import android.os.storage.StorageManager;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.Log;
import android.util.Log;


import com.android.server.pm.dex.DexManager;

import java.io.File;
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
@@ -59,21 +62,33 @@ public class BackgroundDexOptService extends JobService {
            "android",
            "android",
            BackgroundDexOptService.class.getName());
            BackgroundDexOptService.class.getName());


    // Possible return codes of individual optimization steps.

    // Optimizations finished. All packages were processed.
    private static final int OPTIMIZE_PROCESSED = 0;
    // Optimizations should continue. Issued after checking the scheduler, disk space or battery.
    private static final int OPTIMIZE_CONTINUE = 1;
    // Optimizations should be aborted. Job scheduler requested it.
    private static final int OPTIMIZE_ABORT_BY_JOB_SCHEDULER = 2;
    // Optimizations should be aborted. No space left on device.
    private static final int OPTIMIZE_ABORT_NO_SPACE_LEFT = 3;

    /**
    /**
     * Set of failed packages remembered across job runs.
     * Set of failed packages remembered across job runs.
     */
     */
    static final ArraySet<String> sFailedPackageNames = new ArraySet<String>();
    static final ArraySet<String> sFailedPackageNamesPrimary = new ArraySet<String>();
    static final ArraySet<String> sFailedPackageNamesSecondary = new ArraySet<String>();


    /**
    /**
     * Atomics set to true if the JobScheduler requests an abort.
     * Atomics set to true if the JobScheduler requests an abort.
     */
     */
    final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false);
    private final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false);
    final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false);
    private final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false);


    /**
    /**
     * Atomic set to true if one job should exit early because another job was started.
     * Atomic set to true if one job should exit early because another job was started.
     */
     */
    final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
    private final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);


    private final File mDataDir = Environment.getDataDirectory();
    private final File mDataDir = Environment.getDataDirectory();


@@ -104,8 +119,11 @@ public class BackgroundDexOptService extends JobService {
        // The idle maintanance job skips packages which previously failed to
        // The idle maintanance job skips packages which previously failed to
        // compile. The given package has changed and may successfully compile
        // compile. The given package has changed and may successfully compile
        // now. Remove it from the list of known failing packages.
        // now. Remove it from the list of known failing packages.
        synchronized (sFailedPackageNames) {
        synchronized (sFailedPackageNamesPrimary) {
            sFailedPackageNames.remove(packageName);
            sFailedPackageNamesPrimary.remove(packageName);
        }
        synchronized (sFailedPackageNamesSecondary) {
            sFailedPackageNamesSecondary.remove(packageName);
        }
        }
    }
    }


@@ -124,9 +142,9 @@ public class BackgroundDexOptService extends JobService {
        return (100 * level / scale);
        return (100 * level / scale);
    }
    }


    private long getLowStorageThreshold() {
    private long getLowStorageThreshold(Context context) {
        @SuppressWarnings("deprecation")
        @SuppressWarnings("deprecation")
        final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir);
        final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir);
        if (lowThreshold == 0) {
        if (lowThreshold == 0) {
            Log.e(TAG, "Invalid low storage threshold");
            Log.e(TAG, "Invalid low storage threshold");
        }
        }
@@ -155,7 +173,7 @@ public class BackgroundDexOptService extends JobService {
        // Load low battery threshold from the system config. This is a 0-100 integer.
        // Load low battery threshold from the system config. This is a 0-100 integer.
        final int lowBatteryThreshold = getResources().getInteger(
        final int lowBatteryThreshold = getResources().getInteger(
                com.android.internal.R.integer.config_lowBatteryWarningLevel);
                com.android.internal.R.integer.config_lowBatteryWarningLevel);
        final long lowThreshold = getLowStorageThreshold();
        final long lowThreshold = getLowStorageThreshold(this);


        mAbortPostBootUpdate.set(false);
        mAbortPostBootUpdate.set(false);


@@ -206,61 +224,123 @@ public class BackgroundDexOptService extends JobService {
        new Thread("BackgroundDexOptService_IdleOptimization") {
        new Thread("BackgroundDexOptService_IdleOptimization") {
            @Override
            @Override
            public void run() {
            public void run() {
                idleOptimization(jobParams, pm, pkgs);
                int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this);
                if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
                    Log.w(TAG, "Idle optimizations aborted because of space constraints.");
                    // If we didn't abort we ran to completion (or stopped because of space).
                    // Abandon our timeslice and do not reschedule.
                    jobFinished(jobParams, /* reschedule */ false);
                }
            }
            }
        }.start();
        }.start();
        return true;
        return true;
    }
    }


    private void idleOptimization(JobParameters jobParams, PackageManagerService pm,
    // Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes).
            ArraySet<String> pkgs) {
    private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs, Context context) {
        Log.i(TAG, "Performing idle optimizations");
        Log.i(TAG, "Performing idle optimizations");
        // If post-boot update is still running, request that it exits early.
        // If post-boot update is still running, request that it exits early.
        mExitPostBootUpdate.set(true);
        mExitPostBootUpdate.set(true);

        mAbortIdleOptimization.set(false);
        mAbortIdleOptimization.set(false);


        final long lowThreshold = getLowStorageThreshold();
        long lowStorageThreshold = getLowStorageThreshold(context);
        for (String pkg : pkgs) {
        // Optimize primary apks.
            if (mAbortIdleOptimization.get()) {
        int result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ true,
                // JobScheduler requested an early abort.
                sFailedPackageNamesPrimary);
                return;

        if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
            return result;
        }
        }


            synchronized (sFailedPackageNames) {
        if (SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
                if (sFailedPackageNames.contains(pkg)) {
            result = reconcileSecondaryDexFiles(pm.getDexManager());
                    // Skip previously failing package
            if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
                    continue;
                return result;
            }

            result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ false,
                    sFailedPackageNamesSecondary);
        }
        }
        return result;
    }
    }


            long usableSpace = mDataDir.getUsableSpace();
    private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
            if (usableSpace < lowThreshold) {
            long lowStorageThreshold, boolean is_for_primary_dex,
                // Rather bail than completely fill up the disk.
            ArraySet<String> failedPackageNames) {
                Log.w(TAG, "Aborting background dex opt job due to low storage: " +
        for (String pkg : pkgs) {
                        usableSpace);
            int abort_code = abortIdleOptimizations(lowStorageThreshold);
                break;
            if (abort_code != OPTIMIZE_CONTINUE) {
                return abort_code;
            }
            }


            synchronized (failedPackageNames) {
                if (failedPackageNames.contains(pkg)) {
                    // Skip previously failing package
                    continue;
                } else {
                    // Conservatively add package to the list of failing ones in case performDexOpt
                    // Conservatively add package to the list of failing ones in case performDexOpt
                    // never returns.
                    // never returns.
            synchronized (sFailedPackageNames) {
                    failedPackageNames.add(pkg);
                sFailedPackageNames.add(pkg);
                }
            }
            }

            // Optimize package if needed. Note that there can be no race between
            // Optimize package if needed. Note that there can be no race between
            // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
            // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
            if (pm.performDexOpt(pkg,
            boolean success = is_for_primary_dex
                    ? pm.performDexOpt(pkg,
                            /* checkProfiles */ true,
                            /* checkProfiles */ true,
                            PackageManagerService.REASON_BACKGROUND_DEXOPT,
                            PackageManagerService.REASON_BACKGROUND_DEXOPT,
                    /* force */ false)) {
                            /* force */ false)
                    : pm.performDexOptSecondary(pkg,
                            PackageManagerServiceCompilerMapping.getFullCompilerFilter(),
                            /* force */ true);
            if (success) {
                // Dexopt succeeded, remove package from the list of failing ones.
                // Dexopt succeeded, remove package from the list of failing ones.
                synchronized (sFailedPackageNames) {
                synchronized (failedPackageNames) {
                    sFailedPackageNames.remove(pkg);
                    failedPackageNames.remove(pkg);
                }
                }
            }
            }
        }
        }
        // Ran to completion, so we abandon our timeslice and do not reschedule.
        return OPTIMIZE_PROCESSED;
        jobFinished(jobParams, /* reschedule */ false);
    }

    private int reconcileSecondaryDexFiles(DexManager dm) {
        // TODO(calin): should we blacklist packages for which we fail to reconcile?
        for (String p : dm.getAllPackagesWithSecondaryDexFiles()) {
            if (mAbortIdleOptimization.get()) {
                return OPTIMIZE_ABORT_BY_JOB_SCHEDULER;
            }
            dm.reconcileSecondaryDexFiles(p);
        }
        return OPTIMIZE_PROCESSED;
    }

    // Evaluate whether or not idle optimizations should continue.
    private int abortIdleOptimizations(long lowStorageThreshold) {
        if (mAbortIdleOptimization.get()) {
            // JobScheduler requested an early abort.
            return OPTIMIZE_ABORT_BY_JOB_SCHEDULER;
        }
        long usableSpace = mDataDir.getUsableSpace();
        if (usableSpace < lowStorageThreshold) {
            // Rather bail than completely fill up the disk.
            Log.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace);
            return OPTIMIZE_ABORT_NO_SPACE_LEFT;
        }

        return OPTIMIZE_CONTINUE;
    }

    /**
     * Execute the idle optimizations immediately.
     */
    public static boolean runIdleOptimizationsNow(PackageManagerService pm, Context context) {
        // Create a new object to make sure we don't interfere with the scheduled jobs.
        // Note that this may still run at the same time with the job scheduled by the
        // JobScheduler but the scheduler will not be able to cancel it.
        BackgroundDexOptService bdos = new BackgroundDexOptService();
        int result = bdos.idleOptimization(pm, pm.getOptimizablePackages(), context);
        return result == OPTIMIZE_PROCESSED;
    }
    }


    @Override
    @Override
@@ -281,7 +361,7 @@ public class BackgroundDexOptService extends JobService {
        }
        }


        final ArraySet<String> pkgs = pm.getOptimizablePackages();
        final ArraySet<String> pkgs = pm.getOptimizablePackages();
        if (pkgs == null || pkgs.isEmpty()) {
        if (pkgs.isEmpty()) {
            if (DEBUG_DEXOPT) {
            if (DEBUG_DEXOPT) {
                Log.i(TAG, "No packages to optimize");
                Log.i(TAG, "No packages to optimize");
            }
            }
+22 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,14 @@ public class Installer extends SystemService {
    public static final int DEXOPT_BOOTCOMPLETE   = 1 << 4;
    public static final int DEXOPT_BOOTCOMPLETE   = 1 << 4;
    /** Hint that the dexopt type is profile-guided. */
    /** Hint that the dexopt type is profile-guided. */
    public static final int DEXOPT_PROFILE_GUIDED = 1 << 5;
    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
    // NOTE: keep in sync with installd
    public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
    public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
@@ -425,6 +433,20 @@ public class Installer extends SystemService {
        }
        }
    }
    }


    public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
            String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
        for (int i = 0; i < isas.length; i++) {
            assertValidInstructionSet(isas[i]);
        }
        if (!checkBeforeRemote()) return false;
        try {
            return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas,
                    volumeUuid, flags);
        } catch (Exception e) {
            throw InstallerException.from(e);
        }
    }

    private static void assertValidInstructionSet(String instructionSet)
    private static void assertValidInstructionSet(String instructionSet)
            throws InstallerException {
            throws InstallerException {
        for (String abi : Build.SUPPORTED_ABIS) {
        for (String abi : Build.SUPPORTED_ABIS) {
+119 −10
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.pm;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser;
import android.os.Environment;
import android.os.Environment;
import android.os.PowerManager;
import android.os.PowerManager;
@@ -35,6 +36,7 @@ import java.io.File;
import java.io.IOException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.List;
import java.util.Set;


import dalvik.system.DexFile;
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_PROFILE_GUIDED;
import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
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_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.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
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.
 * Helper class for running dexopt command on packages.
 */
 */
class PackageDexOptimizer {
public class PackageDexOptimizer {
    private static final String TAG = "PackageManager.DexOptimizer";
    private static final String TAG = "PackageManager.DexOptimizer";
    static final String OAT_DIR_NAME = "oat";
    static final String OAT_DIR_NAME = "oat";
    // TODO b/19550105 Remove error codes and use exceptions
    // TODO b/19550105 Remove error codes and use exceptions
    static final int DEX_OPT_SKIPPED = 0;
    public static final int DEX_OPT_SKIPPED = 0;
    static final int DEX_OPT_PERFORMED = 1;
    public static final int DEX_OPT_PERFORMED = 1;
    static final int DEX_OPT_FAILED = -1;
    public static final int DEX_OPT_FAILED = -1;


    private final Installer mInstaller;
    private final Installer mInstaller;
    private final Object mInstallLock;
    private final Object mInstallLock;
@@ -100,6 +106,9 @@ class PackageDexOptimizer {
            return DEX_OPT_SKIPPED;
            return DEX_OPT_SKIPPED;
        }
        }
        synchronized (mInstallLock) {
        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;
            final boolean useLock = mSystemReady;
            if (useLock) {
            if (useLock) {
                mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
                mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
@@ -130,9 +139,11 @@ class PackageDexOptimizer {
        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
        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 &&
        final boolean profileUpdated = checkForProfileUpdates &&
                isProfileUpdated(pkg, sharedGid, compilerFilter);
                isProfileUpdated(pkg, sharedGid, compilerFilter);

        // TODO(calin,jeffhao): shared library paths should be adjusted to include previous code
        // TODO(calin,jeffhao): shared library paths should be adjusted to include previous code
        // paths (b/34169257).
        // paths (b/34169257).
        final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
        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
     * Adjust the given dexopt-needed value. Can be overridden to influence the decision to
     * optimize or not (and in what way).
     * 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
     * The target filter will be updated if the package code is used by other apps
     * or if it has the safe mode flag set.
     * or if it has the safe mode flag set.
     */
     */
    private String getRealCompilerFilter(PackageParser.Package pkg, String targetCompilerFilter) {
    private String getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter,
        int flags = pkg.applicationInfo.flags;
            boolean isUsedByOtherApps) {
        int flags = info.flags;
        boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
        boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
        if (vmSafeMode) {
        if (vmSafeMode) {
            // For the compilation, it doesn't really matter what we return here because installd
            // For the compilation, it doesn't really matter what we return here because installd
@@ -259,7 +344,7 @@ class PackageDexOptimizer {
            return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
            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.
            // If the dex files is used by other apps, we cannot use profile-guided compilation.
            return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
            return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
        }
        }
@@ -272,12 +357,16 @@ class PackageDexOptimizer {
     * filter.
     * filter.
     */
     */
    private int getDexFlags(PackageParser.Package pkg, String compilerFilter) {
    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 vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
        boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
        boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
        // Profile guide compiled oat files should not be public.
        // Profile guide compiled oat files should not be public.
        boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
        boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
        boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
        boolean isPublic = !info.isForwardLocked() && !isProfileGuidedFilter;
        int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
        int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
        int dexFlags =
        int dexFlags =
                (isPublic ? DEXOPT_PUBLIC : 0)
                (isPublic ? DEXOPT_PUBLIC : 0)
@@ -437,6 +526,19 @@ class PackageDexOptimizer {
        if ((flags & DEXOPT_SAFEMODE) == DEXOPT_SAFEMODE) {
        if ((flags & DEXOPT_SAFEMODE) == DEXOPT_SAFEMODE) {
            flagsList.add("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);
        return String.join(",", flagsList);
    }
    }


@@ -461,5 +563,12 @@ class PackageDexOptimizer {
            // TODO: The return value is wrong when patchoat is needed.
            // TODO: The return value is wrong when patchoat is needed.
            return DexFile.DEX2OAT_FROM_SCRATCH;
            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;
        }
    }
    }
}
}
+46 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading