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

Commit 98c05366 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add a checked exception to legacy dexopt code paths."

parents 2a0fb977 06ae4cf5
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -247,6 +247,19 @@ public class FunctionalUtils {
        }
    }

    /**
     * A {@link Supplier} that allows the caller to specify a custom checked {@link Exception} that
     * can be thrown by the implementer. This is usually used when proxying/wrapping calls between
     * different classes.
     *
     * @param <Output> Method return type
     * @param <ExceptionType> Checked exception type
     */
    @FunctionalInterface
    public interface ThrowingCheckedSupplier<Output, ExceptionType extends Exception> {
        Output get() throws ExceptionType;
    }

    /**
     * A {@link Consumer} that allows the caller to specify a custom checked {@link Exception} that
     * can be thrown by the implementer. This is usually used when proxying/wrapping calls between
+44 −28
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.pm;

import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;

import static com.android.server.pm.DexOptHelper.useArtService;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;

@@ -45,6 +46,7 @@ import android.util.TimingsTraceLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
@@ -242,6 +244,7 @@ public class AppDataHelper {
                }
            }

            if (!useArtService()) { // ART Service handles this on demand instead.
                // Prepare the application profiles only for upgrades and
                // first boot (so that we don't repeat the same operation at
                // each boot).
@@ -267,8 +270,13 @@ public class AppDataHelper {
                // profiles.
                if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()
                        || (userId != UserHandle.USER_SYSTEM)) {
                    try {
                        mArtManagerService.prepareAppProfiles(pkg, userId,
                                /* updateReferenceProfileContent= */ false);
                    } catch (LegacyDexoptDisabledException e2) {
                        throw new RuntimeException(e2);
                    }
                }
            }

            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
@@ -578,7 +586,12 @@ public class AppDataHelper {
            Slog.wtf(TAG, "Package was null!", new Throwable());
            return;
        }
        // TODO(b/251903639): Call into ART Service.
        try {
            mArtManagerService.clearAppProfiles(pkg);
        } catch (LegacyDexoptDisabledException e) {
            throw new RuntimeException(e);
        }
    }

    public void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) {
@@ -615,8 +628,11 @@ public class AppDataHelper {
    }

    private void destroyAppProfilesLeafLIF(AndroidPackage pkg) {
        // TODO(b/251903639): Call into ART Service.
        try {
            mInstaller.destroyAppProfiles(pkg.getPackageName());
        } catch (LegacyDexoptDisabledException e) {
            throw new RuntimeException(e);
        } catch (Installer.InstallerException e) {
            Slog.w(TAG, String.valueOf(e));
        }
+85 −56
Original line number Diff line number Diff line
@@ -55,9 +55,11 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.FunctionalUtils.ThrowingCheckedSupplier;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.PinnerService;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.PackageDexOptimizer.DexOptResult;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
@@ -71,7 +73,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * Controls background dex optimization run as idle job or command line.
@@ -202,7 +203,8 @@ public final class BackgroundDexOptService {
    }

    /** Start scheduling job after boot completion */
    public void systemReady() {
    public void systemReady() throws LegacyDexoptDisabledException {
        Installer.checkLegacyDexoptDisabled();
        if (mInjector.isBackgroundDexOptDisabled()) {
            return;
        }
@@ -272,7 +274,8 @@ public final class BackgroundDexOptService {
     * @return true if dex optimization is complete. false if the task is cancelled or if there was
     *         an error.
     */
    public boolean runBackgroundDexoptJob(@Nullable List<String> packageNames) {
    public boolean runBackgroundDexoptJob(@Nullable List<String> packageNames)
            throws LegacyDexoptDisabledException {
        enforceRootOrShell();
        long identity = Binder.clearCallingIdentity();
        try {
@@ -301,7 +304,8 @@ public final class BackgroundDexOptService {
     *
     * <p>This is only for shell command and only root or shell user can use this.
     */
    public void cancelBackgroundDexoptJob() {
    public void cancelBackgroundDexoptJob() throws LegacyDexoptDisabledException {
        Installer.checkLegacyDexoptDisabled();
        enforceRootOrShell();
        Binder.withCleanCallingIdentity(() -> cancelDexOptAndWaitForCompletion());
    }
@@ -315,7 +319,8 @@ public final class BackgroundDexOptService {
     *
     * @param disable True if JobScheduler invocations should be disabled, false otherwise.
     */
    public void setDisableJobSchedulerJobs(boolean disable) {
    public void setDisableJobSchedulerJobs(boolean disable) throws LegacyDexoptDisabledException {
        Installer.checkLegacyDexoptDisabled();
        enforceRootOrShell();
        synchronized (mLock) {
            mDisableJobSchedulerJobs = disable;
@@ -323,14 +328,18 @@ public final class BackgroundDexOptService {
    }

    /** Adds listener for package update */
    public void addPackagesUpdatedListener(PackagesUpdatedListener listener) {
    public void addPackagesUpdatedListener(PackagesUpdatedListener listener)
            throws LegacyDexoptDisabledException {
        Installer.checkLegacyDexoptDisabled();
        synchronized (mLock) {
            mPackagesUpdatedListeners.add(listener);
        }
    }

    /** Removes package update listener */
    public void removePackagesUpdatedListener(PackagesUpdatedListener listener) {
    public void removePackagesUpdatedListener(PackagesUpdatedListener listener)
            throws LegacyDexoptDisabledException {
        Installer.checkLegacyDexoptDisabled();
        synchronized (mLock) {
            mPackagesUpdatedListeners.remove(listener);
        }
@@ -340,7 +349,8 @@ public final class BackgroundDexOptService {
     * Notifies package change and removes the package from the failed package list so that
     * the package can run dexopt again.
     */
    public void notifyPackageChanged(String packageName) {
    public void notifyPackageChanged(String packageName) throws LegacyDexoptDisabledException {
        Installer.checkLegacyDexoptDisabled();
        // The idle maintenance job skips packages which previously failed to
        // compile. The given package has changed and may successfully compile
        // now. Remove it from the list of known failing packages.
@@ -387,6 +397,7 @@ public final class BackgroundDexOptService {
                // Post boot job not finished yet. Run post boot job first.
                return false;
            }
            try {
                resetStatesForNewDexOptRunLocked(mInjector.createAndStartThread(
                        "BackgroundDexOptService_" + (isPostBootUpdateJob ? "PostBoot" : "Idle"),
                        () -> {
@@ -397,6 +408,8 @@ public final class BackgroundDexOptService {
                            try {
                                completed = runIdleOptimization(
                                        pm, pkgs, params.getJobId() == JOB_POST_BOOT_UPDATE);
                            } catch (LegacyDexoptDisabledException e) {
                                Slog.wtf(TAG, e);
                            } finally { // Those cleanup should be done always.
                                tr.traceEnd();
                                Slog.i(TAG,
@@ -418,6 +431,9 @@ public final class BackgroundDexOptService {
                                markDexOptCompleted();
                            }
                        }));
            } catch (LegacyDexoptDisabledException e) {
                Slog.wtf(TAG, e);
            }
        }
        return true;
    }
@@ -425,11 +441,16 @@ public final class BackgroundDexOptService {
    /** For BackgroundDexOptJobService to dispatch onStopJob event */
    /* package */ boolean onStopJob(BackgroundDexOptJobService job, JobParameters params) {
        Slog.i(TAG, "onStopJob:" + params.getJobId());
        // This cannot block as it is in main thread, thus dispatch to a newly created thread and
        // cancel it from there.
        // As this event does not happen often, creating a new thread is justified rather than
        // having one thread kept permanently.
        mInjector.createAndStartThread("DexOptCancel", this::cancelDexOptAndWaitForCompletion);
        // This cannot block as it is in main thread, thus dispatch to a newly created thread
        // and cancel it from there. As this event does not happen often, creating a new thread
        // is justified rather than having one thread kept permanently.
        mInjector.createAndStartThread("DexOptCancel", () -> {
            try {
                cancelDexOptAndWaitForCompletion();
            } catch (LegacyDexoptDisabledException e) {
                Slog.wtf(TAG, e);
            }
        });
        // Always reschedule for cancellation.
        return true;
    }
@@ -438,7 +459,7 @@ public final class BackgroundDexOptService {
     * Cancels pending dexopt and wait for completion of the cancellation. This can block the caller
     * until cancellation is done.
     */
    private void cancelDexOptAndWaitForCompletion() {
    private void cancelDexOptAndWaitForCompletion() throws LegacyDexoptDisabledException {
        synchronized (mLock) {
            if (mDexOptThread == null) {
                return;
@@ -496,7 +517,8 @@ public final class BackgroundDexOptService {
    }

    @GuardedBy("mLock")
    private void resetStatesForNewDexOptRunLocked(Thread thread) {
    private void resetStatesForNewDexOptRunLocked(Thread thread)
            throws LegacyDexoptDisabledException {
        mDexOptThread = thread;
        mLastCancelledPackages.clear();
        controlDexOptBlockingLocked(false);
@@ -510,7 +532,7 @@ public final class BackgroundDexOptService {
    }

    @GuardedBy("mLock")
    private void controlDexOptBlockingLocked(boolean block) {
    private void controlDexOptBlockingLocked(boolean block) throws LegacyDexoptDisabledException {
        PackageManagerService pm = mInjector.getPackageManagerService();
        mDexOptHelper.controlDexOptBlocking(block);
    }
@@ -564,8 +586,8 @@ public final class BackgroundDexOptService {
     * Returns whether we've successfully run the job. Note that it will return true even if some
     * packages may have failed compiling.
     */
    private boolean runIdleOptimization(
            PackageManagerService pm, List<String> pkgs, boolean isPostBootUpdate) {
    private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs,
            boolean isPostBootUpdate) throws LegacyDexoptDisabledException {
        synchronized (mLock) {
            mLastExecutionStatus = STATUS_UNSPECIFIED;
            mLastExecutionStartUptimeMs = SystemClock.uptimeMillis();
@@ -631,7 +653,8 @@ public final class BackgroundDexOptService {

    @Status
    private int idleOptimizePackages(PackageManagerService pm, List<String> pkgs,
            long lowStorageThreshold, boolean isPostBootUpdate) {
            long lowStorageThreshold, boolean isPostBootUpdate)
            throws LegacyDexoptDisabledException {
        ArraySet<String> updatedPackages = new ArraySet<>();

        try {
@@ -707,7 +730,8 @@ public final class BackgroundDexOptService {

    @Status
    private int optimizePackages(List<String> pkgs, long lowStorageThreshold,
            ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
            ArraySet<String> updatedPackages, boolean isPostBootUpdate)
            throws LegacyDexoptDisabledException {
        boolean supportSecondaryDex = mInjector.supportSecondaryDex();

        // Keep the error if there is any error from any package.
@@ -760,7 +784,8 @@ public final class BackgroundDexOptService {
     */
    @DexOptResult
    private int downgradePackage(@NonNull Computer snapshot, PackageManagerService pm, String pkg,
            boolean isForPrimaryDex, boolean isPostBootUpdate) {
            boolean isForPrimaryDex, boolean isPostBootUpdate)
            throws LegacyDexoptDisabledException {
        if (DEBUG) {
            Slog.d(TAG, "Downgrading " + pkg);
        }
@@ -808,7 +833,7 @@ public final class BackgroundDexOptService {
    }

    @Status
    private int reconcileSecondaryDexFiles() {
    private int reconcileSecondaryDexFiles() throws LegacyDexoptDisabledException {
        // TODO(calin): should we denylist packages for which we fail to reconcile?
        for (String p : mInjector.getDexManager().getAllPackagesWithSecondaryDexFiles()) {
            if (isCancelling()) {
@@ -829,7 +854,8 @@ public final class BackgroundDexOptService {
     * @return PackageDexOptimizer#DEX_OPT_*
     */
    @DexOptResult
    private int optimizePackage(String pkg, boolean isForPrimaryDex, boolean isPostBootUpdate) {
    private int optimizePackage(String pkg, boolean isForPrimaryDex, boolean isPostBootUpdate)
            throws LegacyDexoptDisabledException {
        int reason = isPostBootUpdate ? PackageManagerService.REASON_POST_BOOT
                                      : PackageManagerService.REASON_BACKGROUND_DEXOPT;
        String filter = getCompilerFilterForReason(reason);
@@ -857,7 +883,8 @@ public final class BackgroundDexOptService {
    }

    @DexOptResult
    private int performDexOptPrimary(String pkg, int reason, String filter, int dexoptFlags) {
    private int performDexOptPrimary(String pkg, int reason, String filter, int dexoptFlags)
            throws LegacyDexoptDisabledException {
        DexoptOptions dexoptOptions =
                new DexoptOptions(pkg, reason, filter, /*splitName=*/null, dexoptFlags);
        return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/true,
@@ -865,7 +892,8 @@ public final class BackgroundDexOptService {
    }

    @DexOptResult
    private int performDexOptSecondary(String pkg, int reason, String filter, int dexoptFlags) {
    private int performDexOptSecondary(String pkg, int reason, String filter, int dexoptFlags)
            throws LegacyDexoptDisabledException {
        DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason, filter, /*splitName=*/null,
                dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX);
        return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/false,
@@ -885,8 +913,9 @@ public final class BackgroundDexOptService {
     *  {@link PackageDexOptimizer#DEX_OPT_FAILED}
     */
    @DexOptResult
    private int trackPerformDexOpt(
            String pkg, boolean isForPrimaryDex, Supplier<Integer> performDexOptWrapper) {
    private int trackPerformDexOpt(String pkg, boolean isForPrimaryDex,
            ThrowingCheckedSupplier<Integer, LegacyDexoptDisabledException> performDexOptWrapper)
            throws LegacyDexoptDisabledException {
        ArraySet<String> failedPackageNames;
        synchronized (mLock) {
            failedPackageNames =
+8 −2
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@ import com.android.internal.util.CollectionUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -3009,8 +3010,13 @@ public class ComputerEngine implements Computer {
                    ipw.println("[" + pkgName + "]");
                    ipw.increaseIndent();

                    // TODO(b/251903639): Call into ART Service.
                    try {
                        mPackageDexOptimizer.dumpDexoptState(ipw, pkg, pkgSetting,
                                mDexManager.getPackageUseInfoOrDefault(pkgName));
                    } catch (LegacyDexoptDisabledException e) {
                        throw new RuntimeException(e);
                    }
                    ipw.decreaseIndent();
                }
                ipw.println("BgDexopt state:");
+38 −15
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@ import com.android.server.art.DexUseManagerLocal;
import com.android.server.art.model.ArtFlags;
import com.android.server.art.model.OptimizeParams;
import com.android.server.art.model.OptimizeResult;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.PackageDexOptimizer.DexOptResult;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
@@ -125,8 +127,9 @@ public final class DexOptHelper {
     * and {@code numberOfPackagesFailed}.
     */
    public int[] performDexOptUpgrade(List<PackageStateInternal> packageStates, boolean showDialog,
            final int compilationReason, boolean bootComplete) {

            final int compilationReason, boolean bootComplete)
            throws LegacyDexoptDisabledException {
        Installer.checkLegacyDexoptDisabled();
        int numberOfPackagesVisited = 0;
        int numberOfPackagesOptimized = 0;
        int numberOfPackagesSkipped = 0;
@@ -158,7 +161,7 @@ public final class DexOptHelper {
                            // even if things are already compiled.
                            // useProfileForDexopt = true;
                        }
                    } catch (Exception e) {
                    } catch (InstallerException | RuntimeException e) {
                        Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ",
                                e);
                    }
@@ -193,7 +196,7 @@ public final class DexOptHelper {
                                } else {
                                    useProfileForDexopt = true;
                                }
                            } catch (Exception e) {
                            } catch (InstallerException | RuntimeException e) {
                                Log.e(TAG, "Failed to copy profile "
                                        + profileFile.getAbsolutePath() + " ", e);
                            }
@@ -284,7 +287,8 @@ public final class DexOptHelper {
     * Checks if system UI package (typically "com.android.systemui") needs to be re-compiled, and
     * compiles it if needed.
     */
    private void checkAndDexOptSystemUi() {
    private void checkAndDexOptSystemUi() throws LegacyDexoptDisabledException {
        Installer.checkLegacyDexoptDisabled();
        Computer snapshot = mPm.snapshotComputer();
        String sysUiPackageName =
                mPm.mContext.getString(com.android.internal.R.string.config_systemUi);
@@ -320,7 +324,7 @@ public final class DexOptHelper {
                            Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath());
                        }
                    }
                } catch (Exception e) {
                } catch (InstallerException | RuntimeException e) {
                    Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath(), e);
                }
            }
@@ -341,7 +345,7 @@ public final class DexOptHelper {
    }

    @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
    public void performPackageDexOptUpgradeIfNeeded() {
    public void performPackageDexOptUpgradeIfNeeded() throws LegacyDexoptDisabledException {
        PackageManagerServiceUtils.enforceSystemOrRoot(
                "Only the system can request package update");

@@ -413,7 +417,12 @@ public final class DexOptHelper {
        }

        if (options.isDexoptOnlySecondaryDex()) {
            // TODO(b/251903639): Call into ART Service.
            try {
                return mPm.getDexManager().dexoptSecondaryDex(options);
            } catch (LegacyDexoptDisabledException e) {
                throw new RuntimeException(e);
            }
        } else {
            int dexoptStatus = performDexOptWithStatus(options);
            return dexoptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
@@ -470,6 +479,8 @@ public final class DexOptHelper {
        final long callingId = Binder.clearCallingIdentity();
        try {
            return performDexOptInternalWithDependenciesLI(p, pkgSetting, options);
        } catch (LegacyDexoptDisabledException e) {
            throw new RuntimeException(e);
        } finally {
            Binder.restoreCallingIdentity(callingId);
        }
@@ -542,7 +553,8 @@ public final class DexOptHelper {

    @DexOptResult
    private int performDexOptInternalWithDependenciesLI(
            AndroidPackage p, @NonNull PackageStateInternal pkgSetting, DexoptOptions options) {
            AndroidPackage p, @NonNull PackageStateInternal pkgSetting, DexoptOptions options)
            throws LegacyDexoptDisabledException {
        // System server gets a special path.
        if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) {
            return mPm.getDexManager().dexoptSystemServer(options);
@@ -621,7 +633,11 @@ public final class DexOptHelper {
        if (artSrvRes.isPresent()) {
            res = artSrvRes.get();
        } else {
            try {
                res = performDexOptInternalWithDependenciesLI(pkg, packageState, options);
            } catch (LegacyDexoptDisabledException e) {
                throw new RuntimeException(e);
            }
        }

        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -666,8 +682,8 @@ public final class DexOptHelper {
        return installerPkg.getUid() == Binder.getCallingUid();
    }

    public boolean performDexOptSecondary(String packageName, String compilerFilter,
            boolean force) {
    public boolean performDexOptSecondary(
            String packageName, String compilerFilter, boolean force) {
        int flags = DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX
                | DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES
                | DexoptOptions.DEXOPT_BOOT_COMPLETE
@@ -869,7 +885,7 @@ public final class DexOptHelper {
        }
    }

    /*package*/ void controlDexOptBlocking(boolean block) {
    /*package*/ void controlDexOptBlocking(boolean block) throws LegacyDexoptDisabledException {
        mPm.mPackageDexOptimizer.controlDexOptBlocking(block);
    }

@@ -928,11 +944,18 @@ public final class DexOptHelper {
        Slog.i(TAG, "Falling back to old PackageManager dexopt for " + packageName + ": " + reason);
    }

    /**
     * Returns true if ART Service should be used for package optimization.
     */
    public static boolean useArtService() {
        return SystemProperties.getBoolean("dalvik.vm.useartservice", false);
    }

    /**
     * Returns {@link DexUseManagerLocal} if ART Service should be used for package optimization.
     */
    public static @Nullable DexUseManagerLocal getDexUseManagerLocal() {
        if (!"true".equals(SystemProperties.get("dalvik.vm.useartservice", ""))) {
        if (!useArtService()) {
            return null;
        }
        try {
@@ -946,7 +969,7 @@ public final class DexOptHelper {
     * Returns {@link ArtManagerLocal} if ART Service should be used for package optimization.
     */
    private static @Nullable ArtManagerLocal getArtManagerLocal() {
        if (!"true".equals(SystemProperties.get("dalvik.vm.useartservice", ""))) {
        if (!useArtService()) {
            return null;
        }
        try {
Loading