summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java61
2 files changed, 78 insertions, 3 deletions
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 fed3c42ab87f..a900d162ab96 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
@@ -369,8 +369,23 @@ public final class FlexibilityController extends StateController {
@VisibleForTesting
@GuardedBy("mLock")
long getLifeCycleBeginningElapsedLocked(JobStatus js) {
+ long earliestRuntime = js.getEarliestRunTime() == JobStatus.NO_EARLIEST_RUNTIME
+ ? js.enqueueTime : js.getEarliestRunTime();
+ if (js.getJob().isPeriodic() && js.getNumPreviousAttempts() == 0) {
+ // Rescheduling periodic jobs (after a successful execution) may result in the job's
+ // start time being a little after the "true" periodic start time (to avoid jobs
+ // running back to back). See JobSchedulerService#getRescheduleJobForPeriodic for more
+ // details. Since rescheduled periodic jobs may already be delayed slightly by this
+ // policy, don't penalize them further by then enforcing the full set of applied
+ // flex constraints at the beginning of the newly determined start time. Let the flex
+ // constraint requirement start closer to the true periodic start time.
+ final long truePeriodicStartTimeElapsed =
+ js.getLatestRunTimeElapsed() - js.getJob().getFlexMillis();
+ // For now, treat the lifecycle beginning as the midpoint between the true periodic
+ // start time and the adjusted start time.
+ earliestRuntime = (earliestRuntime + truePeriodicStartTimeElapsed) / 2;
+ }
if (js.getJob().isPrefetch()) {
- final long earliestRuntime = Math.max(js.enqueueTime, js.getEarliestRunTime());
final long estimatedLaunchTime =
mPrefetchController.getNextEstimatedLaunchTimeLocked(js);
long prefetchWindowStart = mPrefetchLifeCycleStart.getOrDefault(
@@ -381,8 +396,7 @@ public final class FlexibilityController extends StateController {
}
return Math.max(prefetchWindowStart, earliestRuntime);
}
- return js.getEarliestRunTime() == JobStatus.NO_EARLIEST_RUNTIME
- ? js.enqueueTime : js.getEarliestRunTime();
+ return earliestRuntime;
}
@VisibleForTesting
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 0659f7e9a064..debc69604690 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
@@ -23,6 +23,7 @@ import static android.app.job.JobInfo.NETWORK_TYPE_CELLULAR;
import static android.app.job.JobInfo.NETWORK_TYPE_NONE;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+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;
@@ -422,6 +423,66 @@ public class FlexibilityControllerTest {
}
@Test
+ public void testGetLifeCycleBeginningElapsedLocked_Periodic() {
+ // Periodic with lifecycle
+ JobInfo.Builder jbBasic = createJob(0).setPeriodic(HOUR_IN_MILLIS);
+ JobInfo.Builder jbFlex = createJob(0)
+ .setPeriodic(HOUR_IN_MILLIS, 20 * MINUTE_IN_MILLIS);
+ JobStatus jsBasic =
+ createJobStatus("testGetLifeCycleBeginningElapsedLocked_Periodic", jbBasic);
+ JobStatus jsFlex =
+ createJobStatus("testGetLifeCycleBeginningElapsedLocked_Periodic", jbFlex);
+
+ final long nowElapsed = JobSchedulerService.sElapsedRealtimeClock.millis();
+ // Base case, no start adjustment
+ assertEquals(nowElapsed,
+ mFlexibilityController.getLifeCycleBeginningElapsedLocked(jsBasic));
+ assertEquals(nowElapsed + 40 * MINUTE_IN_MILLIS,
+ mFlexibilityController.getLifeCycleBeginningElapsedLocked(jsFlex));
+
+ // Rescheduled with start adjustment
+ final long adjustmentMs = 4 * MINUTE_IN_MILLIS;
+ jsBasic = new JobStatus(jsBasic,
+ // "True" start is nowElapsed + HOUR_IN_MILLIS
+ nowElapsed + HOUR_IN_MILLIS + adjustmentMs,
+ nowElapsed + 2 * HOUR_IN_MILLIS,
+ 0 /* numFailures */, 0 /* numSystemStops */,
+ JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
+ 0, 0);
+ jsFlex = new JobStatus(jsFlex,
+ // "True" start is nowElapsed + 2 * HOUR_IN_MILLIS - 20 * MINUTE_IN_MILLIS
+ nowElapsed + 2 * HOUR_IN_MILLIS - 20 * MINUTE_IN_MILLIS + adjustmentMs,
+ nowElapsed + 2 * HOUR_IN_MILLIS,
+ 0 /* numFailures */, 0 /* numSystemStops */,
+ JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
+ 0, 0);
+
+ assertEquals(nowElapsed + HOUR_IN_MILLIS + adjustmentMs / 2,
+ mFlexibilityController.getLifeCycleBeginningElapsedLocked(jsBasic));
+ assertEquals(nowElapsed + 2 * HOUR_IN_MILLIS - 20 * MINUTE_IN_MILLIS + adjustmentMs / 2,
+ mFlexibilityController.getLifeCycleBeginningElapsedLocked(jsFlex));
+
+ // Rescheduled for failure
+ jsBasic = new JobStatus(jsBasic,
+ nowElapsed + 30 * MINUTE_IN_MILLIS,
+ NO_LATEST_RUNTIME,
+ 1 /* numFailures */, 1 /* numSystemStops */,
+ JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
+ 0, 0);
+ jsFlex = new JobStatus(jsFlex,
+ nowElapsed + 30 * MINUTE_IN_MILLIS,
+ NO_LATEST_RUNTIME,
+ 1 /* numFailures */, 1 /* numSystemStops */,
+ JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
+ 0, 0);
+
+ assertEquals(nowElapsed + 30 * MINUTE_IN_MILLIS,
+ mFlexibilityController.getLifeCycleBeginningElapsedLocked(jsBasic));
+ assertEquals(nowElapsed + 30 * MINUTE_IN_MILLIS,
+ mFlexibilityController.getLifeCycleBeginningElapsedLocked(jsFlex));
+ }
+
+ @Test
public void testGetLifeCycleBeginningElapsedLocked_Prefetch() {
// prefetch with lifecycle
when(mPrefetchController.getLaunchTimeThresholdMs()).thenReturn(700L);