Merge "Allow syncs to be scheduled as EJs." into sc-dev
This commit is contained in:
commit
5c9a0355f8
@ -182,6 +182,8 @@ public class RequestSync {
|
||||
mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
|
||||
} else if (opt.equals("--rc") || opt.equals("--require-charging")) {
|
||||
mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING, true);
|
||||
} else if (opt.equals("--ej") || opt.equals("--schedule-as-ej")) {
|
||||
mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true);
|
||||
} else if (opt.equals("-e") || opt.equals("--es") || opt.equals("--extra-string")) {
|
||||
final String key = nextArgRequired();
|
||||
final String value = nextArgRequired();
|
||||
|
@ -10238,6 +10238,7 @@ package android.content {
|
||||
field public static final String SYNC_EXTRAS_MANUAL = "force";
|
||||
field public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
|
||||
field public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
|
||||
field public static final String SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB = "schedule_as_expedited_job";
|
||||
field public static final String SYNC_EXTRAS_UPLOAD = "upload";
|
||||
field public static final int SYNC_OBSERVER_TYPE_ACTIVE = 4; // 0x4
|
||||
field public static final int SYNC_OBSERVER_TYPE_PENDING = 2; // 0x2
|
||||
@ -11560,6 +11561,7 @@ package android.content {
|
||||
method public android.content.SyncRequest.Builder setManual(boolean);
|
||||
method public android.content.SyncRequest.Builder setNoRetry(boolean);
|
||||
method public android.content.SyncRequest.Builder setRequiresCharging(boolean);
|
||||
method @NonNull public android.content.SyncRequest.Builder setScheduleAsExpeditedJob(boolean);
|
||||
method public android.content.SyncRequest.Builder setSyncAdapter(android.accounts.Account, String);
|
||||
method public android.content.SyncRequest.Builder syncOnce();
|
||||
method public android.content.SyncRequest.Builder syncPeriodic(long, long);
|
||||
|
@ -132,8 +132,11 @@ public abstract class ContentResolver implements ContentInterface {
|
||||
public static final String SYNC_EXTRAS_ACCOUNT = "account";
|
||||
|
||||
/**
|
||||
* If this extra is set to true, the sync request will be scheduled
|
||||
* at the front of the sync request queue and without any delay
|
||||
* If this extra is set to true, the sync request will be scheduled at the front of the
|
||||
* sync request queue, but it is still subject to JobScheduler quota and throttling due to
|
||||
* App Standby buckets.
|
||||
*
|
||||
* <p>This is different from {@link #SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB}.
|
||||
*/
|
||||
public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
|
||||
|
||||
@ -144,6 +147,29 @@ public abstract class ContentResolver implements ContentInterface {
|
||||
*/
|
||||
public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
|
||||
|
||||
/**
|
||||
* Run this sync operation as an "expedited job"
|
||||
* (see {@link android.app.job.JobInfo.Builder#setExpedited(boolean)}).
|
||||
* Normally (if this flag isn't specified), sync operations are executed as regular
|
||||
* {@link android.app.job.JobService} jobs.
|
||||
*
|
||||
* <p> Because Expedited Jobs have various restrictions compared to regular jobs, this flag
|
||||
* cannot be combined with certain other flags, otherwise an
|
||||
* <code>IllegalArgumentException</code> will be thrown. Notably, because Expedited Jobs do not
|
||||
* support various constraints, the following restriction apply:
|
||||
* <ul>
|
||||
* <li>Can't be used with {@link #SYNC_EXTRAS_REQUIRE_CHARGING}
|
||||
* <li>Can't be used with {@link #SYNC_EXTRAS_EXPEDITED}
|
||||
* <li>Can't be used on periodic syncs.
|
||||
* <li>When an expedited-job-sync fails and a retry is scheduled, the retried sync will be
|
||||
* scheduled as a regular job unless {@link #SYNC_EXTRAS_IGNORE_BACKOFF} is set.
|
||||
* </ul>
|
||||
*
|
||||
* <p>This is different from {@link #SYNC_EXTRAS_EXPEDITED}.
|
||||
*/
|
||||
@SuppressLint("IntentName")
|
||||
public static final String SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB = "schedule_as_expedited_job";
|
||||
|
||||
/**
|
||||
* @deprecated instead use
|
||||
* {@link #SYNC_EXTRAS_MANUAL}
|
||||
@ -3219,6 +3245,18 @@ public abstract class ContentResolver implements ContentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
* Helper function to throw an <code>IllegalArgumentException</code> if any illegal
|
||||
* extras were set for a sync scheduled as an expedited job.
|
||||
*
|
||||
* @param extras bundle to validate.
|
||||
*/
|
||||
public static boolean hasInvalidScheduleAsEjExtras(Bundle extras) {
|
||||
return extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING)
|
||||
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that a sync should be requested with the specified the account, authority,
|
||||
* and extras at the given frequency. If there is already another periodic sync scheduled
|
||||
@ -3233,7 +3271,8 @@ public abstract class ContentResolver implements ContentInterface {
|
||||
* Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
|
||||
* {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
|
||||
* {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
|
||||
* {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
|
||||
* {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL},
|
||||
* {@link #SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB} set to true.
|
||||
* If any are supplied then an {@link IllegalArgumentException} will be thrown.
|
||||
*
|
||||
* <p>This method requires the caller to hold the permission
|
||||
@ -3273,16 +3312,14 @@ public abstract class ContentResolver implements ContentInterface {
|
||||
* @param extras bundle to validate.
|
||||
*/
|
||||
public static boolean invalidPeriodicExtras(Bundle extras) {
|
||||
if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
|
||||
return extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
|
||||
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
|
||||
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
|
||||
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
|
||||
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
|
||||
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
|
||||
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)
|
||||
|| extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,6 +17,7 @@
|
||||
package android.content;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.annotation.NonNull;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@ -58,6 +59,8 @@ public class SyncRequest implements Parcelable {
|
||||
private final boolean mIsAuthority;
|
||||
/** Sync should be run in lieu of other syncs. */
|
||||
private final boolean mIsExpedited;
|
||||
/** Sync sound be ran as an expedited job. */
|
||||
private final boolean mIsScheduledAsExpeditedJob;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
@ -77,6 +80,14 @@ public class SyncRequest implements Parcelable {
|
||||
return mIsExpedited;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
* @return whether this sync is scheduled as an expedited job.
|
||||
*/
|
||||
public boolean isScheduledAsExpeditedJob() {
|
||||
return mIsScheduledAsExpeditedJob;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*
|
||||
@ -149,6 +160,7 @@ public class SyncRequest implements Parcelable {
|
||||
parcel.writeInt((mDisallowMetered ? 1 : 0));
|
||||
parcel.writeInt((mIsAuthority ? 1 : 0));
|
||||
parcel.writeInt((mIsExpedited? 1 : 0));
|
||||
parcel.writeInt(mIsScheduledAsExpeditedJob ? 1 : 0);
|
||||
parcel.writeParcelable(mAccountToSync, flags);
|
||||
parcel.writeString(mAuthority);
|
||||
}
|
||||
@ -161,6 +173,7 @@ public class SyncRequest implements Parcelable {
|
||||
mDisallowMetered = (in.readInt() != 0);
|
||||
mIsAuthority = (in.readInt() != 0);
|
||||
mIsExpedited = (in.readInt() != 0);
|
||||
mIsScheduledAsExpeditedJob = (in.readInt() != 0);
|
||||
mAccountToSync = in.readParcelable(null);
|
||||
mAuthority = in.readString();
|
||||
}
|
||||
@ -174,6 +187,7 @@ public class SyncRequest implements Parcelable {
|
||||
mIsPeriodic = (b.mSyncType == Builder.SYNC_TYPE_PERIODIC);
|
||||
mIsAuthority = (b.mSyncTarget == Builder.SYNC_TARGET_ADAPTER);
|
||||
mIsExpedited = b.mExpedited;
|
||||
mIsScheduledAsExpeditedJob = b.mScheduleAsExpeditedJob;
|
||||
mExtras = new Bundle(b.mCustomExtras);
|
||||
// For now we merge the sync config extras & the custom extras into one bundle.
|
||||
// TODO: pass the configuration extras through separately.
|
||||
@ -258,6 +272,11 @@ public class SyncRequest implements Parcelable {
|
||||
*/
|
||||
private boolean mRequiresCharging;
|
||||
|
||||
/**
|
||||
* Whether the sync should be scheduled as an expedited job.
|
||||
*/
|
||||
private boolean mScheduleAsExpeditedJob;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
@ -309,7 +328,8 @@ public class SyncRequest implements Parcelable {
|
||||
* {@link ContentResolver#SYNC_EXTRAS_INITIALIZE},
|
||||
* {@link ContentResolver#SYNC_EXTRAS_FORCE},
|
||||
* {@link ContentResolver#SYNC_EXTRAS_EXPEDITED},
|
||||
* {@link ContentResolver#SYNC_EXTRAS_MANUAL}
|
||||
* {@link ContentResolver#SYNC_EXTRAS_MANUAL},
|
||||
* {@link ContentResolver#SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB}
|
||||
* set to true. If any are supplied then an <code>IllegalArgumentException</code> will
|
||||
* be thrown.
|
||||
*
|
||||
@ -499,6 +519,22 @@ public class SyncRequest implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for setting
|
||||
* {@link ContentResolver#SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB}.
|
||||
*
|
||||
* <p> Not to be confused with {@link ContentResolver#SYNC_EXTRAS_EXPEDITED}.
|
||||
*
|
||||
* <p> Not valid for periodic syncs, expedited syncs, and syncs that require charging - an
|
||||
* <code>IllegalArgumentException</code> will be thrown in {@link #build()}.
|
||||
*
|
||||
* @param scheduleAsExpeditedJob whether to schedule as an expedited job. Default false.
|
||||
*/
|
||||
public @NonNull Builder setScheduleAsExpeditedJob(boolean scheduleAsExpeditedJob) {
|
||||
mScheduleAsExpeditedJob = scheduleAsExpeditedJob;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs validation over the request and throws the runtime exception
|
||||
* <code>IllegalArgumentException</code> if this validation fails.
|
||||
@ -507,11 +543,6 @@ public class SyncRequest implements Parcelable {
|
||||
* builder.
|
||||
*/
|
||||
public SyncRequest build() {
|
||||
// Validate the extras bundle
|
||||
ContentResolver.validateSyncExtrasBundle(mCustomExtras);
|
||||
if (mCustomExtras == null) {
|
||||
mCustomExtras = new Bundle();
|
||||
}
|
||||
// Combine builder extra flags into the config bundle.
|
||||
mSyncConfigExtras = new Bundle();
|
||||
if (mIgnoreBackoff) {
|
||||
@ -532,17 +563,35 @@ public class SyncRequest implements Parcelable {
|
||||
if (mExpedited) {
|
||||
mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
|
||||
}
|
||||
if (mScheduleAsExpeditedJob) {
|
||||
mSyncConfigExtras.putBoolean(
|
||||
ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true);
|
||||
}
|
||||
if (mIsManual) {
|
||||
mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
|
||||
mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
|
||||
}
|
||||
|
||||
if (mCustomExtras == null) {
|
||||
mCustomExtras = new Bundle();
|
||||
}
|
||||
// Validate the extras bundles
|
||||
ContentResolver.validateSyncExtrasBundle(mCustomExtras);
|
||||
// If this is a periodic sync ensure than invalid extras were not set.
|
||||
if (mSyncType == SYNC_TYPE_PERIODIC) {
|
||||
// If this is a periodic sync ensure than invalid extras were not set.
|
||||
if (ContentResolver.invalidPeriodicExtras(mCustomExtras) ||
|
||||
ContentResolver.invalidPeriodicExtras(mSyncConfigExtras)) {
|
||||
throw new IllegalArgumentException("Illegal extras were set");
|
||||
}
|
||||
}
|
||||
// If this sync is scheduled as an EJ, ensure that invalid extras were not set.
|
||||
if (mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB)
|
||||
|| mScheduleAsExpeditedJob) {
|
||||
if (ContentResolver.hasInvalidScheduleAsEjExtras(mCustomExtras)
|
||||
|| ContentResolver.hasInvalidScheduleAsEjExtras(mSyncConfigExtras)) {
|
||||
throw new IllegalArgumentException("Illegal extras were set");
|
||||
}
|
||||
}
|
||||
// Ensure that a target for the sync has been set.
|
||||
if (mSyncTarget == SYNC_TARGET_UNKNOWN) {
|
||||
throw new IllegalArgumentException("Must specify an adapter with" +
|
||||
|
@ -264,6 +264,10 @@ public class SyncManager {
|
||||
|
||||
private final SyncLogger mLogger;
|
||||
|
||||
// NOTE: this is a temporary allow-list for testing purposes; it will be removed before release.
|
||||
private final String[] mEjSyncAllowedPackages = new String[]{
|
||||
"com.google.android.google", "com.android.frameworks.servicestests"};
|
||||
|
||||
private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
|
||||
for (JobInfo job: pendingJobs) {
|
||||
if (job.getId() == jobId) {
|
||||
@ -983,6 +987,14 @@ public class SyncManager {
|
||||
}
|
||||
}
|
||||
|
||||
final boolean scheduleAsEj =
|
||||
extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
|
||||
// NOTE: this is a temporary check for internal testing - to be removed before release.
|
||||
if (scheduleAsEj && !ArrayUtils.contains(mEjSyncAllowedPackages, callingPackage)) {
|
||||
throw new IllegalArgumentException(
|
||||
callingPackage + " is not allowed to schedule a sync as an EJ yet.");
|
||||
}
|
||||
|
||||
for (AccountAndUser account : accounts) {
|
||||
// If userId is specified, do not sync accounts of other users
|
||||
if (userId >= UserHandle.USER_SYSTEM && account.userId >= UserHandle.USER_SYSTEM
|
||||
@ -1490,6 +1502,12 @@ public class SyncManager {
|
||||
+ logSafe(syncOperation.target));
|
||||
backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
|
||||
SyncStorageEngine.NOT_IN_BACKOFF_MODE);
|
||||
} else {
|
||||
// if an EJ is being backed-off but doesn't have SYNC_EXTRAS_IGNORE_BACKOFF set,
|
||||
// reschedule it as a regular job
|
||||
if (syncOperation.isScheduledAsExpeditedJob()) {
|
||||
syncOperation.scheduleEjAsRegularJob = true;
|
||||
}
|
||||
}
|
||||
long now = SystemClock.elapsedRealtime();
|
||||
long backoffDelay = backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE ? 0
|
||||
@ -1640,6 +1658,10 @@ public class SyncManager {
|
||||
b.setRequiresCharging(true);
|
||||
}
|
||||
|
||||
if (syncOperation.isScheduledAsExpeditedJob() && !syncOperation.scheduleEjAsRegularJob) {
|
||||
b.setExpedited(true);
|
||||
}
|
||||
|
||||
if (syncOperation.syncExemptionFlag
|
||||
== ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
|
||||
DeviceIdleInternal dic =
|
||||
@ -3951,6 +3973,9 @@ public class SyncManager {
|
||||
if (key.equals(ContentResolver.SYNC_EXTRAS_EXPEDITED)) {
|
||||
return true;
|
||||
}
|
||||
if (key.equals(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB)) {
|
||||
return true;
|
||||
}
|
||||
if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -103,6 +103,13 @@ public class SyncOperation {
|
||||
/** Stores the number of times this sync operation failed and had to be retried. */
|
||||
int retries;
|
||||
|
||||
/**
|
||||
* Indicates if a sync that was originally scheduled as an EJ is being re-scheduled as a
|
||||
* regular job. Specifically, this will be {@code true} if a sync is being backed-off but
|
||||
* {@link ContentResolver#SYNC_EXTRAS_IGNORE_BACKOFF} is not set.
|
||||
*/
|
||||
boolean scheduleEjAsRegularJob;
|
||||
|
||||
/** jobId of the JobScheduler job corresponding to this sync */
|
||||
public int jobId;
|
||||
|
||||
@ -408,6 +415,12 @@ public class SyncOperation {
|
||||
if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
|
||||
sb.append(" EXPEDITED");
|
||||
}
|
||||
if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false)) {
|
||||
sb.append(" EXPEDITED-JOB");
|
||||
if (scheduleEjAsRegularJob) {
|
||||
sb.append("(scheduled-as-regular)");
|
||||
}
|
||||
}
|
||||
switch (syncExemptionFlag) {
|
||||
case ContentResolver.SYNC_EXEMPTION_NONE:
|
||||
break;
|
||||
@ -537,6 +550,11 @@ public class SyncOperation {
|
||||
return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING, false);
|
||||
}
|
||||
|
||||
boolean isScheduledAsExpeditedJob() {
|
||||
return mImmutableExtras.getBoolean(
|
||||
ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
|
||||
}
|
||||
|
||||
boolean isAppStandbyExempted() {
|
||||
return syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE;
|
||||
}
|
||||
|
@ -153,4 +153,25 @@ public class SyncOperationTest extends AndroidTestCase {
|
||||
assertEquals("Period not restored", periodic.periodMillis, oneoff.periodMillis);
|
||||
assertEquals("Flex not restored", periodic.flexMillis, oneoff.flexMillis);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testScheduleAsEjIsInExtras() {
|
||||
Account account1 = new Account("account1", "type1");
|
||||
Bundle b1 = new Bundle();
|
||||
b1.putBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true);
|
||||
|
||||
SyncOperation op1 = new SyncOperation(account1, 0, 1, "foo", 0,
|
||||
SyncOperation.REASON_USER_START, "authority1", b1, false,
|
||||
ContentResolver.SYNC_EXEMPTION_NONE);
|
||||
assertTrue(op1.isScheduledAsExpeditedJob());
|
||||
|
||||
PersistableBundle pb = op1.toJobInfoExtras();
|
||||
assertTrue("EJ extra not found in job extras",
|
||||
((PersistableBundle) pb.get("syncExtras"))
|
||||
.containsKey(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB));
|
||||
|
||||
SyncOperation op2 = SyncOperation.maybeCreateFromJobExtras(pb);
|
||||
assertTrue("EJ extra not found in extras", op2.getClonedExtras()
|
||||
.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user