diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 040a1164fc734..8bb03e911528e 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -2293,7 +2293,8 @@ public class JobSchedulerService extends com.android.server.SystemService /** Returns the maximum amount of time this job could run for. */ public long getMaxJobExecutionTimeMs(JobStatus job) { synchronized (mLock) { - return mQuotaController.getMaxJobExecutionTimeMsLocked(job); + return Math.min(mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, + mQuotaController.getMaxJobExecutionTimeMsLocked(job)); } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java index 2faa8360bf44f..b70e68b739d8d 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -995,12 +995,18 @@ public final class QuotaController extends StateController { if (standbyBucket == NEVER_INDEX) { return 0; } + List sessions = mTimingSessions.get(userId, packageName); + final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket); if (sessions == null || sessions.size() == 0) { + // Regular ACTIVE case. Since the bucket size equals the allowed time, the app jobs can + // essentially run until they reach the maximum limit. + if (stats.windowSizeMs == mAllowedTimePerPeriodMs) { + return mMaxExecutionTimeMs; + } return mAllowedTimePerPeriodMs; } - final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket); final long startWindowElapsed = nowElapsed - stats.windowSizeMs; final long startMaxElapsed = nowElapsed - MAX_PERIOD_MS; final long allowedTimeRemainingMs = mAllowedTimePerPeriodMs - stats.executionTimeInWindowMs; diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index bf95f4c51d960..29db7409131e5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -1325,6 +1325,46 @@ public class QuotaControllerTest { } } + @Test + public void testGetMaxJobExecutionTimeLocked_Regular_Active() { + JobStatus job = createJobStatus("testGetMaxJobExecutionTimeLocked_Regular_Active", 0); + setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, 10 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, 10 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_MAX_EXECUTION_TIME_MS, 2 * HOUR_IN_MILLIS); + setDischarging(); + setStandbyBucket(ACTIVE_INDEX, job); + setProcessState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY); + + // ACTIVE apps (where allowed time = window size) should be capped at max execution limit. + synchronized (mQuotaController.mLock) { + assertEquals(2 * HOUR_IN_MILLIS, + mQuotaController.getMaxJobExecutionTimeMsLocked((job))); + } + + // Make sure sessions are factored in properly. + mQuotaController.saveTimingSession(0, SOURCE_PACKAGE, + createTimingSession(sElapsedRealtimeClock.millis() - (6 * HOUR_IN_MILLIS), + 30 * MINUTE_IN_MILLIS, 1), false); + synchronized (mQuotaController.mLock) { + assertEquals(90 * MINUTE_IN_MILLIS, + mQuotaController.getMaxJobExecutionTimeMsLocked((job))); + } + + mQuotaController.saveTimingSession(0, SOURCE_PACKAGE, + createTimingSession(sElapsedRealtimeClock.millis() - (5 * HOUR_IN_MILLIS), + 30 * MINUTE_IN_MILLIS, 1), false); + mQuotaController.saveTimingSession(0, SOURCE_PACKAGE, + createTimingSession(sElapsedRealtimeClock.millis() - (4 * HOUR_IN_MILLIS), + 30 * MINUTE_IN_MILLIS, 1), false); + mQuotaController.saveTimingSession(0, SOURCE_PACKAGE, + createTimingSession(sElapsedRealtimeClock.millis() - (3 * HOUR_IN_MILLIS), + 25 * MINUTE_IN_MILLIS, 1), false); + synchronized (mQuotaController.mLock) { + assertEquals(5 * MINUTE_IN_MILLIS, + mQuotaController.getMaxJobExecutionTimeMsLocked((job))); + } + } + @Test public void testGetMaxJobExecutionTimeLocked_EJ() { final long timeUsedMs = 3 * MINUTE_IN_MILLIS;