summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java55
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java31
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java71
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java23
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java68
6 files changed, 200 insertions, 52 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 963307b110cf..a5a08fb9997c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -573,6 +573,7 @@ public class JobSchedulerService extends com.android.server.SystemService
case Constants.KEY_MIN_LINEAR_BACKOFF_TIME_MS:
case Constants.KEY_MIN_EXP_BACKOFF_TIME_MS:
case Constants.KEY_SYSTEM_STOP_TO_FAILURE_RATIO:
+ case Constants.KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF:
mConstants.updateBackoffConstantsLocked();
break;
case Constants.KEY_CONN_CONGESTION_DELAY_FRAC:
@@ -679,6 +680,8 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final String KEY_MIN_EXP_BACKOFF_TIME_MS = "min_exp_backoff_time_ms";
private static final String KEY_SYSTEM_STOP_TO_FAILURE_RATIO =
"system_stop_to_failure_ratio";
+ private static final String KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF =
+ "abandoned_job_timeouts_before_aggressive_backoff";
private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
private static final String KEY_CONN_USE_CELL_SIGNAL_STRENGTH =
@@ -750,6 +753,7 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
private static final long DEFAULT_MIN_EXP_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
private static final int DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO = 3;
+ private static final int DEFAULT_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF = 3;
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
private static final boolean DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH = true;
@@ -845,7 +849,12 @@ public class JobSchedulerService extends com.android.server.SystemService
* incremental failure in the backoff policy calculation.
*/
int SYSTEM_STOP_TO_FAILURE_RATIO = DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO;
-
+ /**
+ * Number of consecutive timeouts by abandoned jobs before we change to aggressive backoff
+ * policy.
+ */
+ int ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF =
+ DEFAULT_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF;
/**
* The fraction of a job's running window that must pass before we
* consider running it when the network is congested.
@@ -1078,6 +1087,10 @@ public class JobSchedulerService extends com.android.server.SystemService
SYSTEM_STOP_TO_FAILURE_RATIO = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_SYSTEM_STOP_TO_FAILURE_RATIO,
DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO);
+ ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF,
+ DEFAULT_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF);
}
// TODO(141645789): move into ConnectivityController.CcConfig
@@ -1287,6 +1300,8 @@ public class JobSchedulerService extends com.android.server.SystemService
pw.print(KEY_MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS).println();
pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println();
pw.print(KEY_SYSTEM_STOP_TO_FAILURE_RATIO, SYSTEM_STOP_TO_FAILURE_RATIO).println();
+ pw.print(KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF,
+ ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF).println();
pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
pw.print(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
pw.print(KEY_CONN_USE_CELL_SIGNAL_STRENGTH, CONN_USE_CELL_SIGNAL_STRENGTH).println();
@@ -2997,6 +3012,7 @@ public class JobSchedulerService extends com.android.server.SystemService
final long initialBackoffMillis = job.getInitialBackoffMillis();
int numFailures = failureToReschedule.getNumFailures();
+ int numAbandonedFailures = failureToReschedule.getNumAbandonedFailures();
int numSystemStops = failureToReschedule.getNumSystemStops();
// We should back off slowly if JobScheduler keeps stopping the job,
// but back off immediately if the issue appeared to be the app's fault
@@ -3006,9 +3022,19 @@ public class JobSchedulerService extends com.android.server.SystemService
|| internalStopReason == JobParameters.INTERNAL_STOP_REASON_ANR
|| stopReason == JobParameters.STOP_REASON_USER) {
numFailures++;
+ } else if (android.app.job.Flags.handleAbandonedJobs()
+ && internalStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED) {
+ numAbandonedFailures++;
+ numFailures++;
} else {
numSystemStops++;
}
+
+ int backoffPolicy = job.getBackoffPolicy();
+ if (shouldUseAggressiveBackoff(numAbandonedFailures)) {
+ backoffPolicy = JobInfo.BACKOFF_POLICY_EXPONENTIAL;
+ }
+
final int backoffAttempts =
numFailures + numSystemStops / mConstants.SYSTEM_STOP_TO_FAILURE_RATIO;
final long earliestRuntimeMs;
@@ -3017,7 +3043,7 @@ public class JobSchedulerService extends com.android.server.SystemService
earliestRuntimeMs = JobStatus.NO_EARLIEST_RUNTIME;
} else {
long delayMillis;
- switch (job.getBackoffPolicy()) {
+ switch (backoffPolicy) {
case JobInfo.BACKOFF_POLICY_LINEAR: {
long backoff = initialBackoffMillis;
if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME_MS) {
@@ -3046,7 +3072,7 @@ public class JobSchedulerService extends com.android.server.SystemService
}
JobStatus newJob = new JobStatus(failureToReschedule,
earliestRuntimeMs,
- JobStatus.NO_LATEST_RUNTIME, numFailures, numSystemStops,
+ JobStatus.NO_LATEST_RUNTIME, numFailures, numAbandonedFailures, numSystemStops,
failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis(),
failureToReschedule.getCumulativeExecutionTimeMs());
if (stopReason == JobParameters.STOP_REASON_USER) {
@@ -3069,6 +3095,20 @@ public class JobSchedulerService extends com.android.server.SystemService
}
/**
+ * Returns {@code true} if the given number of abandoned failures indicates that JobScheduler
+ * should use an aggressive backoff policy.
+ *
+ * @param numAbandonedFailures The number of abandoned failures.
+ * @return {@code true} if the given number of abandoned failures indicates that JobScheduler
+ * should use an aggressive backoff policy.
+ */
+ public boolean shouldUseAggressiveBackoff(int numAbandonedFailures) {
+ return android.app.job.Flags.handleAbandonedJobs()
+ && numAbandonedFailures
+ > mConstants.ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF;
+ }
+
+ /**
* Maximum time buffer in which JobScheduler will try to optimize periodic job scheduling. This
* does not cause a job's period to be larger than requested (eg: if the requested period is
* shorter than this buffer). This is used to put a limit on when JobScheduler will intervene
@@ -3147,6 +3187,7 @@ public class JobSchedulerService extends com.android.server.SystemService
return new JobStatus(periodicToReschedule,
elapsedNow + period - flex, elapsedNow + period,
0 /* numFailures */, 0 /* numSystemStops */,
+ 0 /* numAbandonedFailures */,
sSystemClock.millis() /* lastSuccessfulRunTime */,
periodicToReschedule.getLastFailedRunTime(),
0 /* Reset cumulativeExecutionTime because of successful execution */);
@@ -3163,6 +3204,7 @@ public class JobSchedulerService extends com.android.server.SystemService
return new JobStatus(periodicToReschedule,
newEarliestRunTimeElapsed, newLatestRuntimeElapsed,
0 /* numFailures */, 0 /* numSystemStops */,
+ 0 /* numAbandonedFailures */,
sSystemClock.millis() /* lastSuccessfulRunTime */,
periodicToReschedule.getLastFailedRunTime(),
0 /* Reset cumulativeExecutionTime because of successful execution */);
@@ -3171,6 +3213,10 @@ public class JobSchedulerService extends com.android.server.SystemService
@VisibleForTesting
void maybeProcessBuggyJob(@NonNull JobStatus jobStatus, int debugStopReason) {
boolean jobTimedOut = debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT;
+ if (android.app.job.Flags.handleAbandonedJobs()) {
+ jobTimedOut |= (debugStopReason
+ == JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+ }
// If madeActive = 0, the job never actually started.
if (!jobTimedOut && jobStatus.madeActive > 0) {
final long executionDurationMs = sUptimeMillisClock.millis() - jobStatus.madeActive;
@@ -3252,9 +3298,12 @@ public class JobSchedulerService extends com.android.server.SystemService
// we stop it.
final JobStatus rescheduledJob = needsReschedule
? getRescheduleJobForFailureLocked(jobStatus, stopReason, debugStopReason) : null;
+ final boolean isStopReasonAbandoned = android.app.job.Flags.handleAbandonedJobs()
+ && (debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
if (rescheduledJob != null
&& !rescheduledJob.shouldTreatAsUserInitiatedJob()
&& (debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT
+ || isStopReasonAbandoned
|| debugStopReason == JobParameters.INTERNAL_STOP_REASON_PREEMPT)) {
rescheduledJob.disallowRunInBatterySaverAndDoze();
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index d8934d8f83b8..dfb36818c818 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -269,7 +269,9 @@ public final class JobStore {
convertRtcBoundsToElapsed(utcTimes, elapsedNow);
JobStatus newJob = new JobStatus(job,
elapsedRuntimes.first, elapsedRuntimes.second,
- 0, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime(),
+ 0 /* numFailures */, 0 /* numAbandonedFailures */,
+ 0 /* numSystemStops */, job.getLastSuccessfulRunTime(),
+ job.getLastFailedRunTime(),
job.getCumulativeExecutionTimeMs());
newJob.prepareLocked();
toAdd.add(newJob);
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 a3eaefd5f057..5a33aa0ab7eb 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
@@ -316,6 +316,12 @@ public final class JobStatus {
private final int numFailures;
/**
+ * How many times this job has stopped due to {@link
+ * JobParameters#STOP_REASON_TIMEOUT_ABANDONED}.
+ */
+ private final int mNumAbandonedFailures;
+
+ /**
* The number of times JobScheduler has forced this job to stop due to reasons mostly outside
* of the app's control.
*/
@@ -605,6 +611,8 @@ public final class JobStatus {
* @param tag A string associated with the job for debugging/logging purposes.
* @param numFailures Count of how many times this job has requested a reschedule because
* its work was not yet finished.
+ * @param mNumAbandonedFailures Count of how many times this job has requested a reschedule
+ * because it was abandoned.
* @param numSystemStops Count of how many times JobScheduler has forced this job to stop due to
* factors mostly out of the app's control.
* @param earliestRunTimeElapsedMillis Milestone: earliest point in time at which the job
@@ -617,7 +625,7 @@ public final class JobStatus {
*/
private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
int sourceUserId, int standbyBucket, @Nullable String namespace, String tag,
- int numFailures, int numSystemStops,
+ int numFailures, int mNumAbandonedFailures, int numSystemStops,
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs,
int internalFlags,
@@ -677,6 +685,7 @@ public final class JobStatus {
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
this.numFailures = numFailures;
+ this.mNumAbandonedFailures = mNumAbandonedFailures;
mNumSystemStops = numSystemStops;
int requiredConstraints = job.getConstraintFlags();
@@ -750,7 +759,8 @@ public final class JobStatus {
this(jobStatus.getJob(), jobStatus.getUid(),
jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
jobStatus.getStandbyBucket(), jobStatus.getNamespace(),
- jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getNumSystemStops(),
+ jobStatus.getSourceTag(), jobStatus.getNumFailures(),
+ jobStatus.getNumAbandonedFailures(), jobStatus.getNumSystemStops(),
jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
jobStatus.getCumulativeExecutionTimeMs(),
@@ -787,6 +797,7 @@ public final class JobStatus {
this(job, callingUid, sourcePkgName, sourceUserId,
standbyBucket, namespace,
sourceTag, /* numFailures */ 0, /* numSystemStops */ 0,
+ /* mNumAbandonedFailures */ 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTimeMs,
innerFlags, dynamicConstraints);
@@ -806,13 +817,15 @@ public final class JobStatus {
/** Create a new job to be rescheduled with the provided parameters. */
public JobStatus(JobStatus rescheduling,
long newEarliestRuntimeElapsedMillis,
- long newLatestRuntimeElapsedMillis, int numFailures, int numSystemStops,
+ long newLatestRuntimeElapsedMillis, int numFailures,
+ int mNumAbandonedFailures, int numSystemStops,
long lastSuccessfulRunTime, long lastFailedRunTime,
long cumulativeExecutionTimeMs) {
this(rescheduling.job, rescheduling.getUid(),
rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
rescheduling.getStandbyBucket(), rescheduling.getNamespace(),
- rescheduling.getSourceTag(), numFailures, numSystemStops,
+ rescheduling.getSourceTag(), numFailures,
+ mNumAbandonedFailures, numSystemStops,
newEarliestRuntimeElapsedMillis,
newLatestRuntimeElapsedMillis,
lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTimeMs,
@@ -851,7 +864,8 @@ public final class JobStatus {
int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,
sourceUserId, elapsedNow);
return new JobStatus(job, callingUid, sourcePkg, sourceUserId,
- standbyBucket, namespace, tag, /* numFailures */ 0, /* numSystemStops */ 0,
+ standbyBucket, namespace, tag, /* numFailures */ 0,
+ /* mNumAbandonedFailures */ 0, /* numSystemStops */ 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
/* cumulativeExecutionTime */ 0,
@@ -1146,6 +1160,13 @@ public final class JobStatus {
}
/**
+ * Returns the number of times the job stopped previously for STOP_REASON_TIMEOUT_ABANDONED.
+ */
+ public int getNumAbandonedFailures() {
+ return mNumAbandonedFailures;
+ }
+
+ /**
* Returns the number of times the system stopped a previous execution of this job for reasons
* that were likely outside the app's control.
*/
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index dd7ce21e3628..c831475577d8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server.job;
+import static android.app.job.Flags.FLAG_HANDLE_ABANDONED_JOBS;
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;
@@ -82,6 +83,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -1056,6 +1058,75 @@ public class JobSchedulerServiceTest {
/**
* Confirm that
* {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int, int)}
+ * returns a job with the correct delay for abandoned jobs.
+ */
+ @Test
+ @EnableFlags(FLAG_HANDLE_ABANDONED_JOBS)
+ public void testGetRescheduleJobForFailure_abandonedJob() {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ final long initialBackoffMs = MINUTE_IN_MILLIS;
+ mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO = 3;
+
+ JobStatus originalJob = createJobStatus("testGetRescheduleJobForFailure",
+ createJobInfo()
+ .setBackoffCriteria(initialBackoffMs, JobInfo.BACKOFF_POLICY_LINEAR));
+ assertEquals(JobStatus.NO_EARLIEST_RUNTIME, originalJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, originalJob.getLatestRunTimeElapsed());
+
+ // failure = 1, systemStop = 0, abandoned = 1
+ JobStatus rescheduledJob = mService.getRescheduleJobForFailureLocked(originalJob,
+ JobParameters.STOP_REASON_DEVICE_STATE,
+ JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+ assertEquals(nowElapsed + initialBackoffMs, rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+ // failure = 2, systemstop = 0, abandoned = 2
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.STOP_REASON_DEVICE_STATE,
+ JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+ assertEquals(nowElapsed + (2 * initialBackoffMs), rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+ // failure = 3, systemstop = 0, abandoned = 3
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.STOP_REASON_DEVICE_STATE,
+ JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+ assertEquals(nowElapsed + (3 * initialBackoffMs), rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+ // failure = 4, systemstop = 0, abandoned = 4
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.STOP_REASON_DEVICE_STATE,
+ JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED);
+ assertEquals(
+ nowElapsed + ((long) Math.scalb((float) initialBackoffMs, 3)),
+ rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+ // failure = 4, systemstop = 1, abandoned = 4
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.STOP_REASON_DEVICE_STATE,
+ JobParameters.INTERNAL_STOP_REASON_DEVICE_THERMAL);
+ assertEquals(
+ nowElapsed + ((long) Math.scalb((float) initialBackoffMs, 3)),
+ rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+ // failure = 4, systemStop = 4 / SYSTEM_STOP_TO_FAILURE_RATIO, abandoned = 4
+ for (int i = 0; i < mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO; ++i) {
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.STOP_REASON_SYSTEM_PROCESSING,
+ JobParameters.INTERNAL_STOP_REASON_RTC_UPDATED);
+ }
+ assertEquals(
+ nowElapsed + ((long) Math.scalb((float) initialBackoffMs, 4)),
+ rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+ }
+
+ /**
+ * Confirm that
+ * {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int, int)}
* returns a job that is correctly marked as demoted by the user.
*/
@Test
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 c6a6865f1cf1..c64973a67589 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
@@ -706,14 +706,14 @@ public class FlexibilityControllerTest {
// "True" start is nowElapsed + HOUR_IN_MILLIS
nowElapsed + HOUR_IN_MILLIS + adjustmentMs,
nowElapsed + 2 * HOUR_IN_MILLIS,
- 0 /* numFailures */, 0 /* numSystemStops */,
+ 0 /* numFailures */, 0 /* numAbandonedFailures */, 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 */,
+ 0 /* numFailures */, 0 /* numAbandonedFailures */, 0 /* numSystemStops */,
JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
0, 0);
@@ -726,13 +726,13 @@ public class FlexibilityControllerTest {
jsBasic = new JobStatus(jsBasic,
nowElapsed + 30 * MINUTE_IN_MILLIS,
NO_LATEST_RUNTIME,
- 1 /* numFailures */, 1 /* numSystemStops */,
+ 1 /* numFailures */, 0 /* numAbandonedFailures */, 1 /* numSystemStops */,
JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
0, 0);
jsFlex = new JobStatus(jsFlex,
nowElapsed + 30 * MINUTE_IN_MILLIS,
NO_LATEST_RUNTIME,
- 1 /* numFailures */, 1 /* numSystemStops */,
+ 1 /* numFailures */, 0 /* numAbandonedFailures */, 1 /* numSystemStops */,
JobSchedulerService.sSystemClock.millis() /* lastSuccessfulRunTime */,
0, 0);
@@ -847,21 +847,24 @@ public class FlexibilityControllerTest {
JobInfo.Builder jb = createJob(0).setOverrideDeadline(HOUR_IN_MILLIS);
JobStatus js = createJobStatus("time", jb);
js = new JobStatus(
- js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, /* numSystemStops */ 0,
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2,
+ 0 /* numAbandonedFailures */, /* numSystemStops */ 0,
0, FROZEN_TIME, FROZEN_TIME);
assertEquals(mFcConfig.RESCHEDULED_JOB_DEADLINE_MS,
mFlexibilityController.getLifeCycleEndElapsedLocked(js, nowElapsed, 0));
js = new JobStatus(
- js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, /* numSystemStops */ 1,
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2,
+ 0 /* numAbandonedFailures */, /* numSystemStops */ 1,
0, FROZEN_TIME, FROZEN_TIME);
assertEquals(2 * mFcConfig.RESCHEDULED_JOB_DEADLINE_MS,
mFlexibilityController.getLifeCycleEndElapsedLocked(js, nowElapsed, 0));
js = new JobStatus(
- js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0, /* numSystemStops */ 10,
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0,
+ 0 /* numAbandonedFailures */, /* numSystemStops */ 10,
0, FROZEN_TIME, FROZEN_TIME);
assertEquals(mFcConfig.MAX_RESCHEDULED_DEADLINE_MS,
mFlexibilityController.getLifeCycleEndElapsedLocked(js, nowElapsed, 0));
@@ -1092,11 +1095,13 @@ public class FlexibilityControllerTest {
JobInfo.Builder jb = createJob(0);
JobStatus js = createJobStatus("time", jb);
js = new JobStatus(
- js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 1, /* numSystemStops */ 0,
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 1,
+ /* numAbandonedFailures */ 0, /* numSystemStops */ 0,
0, FROZEN_TIME, FROZEN_TIME);
assertFalse(js.hasFlexibilityConstraint());
js = new JobStatus(
- js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0, /* numSystemStops */ 1,
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0,
+ /* numAbandonedFailures */ 0, /* numSystemStops */ 1,
0, FROZEN_TIME, FROZEN_TIME);
assertFalse(js.hasFlexibilityConstraint());
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 2d0f4b69e2fe..86101cf591e7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -459,35 +459,35 @@ public class JobStatusTest {
int numFailures = 1;
int numSystemStops = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
// 2+ failures, priority should be lowered as much as possible.
numFailures = 2;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
numFailures = 5;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
numFailures = 8;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
// System stops shouldn't factor in the downgrade.
numSystemStops = 10;
numFailures = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
// Less than 2 failures, but job is downgraded.
numFailures = 1;
numSystemStops = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
}
@@ -505,44 +505,44 @@ public class JobStatusTest {
int numFailures = 1;
int numSystemStops = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
// Failures in [2,4), priority should be lowered slightly.
numFailures = 2;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
numFailures = 3;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
// Failures in [4,6), priority should be lowered more.
numFailures = 4;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
numFailures = 5;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
// 6+ failures, priority should be lowered as much as possible.
numFailures = 6;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
numFailures = 12;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
// System stops shouldn't factor in the downgrade.
numSystemStops = 10;
numFailures = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
}
@@ -563,32 +563,32 @@ public class JobStatusTest {
int numFailures = 1;
int numSystemStops = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
numFailures = 4;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
numFailures = 5;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
// 6+ failures, priority should be lowered as much as possible.
numFailures = 6;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
numFailures = 12;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
// System stops shouldn't factor in the downgrade.
numSystemStops = 10;
numFailures = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
}
@@ -606,28 +606,28 @@ public class JobStatusTest {
int numFailures = 1;
int numSystemStops = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
// 2+ failures, priority shouldn't be affected while job is still a UI job
numFailures = 2;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
numFailures = 5;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
numFailures = 8;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
// System stops shouldn't factor in the downgrade.
numSystemStops = 10;
numFailures = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
// Job can no long run as user-initiated. Downgrades should be effective.
@@ -641,28 +641,28 @@ public class JobStatusTest {
numFailures = 1;
numSystemStops = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
// 2+ failures, priority should start getting lower
numFailures = 2;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
numFailures = 5;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
numFailures = 8;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
// System stops shouldn't factor in the downgrade.
numSystemStops = 10;
numFailures = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0, 0);
+ 0, numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
}
@@ -772,14 +772,14 @@ public class JobStatusTest {
assertTrue(job.shouldTreatAsUserInitiatedJob());
JobStatus rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
- 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0);
assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
assertFalse(job.shouldTreatAsUserInitiatedJob());
rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
- 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0);
assertFalse(rescheduledJob.shouldTreatAsUserInitiatedJob());
rescheduledJob.removeInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
@@ -797,14 +797,14 @@ public class JobStatusTest {
assertTrue(job.shouldTreatAsUserInitiatedJob());
JobStatus rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
- 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0);
assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ);
assertFalse(job.shouldTreatAsUserInitiatedJob());
rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
- 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0);
assertFalse(rescheduledJob.shouldTreatAsUserInitiatedJob());
rescheduledJob.removeInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ);