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
This commit is contained in:
Kweku Adams
2022-02-11 22:54:13 +00:00
parent dd0811a649
commit 12efc59838
2 changed files with 94 additions and 2 deletions

View File

@@ -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;
}

View File

@@ -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) {