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

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

Merge "Add grace period to estimated launch times." into tm-dev

parents 0fe75d50 1942a321
Loading
Loading
Loading
Loading
+42 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.job.controllers;

import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;

import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.sSystemClock;
@@ -90,6 +91,14 @@ public class PrefetchController extends StateController {
    @CurrentTimeMillisLong
    private long mLaunchTimeThresholdMs = PcConstants.DEFAULT_LAUNCH_TIME_THRESHOLD_MS;

    /**
     * The additional time we'll add to a launch time estimate before considering it obsolete and
     * try to get a new estimate. This will help make prefetch jobs more viable in case an estimate
     * is a few minutes early.
     */
    @GuardedBy("mLock")
    private long mLaunchTimeAllowanceMs = PcConstants.DEFAULT_LAUNCH_TIME_ALLOWANCE_MS;

    @SuppressWarnings("FieldCanBeLocal")
    private final EstimatedLaunchTimeChangedListener mEstimatedLaunchTimeChangedListener =
            new EstimatedLaunchTimeChangedListener() {
@@ -204,7 +213,8 @@ public class PrefetchController extends StateController {
    private long getNextEstimatedLaunchTimeLocked(int userId, @NonNull String pkgName,
            @CurrentTimeMillisLong long now) {
        final Long nextEstimatedLaunchTime = mEstimatedLaunchTimes.get(userId, pkgName);
        if (nextEstimatedLaunchTime == null || nextEstimatedLaunchTime < now) {
        if (nextEstimatedLaunchTime == null
                || nextEstimatedLaunchTime < now - mLaunchTimeAllowanceMs) {
            // Don't query usage stats here because it may have to read from disk.
            mHandler.obtainMessage(MSG_RETRIEVE_ESTIMATED_LAUNCH_TIME, userId, 0, pkgName)
                    .sendToTarget();
@@ -335,7 +345,9 @@ public class PrefetchController extends StateController {
        }

        final long nextEstimatedLaunchTime = getNextEstimatedLaunchTimeLocked(userId, pkgName, now);
        if (nextEstimatedLaunchTime - now > mLaunchTimeThresholdMs) {
        // Avoid setting an alarm for the end of time.
        if (nextEstimatedLaunchTime != Long.MAX_VALUE
                && nextEstimatedLaunchTime - now > mLaunchTimeThresholdMs) {
            // Set alarm to be notified when this crosses the threshold.
            final long timeToCrossThresholdMs =
                    nextEstimatedLaunchTime - (now + mLaunchTimeThresholdMs);
@@ -354,7 +366,7 @@ public class PrefetchController extends StateController {
    private boolean willBeLaunchedSoonLocked(int userId, @NonNull String pkgName,
            @CurrentTimeMillisLong long now) {
        return getNextEstimatedLaunchTimeLocked(userId, pkgName, now)
                <= now + mLaunchTimeThresholdMs;
                <= now + mLaunchTimeThresholdMs - mLaunchTimeAllowanceMs;
    }

    @Override
@@ -494,16 +506,37 @@ public class PrefetchController extends StateController {
        @VisibleForTesting
        static final String KEY_LAUNCH_TIME_THRESHOLD_MS =
                PC_CONSTANT_PREFIX + "launch_time_threshold_ms";
        @VisibleForTesting
        static final String KEY_LAUNCH_TIME_ALLOWANCE_MS =
                PC_CONSTANT_PREFIX + "launch_time_allowance_ms";

        private static final long DEFAULT_LAUNCH_TIME_THRESHOLD_MS = 7 * HOUR_IN_MILLIS;
        private static final long DEFAULT_LAUNCH_TIME_ALLOWANCE_MS = 20 * MINUTE_IN_MILLIS;

        /** How much time each app will have to run jobs within their standby bucket window. */
        public long LAUNCH_TIME_THRESHOLD_MS = DEFAULT_LAUNCH_TIME_THRESHOLD_MS;

        /**
         * How much additional time to add to an estimated launch time before considering it
         * unusable.
         */
        public long LAUNCH_TIME_ALLOWANCE_MS = DEFAULT_LAUNCH_TIME_ALLOWANCE_MS;

        @GuardedBy("mLock")
        public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
                @NonNull String key) {
            switch (key) {
                case KEY_LAUNCH_TIME_ALLOWANCE_MS:
                    LAUNCH_TIME_ALLOWANCE_MS =
                            properties.getLong(key, DEFAULT_LAUNCH_TIME_ALLOWANCE_MS);
                    // Limit the allowance to the range [0 minutes, 2 hours].
                    long newLaunchTimeAllowanceMs = Math.min(2 * HOUR_IN_MILLIS,
                            Math.max(0, LAUNCH_TIME_ALLOWANCE_MS));
                    if (mLaunchTimeAllowanceMs != newLaunchTimeAllowanceMs) {
                        mLaunchTimeAllowanceMs = newLaunchTimeAllowanceMs;
                        mShouldReevaluateConstraints = true;
                    }
                    break;
                case KEY_LAUNCH_TIME_THRESHOLD_MS:
                    LAUNCH_TIME_THRESHOLD_MS =
                            properties.getLong(key, DEFAULT_LAUNCH_TIME_THRESHOLD_MS);
@@ -528,6 +561,7 @@ public class PrefetchController extends StateController {
            pw.increaseIndent();

            pw.print(KEY_LAUNCH_TIME_THRESHOLD_MS, LAUNCH_TIME_THRESHOLD_MS).println();
            pw.print(KEY_LAUNCH_TIME_ALLOWANCE_MS, LAUNCH_TIME_ALLOWANCE_MS).println();

            pw.decreaseIndent();
        }
@@ -535,6 +569,11 @@ public class PrefetchController extends StateController {

    //////////////////////// TESTING HELPERS /////////////////////////////

    @VisibleForTesting
    long getLaunchTimeAllowanceMs() {
        return mLaunchTimeAllowanceMs;
    }

    @VisibleForTesting
    long getLaunchTimeThresholdMs() {
        return mLaunchTimeThresholdMs;
+46 −0
Original line number Diff line number Diff line
@@ -233,27 +233,34 @@ public class PrefetchControllerTest {
    @Test
    public void testConstantsUpdating_ValidValues() {
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 5 * HOUR_IN_MILLIS);
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 5 * MINUTE_IN_MILLIS);

        assertEquals(5 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs());
        assertEquals(5 * MINUTE_IN_MILLIS, mPrefetchController.getLaunchTimeAllowanceMs());
    }

    @Test
    public void testConstantsUpdating_InvalidValues() {
        // Test negatives/too low.
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 4 * MINUTE_IN_MILLIS);
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, -MINUTE_IN_MILLIS);

        assertEquals(HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs());
        assertEquals(0, mPrefetchController.getLaunchTimeAllowanceMs());

        // Test larger than a day. Controller should cap at one day.
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 25 * HOUR_IN_MILLIS);
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 5 * HOUR_IN_MILLIS);

        assertEquals(24 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs());
        assertEquals(2 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeAllowanceMs());
    }

    @Test
    public void testConstantsUpdating_ThresholdChangesAlarms() {
        final long launchDelayMs = 11 * HOUR_IN_MILLIS;
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
        when(mUsageStatsManagerInternal
                .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
                .thenReturn(sSystemClock.millis() + launchDelayMs);
@@ -276,6 +283,7 @@ public class PrefetchControllerTest {

    @Test
    public void testConstraintNotSatisfiedWhenLaunchLate() {
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);

        final JobStatus job = createJobStatus("testConstraintNotSatisfiedWhenLaunchLate", 1);
@@ -290,6 +298,8 @@ public class PrefetchControllerTest {

    @Test
    public void testConstraintSatisfiedWhenLaunchSoon() {
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);

        final JobStatus job = createJobStatus("testConstraintSatisfiedWhenLaunchSoon", 2);
        when(mUsageStatsManagerInternal
                .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
@@ -338,6 +348,8 @@ public class PrefetchControllerTest {

    @Test
    public void testConstraintSatisfiedWhenWidget() {
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);

        final JobStatus jobNonWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 1);
        final JobStatus jobWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 2);

@@ -365,6 +377,7 @@ public class PrefetchControllerTest {
    @Test
    public void testEstimatedLaunchTimeChangedToLate() {
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
        when(mUsageStatsManagerInternal
                .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
                .thenReturn(sSystemClock.millis() + HOUR_IN_MILLIS);
@@ -393,6 +406,7 @@ public class PrefetchControllerTest {
    @Test
    public void testEstimatedLaunchTimeChangedToSoon() {
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 0);
        when(mUsageStatsManagerInternal
                .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
                .thenReturn(sSystemClock.millis() + 10 * HOUR_IN_MILLIS);
@@ -413,4 +427,36 @@ public class PrefetchControllerTest {
        verify(mJobSchedulerService, timeout(DEFAULT_WAIT_MS)).onControllerStateChanged(any());
        assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
    }

    @Test
    public void testEstimatedLaunchTimeAllowance() {
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_ALLOWANCE_MS, 15 * MINUTE_IN_MILLIS);
        when(mUsageStatsManagerInternal
                .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
                .thenReturn(sSystemClock.millis() + 10 * HOUR_IN_MILLIS);

        InOrder inOrder = inOrder(mUsageStatsManagerInternal);

        JobStatus jobStatus = createJobStatus("testEstimatedLaunchTimeAllowance", 1);
        trackJobs(jobStatus);
        inOrder.verify(mUsageStatsManagerInternal, timeout(DEFAULT_WAIT_MS))
                .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID);
        // The allowance shouldn't shift the alarm
        verify(mAlarmManager, timeout(DEFAULT_WAIT_MS).times(1))
                .setWindow(
                        anyInt(), eq(sElapsedRealtimeClock.millis() + 3 * HOUR_IN_MILLIS),
                        anyLong(), eq(TAG_PREFETCH), any(), any());
        assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));

        mEstimatedLaunchTimeChangedListener.onEstimatedLaunchTimeChanged(SOURCE_USER_ID,
                SOURCE_PACKAGE, sSystemClock.millis() + HOUR_IN_MILLIS);

        inOrder.verify(mUsageStatsManagerInternal, timeout(DEFAULT_WAIT_MS).times(0))
                .getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID);
        verify(mJobSchedulerService, timeout(DEFAULT_WAIT_MS)).onControllerStateChanged(any());
        assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));

        sSystemClock = getShiftedClock(sSystemClock, HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
    }
}