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

Commit 12efc598 authored by Kweku Adams's avatar Kweku Adams
Browse files

Account for session phase out.

It's possible for "time until quota is consumed" to be positive when
remaining time is 0 since TimingSessions may be phasing out of the
window. Properly account for that in the early returns.

Bug: 218216817
Test: atest FrameworksMockingServicesTests:QuotaControllerTest
Change-Id: I714b3f1bbdbb01c8d45e7b73bd5d2cfa16b29c4e
parent dd0811a6
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1099,7 +1099,7 @@ public final class QuotaController extends StateController {
        final long maxExecutionTimeRemainingMs =
                mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs;

        if (maxExecutionTimeRemainingMs <= 0) {
        if (maxExecutionTimeRemainingMs < 0) {
            return 0;
        }

@@ -1110,7 +1110,7 @@ public final class QuotaController extends StateController {
                    sessions, startMaxElapsed, maxExecutionTimeRemainingMs);
        }

        if (allowedTimeRemainingMs <= 0) {
        if (allowedTimeRemainingMs < 0) {
            return 0;
        }

+92 −0
Original line number Diff line number Diff line
@@ -1794,6 +1794,98 @@ public class QuotaControllerTest {
        }
    }

    /**
     * Test getTimeUntilQuotaConsumedLocked when allowed time equals the bucket window size.
     */
    @Test
    public void testGetTimeUntilQuotaConsumedLocked_EdgeOfWindow_AllowedEqualsWindow() {
        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                createTimingSession(now - (24 * HOUR_IN_MILLIS),
                        mQcConstants.MAX_EXECUTION_TIME_MS - 10 * MINUTE_IN_MILLIS, 5),
                false);
        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                createTimingSession(now - (10 * MINUTE_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5),
                false);

        setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS,
                10 * MINUTE_IN_MILLIS);
        setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_EXEMPTED_MS, 10 * MINUTE_IN_MILLIS);
        // window size = allowed time, so jobs can essentially run non-stop until they reach the
        // max execution time.
        setStandbyBucket(EXEMPTED_INDEX);
        synchronized (mQuotaController.mLock) {
            assertEquals(0,
                    mQuotaController.getRemainingExecutionTimeLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE));
            assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 10 * MINUTE_IN_MILLIS,
                    mQuotaController.getTimeUntilQuotaConsumedLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
        }
    }

    /**
     * Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket
     * window and the session is rolling out of the window.
     */
    @Test
    public void testGetTimeUntilQuotaConsumedLocked_EdgeOfWindow_BucketWindow() {
        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();

        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                createTimingSession(now - (24 * HOUR_IN_MILLIS),
                        10 * MINUTE_IN_MILLIS, 5), false);
        setStandbyBucket(RARE_INDEX);
        synchronized (mQuotaController.mLock) {
            assertEquals(0,
                    mQuotaController.getRemainingExecutionTimeLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE));
            assertEquals(10 * MINUTE_IN_MILLIS,
                    mQuotaController.getTimeUntilQuotaConsumedLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
        }

        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                createTimingSession(now - (8 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
        setStandbyBucket(FREQUENT_INDEX);
        synchronized (mQuotaController.mLock) {
            assertEquals(0,
                    mQuotaController.getRemainingExecutionTimeLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE));
            assertEquals(10 * MINUTE_IN_MILLIS,
                    mQuotaController.getTimeUntilQuotaConsumedLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
        }

        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                createTimingSession(now - (2 * HOUR_IN_MILLIS),
                        10 * MINUTE_IN_MILLIS, 5), false);
        setStandbyBucket(WORKING_INDEX);
        synchronized (mQuotaController.mLock) {
            assertEquals(0,
                    mQuotaController.getRemainingExecutionTimeLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE));
            assertEquals(10 * MINUTE_IN_MILLIS,
                    mQuotaController.getTimeUntilQuotaConsumedLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
        }

        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                createTimingSession(now - (10 * MINUTE_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5),
                false);
        // ACTIVE window = allowed time, so jobs can essentially run non-stop until they reach the
        // max execution time.
        setStandbyBucket(ACTIVE_INDEX);
        synchronized (mQuotaController.mLock) {
            assertEquals(0,
                    mQuotaController.getRemainingExecutionTimeLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE));
            assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 30 * MINUTE_IN_MILLIS,
                    mQuotaController.getTimeUntilQuotaConsumedLocked(
                            SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
        }
    }

    @Test
    public void testIsWithinQuotaLocked_NeverApp() {
        synchronized (mQuotaController.mLock) {