summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java93
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java6
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java71
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java70
6 files changed, 214 insertions, 39 deletions
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 900c90203f41..903248f5f0b4 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -159,6 +159,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -301,6 +302,8 @@ public class JobSchedulerService extends com.android.server.SystemService
private final ConnectivityController mConnectivityController;
/** Need directly for sending uid state changes */
private final DeviceIdleJobsController mDeviceIdleJobsController;
+ /** Need directly for sending exempted bucket changes */
+ private final FlexibilityController mFlexibilityController;
/** Needed to get next estimated launch time. */
private final PrefetchController mPrefetchController;
/** Needed to get remaining quota time. */
@@ -513,6 +516,10 @@ public class JobSchedulerService extends com.android.server.SystemService
if (name == null) {
continue;
}
+ if (DEBUG) {
+ Slog.d(TAG, "DeviceConfig " + name
+ + " changed to " + properties.getString(name, null));
+ }
switch (name) {
case Constants.KEY_ENABLE_API_QUOTAS:
case Constants.KEY_ENABLE_EXECUTION_SAFEGUARDS_UDC:
@@ -2532,17 +2539,17 @@ public class JobSchedulerService extends com.android.server.SystemService
mControllers = new ArrayList<StateController>();
mPrefetchController = new PrefetchController(this);
mControllers.add(mPrefetchController);
- final FlexibilityController flexibilityController =
+ mFlexibilityController =
new FlexibilityController(this, mPrefetchController);
- mControllers.add(flexibilityController);
+ mControllers.add(mFlexibilityController);
mConnectivityController =
- new ConnectivityController(this, flexibilityController);
+ new ConnectivityController(this, mFlexibilityController);
mControllers.add(mConnectivityController);
mControllers.add(new TimeController(this));
- final IdleController idleController = new IdleController(this, flexibilityController);
+ final IdleController idleController = new IdleController(this, mFlexibilityController);
mControllers.add(idleController);
final BatteryController batteryController =
- new BatteryController(this, flexibilityController);
+ new BatteryController(this, mFlexibilityController);
mControllers.add(batteryController);
mStorageController = new StorageController(this);
mControllers.add(mStorageController);
@@ -3191,6 +3198,13 @@ public class JobSchedulerService extends com.android.server.SystemService
}
@Override
+ public void onExemptedBucketChanged(@NonNull ArraySet<JobStatus> changedJobs) {
+ if (changedJobs.size() > 0) {
+ mFlexibilityController.onExemptedBucketChanged(changedJobs);
+ }
+ }
+
+ @Override
public void onRestrictionStateChanged(@NonNull JobRestriction restriction,
boolean stopOvertimeJobs) {
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
@@ -3497,7 +3511,10 @@ public class JobSchedulerService extends com.android.server.SystemService
}
final boolean shouldForceBatchJob;
- if (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob()) {
+ if (job.overrideState > JobStatus.OVERRIDE_NONE) {
+ // The job should run for some test. Don't force batch it.
+ shouldForceBatchJob = false;
+ } else if (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob()) {
// Never batch expedited or user-initiated jobs, even for RESTRICTED apps.
shouldForceBatchJob = false;
} else if (job.getEffectiveStandbyBucket() == RESTRICTED_INDEX) {
@@ -4950,6 +4967,8 @@ public class JobSchedulerService extends com.android.server.SystemService
Slog.d(TAG, "executeRunCommand(): " + pkgName + "/" + namespace + "/" + userId
+ " " + jobId + " s=" + satisfied + " f=" + force);
+ final CountDownLatch delayLatch = new CountDownLatch(1);
+ final JobStatus js;
try {
final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0,
userId != UserHandle.USER_ALL ? userId : UserHandle.USER_SYSTEM);
@@ -4958,7 +4977,7 @@ public class JobSchedulerService extends com.android.server.SystemService
}
synchronized (mLock) {
- final JobStatus js = mJobs.getJobByUidAndJobId(uid, namespace, jobId);
+ js = mJobs.getJobByUidAndJobId(uid, namespace, jobId);
if (js == null) {
return JobSchedulerShellCommand.CMD_ERR_NO_JOB;
}
@@ -4969,23 +4988,71 @@ public class JobSchedulerService extends com.android.server.SystemService
// Re-evaluate constraints after the override is set in case one of the overridden
// constraints was preventing another constraint from thinking it needed to update.
for (int c = mControllers.size() - 1; c >= 0; --c) {
- mControllers.get(c).reevaluateStateLocked(uid);
+ mControllers.get(c).evaluateStateLocked(js);
}
if (!js.isConstraintsSatisfied()) {
- js.overrideState = JobStatus.OVERRIDE_NONE;
- return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS;
+ if (js.hasConnectivityConstraint()
+ && !js.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)
+ && js.wouldBeReadyWithConstraint(JobStatus.CONSTRAINT_CONNECTIVITY)) {
+ // Because of how asynchronous the connectivity signals are, JobScheduler
+ // may not get the connectivity satisfaction signal immediately. In this
+ // case, wait a few seconds to see if it comes in before saying the
+ // connectivity constraint isn't satisfied.
+ mHandler.postDelayed(
+ checkConstraintRunnableForTesting(
+ mHandler, js, delayLatch, 5, 1000),
+ 1000);
+ } else {
+ // There's no asynchronous signal to wait for. We can immediately say the
+ // job's constraints aren't satisfied and return.
+ js.overrideState = JobStatus.OVERRIDE_NONE;
+ return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS;
+ }
+ } else {
+ delayLatch.countDown();
}
-
- queueReadyJobsForExecutionLocked();
- maybeRunPendingJobsLocked();
}
} catch (RemoteException e) {
// can't happen
+ return 0;
+ }
+
+ // Choose to block the return until we're sure about the state of the connectivity job
+ // so that tests can expect a reliable state after calling the run command.
+ try {
+ delayLatch.await(7L, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Couldn't wait for asynchronous constraint change", e);
+ }
+
+ synchronized (mLock) {
+ if (!js.isConstraintsSatisfied()) {
+ js.overrideState = JobStatus.OVERRIDE_NONE;
+ return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS;
+ }
+
+ queueReadyJobsForExecutionLocked();
+ maybeRunPendingJobsLocked();
}
return 0;
}
+ private static Runnable checkConstraintRunnableForTesting(@NonNull final Handler handler,
+ @NonNull final JobStatus js, @NonNull final CountDownLatch latch,
+ final int remainingAttempts, final long delayMs) {
+ return () -> {
+ if (remainingAttempts <= 0 || js.isConstraintsSatisfied()) {
+ latch.countDown();
+ return;
+ }
+ handler.postDelayed(
+ checkConstraintRunnableForTesting(
+ handler, js, latch, remainingAttempts - 1, delayMs),
+ delayMs);
+ };
+ }
+
// Shell command infrastructure: immediately timeout currently executing jobs
int executeStopCommand(PrintWriter pw, String pkgName, int userId,
@Nullable String namespace, boolean hasJobId, int jobId,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java b/apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java
index 50064bde0bbe..411a24de4bcb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java
@@ -62,6 +62,12 @@ public interface StateChangedListener {
/**
* Called when these jobs are added or removed from the
+ * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_EXEMPTED} bucket.
+ */
+ void onExemptedBucketChanged(@NonNull ArraySet<JobStatus> jobs);
+
+ /**
+ * Called when these jobs are added or removed from the
* {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket.
*/
void onRestrictedBucketChanged(@NonNull List<JobStatus> jobs);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
index 0e67b9ac944f..e4cb569d3d35 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
@@ -20,6 +20,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static com.android.server.job.JobSchedulerService.EXEMPTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BATTERY_NOT_LOW;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CHARGING;
@@ -180,8 +181,12 @@ public final class FlexibilityController extends StateController {
}
};
- private static final int MSG_UPDATE_JOBS = 0;
- private static final int MSG_UPDATE_JOB = 1;
+ private static final int MSG_CHECK_ALL_JOBS = 0;
+ /** Check the jobs in {@link #mJobsToCheck} */
+ private static final int MSG_CHECK_JOBS = 1;
+
+ @GuardedBy("mLock")
+ private final ArraySet<JobStatus> mJobsToCheck = new ArraySet<>();
public FlexibilityController(
JobSchedulerService service, PrefetchController prefetchController) {
@@ -266,7 +271,14 @@ public final class FlexibilityController extends StateController {
@GuardedBy("mLock")
boolean isFlexibilitySatisfiedLocked(JobStatus js) {
return !mFlexibilityEnabled
+ // Exclude all jobs of the TOP app
|| mService.getUidBias(js.getSourceUid()) == JobInfo.BIAS_TOP_APP
+ // Only exclude DEFAULT+ priority jobs for BFGS+ apps
+ || (mService.getUidBias(js.getSourceUid()) >= JobInfo.BIAS_BOUND_FOREGROUND_SERVICE
+ && js.getEffectivePriority() >= JobInfo.PRIORITY_DEFAULT)
+ // Only exclude DEFAULT+ priority jobs for EXEMPTED apps
+ || (js.getStandbyBucket() == EXEMPTED_INDEX
+ && js.getEffectivePriority() >= JobInfo.PRIORITY_DEFAULT)
|| hasEnoughSatisfiedConstraintsLocked(js)
|| mService.isCurrentlyRunningLocked(js);
}
@@ -371,11 +383,19 @@ public final class FlexibilityController extends StateController {
// Push the job update to the handler to avoid blocking other controllers and
// potentially batch back-to-back controller state updates together.
- mHandler.obtainMessage(MSG_UPDATE_JOBS).sendToTarget();
+ mHandler.obtainMessage(MSG_CHECK_ALL_JOBS).sendToTarget();
}
}
}
+ /** Called with a set of apps who have been added to or removed from the exempted bucket. */
+ public void onExemptedBucketChanged(@NonNull ArraySet<JobStatus> changedJobs) {
+ synchronized (mLock) {
+ mJobsToCheck.addAll(changedJobs);
+ mHandler.sendEmptyMessage(MSG_CHECK_JOBS);
+ }
+ }
+
/** Checks if the given constraint is satisfied in the flexibility controller. */
@VisibleForTesting
boolean isConstraintSatisfied(int constraint) {
@@ -485,7 +505,9 @@ public final class FlexibilityController extends StateController {
@Override
@GuardedBy("mLock")
public void onUidBiasChangedLocked(int uid, int prevBias, int newBias) {
- if (prevBias != JobInfo.BIAS_TOP_APP && newBias != JobInfo.BIAS_TOP_APP) {
+ if (prevBias < JobInfo.BIAS_BOUND_FOREGROUND_SERVICE
+ && newBias < JobInfo.BIAS_BOUND_FOREGROUND_SERVICE) {
+ // All changes are below BFGS. There's no significant change to care about.
return;
}
final long nowElapsed = sElapsedRealtimeClock.millis();
@@ -710,7 +732,8 @@ public final class FlexibilityController extends StateController {
}
mFlexibilityTracker.setNumDroppedFlexibleConstraints(js,
js.getNumAppliedFlexibleConstraints());
- mHandler.obtainMessage(MSG_UPDATE_JOB, js).sendToTarget();
+ mJobsToCheck.add(js);
+ mHandler.sendEmptyMessage(MSG_CHECK_JOBS);
return;
}
if (nextTimeElapsed == NO_LIFECYCLE_END) {
@@ -761,10 +784,11 @@ public final class FlexibilityController extends StateController {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_UPDATE_JOBS:
- removeMessages(MSG_UPDATE_JOBS);
+ case MSG_CHECK_ALL_JOBS:
+ removeMessages(MSG_CHECK_ALL_JOBS);
synchronized (mLock) {
+ mJobsToCheck.clear();
final long nowElapsed = sElapsedRealtimeClock.millis();
final ArraySet<JobStatus> changedJobs = new ArraySet<>();
@@ -790,19 +814,25 @@ public final class FlexibilityController extends StateController {
}
break;
- case MSG_UPDATE_JOB:
+ case MSG_CHECK_JOBS:
synchronized (mLock) {
- final JobStatus js = (JobStatus) msg.obj;
- if (DEBUG) {
- Slog.d("blah", "Checking on " + js.toShortString());
- }
final long nowElapsed = sElapsedRealtimeClock.millis();
- if (js.setFlexibilityConstraintSatisfied(
- nowElapsed, isFlexibilitySatisfiedLocked(js))) {
- // TODO(141645789): add method that will take a single job
- ArraySet<JobStatus> changedJob = new ArraySet<>();
- changedJob.add(js);
- mStateChangedListener.onControllerStateChanged(changedJob);
+ ArraySet<JobStatus> changedJobs = new ArraySet<>();
+
+ for (int i = mJobsToCheck.size() - 1; i >= 0; --i) {
+ final JobStatus js = mJobsToCheck.valueAt(i);
+ if (DEBUG) {
+ Slog.d(TAG, "Checking on " + js.toShortString());
+ }
+ if (js.setFlexibilityConstraintSatisfied(
+ nowElapsed, isFlexibilitySatisfiedLocked(js))) {
+ changedJobs.add(js);
+ }
+ }
+
+ mJobsToCheck.clear();
+ if (changedJobs.size() > 0) {
+ mStateChangedListener.onControllerStateChanged(changedJobs);
}
}
break;
@@ -985,7 +1015,10 @@ public final class FlexibilityController extends StateController {
pw.println(":");
pw.increaseIndent();
- pw.print(KEY_APPLIED_CONSTRAINTS, APPLIED_CONSTRAINTS).println();
+ pw.print(KEY_APPLIED_CONSTRAINTS, APPLIED_CONSTRAINTS);
+ pw.print("(");
+ JobStatus.dumpConstraints(pw, APPLIED_CONSTRAINTS);
+ pw.println(")");
pw.print(KEY_DEADLINE_PROXIMITY_LIMIT, DEADLINE_PROXIMITY_LIMIT_MS).println();
pw.print(KEY_FALLBACK_FLEXIBILITY_DEADLINE, FALLBACK_FLEXIBILITY_DEADLINE_MS).println();
pw.print(KEY_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS,
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 0d5d11e98860..a095a16817d8 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
@@ -106,11 +106,8 @@ public final class JobStatus {
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
public static final long NO_EARLIEST_RUNTIME = 0L;
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE; // 1 << 2
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static final int CONSTRAINT_BATTERY_NOT_LOW =
JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -2194,7 +2191,7 @@ public final class JobStatus {
* @return Whether or not this job would be ready to run if it had the specified constraint
* granted, based on its requirements.
*/
- boolean wouldBeReadyWithConstraint(int constraint) {
+ public boolean wouldBeReadyWithConstraint(int constraint) {
return readinessStatusWithConstraint(constraint, true);
}
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 8ddbf691359f..04da7814244e 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
@@ -2511,6 +2511,7 @@ public final class QuotaController extends StateController {
+ " to bucketIndex " + bucketIndex);
}
List<JobStatus> restrictedChanges = new ArrayList<>();
+ ArraySet<JobStatus> exemptedChanges = new ArraySet<>();
synchronized (mLock) {
ShrinkableDebits debits = mEJStats.get(userId, packageName);
if (debits != null) {
@@ -2530,6 +2531,10 @@ public final class QuotaController extends StateController {
&& bucketIndex != js.getStandbyBucket()) {
restrictedChanges.add(js);
}
+ if ((bucketIndex == EXEMPTED_INDEX || js.getStandbyBucket() == EXEMPTED_INDEX)
+ && bucketIndex != js.getStandbyBucket()) {
+ exemptedChanges.add(js);
+ }
js.setStandbyBucket(bucketIndex);
}
Timer timer = mPkgTimers.get(userId, packageName);
@@ -2544,6 +2549,9 @@ public final class QuotaController extends StateController {
maybeUpdateConstraintForPkgLocked(
sElapsedRealtimeClock.millis(), userId, packageName));
}
+ if (exemptedChanges.size() > 0) {
+ mStateChangedListener.onExemptedBucketChanged(exemptedChanges);
+ }
if (restrictedChanges.size() > 0) {
mStateChangedListener.onRestrictedBucketChanged(restrictedChanges);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
index 650c473533ed..d24500d180f2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
@@ -28,6 +28,8 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
+import static com.android.server.job.JobSchedulerService.EXEMPTED_INDEX;
import static com.android.server.job.controllers.FlexibilityController.FcConfig.DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS;
import static com.android.server.job.controllers.FlexibilityController.FcConfig.DEFAULT_UNSEEN_CONSTRAINT_GRACE_PERIOD_MS;
import static com.android.server.job.controllers.FlexibilityController.FcConfig.KEY_APPLIED_CONSTRAINTS;
@@ -212,6 +214,7 @@ public class FlexibilityControllerTest {
JobStatus js = JobStatus.createFromJobInfo(
jobInfo, 1000, SOURCE_PACKAGE, SOURCE_USER_ID, "FCTest", testTag);
js.enqueueTime = FROZEN_TIME;
+ js.setStandbyBucket(ACTIVE_INDEX);
if (js.hasFlexibilityConstraint()) {
js.setNumAppliedFlexibleConstraints(Integer.bitCount(
mFlexibilityController.getRelevantAppliedConstraintsLocked(js)));
@@ -847,14 +850,75 @@ public class FlexibilityControllerTest {
}
@Test
+ public void testAllowlistedAppBypass() {
+ JobStatus jsHigh = createJobStatus("testAllowlistedAppBypass",
+ createJob(0).setPriority(JobInfo.PRIORITY_HIGH));
+ JobStatus jsDefault = createJobStatus("testAllowlistedAppBypass",
+ createJob(0).setPriority(JobInfo.PRIORITY_DEFAULT));
+ JobStatus jsLow = createJobStatus("testAllowlistedAppBypass",
+ createJob(0).setPriority(JobInfo.PRIORITY_LOW));
+ JobStatus jsMin = createJobStatus("testAllowlistedAppBypass",
+ createJob(0).setPriority(JobInfo.PRIORITY_MIN));
+ jsHigh.setStandbyBucket(EXEMPTED_INDEX);
+ jsDefault.setStandbyBucket(EXEMPTED_INDEX);
+ jsLow.setStandbyBucket(EXEMPTED_INDEX);
+ jsMin.setStandbyBucket(EXEMPTED_INDEX);
+
+ synchronized (mFlexibilityController.mLock) {
+ assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(jsHigh));
+ assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(jsDefault));
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsLow));
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsMin));
+ }
+ }
+
+ @Test
+ public void testForegroundAppBypass() {
+ JobStatus jsHigh = createJobStatus("testAllowlistedAppBypass",
+ createJob(0).setPriority(JobInfo.PRIORITY_HIGH));
+ JobStatus jsDefault = createJobStatus("testAllowlistedAppBypass",
+ createJob(0).setPriority(JobInfo.PRIORITY_DEFAULT));
+ JobStatus jsLow = createJobStatus("testAllowlistedAppBypass",
+ createJob(0).setPriority(JobInfo.PRIORITY_LOW));
+ JobStatus jsMin = createJobStatus("testAllowlistedAppBypass",
+ createJob(0).setPriority(JobInfo.PRIORITY_MIN));
+
+ when(mJobSchedulerService.getUidBias(mSourceUid)).thenReturn(JobInfo.BIAS_DEFAULT);
+ synchronized (mFlexibilityController.mLock) {
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsHigh));
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsDefault));
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsLow));
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsMin));
+ }
+
+ when(mJobSchedulerService.getUidBias(mSourceUid))
+ .thenReturn(JobInfo.BIAS_BOUND_FOREGROUND_SERVICE);
+ synchronized (mFlexibilityController.mLock) {
+ assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(jsHigh));
+ assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(jsDefault));
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsLow));
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsMin));
+ }
+
+ when(mJobSchedulerService.getUidBias(mSourceUid))
+ .thenReturn(JobInfo.BIAS_FOREGROUND_SERVICE);
+ synchronized (mFlexibilityController.mLock) {
+ assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(jsHigh));
+ assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(jsDefault));
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsLow));
+ assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(jsMin));
+ }
+ }
+
+ @Test
public void testTopAppBypass() {
- JobInfo.Builder jb = createJob(0);
+ JobInfo.Builder jb = createJob(0).setPriority(JobInfo.PRIORITY_MIN);
JobStatus js = createJobStatus("testTopAppBypass", jb);
mJobStore.add(js);
// Needed because if before and after Uid bias is the same, nothing happens.
when(mJobSchedulerService.getUidBias(mSourceUid))
- .thenReturn(JobInfo.BIAS_FOREGROUND_SERVICE);
+ .thenReturn(JobInfo.BIAS_DEFAULT);
synchronized (mFlexibilityController.mLock) {
mFlexibilityController.maybeStartTrackingJobLocked(js, null);
@@ -865,7 +929,7 @@ public class FlexibilityControllerTest {
assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(js));
assertTrue(js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE));
- setUidBias(mSourceUid, JobInfo.BIAS_FOREGROUND_SERVICE);
+ setUidBias(mSourceUid, JobInfo.BIAS_SYNC_INITIALIZATION);
assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(js));
assertFalse(js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE));