Shift job readiness re-evaluation check.

Sometimes controllers actually update their relative bit on the job
when the JobSchedulerService double checks with controllers. However,
if JSS is looping through the changedJobs list when this happens, the
controller will tell JSS of the change, but adding it to the changedJobs
list will be a no-op so the job won't be added to the pending job list.
And if the controller gets a callback and evaluate the job on its own,
the bit won't change and so the job won't be added to the changedJobs
list. This leads to inconsistent behavior based on timing/order of
operations. Shifting the controller re-evaluation to when we're
determine the job's readiness fixes the issue.

Bug: 263216453
Bug: 263699506
Bug: 271128261
Test: atest --rerun-until-failure 50 android.jobscheduler.cts.JobThrottlingTest#testRestrictedEJAllowedWhenAutoRestrictedBucketFeatureOn
Test: atest FrameworksMockingServicesTests:JobSchedulerServiceTest
Change-Id: Idb41cf030f63c697adb8e7bfebc132019f9dffbc
This commit is contained in:
Kweku Adams
2023-04-17 20:03:24 +00:00
parent 728b80a325
commit a2282a9c65
2 changed files with 8 additions and 8 deletions

View File

@@ -1577,8 +1577,6 @@ public class JobSchedulerService extends com.android.server.SystemService
mJobPackageTracker.notePending(jobStatus);
mPendingJobQueue.add(jobStatus);
maybeRunPendingJobsLocked();
} else {
evaluateControllerStatesLocked(jobStatus);
}
}
return JobScheduler.RESULT_SUCCESS;
@@ -3050,8 +3048,6 @@ public class JobSchedulerService extends com.android.server.SystemService
Slog.d(TAG, " queued " + job.toShortString());
}
newReadyJobs.add(job);
} else {
evaluateControllerStatesLocked(job);
}
}
@@ -3171,7 +3167,6 @@ public class JobSchedulerService extends com.android.server.SystemService
} else if (mPendingJobQueue.remove(job)) {
noteJobNonPending(job);
}
evaluateControllerStatesLocked(job);
}
}
@@ -3297,7 +3292,7 @@ public class JobSchedulerService extends com.android.server.SystemService
@GuardedBy("mLock")
boolean isReadyToBeExecutedLocked(JobStatus job, boolean rejectActive) {
final boolean jobReady = job.isReady();
final boolean jobReady = job.isReady() || evaluateControllerStatesLocked(job);
if (DEBUG) {
Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
@@ -3372,12 +3367,17 @@ public class JobSchedulerService extends com.android.server.SystemService
return !appIsBad;
}
/**
* Gets each controller to evaluate the job's state
* and then returns the value of {@link JobStatus#isReady()}.
*/
@VisibleForTesting
void evaluateControllerStatesLocked(final JobStatus job) {
boolean evaluateControllerStatesLocked(final JobStatus job) {
for (int c = mControllers.size() - 1; c >= 0; --c) {
final StateController sc = mControllers.get(c);
sc.evaluateStateLocked(job);
}
return job.isReady();
}
/**

View File

@@ -1132,7 +1132,7 @@ public class JobSchedulerServiceTest {
@Test
public void testRareJobBatching() {
spyOn(mService);
doNothing().when(mService).evaluateControllerStatesLocked(any());
doReturn(false).when(mService).evaluateControllerStatesLocked(any());
doNothing().when(mService).noteJobsPending(any());
doReturn(true).when(mService).isReadyToBeExecutedLocked(any(), anyBoolean());
advanceElapsedClock(24 * HOUR_IN_MILLIS);