Merge "Address various JobScheduler API feedback." into oc-dev
am: e3cc9287ac
Change-Id: I8801bb55abacae1aa2f1cf4d109087dc0209e4cf
This commit is contained in:
@@ -6893,15 +6893,15 @@ package android.app.job {
|
||||
public abstract class JobServiceEngine {
|
||||
ctor public JobServiceEngine(android.app.Service);
|
||||
method public final android.os.IBinder getBinder();
|
||||
method public final void jobFinished(android.app.job.JobParameters, boolean);
|
||||
method public void jobFinished(android.app.job.JobParameters, boolean);
|
||||
method public abstract boolean onStartJob(android.app.job.JobParameters);
|
||||
method public abstract boolean onStopJob(android.app.job.JobParameters);
|
||||
}
|
||||
|
||||
public final class JobWorkItem implements android.os.Parcelable {
|
||||
ctor public JobWorkItem(android.content.Intent);
|
||||
ctor public JobWorkItem(android.os.Parcel);
|
||||
method public int describeContents();
|
||||
method public int getDeliveryCount();
|
||||
method public android.content.Intent getIntent();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
|
||||
|
||||
@@ -7329,15 +7329,15 @@ package android.app.job {
|
||||
public abstract class JobServiceEngine {
|
||||
ctor public JobServiceEngine(android.app.Service);
|
||||
method public final android.os.IBinder getBinder();
|
||||
method public final void jobFinished(android.app.job.JobParameters, boolean);
|
||||
method public void jobFinished(android.app.job.JobParameters, boolean);
|
||||
method public abstract boolean onStartJob(android.app.job.JobParameters);
|
||||
method public abstract boolean onStopJob(android.app.job.JobParameters);
|
||||
}
|
||||
|
||||
public final class JobWorkItem implements android.os.Parcelable {
|
||||
ctor public JobWorkItem(android.content.Intent);
|
||||
ctor public JobWorkItem(android.os.Parcel);
|
||||
method public int describeContents();
|
||||
method public int getDeliveryCount();
|
||||
method public android.content.Intent getIntent();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
|
||||
|
||||
@@ -6923,15 +6923,15 @@ package android.app.job {
|
||||
public abstract class JobServiceEngine {
|
||||
ctor public JobServiceEngine(android.app.Service);
|
||||
method public final android.os.IBinder getBinder();
|
||||
method public final void jobFinished(android.app.job.JobParameters, boolean);
|
||||
method public void jobFinished(android.app.job.JobParameters, boolean);
|
||||
method public abstract boolean onStartJob(android.app.job.JobParameters);
|
||||
method public abstract boolean onStopJob(android.app.job.JobParameters);
|
||||
}
|
||||
|
||||
public final class JobWorkItem implements android.os.Parcelable {
|
||||
ctor public JobWorkItem(android.content.Intent);
|
||||
ctor public JobWorkItem(android.os.Parcel);
|
||||
method public int describeContents();
|
||||
method public int getDeliveryCount();
|
||||
method public android.content.Intent getIntent();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
|
||||
|
||||
@@ -837,8 +837,12 @@ public class JobInfo implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set optional transient extras. This is incompatible with jobs that are also
|
||||
* persisted with {@link #setPersisted(boolean)}; mixing the two is not allowed.
|
||||
* Set optional transient extras.
|
||||
*
|
||||
* <p>Because setting this property is not compatible with persisted
|
||||
* jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
|
||||
* {@link android.app.job.JobInfo.Builder#build()} is called.</p>
|
||||
*
|
||||
* @param extras Bundle containing extras you want the scheduler to hold on to for you.
|
||||
*/
|
||||
public Builder setTransientExtras(@NonNull Bundle extras) {
|
||||
|
||||
@@ -180,6 +180,12 @@ public class JobParameters implements Parcelable {
|
||||
* doing so any pending as well as remaining uncompleted work will be re-queued
|
||||
* for the next time the job runs.</p>
|
||||
*
|
||||
* <p>This example shows how to construct a JobService that will serially dequeue and
|
||||
* process work that is available for it:</p>
|
||||
*
|
||||
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/JobWorkService.java
|
||||
* service}
|
||||
*
|
||||
* @return Returns a new {@link JobWorkItem} if there is one pending, otherwise null.
|
||||
* If null is returned, the system will also stop the job if all work has also been completed.
|
||||
* (This means that for correct operation, you must always call dequeueWork() after you have
|
||||
|
||||
@@ -75,21 +75,22 @@ public abstract class JobScheduler {
|
||||
public abstract int schedule(@NonNull JobInfo job);
|
||||
|
||||
/**
|
||||
* Similar to {@link #schedule}, but allows you to enqueue work for an existing job. If a job
|
||||
* with the same ID is already scheduled, it will be replaced with the new {@link JobInfo}, but
|
||||
* any previously enqueued work will remain and be dispatched the next time it runs. If a job
|
||||
* with the same ID is already running, the new work will be enqueued for it.
|
||||
* Similar to {@link #schedule}, but allows you to enqueue work for a new <em>or existing</em>
|
||||
* job. If a job with the same ID is already scheduled, it will be replaced with the
|
||||
* new {@link JobInfo}, but any previously enqueued work will remain and be dispatched the
|
||||
* next time it runs. If a job with the same ID is already running, the new work will be
|
||||
* enqueued for it.
|
||||
*
|
||||
* <p>The work you enqueue is later retrieved through
|
||||
* {@link JobParameters#dequeueWork() JobParameters.dequeueWork()}. Be sure to see there
|
||||
* {@link JobParameters#dequeueWork() JobParameters.dequeueWork}. Be sure to see there
|
||||
* about how to process work; the act of enqueueing work changes how you should handle the
|
||||
* overall lifecycle of an executing job.</p>
|
||||
*
|
||||
* <p>It is strongly encouraged that you use the same {@link JobInfo} for all work you
|
||||
* enqueue. This will allow the system to optimal schedule work along with any pending
|
||||
* enqueue. This will allow the system to optimally schedule work along with any pending
|
||||
* and/or currently running work. If the JobInfo changes from the last time the job was
|
||||
* enqueued, the system will need to update the associated JobInfo, which can cause a disruption
|
||||
* in exection. In particular, this can result in any currently running job that is processing
|
||||
* in execution. In particular, this can result in any currently running job that is processing
|
||||
* previous work to be stopped and restarted with the new JobInfo.</p>
|
||||
*
|
||||
* <p>It is recommended that you avoid using
|
||||
@@ -100,7 +101,7 @@ public abstract class JobScheduler {
|
||||
* (That said, you should be relatively safe with a simple set of consistent data in these
|
||||
* fields.) You should never use {@link JobInfo.Builder#setClipData(ClipData, int)} with
|
||||
* work you are enqueue, since currently this will always be treated as a different JobInfo,
|
||||
* even if the ClipData contents is exactly the same.</p>
|
||||
* even if the ClipData contents are exactly the same.</p>
|
||||
*
|
||||
* @param job The job you wish to enqueue work for. See
|
||||
* {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
|
||||
|
||||
@@ -32,7 +32,11 @@ import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* Helper for implementing a {@link android.app.Service} that interacts with
|
||||
* {@link JobScheduler}.
|
||||
* {@link JobScheduler}. This is not intended for use by regular applications, but
|
||||
* allows frameworks built on top of the platform to create their own
|
||||
* {@link android.app.Service} that interact with {@link JobScheduler} as well as
|
||||
* add in additional functionality. If you just want to execute jobs normally, you
|
||||
* should instead be looking at {@link JobService}.
|
||||
*/
|
||||
public abstract class JobServiceEngine {
|
||||
private static final String TAG = "JobServiceEngine";
|
||||
@@ -215,7 +219,7 @@ public abstract class JobServiceEngine {
|
||||
* {@link JobService#jobFinished(JobParameters, boolean)} JobService.jobFinished} for more
|
||||
* information.
|
||||
*/
|
||||
public final void jobFinished(JobParameters params, boolean needsReschedule) {
|
||||
public void jobFinished(JobParameters params, boolean needsReschedule) {
|
||||
Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
|
||||
m.arg2 = needsReschedule ? 1 : 0;
|
||||
m.sendToTarget();
|
||||
|
||||
@@ -22,15 +22,19 @@ import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* A unit of work that can be enqueued for a job using
|
||||
* {@link JobScheduler#enqueue JobScheduler.enqueue}.
|
||||
* {@link JobScheduler#enqueue JobScheduler.enqueue}. See
|
||||
* {@link JobParameters#dequeueWork() JobParameters.dequeueWork} for more details.
|
||||
*/
|
||||
final public class JobWorkItem implements Parcelable {
|
||||
final Intent mIntent;
|
||||
int mDeliveryCount;
|
||||
int mWorkId;
|
||||
Object mGrants;
|
||||
|
||||
/**
|
||||
* Create a new piece of work.
|
||||
* Create a new piece of work, which can be submitted to
|
||||
* {@link JobScheduler#enqueue JobScheduler.enqueue}.
|
||||
*
|
||||
* @param intent The general Intent describing this work.
|
||||
*/
|
||||
public JobWorkItem(Intent intent) {
|
||||
@@ -44,6 +48,23 @@ final public class JobWorkItem implements Parcelable {
|
||||
return mIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of the number of times this work item has been delivered
|
||||
* to the job. The value will be > 1 if it has been redelivered because the job
|
||||
* was stopped or crashed while it had previously been delivered but before the
|
||||
* job had called {@link JobParameters#completeWork JobParameters.completeWork} for it.
|
||||
*/
|
||||
public int getDeliveryCount() {
|
||||
return mDeliveryCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void bumpDeliveryCount() {
|
||||
mDeliveryCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -73,7 +94,17 @@ final public class JobWorkItem implements Parcelable {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "JobWorkItem{id=" + mWorkId + " intent=" + mIntent + "}";
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
sb.append("JobWorkItem{id=");
|
||||
sb.append(mWorkId);
|
||||
sb.append(" intent=");
|
||||
sb.append(mIntent);
|
||||
if (mDeliveryCount != 0) {
|
||||
sb.append(" dcount=");
|
||||
sb.append(mDeliveryCount);
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
@@ -87,6 +118,7 @@ final public class JobWorkItem implements Parcelable {
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
out.writeInt(mDeliveryCount);
|
||||
out.writeInt(mWorkId);
|
||||
}
|
||||
|
||||
@@ -101,12 +133,13 @@ final public class JobWorkItem implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
public JobWorkItem(Parcel in) {
|
||||
JobWorkItem(Parcel in) {
|
||||
if (in.readInt() != 0) {
|
||||
mIntent = Intent.CREATOR.createFromParcel(in);
|
||||
} else {
|
||||
mIntent = null;
|
||||
}
|
||||
mDeliveryCount = in.readInt();
|
||||
mWorkId = in.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1367,26 +1367,48 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
* - The component is enabled and runnable.
|
||||
*/
|
||||
private boolean isReadyToBeExecutedLocked(JobStatus job) {
|
||||
final boolean jobExists = mJobs.containsJob(job);
|
||||
final boolean jobReady = job.isReady();
|
||||
final boolean jobPending = mPendingJobs.contains(job);
|
||||
final boolean jobActive = isCurrentlyActiveLocked(job);
|
||||
final boolean jobBackingUp = mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0;
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
|
||||
+ " ready=" + jobReady);
|
||||
}
|
||||
|
||||
// This is a condition that is very likely to be false (most jobs that are
|
||||
// scheduled are sitting there, not ready yet) and very cheap to check (just
|
||||
// a few conditions on data in JobStatus).
|
||||
if (!jobReady) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean jobExists = mJobs.containsJob(job);
|
||||
|
||||
final int userId = job.getUserId();
|
||||
final boolean userStarted = ArrayUtils.contains(mStartedUsers, userId);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
|
||||
+ " exists=" + jobExists
|
||||
+ " ready=" + jobReady + " pending=" + jobPending
|
||||
+ " active=" + jobActive + " backingup=" + jobBackingUp
|
||||
+ " userStarted=" + userStarted);
|
||||
+ " exists=" + jobExists + " userStarted=" + userStarted);
|
||||
}
|
||||
|
||||
// Short circuit: don't do the expensive PM check unless we really think
|
||||
// we might need to run this job now.
|
||||
if (!jobExists || !userStarted || !jobReady || jobPending || jobActive || jobBackingUp) {
|
||||
// These are also fairly cheap to check, though they typically will not
|
||||
// be conditions we fail.
|
||||
if (!jobExists || !userStarted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean jobPending = mPendingJobs.contains(job);
|
||||
final boolean jobActive = isCurrentlyActiveLocked(job);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
|
||||
+ " pending=" + jobPending + " active=" + jobActive);
|
||||
}
|
||||
|
||||
// These can be a little more expensive (especially jobActive, since we need to
|
||||
// go through the array of all potentially active jobs), so we are doing them
|
||||
// later... but still before checking with the package manager!
|
||||
if (jobPending || jobActive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -339,6 +339,7 @@ public final class JobStatus {
|
||||
executingWork = new ArrayList<>();
|
||||
}
|
||||
executingWork.add(work);
|
||||
work.bumpDeliveryCount();
|
||||
}
|
||||
return work;
|
||||
}
|
||||
@@ -661,6 +662,9 @@ public final class JobStatus {
|
||||
/**
|
||||
* @return Whether or not this job is ready to run, based on its requirements. This is true if
|
||||
* the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
|
||||
* TODO: This function is called a *lot*. We should probably just have it check an
|
||||
* already-computed boolean, which we updated whenever we see one of the states it depends
|
||||
* on here change.
|
||||
*/
|
||||
public boolean isReady() {
|
||||
// Deadline constraint trumps other constraints (except for periodic jobs where deadline
|
||||
@@ -856,7 +860,8 @@ public final class JobStatus {
|
||||
|
||||
private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
|
||||
pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #");
|
||||
pw.print(work.getWorkId()); pw.print(" "); pw.println(work.getIntent());
|
||||
pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount());
|
||||
pw.print("x "); pw.println(work.getIntent());
|
||||
if (work.getGrants() != null) {
|
||||
pw.print(prefix); pw.println(" URI grants:");
|
||||
((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " ");
|
||||
|
||||
Reference in New Issue
Block a user