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

Commit 8bcd66d3 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Reduce app size by downgrading inactive apps"

parents a546c381 3aeca17a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -513,7 +513,7 @@ interface IPackageManager {
     * configuration.
     */
    boolean performDexOpt(String packageName, boolean checkProfiles,
            int compileReason, boolean force, boolean bootComplete);
            int compileReason, boolean force, boolean bootComplete, boolean downgrade);

    /**
     * Ask the package manager to perform a dex-opt with the given compiler filter.
+1 −1
Original line number Diff line number Diff line
@@ -577,7 +577,7 @@ public class ZygoteInit {
                try {
                    installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
                            instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
                            uuid, sharedLibraries, seInfo);
                            uuid, sharedLibraries, seInfo, false /* downgrade */);
                } catch (RemoteException | ServiceSpecificException e) {
                    // Ignore (but log), we need this on the classpath for fallback mode.
                    Log.w(TAG, "Failed compiling classpath element for system server: "
+74 −12
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.server.pm;

import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;

import android.app.AlarmManager;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
@@ -40,6 +39,7 @@ import com.android.server.LocalServices;
import com.android.server.PinnerService;

import java.io.File;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.TimeUnit;

@@ -73,6 +73,9 @@ public class BackgroundDexOptService extends JobService {
    // Optimizations should be aborted. No space left on device.
    private static final int OPTIMIZE_ABORT_NO_SPACE_LEFT = 3;

    // Used for calculating space threshold for downgrading unused apps.
    private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2;

    /**
     * Set of failed packages remembered across job runs.
     */
@@ -92,6 +95,9 @@ public class BackgroundDexOptService extends JobService {

    private final File mDataDir = Environment.getDataDirectory();

    private static final long mDowngradeUnusedAppsThresholdInMillis =
            getDowngradeUnusedAppsThresholdInMillis();

    public static void schedule(Context context) {
        JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);

@@ -215,7 +221,8 @@ public class BackgroundDexOptService extends JobService {
                    /* checkProfiles */ false,
                    PackageManagerService.REASON_BOOT,
                    /* force */ false,
                    /* bootComplete */ true);
                    /* bootComplete */ true,
                    /* downgrade */ false);
            if (result == PackageDexOptimizer.DEX_OPT_PERFORMED)  {
                updatedPackages.add(pkg);
            }
@@ -243,7 +250,8 @@ public class BackgroundDexOptService extends JobService {
    }

    // Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes).
    private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs, Context context) {
    private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
            Context context) {
        Log.i(TAG, "Performing idle optimizations");
        // If post-boot update is still running, request that it exits early.
        mExitPostBootUpdate.set(true);
@@ -274,9 +282,16 @@ public class BackgroundDexOptService extends JobService {
            long lowStorageThreshold, boolean is_for_primary_dex,
            ArraySet<String> failedPackageNames) {
        ArraySet<String> updatedPackages = new ArraySet<>();
        Set<String> unusedPackages = pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
        // Only downgrade apps when space is low on device.
        // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
        // up disk before user hits the actual lowStorageThreshold.
        final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE *
                lowStorageThreshold;
        boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
        for (String pkg : pkgs) {
            int abort_code = abortIdleOptimizations(lowStorageThreshold);
            if (abort_code != OPTIMIZE_CONTINUE) {
            if (abort_code == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
                return abort_code;
            }

@@ -284,11 +299,36 @@ public class BackgroundDexOptService extends JobService {
                if (failedPackageNames.contains(pkg)) {
                    // Skip previously failing package
                    continue;
                }
            }

            int reason;
            boolean downgrade;
            // Downgrade unused packages.
            if (unusedPackages.contains(pkg) && shouldDowngrade) {
                // This applies for system apps or if packages location is not a directory, i.e.
                // monolithic install.
                if (is_for_primary_dex && !pm.canHaveOatDir(pkg)) {
                    // For apps that don't have the oat directory, instead of downgrading,
                    // remove their compiler artifacts from dalvik cache.
                    pm.deleteOatArtifactsOfPackage(pkg);
                    continue;
                } else {
                    // Conservatively add package to the list of failing ones in case performDexOpt
                    // never returns.
                    failedPackageNames.add(pkg);
                    reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
                    downgrade = true;
                }
            } else if (abort_code != OPTIMIZE_ABORT_NO_SPACE_LEFT) {
                reason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
                downgrade = false;
            } else {
                // can't dexopt because of low space.
                continue;
            }

            synchronized (failedPackageNames) {
                // Conservatively add package to the list of failing ones in case
                // performDexOpt never returns.
                failedPackageNames.add(pkg);
            }

            // Optimize package if needed. Note that there can be no race between
@@ -297,17 +337,19 @@ public class BackgroundDexOptService extends JobService {
            if (is_for_primary_dex) {
                int result = pm.performDexOptWithStatus(pkg,
                        /* checkProfiles */ true,
                        PackageManagerService.REASON_BACKGROUND_DEXOPT,
                        /* force */ false,
                        /* bootComplete */ true);
                        reason,
                        false /* forceCompile*/,
                        true /* bootComplete */,
                        downgrade);
                success = result != PackageDexOptimizer.DEX_OPT_FAILED;
                if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
                    updatedPackages.add(pkg);
                }
            } else {
                success = pm.performDexOptSecondary(pkg,
                        PackageManagerService.REASON_BACKGROUND_DEXOPT,
                        /* force */ false);
                        reason,
                        false /* force */,
                        downgrade);
            }
            if (success) {
                // Dexopt succeeded, remove package from the list of failing ones.
@@ -347,6 +389,16 @@ public class BackgroundDexOptService extends JobService {
        return OPTIMIZE_CONTINUE;
    }

    // Evaluate whether apps should be downgraded.
    private boolean shouldDowngrade(long lowStorageThresholdForDowngrade) {
        long usableSpace = mDataDir.getUsableSpace();
        if (usableSpace < lowStorageThresholdForDowngrade) {
            return true;
        }

        return false;
    }

    /**
     * Execute the idle optimizations immediately.
     */
@@ -415,4 +467,14 @@ public class BackgroundDexOptService extends JobService {
            pinnerService.update(updatedPackages);
        }
    }

    private static long getDowngradeUnusedAppsThresholdInMillis() {
        final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days";
        String sysPropValue = SystemProperties.get(sysPropKey);
        if (sysPropValue == null || sysPropValue.isEmpty()) {
            Log.w(TAG, "SysProp " + sysPropKey + " not set");
            return Long.MAX_VALUE;
        }
        return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -279,13 +279,13 @@ public class Installer extends SystemService {
    public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
            int dexoptNeeded, @Nullable String outputPath, int dexFlags,
            String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
            @Nullable String seInfo)
            @Nullable String seInfo, boolean downgrade)
            throws InstallerException {
        assertValidInstructionSet(instructionSet);
        if (!checkBeforeRemote()) return;
        try {
            mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
                    dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo);
                    dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade);
        } catch (Exception e) {
            throw InstallerException.from(e);
        }
+9 −7
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;

@@ -40,7 +39,6 @@ import com.android.server.pm.Installer.InstallerException;
import java.io.File;
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -261,11 +259,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
            public void dexopt(String apkPath, int uid, @Nullable String pkgName,
                    String instructionSet, int dexoptNeeded, @Nullable String outputPath,
                    int dexFlags, String compilerFilter, @Nullable String volumeUuid,
                    @Nullable String sharedLibraries, @Nullable String seInfo) throws InstallerException {
                    @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade)
                    throws InstallerException {
                final StringBuilder builder = new StringBuilder();

                // The version. Right now it's 2.
                builder.append("2 ");
                // The version. Right now it's 3.
                builder.append("3 ");

                builder.append("dexopt");

@@ -280,6 +279,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
                encodeParameter(builder, volumeUuid);
                encodeParameter(builder, sharedLibraries);
                encodeParameter(builder, seInfo);
                encodeParameter(builder, downgrade);

                commands.add(builder.toString());
            }
@@ -319,12 +319,14 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
                getCompilerFilterForReason(compilationReason),
                null /* CompilerStats.PackageStats */,
                mPackageManagerService.getDexManager().isUsedByOtherApps(pkg.packageName),
                true /* bootComplete */);
                true /* bootComplete */,
                false /* downgrade */);

        mPackageManagerService.getDexManager().dexoptSecondaryDex(pkg.packageName,
                getCompilerFilterForReason(compilationReason),
                false /* force */,
                false /* compileOnlySharedDex */);
                false /* compileOnlySharedDex */,
                false /* downgrade */);
        return commands;
    }

Loading