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

Commit 7bdf3c61 authored by Amith Yamasani's avatar Amith Yamasani Committed by android-build-merger
Browse files

Merge "Fallback to ML prediction after short ACTIVE states" into pi-dev

am: 50c069e4

Change-Id: Idd2b0abba22ec10e263fe3ab49ecc7346b9bc941
parents 93c6045a 50c069e4
Loading
Loading
Loading
Loading
+17 −9
Original line number Diff line number Diff line
@@ -184,6 +184,9 @@ public final class UsageStatsManager {
    /** @hide */
    public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV  = 0x000A;

    /** @hide */
    public static final int REASON_SUB_PREDICTED_RESTORED       = 0x0001;

    /** @hide */
    @IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = {
            STANDBY_BUCKET_EXEMPTED,
@@ -620,36 +623,41 @@ public final class UsageStatsManager {
                break;
            case REASON_MAIN_PREDICTED:
                sb.append("p");
                switch (standbyReason & REASON_SUB_MASK) {
                    case REASON_SUB_PREDICTED_RESTORED:
                        sb.append("-r");
                        break;
                }
                break;
            case REASON_MAIN_TIMEOUT:
                sb.append("t");
                break;
            case REASON_MAIN_USAGE:
                sb.append("u-");
                sb.append("u");
                switch (standbyReason & REASON_SUB_MASK) {
                    case REASON_SUB_USAGE_SYSTEM_INTERACTION:
                        sb.append("si");
                        sb.append("-si");
                        break;
                    case REASON_SUB_USAGE_NOTIFICATION_SEEN:
                        sb.append("ns");
                        sb.append("-ns");
                        break;
                    case REASON_SUB_USAGE_USER_INTERACTION:
                        sb.append("ui");
                        sb.append("-ui");
                        break;
                    case REASON_SUB_USAGE_MOVE_TO_FOREGROUND:
                        sb.append("mf");
                        sb.append("-mf");
                        break;
                    case REASON_SUB_USAGE_MOVE_TO_BACKGROUND:
                        sb.append("mb");
                        sb.append("-mb");
                        break;
                    case REASON_SUB_USAGE_SYSTEM_UPDATE:
                        sb.append("su");
                        sb.append("-su");
                        break;
                    case REASON_SUB_USAGE_ACTIVE_TIMEOUT:
                        sb.append("at");
                        sb.append("-at");
                        break;
                    case REASON_SUB_USAGE_SYNC_ADAPTER:
                        sb.append("sa");
                        sb.append("-sa");
                        break;
                    case REASON_SUB_USAGE_SLICE_PINNED:
                        sb.append("slp");
+35 −25
Original line number Diff line number Diff line
@@ -281,6 +281,7 @@ public class AppStandbyControllerTests {
        MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
        mInjector = new MyInjector(myContext, Looper.getMainLooper());
        mController = setupController();
        setChargingState(mController, false);
    }

    @Test
@@ -381,8 +382,6 @@ public class AppStandbyControllerTests {

    @Test
    public void testForcedIdle() throws Exception {
        setChargingState(mController, false);

        mController.forceIdleState(PACKAGE_1, USER_ID, true);
        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
        assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
@@ -395,8 +394,6 @@ public class AppStandbyControllerTests {

    @Test
    public void testNotificationEvent() throws Exception {
        setChargingState(mController, false);

        reportEvent(mController, USER_INTERACTION, 0);
        assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
        mInjector.mElapsedRealtime = 1;
@@ -410,8 +407,6 @@ public class AppStandbyControllerTests {

    @Test
    public void testSlicePinnedEvent() throws Exception {
        setChargingState(mController, false);

        reportEvent(mController, USER_INTERACTION, 0);
        assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
        mInjector.mElapsedRealtime = 1;
@@ -425,8 +420,6 @@ public class AppStandbyControllerTests {

    @Test
    public void testSlicePinnedPrivEvent() throws Exception {
        setChargingState(mController, false);

        mController.forceIdleState(PACKAGE_1, USER_ID, true);
        reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime);
        assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
@@ -434,14 +427,13 @@ public class AppStandbyControllerTests {

    @Test
    public void testPredictionTimedout() throws Exception {
        setChargingState(mController, false);
        // Set it to timeout or usage, so that prediction can override it
        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
                REASON_MAIN_TIMEOUT, 1 * HOUR_MS);
                REASON_MAIN_TIMEOUT, HOUR_MS);
        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));

        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
                REASON_MAIN_PREDICTED, 1 * HOUR_MS);
                REASON_MAIN_PREDICTED, HOUR_MS);
        assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));

        // Fast forward 12 hours
@@ -464,7 +456,6 @@ public class AppStandbyControllerTests {

    @Test
    public void testOverrides() throws Exception {
        setChargingState(mController, false);
        // Can force to NEVER
        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
                REASON_MAIN_FORCED, 1 * HOUR_MS);
@@ -494,8 +485,6 @@ public class AppStandbyControllerTests {

    @Test
    public void testTimeout() throws Exception {
        setChargingState(mController, false);

        reportEvent(mController, USER_INTERACTION, 0);
        assertBucket(STANDBY_BUCKET_ACTIVE);

@@ -505,19 +494,19 @@ public class AppStandbyControllerTests {
        assertBucket(STANDBY_BUCKET_ACTIVE);

        // bucketing works after timeout
        mInjector.mElapsedRealtime = FREQUENT_THRESHOLD - 100;
        mInjector.mElapsedRealtime = mController.mPredictionTimeoutMillis - 100;
        mController.checkIdleStates(USER_ID);
        assertBucket(STANDBY_BUCKET_WORKING_SET);

        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
                REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
        // Use recent prediction
        assertBucket(STANDBY_BUCKET_FREQUENT);

        // Way past prediction timeout, use system thresholds
        mInjector.mElapsedRealtime = RARE_THRESHOLD * 4;
        mController.checkIdleStates(USER_ID);
        assertBucket(STANDBY_BUCKET_RARE);
    }

    @Test
    public void testCascadingTimeouts() throws Exception {
        setChargingState(mController, false);

        reportEvent(mController, USER_INTERACTION, 0);
        assertBucket(STANDBY_BUCKET_ACTIVE);

@@ -539,8 +528,6 @@ public class AppStandbyControllerTests {

    @Test
    public void testOverlappingTimeouts() throws Exception {
        setChargingState(mController, false);

        reportEvent(mController, USER_INTERACTION, 0);
        assertBucket(STANDBY_BUCKET_ACTIVE);

@@ -596,8 +583,6 @@ public class AppStandbyControllerTests {

    @Test
    public void testPredictionNotOverridden() throws Exception {
        setChargingState(mController, false);

        reportEvent(mController, USER_INTERACTION, 0);
        assertBucket(STANDBY_BUCKET_ACTIVE);

@@ -622,6 +607,31 @@ public class AppStandbyControllerTests {
        assertBucket(STANDBY_BUCKET_ACTIVE);
    }

    @Test
    public void testPredictionStrikesBack() throws Exception {
        reportEvent(mController, USER_INTERACTION, 0);
        assertBucket(STANDBY_BUCKET_ACTIVE);

        // Predict to FREQUENT
        mInjector.mElapsedRealtime = RARE_THRESHOLD;
        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
                REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
        assertBucket(STANDBY_BUCKET_FREQUENT);

        // Add a short timeout event
        mInjector.mElapsedRealtime += 1000;
        reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime);
        assertBucket(STANDBY_BUCKET_ACTIVE);
        mInjector.mElapsedRealtime += 1000;
        mController.checkIdleStates(USER_ID);
        assertBucket(STANDBY_BUCKET_ACTIVE);

        // Verify it reverted to predicted
        mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD / 2;
        mController.checkIdleStates(USER_ID);
        assertBucket(STANDBY_BUCKET_FREQUENT);
    }

    @Test
    public void testAddActiveDeviceAdmin() {
        assertActiveAdmins(USER_ID, (String[]) null);
+17 −0
Original line number Diff line number Diff line
@@ -70,6 +70,8 @@ public class AppIdleHistory {
    private SparseArray<ArrayMap<String,AppUsageHistory>> mIdleHistory = new SparseArray<>();
    private static final long ONE_MINUTE = 60 * 1000;

    private static final int STANDBY_BUCKET_UNKNOWN = -1;

    @VisibleForTesting
    static final String APP_IDLE_FILENAME = "app_idle_stats.xml";
    private static final String TAG_PACKAGES = "packages";
@@ -111,6 +113,9 @@ public class AppIdleHistory {
        long lastUsedScreenTime;
        // Last predicted time using elapsed timebase
        long lastPredictedTime;
        // Last predicted bucket
        @UsageStatsManager.StandbyBuckets
        int lastPredictedBucket = STANDBY_BUCKET_UNKNOWN;
        // Standby bucket
        @UsageStatsManager.StandbyBuckets
        int currentBucket;
@@ -342,6 +347,7 @@ public class AppIdleHistory {
        appUsageHistory.bucketingReason = reason;
        if ((reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED) {
            appUsageHistory.lastPredictedTime = getElapsedTime(elapsedRealtime);
            appUsageHistory.lastPredictedBucket = bucket;
        }
        if (DEBUG) {
            Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
@@ -349,6 +355,17 @@ public class AppIdleHistory {
        }
    }

    /**
     * Update the prediction for the app but don't change the actual bucket
     * @param app The app for which the prediction was made
     * @param elapsedTimeAdjusted The elapsed time in the elapsed duration timebase
     * @param bucket The predicted bucket
     */
    public void updateLastPrediction(AppUsageHistory app, long elapsedTimeAdjusted, int bucket) {
        app.lastPredictedTime = elapsedTimeAdjusted;
        app.lastPredictedBucket = bucket;
    }

    /**
     * Marks the last time a job was run, with the given elapsedRealtime. The time stored is
     * based on the elapsed timebase.
+24 −9
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
@@ -539,12 +540,21 @@ public class AppStandbyController {
                }
                final int oldBucket = app.currentBucket;
                int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
                boolean predictionLate = false;
                boolean predictionLate = predictionTimedOut(app, elapsedRealtime);
                // Compute age-based bucket
                if (oldMainReason == REASON_MAIN_DEFAULT
                        || oldMainReason == REASON_MAIN_USAGE
                        || oldMainReason == REASON_MAIN_TIMEOUT
                        || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
                        || predictionLate) {

                    if (!predictionLate && app.lastPredictedBucket >= STANDBY_BUCKET_ACTIVE
                            && app.lastPredictedBucket <= STANDBY_BUCKET_RARE) {
                        newBucket = app.lastPredictedBucket;
                        reason = REASON_MAIN_PREDICTED | REASON_SUB_PREDICTED_RESTORED;
                        if (DEBUG) {
                            Slog.d(TAG, "Restored predicted newBucket = " + newBucket);
                        }
                    } else {
                        newBucket = getBucketForLocked(packageName, userId,
                                elapsedRealtime);
                        if (DEBUG) {
@@ -552,6 +562,8 @@ public class AppStandbyController {
                        }
                        reason = REASON_MAIN_TIMEOUT;
                    }
                }

                // Check if the app is within one of the timeouts for forced bucket elevation
                final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
                if (newBucket >= STANDBY_BUCKET_ACTIVE
@@ -588,8 +600,7 @@ public class AppStandbyController {

    /** Returns true if there hasn't been a prediction for the app in a while. */
    private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
        return (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED
                && app.lastPredictedTime > 0
        return app.lastPredictedTime > 0
                && mAppIdleHistory.getElapsedTime(elapsedRealtime)
                    - app.lastPredictedTime > mPredictionTimeoutMillis;
    }
@@ -1035,6 +1046,10 @@ public class AppStandbyController {
            if (predicted) {
                // Check if the app is within one of the timeouts for forced bucket elevation
                final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
                // In case of not using the prediction, just keep track of it for applying after
                // ACTIVE or WORKING_SET timeout.
                mAppIdleHistory.updateLastPrediction(app, elapsedTimeAdjusted, newBucket);

                if (newBucket > STANDBY_BUCKET_ACTIVE
                        && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
                    newBucket = STANDBY_BUCKET_ACTIVE;