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

Commit 5d8c1369 authored by Chris Wailes's avatar Chris Wailes Committed by Christian Wailes
Browse files

Make BackgroundDexOpt aware of thermal state

This change makes the BackgroundDexOpt service consider the thermal
state of the device before running.  If the device is in a moderate thermal
state or worse background dexopt will not run.

Bug: 165935246
Bug: 181795682
Test: Treehugger && atest BackgroundDexOptServiceIntegrationTests
Change-Id: Ie5ccbab7aa6d414241780136407f397d326340bf
parent 8a6ffdc5
Loading
Loading
Loading
Loading
+43 −2
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@ import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.os.BatteryManagerInternal;
import android.os.Environment;
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -82,10 +85,15 @@ public class BackgroundDexOptService extends JobService {
    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;
    // Optimizations should be aborted. Thermal throttling level too high.
    private static final int OPTIMIZE_ABORT_THERMAL = 4;

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

    // Thermal cutoff value used if one isn't defined by a system property.
    private static final int THERMAL_CUTOFF_DEFAULT = PowerManager.THERMAL_STATUS_MODERATE;

    /**
     * Set of failed packages remembered across job runs.
     */
@@ -107,8 +115,14 @@ public class BackgroundDexOptService extends JobService {
    private static final long mDowngradeUnusedAppsThresholdInMillis =
            getDowngradeUnusedAppsThresholdInMillis();

    private final IThermalService mThermalService =
            IThermalService.Stub.asInterface(
                ServiceManager.getService(Context.THERMAL_SERVICE));

    private static List<PackagesUpdatedListener> sPackagesUpdatedListeners = new ArrayList<>();

    private int mThermalStatusCutoff = THERMAL_CUTOFF_DEFAULT;

    public static void schedule(Context context) {
        if (isBackgroundDexoptDisabled()) {
            return;
@@ -251,12 +265,18 @@ public class BackgroundDexOptService extends JobService {
                    Slog.w(TAG, "Idle optimizations aborted because of space constraints.");
                } else if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
                    Slog.w(TAG, "Idle optimizations aborted by job scheduler.");
                } else if (result == OPTIMIZE_ABORT_THERMAL) {
                    Slog.w(TAG, "Idle optimizations aborted by thermal throttling.");
                } else {
                    Slog.w(TAG, "Idle optimizations ended with unexpected code: " + result);
                }
                if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {

                if (result == OPTIMIZE_ABORT_THERMAL) {
                    // Abandon our timeslice and reschedule
                    jobFinished(jobParams, /* wantsReschedule */ true);
                } else if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
                    // Abandon our timeslice and do not reschedule.
                    jobFinished(jobParams, /* reschedule */ false);
                    jobFinished(jobParams, /* wantsReschedule */ false);
                }
            }
        }.start();
@@ -542,6 +562,24 @@ public class BackgroundDexOptService extends JobService {
            // JobScheduler requested an early abort.
            return OPTIMIZE_ABORT_BY_JOB_SCHEDULER;
        }

        // Abort background dexopt if the device is in a moderate or stronger thermal throttling
        // state.
        try {
            final int thermalStatus = mThermalService.getCurrentThermalStatus();

            if (DEBUG) {
                Log.i(TAG, "Thermal throttling status during bgdexopt: " + thermalStatus);
            }

            if (thermalStatus >= mThermalStatusCutoff) {
                return OPTIMIZE_ABORT_THERMAL;
            }
        } catch (RemoteException ex) {
            // Because this is a intra-process Binder call it is impossible for a RemoteException
            // to be raised.
        }

        long usableSpace = mDataDir.getUsableSpace();
        if (usableSpace < lowStorageThreshold) {
            // Rather bail than completely fill up the disk.
@@ -603,6 +641,9 @@ public class BackgroundDexOptService extends JobService {
            return false;
        }

        mThermalStatusCutoff =
            SystemProperties.getInt("dalvik.vm.dexopt.thermal-cutoff", THERMAL_CUTOFF_DEFAULT);

        boolean result;
        if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
            result = runPostBootUpdate(params, pm, pkgs);
+1 −0
Original line number Diff line number Diff line
include platform/art:/OWNERS
+32 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.AlarmManager;
import android.content.Context;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.storage.StorageManager;
import android.util.Log;
@@ -201,11 +202,16 @@ public final class BackgroundDexOptServiceIntegrationTests {
        fillUpStorage((long) (getStorageLowBytes() * LOW_STORAGE_MULTIPLIER));
    }

    // TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
    private static void runBackgroundDexOpt() throws IOException {
        runBackgroundDexOpt("Success");
    }

    // TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
    private static void runBackgroundDexOpt(String expectedStatus) throws IOException {
        String result = runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME);
        if (!result.trim().equals("Success")) {
            throw new IllegalStateException("Expected command success, received >" + result + "<");
        if (!result.trim().equals(expectedStatus)) {
            throw new IllegalStateException("Expected status: " + expectedStatus
                + "; Received: " + result.trim());
        }
    }

@@ -242,6 +248,16 @@ public final class BackgroundDexOptServiceIntegrationTests {
        runShellCommand(String.format("cmd package compile -f -m %s %s", filter, pkg));
    }

    // Override the thermal status of the device
    public static void overrideThermalStatus(int status) throws IOException {
        runShellCommand("cmd thermalservice override-status " + status);
    }

    // Reset the thermal status of the device
    public static void resetThermalStatus() throws IOException {
        runShellCommand("cmd thermalservice reset");
    }

    // Test that background dexopt under normal conditions succeeds.
    @Test
    public void testBackgroundDexOpt() throws IOException {
@@ -307,4 +323,17 @@ public final class BackgroundDexOptServiceIntegrationTests {
        }
    }

    // Test that background dexopt job doesn't trigger if the device is under thermal throttling.
    @Test
    public void testBackgroundDexOptThermalThrottling() throws IOException {
        try {
            compilePackageWithFilter(PACKAGE_NAME, "verify");
            overrideThermalStatus(PowerManager.THERMAL_STATUS_MODERATE);
            // The bgdexopt task should fail when onStartJob is run
            runBackgroundDexOpt("Failure");
            Assert.assertEquals("verify", getCompilerFilter(PACKAGE_NAME));
        } finally {
            resetThermalStatus();
        }
    }
}