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

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

Merge "Let apps timeout into the RESTRICTED bucket."

parents 1a9afb72 4297b5da
Loading
Loading
Loading
Loading
+66 −16
Original line number Diff line number Diff line
@@ -136,25 +136,59 @@ public class AppStandbyController implements AppStandbyInternal {
    private static final long ONE_HOUR = ONE_MINUTE * 60;
    private static final long ONE_DAY = ONE_HOUR * 24;

    static final long[] SCREEN_TIME_THRESHOLDS = {
    /**
     * The minimum amount of time the screen must have been on before an app can time out from its
     * current bucket to the next bucket.
     */
    private static final long[] SCREEN_TIME_THRESHOLDS = {
            0,
            0,
            COMPRESS_TIME ? 120 * 1000 : 1 * ONE_HOUR,
            COMPRESS_TIME ? 240 * 1000 : 2 * ONE_HOUR
            COMPRESS_TIME ? 2 * ONE_MINUTE : 1 * ONE_HOUR,
            COMPRESS_TIME ? 4 * ONE_MINUTE : 2 * ONE_HOUR,
            COMPRESS_TIME ? 8 * ONE_MINUTE : 6 * ONE_HOUR
    };

    static final long[] ELAPSED_TIME_THRESHOLDS = {
    /** The minimum allowed values for each index in {@link #SCREEN_TIME_THRESHOLDS}. */
    private static final long[] MINIMUM_SCREEN_TIME_THRESHOLDS = COMPRESS_TIME
            ? new long[SCREEN_TIME_THRESHOLDS.length]
            : new long[]{
                    0,
                    0,
                    0,
                    30 * ONE_MINUTE,
                    ONE_HOUR
            };

    /**
     * The minimum amount of elapsed time that must have passed before an app can time out from its
     * current bucket to the next bucket.
     */
    private static final long[] ELAPSED_TIME_THRESHOLDS = {
            0,
            COMPRESS_TIME ?  1 * ONE_MINUTE : 12 * ONE_HOUR,
            COMPRESS_TIME ?  4 * ONE_MINUTE : 24 * ONE_HOUR,
            COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR
            COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR,
            // TODO(149050681): increase timeout to 30+ days
            COMPRESS_TIME ? 32 * ONE_MINUTE : 4 * ONE_DAY
    };

    static final int[] THRESHOLD_BUCKETS = {
    /** The minimum allowed values for each index in {@link #ELAPSED_TIME_THRESHOLDS}. */
    private static final long[] MINIMUM_ELAPSED_TIME_THRESHOLDS = COMPRESS_TIME
            ? new long[ELAPSED_TIME_THRESHOLDS.length]
            : new long[]{
                    0,
                    ONE_HOUR,
                    ONE_HOUR,
                    2 * ONE_HOUR,
                    4 * ONE_DAY
            };

    private static final int[] THRESHOLD_BUCKETS = {
            STANDBY_BUCKET_ACTIVE,
            STANDBY_BUCKET_WORKING_SET,
            STANDBY_BUCKET_FREQUENT,
            STANDBY_BUCKET_RARE
            STANDBY_BUCKET_RARE,
            STANDBY_BUCKET_RESTRICTED
    };

    /** Default expiration time for bucket prediction. After this, use thresholds to downgrade. */
@@ -204,7 +238,15 @@ public class AppStandbyController implements AppStandbyInternal {
    static final int MSG_REPORT_EXEMPTED_SYNC_START = 13;

    long mCheckIdleIntervalMillis;
    /**
     * The minimum amount of time the screen must have been on before an app can time out from its
     * current bucket to the next bucket.
     */
    long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS;
    /**
     * The minimum amount of elapsed time that must have passed before an app can time out from its
     * current bucket to the next bucket.
     */
    long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS;
    /** Minimum time a strong usage event should keep the bucket elevated. */
    long mStrongUsageTimeoutMillis;
@@ -1147,9 +1189,11 @@ public class AppStandbyController implements AppStandbyInternal {
            final boolean isForcedByUser =
                    (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER;

            // If the current bucket is RESTRICTED, only user force or usage should bring it out.
            // If the current bucket is RESTRICTED, only user force or usage should bring it out,
            // unless the app was put into the bucket due to timing out.
            if (app.currentBucket == STANDBY_BUCKET_RESTRICTED && !isUserUsage(reason)
                    && !isForcedByUser) {
                    && !isForcedByUser
                    && (app.bucketingReason & REASON_MAIN_MASK) != REASON_MAIN_TIMEOUT) {
                return;
            }

@@ -1829,12 +1873,12 @@ public class AppStandbyController implements AppStandbyInternal {

                String screenThresholdsValue = mParser.getString(KEY_SCREEN_TIME_THRESHOLDS, null);
                mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue,
                        SCREEN_TIME_THRESHOLDS);
                        SCREEN_TIME_THRESHOLDS, MINIMUM_SCREEN_TIME_THRESHOLDS);

                String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS,
                        null);
                mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue,
                        ELAPSED_TIME_THRESHOLDS);
                        ELAPSED_TIME_THRESHOLDS, MINIMUM_ELAPSED_TIME_THRESHOLDS);
                mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4,
                        COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours
                mStrongUsageTimeoutMillis = mParser.getDurationMillis(
@@ -1870,8 +1914,8 @@ public class AppStandbyController implements AppStandbyInternal {

                mUnexemptedSyncScheduledTimeoutMillis = mParser.getDurationMillis(
                        KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION,
                                COMPRESS_TIME ? ONE_MINUTE
                                        : DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT); // TODO
                                COMPRESS_TIME
                                        ? ONE_MINUTE : DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT);

                mSystemInteractionTimeoutMillis = mParser.getDurationMillis(
                        KEY_SYSTEM_INTERACTION_HOLD_DURATION,
@@ -1888,7 +1932,7 @@ public class AppStandbyController implements AppStandbyInternal {
            setAppIdleEnabled(mInjector.isAppIdleEnabled());
        }

        long[] parseLongArray(String values, long[] defaults) {
        long[] parseLongArray(String values, long[] defaults, long[] minValues) {
            if (values == null) return defaults;
            if (values.isEmpty()) {
                // Reset to defaults
@@ -1896,13 +1940,19 @@ public class AppStandbyController implements AppStandbyInternal {
            } else {
                String[] thresholds = values.split("/");
                if (thresholds.length == THRESHOLD_BUCKETS.length) {
                    if (minValues.length != THRESHOLD_BUCKETS.length) {
                        Slog.wtf(TAG, "minValues array is the wrong size");
                        // Use zeroes as the minimums.
                        minValues = new long[THRESHOLD_BUCKETS.length];
                    }
                    long[] array = new long[THRESHOLD_BUCKETS.length];
                    for (int i = 0; i < THRESHOLD_BUCKETS.length; i++) {
                        try {
                            if (thresholds[i].startsWith("P") || thresholds[i].startsWith("p")) {
                                array[i] = Duration.parse(thresholds[i]).toMillis();
                                array[i] = Math.max(minValues[i],
                                        Duration.parse(thresholds[i]).toMillis());
                            } else {
                                array[i] = Long.parseLong(thresholds[i]);
                                array[i] = Math.max(minValues[i], Long.parseLong(thresholds[i]));
                            }
                        } catch (NumberFormatException|DateTimeParseException e) {
                            return defaults;
+27 −8
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ public class AppStandbyControllerTests {
    private static final long WORKING_SET_THRESHOLD = 12 * HOUR_MS;
    private static final long FREQUENT_THRESHOLD = 24 * HOUR_MS;
    private static final long RARE_THRESHOLD = 48 * HOUR_MS;
    private static final long RESTRICTED_THRESHOLD = 96 * HOUR_MS;

    /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */
    private static boolean isPackageInstalled = true;
@@ -232,9 +233,8 @@ public class AppStandbyControllerTests {
        @Override
        String getAppIdleSettings() {
            return "screen_thresholds=0/0/0/" + HOUR_MS + ",elapsed_thresholds=0/"
                    + WORKING_SET_THRESHOLD + "/"
                    + FREQUENT_THRESHOLD + "/"
                    + RARE_THRESHOLD;
                    + WORKING_SET_THRESHOLD + "/" + FREQUENT_THRESHOLD + "/" + RARE_THRESHOLD
                    + "/" + RESTRICTED_THRESHOLD;
        }

        @Override
@@ -372,12 +372,15 @@ public class AppStandbyControllerTests {
        // RARE bucket
        assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE);

        // RESTRICTED bucket
        assertTimeout(mController, RESTRICTED_THRESHOLD + 1, STANDBY_BUCKET_RESTRICTED);

        reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1, PACKAGE_1);

        assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE);

        // RARE bucket
        assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE);
        // RESTRICTED bucket
        assertTimeout(mController, RESTRICTED_THRESHOLD * 2 + 2, STANDBY_BUCKET_RESTRICTED);
    }

    @Test
@@ -437,7 +440,7 @@ public class AppStandbyControllerTests {
        assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));

        mInjector.setDisplayOn(true);
        assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE);
        assertTimeout(mController, RARE_THRESHOLD + 2 * HOUR_MS + 1, STANDBY_BUCKET_RARE);
    }

    @Test
@@ -642,7 +645,7 @@ public class AppStandbyControllerTests {
        assertBucket(STANDBY_BUCKET_FREQUENT);

        // Way past prediction timeout, use system thresholds
        mInjector.mElapsedRealtime = RARE_THRESHOLD * 4;
        mInjector.mElapsedRealtime = RARE_THRESHOLD;
        mController.checkIdleStates(USER_ID);
        assertBucket(STANDBY_BUCKET_RARE);
    }
@@ -669,7 +672,7 @@ public class AppStandbyControllerTests {
        assertBucket(STANDBY_BUCKET_RESTRICTED);

        // Way past all timeouts. Make sure timeout processing doesn't raise bucket.
        mInjector.mElapsedRealtime += RARE_THRESHOLD * 4;
        mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
        mController.checkIdleStates(USER_ID);
        assertBucket(STANDBY_BUCKET_RESTRICTED);
    }
@@ -696,6 +699,22 @@ public class AppStandbyControllerTests {
        assertBucket(STANDBY_BUCKET_RESTRICTED);
    }

    @Test
    public void testPredictionRaiseFromRestrictedTimeout() {
        reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);

        // Way past all timeouts. App times out into RESTRICTED bucket.
        mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
        mController.checkIdleStates(USER_ID);
        assertBucket(STANDBY_BUCKET_RESTRICTED);

        // Since the app timed out into RESTRICTED, prediction should be able to remove from the
        // bucket.
        mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
                REASON_MAIN_PREDICTED);
    }

    @Test
    public void testCascadingTimeouts() throws Exception {
        reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);