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 1910553327e12..df0a0ee386746 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -1502,11 +1502,14 @@ public class JobSchedulerService extends com.android.server.SystemService mControllers.add(mBatteryController); mStorageController = new StorageController(this); mControllers.add(mStorageController); - mControllers.add(new BackgroundJobsController(this)); + final BackgroundJobsController backgroundJobsController = + new BackgroundJobsController(this); + mControllers.add(backgroundJobsController); mControllers.add(new ContentObserverController(this)); mDeviceIdleJobsController = new DeviceIdleJobsController(this); mControllers.add(mDeviceIdleJobsController); - mQuotaController = new QuotaController(this); + mQuotaController = + new QuotaController(this, backgroundJobsController, connectivityController); mControllers.add(mQuotaController); mControllers.add(new ComponentController(this)); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java index f647db901f481..04d694778e1a3 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java @@ -77,6 +77,11 @@ public final class BackgroundJobsController extends StateController { boolean forUpdate) { } + @Override + public void evaluateStateLocked(JobStatus jobStatus) { + updateSingleJobRestrictionLocked(jobStatus, UNKNOWN); + } + @Override public void dumpControllerStateLocked(final IndentingPrintWriter pw, final Predicate predicate) { diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index cd7124719d30a..51525e0c38f50 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -1151,6 +1151,11 @@ public final class JobStatus { if (setConstraintSatisfied(CONSTRAINT_WITHIN_EXPEDITED_QUOTA, state)) { // The constraint was changed. Update the ready flag. mReadyWithinExpeditedQuota = state; + // DeviceIdleJobsController currently only tracks jobs with the WILL_BE_FOREGROUND flag. + // Making it also track requested-expedited jobs would add unnecessary hops since the + // controller would then defer to canRunInDoze. Avoid the hops and just update + // mReadyNotDozing directly. + mReadyNotDozing = isConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING) || canRunInDoze(); return true; } return false; 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 7b87dfbae2f6b..2d55aa5d54954 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 @@ -347,6 +347,9 @@ public final class QuotaController extends StateController { private final QcHandler mHandler; private final QcConstants mQcConstants; + private final BackgroundJobsController mBackgroundJobsController; + private final ConnectivityController mConnectivityController; + /** How much time each app will have to run jobs within their standby bucket window. */ private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS; @@ -552,7 +555,9 @@ public final class QuotaController extends StateController { */ private static final int MSG_PROCESS_USAGE_EVENT = 5; - public QuotaController(JobSchedulerService service) { + public QuotaController(@NonNull JobSchedulerService service, + @NonNull BackgroundJobsController backgroundJobsController, + @NonNull ConnectivityController connectivityController) { super(service); mHandler = new QcHandler(mContext.getMainLooper()); mChargeTracker = new ChargingTracker(); @@ -560,6 +565,8 @@ public final class QuotaController extends StateController { mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); mQcConstants = new QcConstants(); + mBackgroundJobsController = backgroundJobsController; + mConnectivityController = connectivityController; final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null); @@ -596,7 +603,7 @@ public final class QuotaController extends StateController { final boolean outOfEJQuota; if (jobStatus.isRequestedExpeditedJob()) { final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus); - jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinEJQuota); + setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota); outOfEJQuota = !isWithinEJQuota; } else { outOfEJQuota = false; @@ -1473,7 +1480,7 @@ public final class QuotaController extends StateController { if (js.isRequestedExpeditedJob()) { boolean isWithinEJQuota = isWithinEJQuotaLocked(js); - changed |= js.setExpeditedJobQuotaConstraintSatisfied(isWithinEJQuota); + changed |= setExpeditedConstraintSatisfied(js, isWithinEJQuota); outOfEJQuota |= !isWithinEJQuota; } } @@ -1499,7 +1506,7 @@ public final class QuotaController extends StateController { final boolean outOfEJQuota; if (jobStatus.isRequestedExpeditedJob()) { final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus); - wasJobChanged |= jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinEJQuota); + wasJobChanged |= setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota); outOfEJQuota = !isWithinEJQuota; } else { outOfEJQuota = false; @@ -1650,6 +1657,23 @@ public final class QuotaController extends StateController { return jobStatus.setQuotaConstraintSatisfied(isWithinQuota); } + /** + * If the satisfaction changes, this will tell connectivity & background jobs controller to + * also re-evaluate their state. + */ + private boolean setExpeditedConstraintSatisfied(@NonNull JobStatus jobStatus, + boolean isWithinQuota) { + if (jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinQuota)) { + mBackgroundJobsController.evaluateStateLocked(jobStatus); + mConnectivityController.evaluateStateLocked(jobStatus); + if (isWithinQuota && jobStatus.isReady()) { + mStateChangedListener.onRunJobNow(jobStatus); + } + return true; + } + return false; + } + private final class ChargingTracker extends BroadcastReceiver { /** * Track whether we're charging. This has a slightly different definition than that of 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 344a19a634877..05f1ed8a20b3d 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 @@ -209,7 +209,8 @@ public class QuotaControllerTest { ArgumentCaptor.forClass(BroadcastReceiver.class); ArgumentCaptor uidObserverCaptor = ArgumentCaptor.forClass(IUidObserver.class); - mQuotaController = new QuotaController(mJobSchedulerService); + mQuotaController = new QuotaController(mJobSchedulerService, + mock(BackgroundJobsController.class), mock(ConnectivityController.class)); verify(mContext).registerReceiver(receiverCaptor.capture(), any()); mChargingReceiver = receiverCaptor.getValue();