summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java28
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java50
2 files changed, 60 insertions, 18 deletions
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 1c29982dbd48..4dc37de8a633 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
@@ -36,6 +36,7 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.UidObserver;
+import android.app.job.JobInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
@@ -772,18 +773,23 @@ public final class QuotaController extends StateController {
if (!jobStatus.shouldTreatAsExpeditedJob()) {
// If quota is currently "free", then the job can run for the full amount of time,
// regardless of bucket (hence using charging instead of isQuotaFreeLocked()).
- if (mService.isBatteryCharging()
- // The top and foreground cases here were added because apps in those states
- // aren't really restricted and the work could be something the user is
- // waiting for. Now that user-initiated jobs are a defined concept, we may
- // not need these exemptions as much. However, UIJs are currently limited
- // (as of UDC) to data transfer work. There may be other work that could
- // rely on this exception. Once we add more UIJ types, we can re-evaluate
- // the need for these exceptions.
- // TODO: re-evaluate the need for these exceptions
- || mTopAppCache.get(jobStatus.getSourceUid())
+ if (mService.isBatteryCharging()) {
+ return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
+ }
+ // The top and foreground cases here were added because apps in those states
+ // aren't really restricted and the work could be something the user is
+ // waiting for. Now that user-initiated jobs are a defined concept, we may
+ // not need these exemptions as much. However, UIJs are currently limited
+ // (as of UDC) to data transfer work. There may be other work that could
+ // rely on this exception. Once we add more UIJ types, we can re-evaluate
+ // the need for these exceptions.
+ // TODO: re-evaluate the need for these exceptions
+ final boolean isInPrivilegedState = mTopAppCache.get(jobStatus.getSourceUid())
|| isTopStartedJobLocked(jobStatus)
- || isUidInForeground(jobStatus.getSourceUid())) {
+ || isUidInForeground(jobStatus.getSourceUid());
+ final boolean isJobImportant = jobStatus.getEffectivePriority() >= JobInfo.PRIORITY_HIGH
+ || (jobStatus.getFlags() & JobInfo.FLAG_IMPORTANT_WHILE_FOREGROUND) != 0;
+ if (isInPrivilegedState && isJobImportant) {
return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
}
return getTimeUntilQuotaConsumedLocked(
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 a250ac75635b..07027645411d 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
@@ -368,10 +368,15 @@ public class QuotaControllerTest {
}
}
+ private JobInfo.Builder createJobInfoBuilder(int jobId) {
+ return new JobInfo.Builder(jobId, new ComponentName(mContext, "TestQuotaJobService"));
+ }
+
private JobStatus createJobStatus(String testTag, int jobId) {
- JobInfo jobInfo = new JobInfo.Builder(jobId,
- new ComponentName(mContext, "TestQuotaJobService"))
- .build();
+ return createJobStatus(testTag, createJobInfoBuilder(jobId).build());
+ }
+
+ private JobStatus createJobStatus(String testTag, JobInfo jobInfo) {
return createJobStatus(testTag, SOURCE_PACKAGE, CALLING_UID, jobInfo);
}
@@ -1333,39 +1338,70 @@ public class QuotaControllerTest {
mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
createTimingSession(sElapsedRealtimeClock.millis() - (6 * MINUTE_IN_MILLIS),
3 * MINUTE_IN_MILLIS, 5), false);
+ final long timeUntilQuotaConsumedMs = 7 * MINUTE_IN_MILLIS;
JobStatus job = createJobStatus("testGetMaxJobExecutionTimeLocked", 0);
+ //noinspection deprecation
+ JobStatus jobDefIWF = createJobStatus("testGetMaxJobExecutionTimeLocked",
+ createJobInfoBuilder(1)
+ .setImportantWhileForeground(true)
+ .setPriority(JobInfo.PRIORITY_DEFAULT)
+ .build());
+ JobStatus jobHigh = createJobStatus("testGetMaxJobExecutionTimeLocked",
+ createJobInfoBuilder(2).setPriority(JobInfo.PRIORITY_HIGH).build());
setStandbyBucket(RARE_INDEX, job);
+ setStandbyBucket(RARE_INDEX, jobDefIWF);
+ setStandbyBucket(RARE_INDEX, jobHigh);
setCharging();
synchronized (mQuotaController.mLock) {
assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+ assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((jobDefIWF)));
+ assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((jobHigh)));
}
setDischarging();
setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
synchronized (mQuotaController.mLock) {
- assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(timeUntilQuotaConsumedMs,
mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+ assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((jobDefIWF)));
+ assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((jobHigh)));
}
// Top-started job
setProcessState(ActivityManager.PROCESS_STATE_TOP);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStartTrackingJobLocked(job, null);
+ trackJobs(job, jobDefIWF, jobHigh);
mQuotaController.prepareForExecutionLocked(job);
+ mQuotaController.prepareForExecutionLocked(jobDefIWF);
+ mQuotaController.prepareForExecutionLocked(jobHigh);
}
setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
synchronized (mQuotaController.mLock) {
- assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ assertEquals(timeUntilQuotaConsumedMs,
mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+ assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((jobDefIWF)));
+ assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((jobHigh)));
mQuotaController.maybeStopTrackingJobLocked(job, null);
+ mQuotaController.maybeStopTrackingJobLocked(jobDefIWF, null);
+ mQuotaController.maybeStopTrackingJobLocked(jobHigh, null);
}
setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
synchronized (mQuotaController.mLock) {
- assertEquals(7 * MINUTE_IN_MILLIS,
+ assertEquals(timeUntilQuotaConsumedMs,
mQuotaController.getMaxJobExecutionTimeMsLocked(job));
+ assertEquals(timeUntilQuotaConsumedMs,
+ mQuotaController.getMaxJobExecutionTimeMsLocked(jobDefIWF));
+ assertEquals(timeUntilQuotaConsumedMs,
+ mQuotaController.getMaxJobExecutionTimeMsLocked(jobHigh));
}
}