Keep Tracking Jobs Whose Constraints Have Been Dropped

If a job is close to its deadline than FC will stop tracking it. But if
the deadline changes then the job could wind up in some FC data
structures but not others, and data will not be cleaned up properly when
the job is complete. By continuing to track jobs with 0 constraints and
only stopping when the job is completed, we can avoid this edge case.

Bug:243167593

Test: atest frameworks/base/services/tests/mockingservicestests/src/com/android/server/job
Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/job
Test: atest CtsJobSchedulerTestCases
Change-Id: I665b9f07675e8c18f6dcdaf8813794213f95139b
This commit is contained in:
alexbianchi
2022-08-22 17:58:36 +00:00
committed by Alex Bianchi
parent aa4bae7829
commit 36ccc9004e
2 changed files with 53 additions and 51 deletions

View File

@@ -406,7 +406,7 @@ public final class FlexibilityController extends StateController {
final ArraySet<JobStatus> changedJobs = new ArraySet<>();
synchronized (mLock) {
final long nowElapsed = sElapsedRealtimeClock.millis();
for (int j = 1; j <= mFlexibilityTracker.size(); j++) {
for (int j = 0; j < mFlexibilityTracker.size(); j++) {
final ArraySet<JobStatus> jobs = mFlexibilityTracker
.getJobsByNumRequiredConstraints(j);
for (int i = 0; i < jobs.size(); i++) {
@@ -445,7 +445,7 @@ public final class FlexibilityController extends StateController {
FlexibilityTracker(int numFlexibleConstraints) {
mTrackedJobs = new ArrayList<>();
for (int i = 0; i < numFlexibleConstraints; i++) {
for (int i = 0; i <= numFlexibleConstraints; i++) {
mTrackedJobs.add(new ArraySet<JobStatus>());
}
}
@@ -457,15 +457,15 @@ public final class FlexibilityController extends StateController {
Slog.wtfStack(TAG, "Asked for a larger number of constraints than exists.");
return null;
}
return mTrackedJobs.get(numRequired - 1);
return mTrackedJobs.get(numRequired);
}
/** adds a JobStatus object based on number of required flexible constraints. */
public void add(JobStatus js) {
if (js.getNumRequiredFlexibleConstraints() <= 0) {
if (js.getNumRequiredFlexibleConstraints() < 0) {
return;
}
mTrackedJobs.get(js.getNumRequiredFlexibleConstraints() - 1).add(js);
mTrackedJobs.get(js.getNumRequiredFlexibleConstraints()).add(js);
}
/** Removes a JobStatus object. */
@@ -473,7 +473,7 @@ public final class FlexibilityController extends StateController {
if (js.getNumRequiredFlexibleConstraints() == 0) {
return;
}
mTrackedJobs.get(js.getNumRequiredFlexibleConstraints() - 1).remove(js);
mTrackedJobs.get(js.getNumRequiredFlexibleConstraints()).remove(js);
}
public void resetJobNumDroppedConstraints(JobStatus js, long nowElapsed) {
@@ -498,21 +498,15 @@ public final class FlexibilityController extends StateController {
/**
* Adjusts number of required flexible constraints and sorts it into the tracker.
* Returns false if the job status's number of flexible constraints is now 0.
* Jobs with 0 required flexible constraints are removed from the tracker.
*/
public boolean adjustJobsRequiredConstraints(JobStatus js, int n, long nowElapsed) {
if (n == 0) {
return false;
public boolean adjustJobsRequiredConstraints(JobStatus js, int adjustBy, long nowElapsed) {
if (adjustBy != 0) {
remove(js);
js.adjustNumRequiredFlexibleConstraints(adjustBy);
js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js));
add(js);
}
remove(js);
js.adjustNumRequiredFlexibleConstraints(n);
js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js));
if (js.getNumRequiredFlexibleConstraints() <= 0) {
maybeStopTrackingJobLocked(js, null, false);
return false;
}
add(js);
return true;
return js.getNumRequiredFlexibleConstraints() > 0;
}
public int size() {

View File

@@ -29,6 +29,7 @@ import static com.android.server.job.controllers.FlexibilityController.FcConfig.
import static com.android.server.job.controllers.FlexibilityController.FcConfig.KEY_FALLBACK_FLEXIBILITY_DEADLINE;
import static com.android.server.job.controllers.FlexibilityController.FcConfig.KEY_FLEXIBILITY_ENABLED;
import static com.android.server.job.controllers.FlexibilityController.FcConfig.KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS;
import static com.android.server.job.controllers.FlexibilityController.NUM_FLEXIBLE_CONSTRAINTS;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BATTERY_NOT_LOW;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CHARGING;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_FLEXIBLE;
@@ -190,7 +191,7 @@ public class FlexibilityControllerTest {
*/
@Test
public void testDefaultVariableValues() {
assertEquals(FlexibilityController.NUM_FLEXIBLE_CONSTRAINTS,
assertEquals(NUM_FLEXIBLE_CONSTRAINTS,
mFlexibilityController.mFcConfig.DEFAULT_PERCENT_TO_DROP_FLEXIBLE_CONSTRAINTS.length
);
}
@@ -473,9 +474,9 @@ public class FlexibilityControllerTest {
public void testFlexibilityTracker() {
FlexibilityController.FlexibilityTracker flexTracker =
mFlexibilityController.new
FlexibilityTracker(FlexibilityController.NUM_FLEXIBLE_CONSTRAINTS);
assertEquals(4, flexTracker.size());
FlexibilityTracker(NUM_FLEXIBLE_CONSTRAINTS);
// Plus one for jobs with 0 required constraint.
assertEquals(NUM_FLEXIBLE_CONSTRAINTS + 1, flexTracker.size());
JobStatus[] jobs = new JobStatus[4];
JobInfo.Builder jb;
for (int i = 0; i < jobs.length; i++) {
@@ -495,47 +496,53 @@ public class FlexibilityControllerTest {
synchronized (mFlexibilityController.mLock) {
ArrayList<ArraySet<JobStatus>> trackedJobs = flexTracker.getArrayList();
assertEquals(0, trackedJobs.get(0).size());
assertEquals(1, trackedJobs.get(0).size());
assertEquals(0, trackedJobs.get(1).size());
assertEquals(3, trackedJobs.get(2).size());
assertEquals(0, trackedJobs.get(3).size());
flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME);
assertEquals(0, trackedJobs.get(0).size());
assertEquals(1, trackedJobs.get(1).size());
assertEquals(2, trackedJobs.get(2).size());
assertEquals(0, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(2).size());
assertEquals(3, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(4).size());
flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME);
assertEquals(1, trackedJobs.get(0).size());
assertEquals(0, trackedJobs.get(1).size());
assertEquals(2, trackedJobs.get(2).size());
assertEquals(0, trackedJobs.get(3).size());
assertEquals(1, trackedJobs.get(2).size());
assertEquals(2, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(4).size());
flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME);
assertEquals(0, trackedJobs.get(0).size());
assertEquals(1, trackedJobs.get(0).size());
assertEquals(1, trackedJobs.get(1).size());
assertEquals(0, trackedJobs.get(2).size());
assertEquals(2, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(4).size());
flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME);
assertEquals(2, trackedJobs.get(0).size());
assertEquals(0, trackedJobs.get(1).size());
assertEquals(2, trackedJobs.get(2).size());
assertEquals(0, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(2).size());
assertEquals(2, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(4).size());
flexTracker.remove(jobs[1]);
assertEquals(0, trackedJobs.get(0).size());
assertEquals(2, trackedJobs.get(0).size());
assertEquals(0, trackedJobs.get(1).size());
assertEquals(1, trackedJobs.get(2).size());
assertEquals(0, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(2).size());
assertEquals(1, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(4).size());
flexTracker.resetJobNumDroppedConstraints(jobs[0], FROZEN_TIME);
assertEquals(0, trackedJobs.get(0).size());
assertEquals(2, trackedJobs.get(0).size());
assertEquals(0, trackedJobs.get(1).size());
assertEquals(2, trackedJobs.get(2).size());
assertEquals(0, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(2).size());
assertEquals(2, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(4).size());
flexTracker.adjustJobsRequiredConstraints(jobs[0], -2, FROZEN_TIME);
assertEquals(1, trackedJobs.get(0).size());
assertEquals(0, trackedJobs.get(1).size());
assertEquals(1, trackedJobs.get(2).size());
assertEquals(0, trackedJobs.get(3).size());
assertEquals(2, trackedJobs.get(0).size());
assertEquals(1, trackedJobs.get(1).size());
assertEquals(0, trackedJobs.get(2).size());
assertEquals(1, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(4).size());
final long nowElapsed = ((DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS / 2)
+ HOUR_IN_MILLIS);
@@ -543,10 +550,11 @@ public class FlexibilityControllerTest {
Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC);
flexTracker.resetJobNumDroppedConstraints(jobs[0], nowElapsed);
assertEquals(0, trackedJobs.get(0).size());
assertEquals(1, trackedJobs.get(1).size());
assertEquals(2, trackedJobs.get(0).size());
assertEquals(0, trackedJobs.get(1).size());
assertEquals(1, trackedJobs.get(2).size());
assertEquals(0, trackedJobs.get(3).size());
assertEquals(1, trackedJobs.get(3).size());
assertEquals(0, trackedJobs.get(4).size());
}
}