Loading apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +15 −2 Original line number Diff line number Diff line Loading @@ -1099,7 +1099,7 @@ public final class QuotaController extends StateController { final long maxExecutionTimeRemainingMs = mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs; if (allowedTimeRemainingMs <= 0 || maxExecutionTimeRemainingMs <= 0) { if (maxExecutionTimeRemainingMs <= 0) { return 0; } Loading @@ -1110,6 +1110,10 @@ public final class QuotaController extends StateController { sessions, startMaxElapsed, maxExecutionTimeRemainingMs); } if (allowedTimeRemainingMs <= 0) { return 0; } // Need to check both max time and period time in case one is less than the other. // For example, max time remaining could be less than bucket time remaining, but sessions // contributing to the max time remaining could phase out enough that we'd want to use the Loading Loading @@ -2147,6 +2151,7 @@ public final class QuotaController extends StateController { Slog.v(TAG, "Starting to track " + jobStatus.toShortString()); } // Always maintain list of running jobs, even when quota is free. final boolean priorityLowered = mLowestPriority > jobStatus.getEffectivePriority(); mLowestPriority = Math.min(mLowestPriority, jobStatus.getEffectivePriority()); if (mRunningBgJobs.add(jobStatus) && shouldTrackLocked()) { mBgJobCount++; Loading @@ -2163,6 +2168,8 @@ public final class QuotaController extends StateController { invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName); } scheduleCutoff(); } else if (mRegularJobTimer && priorityLowered) { scheduleCutoff(); } } } Loading @@ -2188,12 +2195,18 @@ public final class QuotaController extends StateController { emitSessionLocked(nowElapsed); cancelCutoff(); mLowestPriority = JobInfo.PRIORITY_MAX; } else if (mLowestPriority == jobStatus.getEffectivePriority()) { } else if (mRegularJobTimer && mLowestPriority == jobStatus.getEffectivePriority()) { // Lowest priority doesn't matter for EJ timers. final int oldPriority = mLowestPriority; mLowestPriority = JobInfo.PRIORITY_MAX; for (int i = mRunningBgJobs.size() - 1; i >= 0; --i) { mLowestPriority = Math.min(mLowestPriority, mRunningBgJobs.valueAt(i).getEffectivePriority()); } if (mLowestPriority != oldPriority) { scheduleCutoff(); } } } } Loading services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -321,6 +321,8 @@ public class QuotaControllerTest { private int bucketIndexToUsageStatsBucket(int bucketIndex) { switch (bucketIndex) { case EXEMPTED_INDEX: return UsageStatsManager.STANDBY_BUCKET_EXEMPTED; case ACTIVE_INDEX: return UsageStatsManager.STANDBY_BUCKET_ACTIVE; case WORKING_INDEX: Loading Loading @@ -1482,6 +1484,34 @@ public class QuotaControllerTest { } } /** * Test getTimeUntilQuotaConsumedLocked when allowed time equals the bucket window size. */ @Test public void testGetTimeUntilQuotaConsumedLocked_AllowedEqualsWindow() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, createTimingSession(now - (8 * HOUR_IN_MILLIS), 20 * 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 - 30 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); } } /** * Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket * window. Loading Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +15 −2 Original line number Diff line number Diff line Loading @@ -1099,7 +1099,7 @@ public final class QuotaController extends StateController { final long maxExecutionTimeRemainingMs = mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs; if (allowedTimeRemainingMs <= 0 || maxExecutionTimeRemainingMs <= 0) { if (maxExecutionTimeRemainingMs <= 0) { return 0; } Loading @@ -1110,6 +1110,10 @@ public final class QuotaController extends StateController { sessions, startMaxElapsed, maxExecutionTimeRemainingMs); } if (allowedTimeRemainingMs <= 0) { return 0; } // Need to check both max time and period time in case one is less than the other. // For example, max time remaining could be less than bucket time remaining, but sessions // contributing to the max time remaining could phase out enough that we'd want to use the Loading Loading @@ -2147,6 +2151,7 @@ public final class QuotaController extends StateController { Slog.v(TAG, "Starting to track " + jobStatus.toShortString()); } // Always maintain list of running jobs, even when quota is free. final boolean priorityLowered = mLowestPriority > jobStatus.getEffectivePriority(); mLowestPriority = Math.min(mLowestPriority, jobStatus.getEffectivePriority()); if (mRunningBgJobs.add(jobStatus) && shouldTrackLocked()) { mBgJobCount++; Loading @@ -2163,6 +2168,8 @@ public final class QuotaController extends StateController { invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName); } scheduleCutoff(); } else if (mRegularJobTimer && priorityLowered) { scheduleCutoff(); } } } Loading @@ -2188,12 +2195,18 @@ public final class QuotaController extends StateController { emitSessionLocked(nowElapsed); cancelCutoff(); mLowestPriority = JobInfo.PRIORITY_MAX; } else if (mLowestPriority == jobStatus.getEffectivePriority()) { } else if (mRegularJobTimer && mLowestPriority == jobStatus.getEffectivePriority()) { // Lowest priority doesn't matter for EJ timers. final int oldPriority = mLowestPriority; mLowestPriority = JobInfo.PRIORITY_MAX; for (int i = mRunningBgJobs.size() - 1; i >= 0; --i) { mLowestPriority = Math.min(mLowestPriority, mRunningBgJobs.valueAt(i).getEffectivePriority()); } if (mLowestPriority != oldPriority) { scheduleCutoff(); } } } } Loading
services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -321,6 +321,8 @@ public class QuotaControllerTest { private int bucketIndexToUsageStatsBucket(int bucketIndex) { switch (bucketIndex) { case EXEMPTED_INDEX: return UsageStatsManager.STANDBY_BUCKET_EXEMPTED; case ACTIVE_INDEX: return UsageStatsManager.STANDBY_BUCKET_ACTIVE; case WORKING_INDEX: Loading Loading @@ -1482,6 +1484,34 @@ public class QuotaControllerTest { } } /** * Test getTimeUntilQuotaConsumedLocked when allowed time equals the bucket window size. */ @Test public void testGetTimeUntilQuotaConsumedLocked_AllowedEqualsWindow() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, createTimingSession(now - (8 * HOUR_IN_MILLIS), 20 * 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 - 30 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); } } /** * Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket * window. Loading