Merge "More small fixes/adjustments to job scheduler." into oc-dev
diff --git a/api/current.txt b/api/current.txt
index 51a2192..d3184d6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6890,7 +6890,7 @@
}
public abstract class JobServiceEngine {
- ctor public JobServiceEngine(android.content.Context);
+ 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 abstract boolean onStartJob(android.app.job.JobParameters);
diff --git a/api/system-current.txt b/api/system-current.txt
index d43cf79..b216832 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7326,7 +7326,7 @@
}
public abstract class JobServiceEngine {
- ctor public JobServiceEngine(android.content.Context);
+ 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 abstract boolean onStartJob(android.app.job.JobParameters);
diff --git a/api/test-current.txt b/api/test-current.txt
index aecb537..e3292f9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6920,7 +6920,7 @@
}
public abstract class JobServiceEngine {
- ctor public JobServiceEngine(android.content.Context);
+ 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 abstract boolean onStartJob(android.app.job.JobParameters);
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index 016a0fa..673d1b8 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -164,6 +164,20 @@
* you should not call {@link JobService#jobFinished(JobParameters, boolean)} yourself
* (otherwise you risk losing an upcoming JobWorkItem that is being enqueued at the same time).
*
+ * <p>Once you are done with the {@link JobWorkItem} returned by this method, you must call
+ * {@link #completeWork(JobWorkItem)} with it to inform the system that you are done
+ * executing the work. The job will not be finished until all dequeued work has been
+ * completed. You do not, however, have to complete each returned work item before deqeueing
+ * the next one -- you can use {@link #dequeueWork()} multiple times before completing
+ * previous work if you want to process work in parallel, and you can complete the work
+ * in whatever order you want.</p>
+ *
+ * <p>If the job runs to the end of its available time period before all work has been
+ * completed, it will stop as normal. You should return true from
+ * {@link JobService#onStopJob(JobParameters)} in order to have the job rescheduled, and by
+ * doing so any pending as well as remaining uncompleted work will be re-queued
+ * for the next time the job runs.</p>
+ *
* @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
diff --git a/core/java/android/app/job/JobServiceEngine.java b/core/java/android/app/job/JobServiceEngine.java
index 879212e..a628619 100644
--- a/core/java/android/app/job/JobServiceEngine.java
+++ b/core/java/android/app/job/JobServiceEngine.java
@@ -54,7 +54,7 @@
/**
* Context we are running in.
*/
- private final Context mContext;
+ private final Service mService;
private final IJobService mBinder;
@@ -182,12 +182,12 @@
/**
* Create a new engine, ready for use.
*
- * @param context The {@link Service} that is creating this engine.
+ * @param service The {@link Service} that is creating this engine and in which it will run.
*/
- public JobServiceEngine(Context context) {
- mContext = context;
+ public JobServiceEngine(Service service) {
+ mService = service;
mBinder = new JobInterface(this);
- mHandler = new JobHandler(mContext.getMainLooper());
+ mHandler = new JobHandler(mService.getMainLooper());
}
/**
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index d01de3c..6f08fbe 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1071,9 +1071,16 @@
if (DEBUG) {
Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
}
+
+ // If the job wants to be rescheduled, we first need to make the next upcoming
+ // job so we can transfer any appropriate state over from the previous job when
+ // we stop it.
+ final JobStatus rescheduledJob = needsReschedule
+ ? getRescheduleJobForFailureLocked(jobStatus) : null;
+
// Do not write back immediately if this is a periodic job. The job may get lost if system
// shuts down before it is added back.
- if (!stopTrackingJobLocked(jobStatus, null, !jobStatus.getJob().isPeriodic())) {
+ if (!stopTrackingJobLocked(jobStatus, rescheduledJob, !jobStatus.getJob().isPeriodic())) {
if (DEBUG) {
Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
}
@@ -1082,18 +1089,14 @@
mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
return;
}
- // Note: there is a small window of time in here where, when rescheduling a job,
- // we will stop monitoring its content providers. This should be fixed by stopping
- // the old job after scheduling the new one, but since we have no lock held here
- // that may cause ordering problems if the app removes jobStatus while in here.
- if (needsReschedule) {
- JobStatus rescheduled = getRescheduleJobForFailureLocked(jobStatus);
+
+ if (rescheduledJob != null) {
try {
- rescheduled.prepareLocked(ActivityManager.getService());
+ rescheduledJob.prepareLocked(ActivityManager.getService());
} catch (SecurityException e) {
- Slog.w(TAG, "Unable to regrant job permissions for " + rescheduled);
+ Slog.w(TAG, "Unable to regrant job permissions for " + rescheduledJob);
}
- startTrackingJobLocked(rescheduled, jobStatus);
+ startTrackingJobLocked(rescheduledJob, jobStatus);
} else if (jobStatus.getJob().isPeriodic()) {
JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
try {
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index e8cc078..66ef90c 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -326,9 +326,18 @@
public void stopTrackingJobLocked(JobStatus incomingJob) {
if (incomingJob != null) {
- // We are replacing with a new job -- transfer the work!
- incomingJob.pendingWork = pendingWork;
+ // We are replacing with a new job -- transfer the work! We do any executing
+ // work first, since that was originally at the front of the pending work.
+ if (executingWork != null && executingWork.size() > 0) {
+ incomingJob.pendingWork = executingWork;
+ }
+ if (incomingJob.pendingWork == null) {
+ incomingJob.pendingWork = pendingWork;
+ } else if (pendingWork != null && pendingWork.size() > 0) {
+ incomingJob.pendingWork.addAll(pendingWork);
+ }
pendingWork = null;
+ executingWork = null;
incomingJob.nextPendingWorkId = nextPendingWorkId;
} else {
// We are completely stopping the job... need to clean up work.