Flex time for periodic jobs in JobScheduler
A periodic job will start only within time satisfying period - flex < time % period < period. Bug: 26254850 Change-Id: I97a840446e5592e5151d784800855d909f1790b8
This commit is contained in:
@@ -6166,6 +6166,7 @@ package android.app.job {
|
||||
method public int describeContents();
|
||||
method public int getBackoffPolicy();
|
||||
method public android.os.PersistableBundle getExtras();
|
||||
method public long getFlexMillis();
|
||||
method public int getId();
|
||||
method public long getInitialBackoffMillis();
|
||||
method public long getIntervalMillis();
|
||||
@@ -6183,6 +6184,8 @@ package android.app.job {
|
||||
field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
|
||||
field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L
|
||||
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
|
||||
field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L
|
||||
field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L
|
||||
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
|
||||
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
|
||||
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
|
||||
@@ -6196,6 +6199,7 @@ package android.app.job {
|
||||
method public android.app.job.JobInfo.Builder setMinimumLatency(long);
|
||||
method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
|
||||
method public android.app.job.JobInfo.Builder setPeriodic(long);
|
||||
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
|
||||
method public android.app.job.JobInfo.Builder setPersisted(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
|
||||
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
|
||||
|
||||
@@ -6381,6 +6381,7 @@ package android.app.job {
|
||||
method public int describeContents();
|
||||
method public int getBackoffPolicy();
|
||||
method public android.os.PersistableBundle getExtras();
|
||||
method public long getFlexMillis();
|
||||
method public int getId();
|
||||
method public long getInitialBackoffMillis();
|
||||
method public long getIntervalMillis();
|
||||
@@ -6398,6 +6399,8 @@ package android.app.job {
|
||||
field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
|
||||
field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L
|
||||
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
|
||||
field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L
|
||||
field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L
|
||||
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
|
||||
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
|
||||
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
|
||||
@@ -6411,6 +6414,7 @@ package android.app.job {
|
||||
method public android.app.job.JobInfo.Builder setMinimumLatency(long);
|
||||
method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
|
||||
method public android.app.job.JobInfo.Builder setPeriodic(long);
|
||||
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
|
||||
method public android.app.job.JobInfo.Builder setPersisted(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
|
||||
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
|
||||
|
||||
@@ -6168,6 +6168,7 @@ package android.app.job {
|
||||
method public int describeContents();
|
||||
method public int getBackoffPolicy();
|
||||
method public android.os.PersistableBundle getExtras();
|
||||
method public long getFlexMillis();
|
||||
method public int getId();
|
||||
method public long getInitialBackoffMillis();
|
||||
method public long getIntervalMillis();
|
||||
@@ -6185,6 +6186,8 @@ package android.app.job {
|
||||
field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
|
||||
field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L
|
||||
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
|
||||
field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L
|
||||
field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L
|
||||
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
|
||||
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
|
||||
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
|
||||
@@ -6198,6 +6201,7 @@ package android.app.job {
|
||||
method public android.app.job.JobInfo.Builder setMinimumLatency(long);
|
||||
method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
|
||||
method public android.app.job.JobInfo.Builder setPeriodic(long);
|
||||
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
|
||||
method public android.app.job.JobInfo.Builder setPersisted(boolean);
|
||||
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
|
||||
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
|
||||
|
||||
@@ -64,6 +64,11 @@ public class JobInfo implements Parcelable {
|
||||
*/
|
||||
public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
|
||||
|
||||
/* Minimum interval for a periodic job, in milliseconds. */
|
||||
public static final long MIN_PERIOD_MILLIS = 60 * 60 * 1000L; // 60 minutes
|
||||
/* Minimum flex for a periodic job, in milliseconds. */
|
||||
public static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
|
||||
|
||||
/**
|
||||
* Default type of backoff.
|
||||
* @hide
|
||||
@@ -83,6 +88,7 @@ public class JobInfo implements Parcelable {
|
||||
private final boolean isPeriodic;
|
||||
private final boolean isPersisted;
|
||||
private final long intervalMillis;
|
||||
private final long flexMillis;
|
||||
private final long initialBackoffMillis;
|
||||
private final int backoffPolicy;
|
||||
|
||||
@@ -165,7 +171,17 @@ public class JobInfo implements Parcelable {
|
||||
* job does not recur periodically.
|
||||
*/
|
||||
public long getIntervalMillis() {
|
||||
return intervalMillis;
|
||||
return intervalMillis >= MIN_PERIOD_MILLIS ? intervalMillis : MIN_PERIOD_MILLIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flex time for this job. Only valid if this is a periodic job.
|
||||
*/
|
||||
public long getFlexMillis() {
|
||||
long interval = getIntervalMillis();
|
||||
long percentClamp = 5 * interval / 100;
|
||||
long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, MIN_FLEX_MILLIS));
|
||||
return clampedFlex <= interval ? clampedFlex : interval;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,6 +232,7 @@ public class JobInfo implements Parcelable {
|
||||
isPeriodic = in.readInt() == 1;
|
||||
isPersisted = in.readInt() == 1;
|
||||
intervalMillis = in.readLong();
|
||||
flexMillis = in.readLong();
|
||||
initialBackoffMillis = in.readLong();
|
||||
backoffPolicy = in.readInt();
|
||||
hasEarlyConstraint = in.readInt() == 1;
|
||||
@@ -234,6 +251,7 @@ public class JobInfo implements Parcelable {
|
||||
isPeriodic = b.mIsPeriodic;
|
||||
isPersisted = b.mIsPersisted;
|
||||
intervalMillis = b.mIntervalMillis;
|
||||
flexMillis = b.mFlexMillis;
|
||||
initialBackoffMillis = b.mInitialBackoffMillis;
|
||||
backoffPolicy = b.mBackoffPolicy;
|
||||
hasEarlyConstraint = b.mHasEarlyConstraint;
|
||||
@@ -258,6 +276,7 @@ public class JobInfo implements Parcelable {
|
||||
out.writeInt(isPeriodic ? 1 : 0);
|
||||
out.writeInt(isPersisted ? 1 : 0);
|
||||
out.writeLong(intervalMillis);
|
||||
out.writeLong(flexMillis);
|
||||
out.writeLong(initialBackoffMillis);
|
||||
out.writeInt(backoffPolicy);
|
||||
out.writeInt(hasEarlyConstraint ? 1 : 0);
|
||||
@@ -299,6 +318,7 @@ public class JobInfo implements Parcelable {
|
||||
private boolean mHasEarlyConstraint;
|
||||
private boolean mHasLateConstraint;
|
||||
private long mIntervalMillis;
|
||||
private long mFlexMillis;
|
||||
// Back-off parameters.
|
||||
private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
|
||||
private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
|
||||
@@ -373,8 +393,21 @@ public class JobInfo implements Parcelable {
|
||||
* @param intervalMillis Millisecond interval for which this job will repeat.
|
||||
*/
|
||||
public Builder setPeriodic(long intervalMillis) {
|
||||
return setPeriodic(intervalMillis, intervalMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this job should recur with the provided interval and flex. The job can
|
||||
* execute at any time in a window of flex length at the end of the period.
|
||||
* @param intervalMillis Millisecond interval for which this job will repeat.
|
||||
* @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
|
||||
* {@link #MIN_FLEX_MILLIS} or 5 percent of the period, whichever is
|
||||
* higher.
|
||||
*/
|
||||
public Builder setPeriodic(long intervalMillis, long flexMillis) {
|
||||
mIsPeriodic = true;
|
||||
mIntervalMillis = intervalMillis;
|
||||
mFlexMillis = flexMillis;
|
||||
mHasEarlyConstraint = mHasLateConstraint = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -613,9 +613,10 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
if (periodicToReschedule.hasDeadlineConstraint()) {
|
||||
runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0L);
|
||||
}
|
||||
long newEarliestRunTimeElapsed = elapsedNow + runEarly;
|
||||
long flex = periodicToReschedule.getJob().getFlexMillis();
|
||||
long period = periodicToReschedule.getJob().getIntervalMillis();
|
||||
long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
|
||||
long newLatestRuntimeElapsed = elapsedNow + runEarly + period;
|
||||
long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex;
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
|
||||
|
||||
@@ -397,6 +397,7 @@ public class JobStore {
|
||||
if (jobStatus.getJob().isPeriodic()) {
|
||||
out.startTag(null, XML_TAG_PERIODIC);
|
||||
out.attribute(null, "period", Long.toString(job.getIntervalMillis()));
|
||||
out.attribute(null, "flex", Long.toString(job.getFlexMillis()));
|
||||
} else {
|
||||
out.startTag(null, XML_TAG_ONEOFF);
|
||||
}
|
||||
@@ -594,13 +595,17 @@ public class JobStore {
|
||||
String val = parser.getAttributeValue(null, "period");
|
||||
final long periodMillis = Long.valueOf(val);
|
||||
jobBuilder.setPeriodic(periodMillis);
|
||||
// As a sanity check, cap the recreated run time to be no later than 2 periods
|
||||
val = parser.getAttributeValue(null, "flex");
|
||||
final long flexMillis = (val != null) ? Long.valueOf(val) : periodMillis;
|
||||
// As a sanity check, cap the recreated run time to be no later than flex+period
|
||||
// from now. This is the latest the periodic could be pushed out. This could
|
||||
// happen if the periodic ran early (at the start of its period), and then the
|
||||
// happen if the periodic ran early (at flex time before period), and then the
|
||||
// device rebooted.
|
||||
if (elapsedRuntimes.second > elapsedNow + 2 * periodMillis) {
|
||||
final long clampedEarlyRuntimeElapsed = elapsedNow + periodMillis;
|
||||
final long clampedLateRuntimeElapsed = elapsedNow + 2 * periodMillis;
|
||||
if (elapsedRuntimes.second > elapsedNow + periodMillis + flexMillis) {
|
||||
final long clampedLateRuntimeElapsed = elapsedNow + flexMillis
|
||||
+ periodMillis;
|
||||
final long clampedEarlyRuntimeElapsed = clampedLateRuntimeElapsed
|
||||
- flexMillis;
|
||||
Slog.w(TAG,
|
||||
String.format("Periodic job for uid='%d' persisted run-time is" +
|
||||
" too big [%s, %s]. Clamping to [%s,%s]",
|
||||
|
||||
@@ -96,8 +96,8 @@ public class JobStatus {
|
||||
final long elapsedNow = SystemClock.elapsedRealtime();
|
||||
|
||||
if (job.isPeriodic()) {
|
||||
earliestRunTimeElapsedMillis = elapsedNow;
|
||||
latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
|
||||
earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
|
||||
} else {
|
||||
earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
|
||||
elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
|
||||
|
||||
Reference in New Issue
Block a user