summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk6
-rw-r--r--CleanSpec.mk3
-rw-r--r--api/current.txt92
-rw-r--r--core/java/android/app/ContextImpl.java8
-rw-r--r--core/java/android/app/JobSchedulerImpl.java (renamed from core/java/android/app/TaskManagerImpl.java)28
-rw-r--r--core/java/android/app/job/IJobCallback.aidl (renamed from core/java/android/app/task/ITaskCallback.aidl)31
-rw-r--r--core/java/android/app/job/IJobScheduler.aidl (renamed from core/java/android/app/task/ITaskManager.aidl)14
-rw-r--r--core/java/android/app/job/IJobService.aidl (renamed from core/java/android/app/task/ITaskService.aidl)19
-rw-r--r--core/java/android/app/job/JobInfo.aidl (renamed from core/java/android/app/task/Task.aidl)5
-rw-r--r--core/java/android/app/job/JobInfo.java (renamed from core/java/android/app/task/Task.java)150
-rw-r--r--core/java/android/app/job/JobParameters.aidl (renamed from core/java/android/app/task/TaskParams.aidl)4
-rw-r--r--core/java/android/app/job/JobParameters.java (renamed from core/java/android/app/task/TaskParams.java)44
-rw-r--r--core/java/android/app/job/JobScheduler.java72
-rw-r--r--core/java/android/app/job/JobService.java (renamed from core/java/android/app/task/TaskService.java)161
-rw-r--r--core/java/android/app/task/TaskManager.java72
-rw-r--r--core/java/android/content/Context.java16
-rw-r--r--core/res/AndroidManifest.xml12
-rw-r--r--core/res/res/values/strings.xml4
-rw-r--r--services/core/java/com/android/server/MountServiceIdler.java28
-rw-r--r--services/core/java/com/android/server/job/JobCompletedListener.java (renamed from services/core/java/com/android/server/task/TaskCompletedListener.java)16
-rw-r--r--services/core/java/com/android/server/job/JobMapReadFinishedListener.java (renamed from services/core/java/com/android/server/task/TaskMapReadFinishedListener.java)12
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java764
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java (renamed from services/core/java/com/android/server/task/TaskServiceContext.java)216
-rw-r--r--services/core/java/com/android/server/job/JobStore.java (renamed from services/core/java/com/android/server/task/TaskStore.java)382
-rw-r--r--services/core/java/com/android/server/job/StateChangedListener.java (renamed from services/core/java/com/android/server/task/StateChangedListener.java)16
-rw-r--r--services/core/java/com/android/server/job/controllers/BatteryController.java (renamed from services/core/java/com/android/server/task/controllers/BatteryController.java)16
-rw-r--r--services/core/java/com/android/server/job/controllers/ConnectivityController.java (renamed from services/core/java/com/android/server/task/controllers/ConnectivityController.java)70
-rw-r--r--services/core/java/com/android/server/job/controllers/IdleController.java (renamed from services/core/java/com/android/server/task/controllers/IdleController.java)16
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java (renamed from services/core/java/com/android/server/task/controllers/TaskStatus.java)115
-rw-r--r--services/core/java/com/android/server/job/controllers/StateController.java (renamed from services/core/java/com/android/server/task/controllers/StateController.java)18
-rw-r--r--services/core/java/com/android/server/job/controllers/TimeController.java (renamed from services/core/java/com/android/server/task/controllers/TimeController.java)146
-rw-r--r--services/core/java/com/android/server/task/TaskManagerService.java764
-rw-r--r--services/java/com/android/server/SystemServer.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java84
-rw-r--r--services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java8
-rw-r--r--tests/JobSchedulerTestApp/AndroidManifest.xml1
-rw-r--r--tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java26
-rw-r--r--tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java48
38 files changed, 1737 insertions, 1758 deletions
diff --git a/Android.mk b/Android.mk
index 7c01ed9..52459ae 100644
--- a/Android.mk
+++ b/Android.mk
@@ -77,9 +77,9 @@ LOCAL_SRC_FILES += \
core/java/android/app/ISearchManagerCallback.aidl \
core/java/android/app/IServiceConnection.aidl \
core/java/android/app/IStopUserCallback.aidl \
- core/java/android/app/task/ITaskCallback.aidl \
- core/java/android/app/task/ITaskManager.aidl \
- core/java/android/app/task/ITaskService.aidl \
+ core/java/android/app/job/IJobCallback.aidl \
+ core/java/android/app/job/IJobScheduler.aidl \
+ core/java/android/app/job/IJobService.aidl \
core/java/android/app/IThumbnailRetriever.aidl \
core/java/android/app/ITransientNotification.aidl \
core/java/android/app/IUiAutomationConnection.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index f3bb9b6..5b027b3 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -197,3 +197,6 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/task)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app/task)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/TaskManager)
diff --git a/api/current.txt b/api/current.txt
index 7d8e796..60d5e067 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5356,23 +5356,9 @@ package android.app.backup {
}
-package android.app.maintenance {
+package android.app.job {
- public abstract class IdleService extends android.app.Service {
- ctor public IdleService();
- method public final void finishIdle();
- method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract boolean onIdleStart();
- method public abstract void onIdleStop();
- field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_IDLE_SERVICE";
- field public static final java.lang.String SERVICE_INTERFACE = "android.service.idle.IdleService";
- }
-
-}
-
-package android.app.task {
-
- public class Task implements android.os.Parcelable {
+ public class JobInfo implements android.os.Parcelable {
method public int describeContents();
method public int getBackoffPolicy();
method public android.os.PersistableBundle getExtras();
@@ -5390,55 +5376,69 @@ package android.app.task {
field public static final android.os.Parcelable.Creator CREATOR;
}
- public static abstract interface Task.BackoffPolicy {
+ public static abstract interface JobInfo.BackoffPolicy {
field public static final int EXPONENTIAL = 1; // 0x1
field public static final int LINEAR = 0; // 0x0
}
- public static final class Task.Builder {
- ctor public Task.Builder(int, android.content.ComponentName);
- method public android.app.task.Task build();
- method public android.app.task.Task.Builder setBackoffCriteria(long, int);
- method public android.app.task.Task.Builder setExtras(android.os.PersistableBundle);
- method public android.app.task.Task.Builder setMinimumLatency(long);
- method public android.app.task.Task.Builder setOverrideDeadline(long);
- method public android.app.task.Task.Builder setPeriodic(long);
- method public android.app.task.Task.Builder setRequiredNetworkCapabilities(int);
- method public android.app.task.Task.Builder setRequiresCharging(boolean);
- method public android.app.task.Task.Builder setRequiresDeviceIdle(boolean);
+ public static final class JobInfo.Builder {
+ ctor public JobInfo.Builder(int, android.content.ComponentName);
+ method public android.app.job.JobInfo build();
+ method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
+ method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
+ 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 setRequiredNetworkCapabilities(int);
+ method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
+ method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
}
- public static abstract interface Task.NetworkType {
+ public static abstract interface JobInfo.NetworkType {
field public static final int ANY = 1; // 0x1
field public static final int NONE = 0; // 0x0
field public static final int UNMETERED = 2; // 0x2
}
- public abstract class TaskManager {
- ctor public TaskManager();
+ public class JobParameters implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.PersistableBundle getExtras();
+ method public int getJobId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public abstract class JobScheduler {
+ ctor public JobScheduler();
method public abstract void cancel(int);
method public abstract void cancelAll();
- method public abstract java.util.List<android.app.task.Task> getAllPendingTasks();
- method public abstract int schedule(android.app.task.Task);
+ method public abstract java.util.List<android.app.job.JobInfo> getAllPendingJobs();
+ method public abstract int schedule(android.app.job.JobInfo);
field public static final int RESULT_FAILURE = 0; // 0x0
field public static final int RESULT_SUCCESS = 1; // 0x1
}
- public class TaskParams implements android.os.Parcelable {
- method public int describeContents();
- method public android.os.PersistableBundle getExtras();
- method public int getTaskId();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
+ public abstract class JobService extends android.app.Service {
+ ctor public JobService();
+ method public final void jobFinished(android.app.job.JobParameters, boolean);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract boolean onStartJob(android.app.job.JobParameters);
+ method public abstract boolean onStopJob(android.app.job.JobParameters);
+ field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
}
- public abstract class TaskService extends android.app.Service {
- ctor public TaskService();
+}
+
+package android.app.maintenance {
+
+ public abstract class IdleService extends android.app.Service {
+ ctor public IdleService();
+ method public final void finishIdle();
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract boolean onStartTask(android.app.task.TaskParams);
- method public abstract boolean onStopTask(android.app.task.TaskParams);
- method public final void taskFinished(android.app.task.TaskParams, boolean);
- field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_TASK_SERVICE";
+ method public abstract boolean onIdleStart();
+ method public abstract void onIdleStop();
+ field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_IDLE_SERVICE";
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.idle.IdleService";
}
}
@@ -7006,6 +7006,7 @@ package android.content {
field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
field public static final java.lang.String LAYOUT_INFLATER_SERVICE = "layout_inflater";
@@ -7026,7 +7027,6 @@ package android.content {
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String STORAGE_SERVICE = "storage";
- field public static final java.lang.String TASK_SERVICE = "task";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5bbc43c..c5190d3 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -133,7 +133,7 @@ import android.view.textservice.TextServicesManager;
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.app.admin.DevicePolicyManager;
-import android.app.task.ITaskManager;
+import android.app.job.IJobScheduler;
import android.app.trust.TrustManager;
import com.android.internal.annotations.GuardedBy;
@@ -697,10 +697,10 @@ class ContextImpl extends Context {
return new UsageStatsManager(ctx.getOuterContext());
}});
- registerService(TASK_SERVICE, new ServiceFetcher() {
+ registerService(JOB_SCHEDULER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(TASK_SERVICE);
- return new TaskManagerImpl(ITaskManager.Stub.asInterface(b));
+ IBinder b = ServiceManager.getService(JOB_SCHEDULER_SERVICE);
+ return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
}});
}
diff --git a/core/java/android/app/TaskManagerImpl.java b/core/java/android/app/JobSchedulerImpl.java
index fe29fb7..09038d5 100644
--- a/core/java/android/app/TaskManagerImpl.java
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -17,38 +17,38 @@
// in android.app so ContextImpl has package access
package android.app;
-import android.app.task.ITaskManager;
-import android.app.task.Task;
-import android.app.task.TaskManager;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.IJobScheduler;
import android.os.RemoteException;
import java.util.List;
/**
- * Concrete implementation of the TaskManager interface
+ * Concrete implementation of the JobScheduler interface
* @hide
*/
-public class TaskManagerImpl extends TaskManager {
- ITaskManager mBinder;
+public class JobSchedulerImpl extends JobScheduler {
+ IJobScheduler mBinder;
- /* package */ TaskManagerImpl(ITaskManager binder) {
+ /* package */ JobSchedulerImpl(IJobScheduler binder) {
mBinder = binder;
}
@Override
- public int schedule(Task task) {
+ public int schedule(JobInfo job) {
try {
- return mBinder.schedule(task);
+ return mBinder.schedule(job);
} catch (RemoteException e) {
- return TaskManager.RESULT_FAILURE;
+ return JobScheduler.RESULT_FAILURE;
}
}
@Override
- public void cancel(int taskId) {
+ public void cancel(int jobId) {
try {
- mBinder.cancel(taskId);
+ mBinder.cancel(jobId);
} catch (RemoteException e) {}
}
@@ -62,9 +62,9 @@ public class TaskManagerImpl extends TaskManager {
}
@Override
- public List<Task> getAllPendingTasks() {
+ public List<JobInfo> getAllPendingJobs() {
try {
- return mBinder.getAllPendingTasks();
+ return mBinder.getAllPendingJobs();
} catch (RemoteException e) {
return null;
}
diff --git a/core/java/android/app/task/ITaskCallback.aidl b/core/java/android/app/job/IJobCallback.aidl
index d8a32fd..2d3948f 100644
--- a/core/java/android/app/task/ITaskCallback.aidl
+++ b/core/java/android/app/job/IJobCallback.aidl
@@ -14,43 +14,40 @@
* limitations under the License.
*/
-package android.app.task;
-
-import android.app.task.ITaskService;
-import android.app.task.TaskParams;
+package android.app.job;
/**
- * The server side of the TaskManager IPC protocols. The app-side implementation
+ * The server side of the JobScheduler IPC protocols. The app-side implementation
* invokes on this interface to indicate completion of the (asynchronous) instructions
* issued by the server.
*
* In all cases, the 'who' parameter is the caller's service binder, used to track
- * which Task Service instance is reporting.
+ * which Job Service instance is reporting.
*
* {@hide}
*/
-interface ITaskCallback {
+interface IJobCallback {
/**
* Immediate callback to the system after sending a start signal, used to quickly detect ANR.
*
- * @param taskId Unique integer used to identify this task.
- * @param ongoing True to indicate that the client is processing the task. False if the task is
+ * @param jobId Unique integer used to identify this job.
+ * @param ongoing True to indicate that the client is processing the job. False if the job is
* complete
*/
- void acknowledgeStartMessage(int taskId, boolean ongoing);
+ void acknowledgeStartMessage(int jobId, boolean ongoing);
/**
* Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
*
- * @param taskId Unique integer used to identify this task.
- * @param rescheulde Whether or not to reschedule this task.
+ * @param jobId Unique integer used to identify this job.
+ * @param reschedule Whether or not to reschedule this job.
*/
- void acknowledgeStopMessage(int taskId, boolean reschedule);
+ void acknowledgeStopMessage(int jobId, boolean reschedule);
/*
- * Tell the task manager that the client is done with its execution, so that it can go on to
+ * Tell the job manager that the client is done with its execution, so that it can go on to
* the next one and stop attributing wakelock time to us etc.
*
- * @param taskId Unique integer used to identify this task.
- * @param reschedule Whether or not to reschedule this task.
+ * @param jobId Unique integer used to identify this job.
+ * @param reschedule Whether or not to reschedule this job.
*/
- void taskFinished(int taskId, boolean reschedule);
+ void jobFinished(int jobId, boolean reschedule);
}
diff --git a/core/java/android/app/task/ITaskManager.aidl b/core/java/android/app/job/IJobScheduler.aidl
index b56c78a..f1258ae 100644
--- a/core/java/android/app/task/ITaskManager.aidl
+++ b/core/java/android/app/job/IJobScheduler.aidl
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package android.app.task;
+package android.app.job;
-import android.app.task.Task;
+import android.app.job.JobInfo;
/**
- * IPC interface that supports the app-facing {@link #TaskManager} api.
+ * IPC interface that supports the app-facing {@link #JobScheduler} api.
* {@hide}
*/
-interface ITaskManager {
- int schedule(in Task task);
- void cancel(int taskId);
+interface IJobScheduler {
+ int schedule(in JobInfo job);
+ void cancel(int jobId);
void cancelAll();
- List<Task> getAllPendingTasks();
+ List<JobInfo> getAllPendingJobs();
}
diff --git a/core/java/android/app/task/ITaskService.aidl b/core/java/android/app/job/IJobService.aidl
index 87b0191..63f8b81 100644
--- a/core/java/android/app/task/ITaskService.aidl
+++ b/core/java/android/app/job/IJobService.aidl
@@ -14,22 +14,19 @@
* limitations under the License.
*/
-package android.app.task;
+package android.app.job;
-import android.app.task.ITaskCallback;
-import android.app.task.TaskParams;
-
-import android.os.Bundle;
+import android.app.job.JobParameters;
/**
* Interface that the framework uses to communicate with application code that implements a
- * TaskService. End user code does not implement this interface directly; instead, the app's
- * service implementation will extend android.app.task.TaskService.
+ * JobService. End user code does not implement this interface directly; instead, the app's
+ * service implementation will extend android.app.job.JobService.
* {@hide}
*/
-oneway interface ITaskService {
- /** Begin execution of application's task. */
- void startTask(in TaskParams taskParams);
+oneway interface IJobService {
+ /** Begin execution of application's job. */
+ void startJob(in JobParameters jobParams);
/** Stop execution of application's task. */
- void stopTask(in TaskParams taskParams);
+ void stopJob(in JobParameters jobParams);
}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/app/job/JobInfo.aidl
index 1f25439..7b198a8 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/app/job/JobInfo.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-package android.app.task;
+package android.app.job;
-parcelable Task;
- \ No newline at end of file
+parcelable JobInfo;
diff --git a/core/java/android/app/task/Task.java b/core/java/android/app/job/JobInfo.java
index 0e660b3..a22e4cd 100644
--- a/core/java/android/app/task/Task.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package android.app.task;
+package android.app.job;
import android.content.ComponentName;
import android.os.Bundle;
@@ -23,22 +23,22 @@ import android.os.Parcelable;
import android.os.PersistableBundle;
/**
- * Container of data passed to the {@link android.app.task.TaskManager} fully encapsulating the
+ * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
* parameters required to schedule work against the calling application. These are constructed
- * using the {@link Task.Builder}.
+ * using the {@link JobInfo.Builder}.
*/
-public class Task implements Parcelable {
+public class JobInfo implements Parcelable {
public interface NetworkType {
/** Default. */
public final int NONE = 0;
- /** This task requires network connectivity. */
+ /** This job requires network connectivity. */
public final int ANY = 1;
- /** This task requires network connectivity that is unmetered. */
+ /** This job requires network connectivity that is unmetered. */
public final int UNMETERED = 2;
}
/**
- * Amount of backoff a task has initially by default, in milliseconds.
+ * Amount of backoff a job has initially by default, in milliseconds.
* @hide.
*/
public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 5000L;
@@ -63,7 +63,7 @@ public class Task implements Parcelable {
public final int EXPONENTIAL = 1;
}
- private final int taskId;
+ private final int jobId;
// TODO: Change this to use PersistableBundle when that lands in master.
private final PersistableBundle extras;
private final ComponentName service;
@@ -80,10 +80,10 @@ public class Task implements Parcelable {
private final int backoffPolicy;
/**
- * Unique task id associated with this class. This is assigned to your task by the scheduler.
+ * Unique job id associated with this class. This is assigned to your job by the scheduler.
*/
public int getId() {
- return taskId;
+ return jobId;
}
/**
@@ -94,43 +94,43 @@ public class Task implements Parcelable {
}
/**
- * Name of the service endpoint that will be called back into by the TaskManager.
+ * Name of the service endpoint that will be called back into by the JobScheduler.
*/
public ComponentName getService() {
return service;
}
/**
- * Whether this task needs the device to be plugged in.
+ * Whether this job needs the device to be plugged in.
*/
public boolean isRequireCharging() {
return requireCharging;
}
/**
- * Whether this task needs the device to be in an Idle maintenance window.
+ * Whether this job needs the device to be in an Idle maintenance window.
*/
public boolean isRequireDeviceIdle() {
return requireDeviceIdle;
}
/**
- * See {@link android.app.task.Task.NetworkType} for a description of this value.
+ * See {@link android.app.job.JobInfo.NetworkType} for a description of this value.
*/
public int getNetworkCapabilities() {
return networkCapabilities;
}
/**
- * Set for a task that does not recur periodically, to specify a delay after which the task
- * will be eligible for execution. This value is not set if the task recurs periodically.
+ * Set for a job that does not recur periodically, to specify a delay after which the job
+ * will be eligible for execution. This value is not set if the job recurs periodically.
*/
public long getMinLatencyMillis() {
return minLatencyMillis;
}
/**
- * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the task recurs
+ * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs
* periodically.
*/
public long getMaxExecutionDelayMillis() {
@@ -138,23 +138,23 @@ public class Task implements Parcelable {
}
/**
- * Track whether this task will repeat with a given period.
+ * Track whether this job will repeat with a given period.
*/
public boolean isPeriodic() {
return isPeriodic;
}
/**
- * Set to the interval between occurrences of this task. This value is <b>not</b> set if the
- * task does not recur periodically.
+ * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
+ * job does not recur periodically.
*/
public long getIntervalMillis() {
return intervalMillis;
}
/**
- * The amount of time the TaskManager will wait before rescheduling a failed task. This value
- * will be increased depending on the backoff policy specified at task creation time. Defaults
+ * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
+ * will be increased depending on the backoff policy specified at job creation time. Defaults
* to 5 seconds.
*/
public long getInitialBackoffMillis() {
@@ -162,7 +162,7 @@ public class Task implements Parcelable {
}
/**
- * See {@link android.app.task.Task.BackoffPolicy} for an explanation of the values this field
+ * See {@link android.app.job.JobInfo.BackoffPolicy} for an explanation of the values this field
* can take. This defaults to exponential.
*/
public int getBackoffPolicy() {
@@ -187,8 +187,8 @@ public class Task implements Parcelable {
return hasLateConstraint;
}
- private Task(Parcel in) {
- taskId = in.readInt();
+ private JobInfo(Parcel in) {
+ jobId = in.readInt();
extras = in.readPersistableBundle();
service = in.readParcelable(null);
requireCharging = in.readInt() == 1;
@@ -204,10 +204,10 @@ public class Task implements Parcelable {
hasLateConstraint = in.readInt() == 1;
}
- private Task(Task.Builder b) {
- taskId = b.mTaskId;
+ private JobInfo(JobInfo.Builder b) {
+ jobId = b.mJobId;
extras = b.mExtras;
- service = b.mTaskService;
+ service = b.mJobService;
requireCharging = b.mRequiresCharging;
requireDeviceIdle = b.mRequiresDeviceIdle;
networkCapabilities = b.mNetworkCapabilities;
@@ -228,7 +228,7 @@ public class Task implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(taskId);
+ out.writeInt(jobId);
out.writePersistableBundle(extras);
out.writeParcelable(service, flags);
out.writeInt(requireCharging ? 1 : 0);
@@ -244,23 +244,23 @@ public class Task implements Parcelable {
out.writeInt(hasLateConstraint ? 1 : 0);
}
- public static final Creator<Task> CREATOR = new Creator<Task>() {
+ public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
@Override
- public Task createFromParcel(Parcel in) {
- return new Task(in);
+ public JobInfo createFromParcel(Parcel in) {
+ return new JobInfo(in);
}
@Override
- public Task[] newArray(int size) {
- return new Task[size];
+ public JobInfo[] newArray(int size) {
+ return new JobInfo[size];
}
};
- /** Builder class for constructing {@link Task} objects. */
+ /** Builder class for constructing {@link JobInfo} objects. */
public static final class Builder {
- private int mTaskId;
+ private int mJobId;
private PersistableBundle mExtras = PersistableBundle.EMPTY;
- private ComponentName mTaskService;
+ private ComponentName mJobService;
// Requirements.
private boolean mRequiresCharging;
private boolean mRequiresDeviceIdle;
@@ -280,15 +280,15 @@ public class Task implements Parcelable {
private boolean mBackoffPolicySet = false;
/**
- * @param taskId Application-provided id for this task. Subsequent calls to cancel, or
- * tasks created with the same taskId, will update the pre-existing task with
+ * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
+ * jobs created with the same jobId, will update the pre-existing job with
* the same id.
- * @param taskService The endpoint that you implement that will receive the callback from the
- * TaskManager.
+ * @param jobService The endpoint that you implement that will receive the callback from the
+ * JobScheduler.
*/
- public Builder(int taskId, ComponentName taskService) {
- mTaskService = taskService;
- mTaskId = taskId;
+ public Builder(int jobId, ComponentName jobService) {
+ mJobService = jobService;
+ mJobId = jobId;
}
/**
@@ -302,10 +302,10 @@ public class Task implements Parcelable {
/**
* Set some description of the kind of network capabilities you would like to have. This
- * will be a parameter defined in {@link android.app.task.Task.NetworkType}.
+ * will be a parameter defined in {@link android.app.job.JobInfo.NetworkType}.
* Not calling this function means the network is not necessary.
* Bear in mind that calling this function defines network as a strict requirement for your
- * task if the network requested is not available your task will never run. See
+ * job if the network requested is not available your job will never run. See
* {@link #setOverrideDeadline(long)} to change this behaviour.
*/
public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
@@ -313,10 +313,10 @@ public class Task implements Parcelable {
return this;
}
- /*
- * Specify that to run this task, the device needs to be plugged in. This defaults to
+ /**
+ * Specify that to run this job, the device needs to be plugged in. This defaults to
* false.
- * @param requireCharging Whether or not the device is plugged in.
+ * @param requiresCharging Whether or not the device is plugged in.
*/
public Builder setRequiresCharging(boolean requiresCharging) {
mRequiresCharging = requiresCharging;
@@ -324,11 +324,11 @@ public class Task implements Parcelable {
}
/**
- * Specify that to run, the task needs the device to be in idle mode. This defaults to
+ * Specify that to run, the job needs the device to be in idle mode. This defaults to
* false.
* <p>Idle mode is a loose definition provided by the system, which means that the device
* is not in use, and has not been in use for some time. As such, it is a good time to
- * perform resource heavy tasks. Bear in mind that battery usage will still be attributed
+ * perform resource heavy jobs. Bear in mind that battery usage will still be attributed
* to your application, and surfaced to the user in battery stats.</p>
* @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
* window.
@@ -339,17 +339,17 @@ public class Task implements Parcelable {
}
/**
- * Specify that this task should recur with the provided interval, not more than once per
- * period. You have no control over when within this interval this task will be executed,
+ * Specify that this job should recur with the provided interval, not more than once per
+ * period. You have no control over when within this interval this job will be executed,
* only the guarantee that it will be executed at most once within this interval.
- * A periodic task will be repeated until the phone is turned off, however it will only be
+ * A periodic job will be repeated until the phone is turned off, however it will only be
* persisted beyond boot if the client app has declared the
* {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. You can schedule
- * periodic tasks without this permission, they simply will cease to exist after the phone
+ * periodic jobs without this permission, they simply will cease to exist after the phone
* restarts.
* Setting this function on the builder with {@link #setMinimumLatency(long)} or
* {@link #setOverrideDeadline(long)} will result in an error.
- * @param intervalMillis Millisecond interval for which this task will repeat.
+ * @param intervalMillis Millisecond interval for which this job will repeat.
*/
public Builder setPeriodic(long intervalMillis) {
mIsPeriodic = true;
@@ -359,11 +359,11 @@ public class Task implements Parcelable {
}
/**
- * Specify that this task should be delayed by the provided amount of time.
- * Because it doesn't make sense setting this property on a periodic task, doing so will
+ * Specify that this job should be delayed by the provided amount of time.
+ * Because it doesn't make sense setting this property on a periodic job, doing so will
* throw an {@link java.lang.IllegalArgumentException} when
- * {@link android.app.task.Task.Builder#build()} is called.
- * @param minLatencyMillis Milliseconds before which this task will not be considered for
+ * {@link android.app.job.JobInfo.Builder#build()} is called.
+ * @param minLatencyMillis Milliseconds before which this job will not be considered for
* execution.
*/
public Builder setMinimumLatency(long minLatencyMillis) {
@@ -373,11 +373,11 @@ public class Task implements Parcelable {
}
/**
- * Set deadline which is the maximum scheduling latency. The task will be run by this
+ * Set deadline which is the maximum scheduling latency. The job will be run by this
* deadline even if other requirements are not met. Because it doesn't make sense setting
- * this property on a periodic task, doing so will throw an
+ * this property on a periodic job, doing so will throw an
* {@link java.lang.IllegalArgumentException} when
- * {@link android.app.task.Task.Builder#build()} is called.
+ * {@link android.app.job.JobInfo.Builder#build()} is called.
*/
public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
mMaxExecutionDelayMillis = maxExecutionDelayMillis;
@@ -389,13 +389,13 @@ public class Task implements Parcelable {
* Set up the back-off/retry policy.
* This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
* 1hr.
- * Note that trying to set a backoff criteria for a task with
+ * Note that trying to set a backoff criteria for a job with
* {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
- * This is because back-off typically does not make sense for these types of tasks. See
- * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
- * for more description of the return value for the case of a task executing while in idle
+ * This is because back-off typically does not make sense for these types of jobs. See
+ * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
+ * for more description of the return value for the case of a job executing while in idle
* mode.
- * @param initialBackoffMillis Millisecond time interval to wait initially when task has
+ * @param initialBackoffMillis Millisecond time interval to wait initially when job has
* failed.
* @param backoffPolicy is one of {@link BackoffPolicy}
*/
@@ -407,25 +407,25 @@ public class Task implements Parcelable {
}
/**
- * @return The task object to hand to the TaskManager. This object is immutable.
+ * @return The job object to hand to the JobScheduler. This object is immutable.
*/
- public Task build() {
+ public JobInfo build() {
mExtras = new PersistableBundle(mExtras); // Make our own copy.
- // Check that a deadline was not set on a periodic task.
+ // Check that a deadline was not set on a periodic job.
if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
- "periodic task.");
+ "periodic job.");
}
if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
- "periodic task");
+ "periodic job");
}
if (mBackoffPolicySet && mRequiresDeviceIdle) {
- throw new IllegalArgumentException("An idle mode task will not respect any" +
+ throw new IllegalArgumentException("An idle mode job will not respect any" +
" back-off policy, so calling setBackoffCriteria with" +
" setRequiresDeviceIdle is an error.");
}
- return new Task(this);
+ return new JobInfo(this);
}
}
diff --git a/core/java/android/app/task/TaskParams.aidl b/core/java/android/app/job/JobParameters.aidl
index 9b25855..e7551b9 100644
--- a/core/java/android/app/task/TaskParams.aidl
+++ b/core/java/android/app/job/JobParameters.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.app.task;
+package android.app.job;
-parcelable TaskParams; \ No newline at end of file
+parcelable JobParameters;
diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/job/JobParameters.java
index f4908c6..724856a 100644
--- a/core/java/android/app/task/TaskParams.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -14,40 +14,42 @@
* limitations under the License
*/
-package android.app.task;
+package android.app.job;
+import android.app.job.IJobCallback;
+import android.app.job.IJobCallback.Stub;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
/**
- * Contains the parameters used to configure/identify your task. You do not create this object
+ * Contains the parameters used to configure/identify your job. You do not create this object
* yourself, instead it is handed in to your application by the System.
*/
-public class TaskParams implements Parcelable {
+public class JobParameters implements Parcelable {
- private final int taskId;
+ private final int jobId;
private final PersistableBundle extras;
private final IBinder callback;
/** @hide */
- public TaskParams(int taskId, PersistableBundle extras, IBinder callback) {
- this.taskId = taskId;
+ public JobParameters(int jobId, PersistableBundle extras, IBinder callback) {
+ this.jobId = jobId;
this.extras = extras;
this.callback = callback;
}
/**
- * @return The unique id of this task, specified at creation time.
+ * @return The unique id of this job, specified at creation time.
*/
- public int getTaskId() {
- return taskId;
+ public int getJobId() {
+ return jobId;
}
/**
- * @return The extras you passed in when constructing this task with
- * {@link android.app.task.Task.Builder#setExtras(android.os.PersistableBundle)}. This will
+ * @return The extras you passed in when constructing this job with
+ * {@link android.app.job.JobInfo.Builder#setExtras(android.os.PersistableBundle)}. This will
* never be null. If you did not set any extras this will be an empty bundle.
*/
public PersistableBundle getExtras() {
@@ -55,12 +57,12 @@ public class TaskParams implements Parcelable {
}
/** @hide */
- public ITaskCallback getCallback() {
- return ITaskCallback.Stub.asInterface(callback);
+ public IJobCallback getCallback() {
+ return IJobCallback.Stub.asInterface(callback);
}
- private TaskParams(Parcel in) {
- taskId = in.readInt();
+ private JobParameters(Parcel in) {
+ jobId = in.readInt();
extras = in.readPersistableBundle();
callback = in.readStrongBinder();
}
@@ -72,20 +74,20 @@ public class TaskParams implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(taskId);
+ dest.writeInt(jobId);
dest.writePersistableBundle(extras);
dest.writeStrongBinder(callback);
}
- public static final Creator<TaskParams> CREATOR = new Creator<TaskParams>() {
+ public static final Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
@Override
- public TaskParams createFromParcel(Parcel in) {
- return new TaskParams(in);
+ public JobParameters createFromParcel(Parcel in) {
+ return new JobParameters(in);
}
@Override
- public TaskParams[] newArray(int size) {
- return new TaskParams[size];
+ public JobParameters[] newArray(int size) {
+ return new JobParameters[size];
}
};
}
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
new file mode 100644
index 0000000..7fe192c
--- /dev/null
+++ b/core/java/android/app/job/JobScheduler.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.job;
+
+import java.util.List;
+
+import android.content.Context;
+
+/**
+ * Class for scheduling various types of jobs with the scheduling framework on the device.
+ *
+ * <p>You do not
+ * instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.JOB_SCHEDULER_SERVICE)}.
+ */
+public abstract class JobScheduler {
+ /**
+ * Returned from {@link #schedule(JobInfo)} when an invalid parameter was supplied. This can occur
+ * if the run-time for your job is too short, or perhaps the system can't resolve the
+ * requisite {@link JobService} in your package.
+ */
+ public static final int RESULT_FAILURE = 0;
+ /**
+ * Returned from {@link #schedule(JobInfo)} if this application has made too many requests for
+ * work over too short a time.
+ */
+ // TODO: Determine if this is necessary.
+ public static final int RESULT_SUCCESS = 1;
+
+ /**
+ * @param job The job you wish scheduled. See
+ * {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
+ * you can schedule.
+ * @return If >0, this int returns the jobId of the successfully scheduled job.
+ * Otherwise you have to compare the return value to the error codes defined in this class.
+ */
+ public abstract int schedule(JobInfo job);
+
+ /**
+ * Cancel a job that is pending in the JobScheduler.
+ * @param jobId unique identifier for this job. Obtain this value from the jobs returned by
+ * {@link #getAllPendingJobs()}.
+ * @return
+ */
+ public abstract void cancel(int jobId);
+
+ /**
+ * Cancel all jobs that have been registered with the JobScheduler by this package.
+ */
+ public abstract void cancelAll();
+
+ /**
+ * @return a list of all the jobs registered by this package that have not yet been executed.
+ */
+ public abstract List<JobInfo> getAllPendingJobs();
+
+}
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/job/JobService.java
index 8ce4484..eea0268 100644
--- a/core/java/android/app/task/TaskService.java
+++ b/core/java/android/app/job/JobService.java
@@ -14,9 +14,12 @@
* limitations under the License
*/
-package android.app.task;
+package android.app.job;
import android.app.Service;
+import android.app.job.IJobCallback;
+import android.app.job.IJobService;
+import android.app.job.IJobService.Stub;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
@@ -28,72 +31,72 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
/**
- * <p>Entry point for the callback from the {@link android.app.task.TaskManager}.</p>
+ * <p>Entry point for the callback from the {@link android.app.job.JobScheduler}.</p>
* <p>This is the base class that handles asynchronous requests that were previously scheduled. You
- * are responsible for overriding {@link TaskService#onStartTask(TaskParams)}, which is where
- * you will implement your task logic.</p>
- * <p>This service executes each incoming task on a {@link android.os.Handler} running on your
+ * are responsible for overriding {@link JobService#onStartJob(JobParameters)}, which is where
+ * you will implement your job logic.</p>
+ * <p>This service executes each incoming job on a {@link android.os.Handler} running on your
* application's main thread. This means that you <b>must</b> offload your execution logic to
* another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result
- * in blocking any future callbacks from the TaskManager - specifically
- * {@link #onStopTask(android.app.task.TaskParams)}, which is meant to inform you that the
+ * in blocking any future callbacks from the JobManager - specifically
+ * {@link #onStopJob(android.app.job.JobParameters)}, which is meant to inform you that the
* scheduling requirements are no longer being met.</p>
*/
-public abstract class TaskService extends Service {
- private static final String TAG = "TaskService";
+public abstract class JobService extends Service {
+ private static final String TAG = "JobService";
/**
- * Task services must be protected with this permission:
+ * Job services must be protected with this permission:
*
* <pre class="prettyprint">
- * <service android:name="MyTaskService"
- * android:permission="android.permission.BIND_TASK_SERVICE" >
+ * <service android:name="MyJobService"
+ * android:permission="android.permission.BIND_JOB_SERVICE" >
* ...
* </service>
* </pre>
*
- * <p>If a task service is declared in the manifest but not protected with this
+ * <p>If a job service is declared in the manifest but not protected with this
* permission, that service will be ignored by the OS.
*/
public static final String PERMISSION_BIND =
- "android.permission.BIND_TASK_SERVICE";
+ "android.permission.BIND_JOB_SERVICE";
/**
* Identifier for a message that will result in a call to
- * {@link #onStartTask(android.app.task.TaskParams)}.
+ * {@link #onStartJob(android.app.job.JobParameters)}.
*/
- private final int MSG_EXECUTE_TASK = 0;
+ private final int MSG_EXECUTE_JOB = 0;
/**
- * Message that will result in a call to {@link #onStopTask(android.app.task.TaskParams)}.
+ * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}.
*/
- private final int MSG_STOP_TASK = 1;
+ private final int MSG_STOP_JOB = 1;
/**
- * Message that the client has completed execution of this task.
+ * Message that the client has completed execution of this job.
*/
- private final int MSG_TASK_FINISHED = 2;
+ private final int MSG_JOB_FINISHED = 2;
/** Lock object for {@link #mHandler}. */
private final Object mHandlerLock = new Object();
/**
- * Handler we post tasks to. Responsible for calling into the client logic, and handling the
+ * Handler we post jobs to. Responsible for calling into the client logic, and handling the
* callback to the system.
*/
@GuardedBy("mHandlerLock")
- TaskHandler mHandler;
+ JobHandler mHandler;
/** Binder for this service. */
- ITaskService mBinder = new ITaskService.Stub() {
+ IJobService mBinder = new IJobService.Stub() {
@Override
- public void startTask(TaskParams taskParams) {
+ public void startJob(JobParameters jobParams) {
ensureHandler();
- Message m = Message.obtain(mHandler, MSG_EXECUTE_TASK, taskParams);
+ Message m = Message.obtain(mHandler, MSG_EXECUTE_JOB, jobParams);
m.sendToTarget();
}
@Override
- public void stopTask(TaskParams taskParams) {
+ public void stopJob(JobParameters jobParams) {
ensureHandler();
- Message m = Message.obtain(mHandler, MSG_STOP_TASK, taskParams);
+ Message m = Message.obtain(mHandler, MSG_STOP_JOB, jobParams);
m.sendToTarget();
}
};
@@ -102,7 +105,7 @@ public abstract class TaskService extends Service {
void ensureHandler() {
synchronized (mHandlerLock) {
if (mHandler == null) {
- mHandler = new TaskHandler(getMainLooper());
+ mHandler = new JobHandler(getMainLooper());
}
}
}
@@ -112,45 +115,45 @@ public abstract class TaskService extends Service {
* (app-specified) mechanism.
* @hide
*/
- class TaskHandler extends Handler {
- TaskHandler(Looper looper) {
+ class JobHandler extends Handler {
+ JobHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
- final TaskParams params = (TaskParams) msg.obj;
+ final JobParameters params = (JobParameters) msg.obj;
switch (msg.what) {
- case MSG_EXECUTE_TASK:
+ case MSG_EXECUTE_JOB:
try {
- boolean workOngoing = TaskService.this.onStartTask(params);
+ boolean workOngoing = JobService.this.onStartJob(params);
ackStartMessage(params, workOngoing);
} catch (Exception e) {
- Log.e(TAG, "Error while executing task: " + params.getTaskId());
+ Log.e(TAG, "Error while executing job: " + params.getJobId());
throw new RuntimeException(e);
}
break;
- case MSG_STOP_TASK:
+ case MSG_STOP_JOB:
try {
- boolean ret = TaskService.this.onStopTask(params);
+ boolean ret = JobService.this.onStopJob(params);
ackStopMessage(params, ret);
} catch (Exception e) {
- Log.e(TAG, "Application unable to handle onStopTask.", e);
+ Log.e(TAG, "Application unable to handle onStopJob.", e);
throw new RuntimeException(e);
}
break;
- case MSG_TASK_FINISHED:
+ case MSG_JOB_FINISHED:
final boolean needsReschedule = (msg.arg2 == 1);
- ITaskCallback callback = params.getCallback();
+ IJobCallback callback = params.getCallback();
if (callback != null) {
try {
- callback.taskFinished(params.getTaskId(), needsReschedule);
+ callback.jobFinished(params.getJobId(), needsReschedule);
} catch (RemoteException e) {
- Log.e(TAG, "Error reporting task finish to system: binder has gone" +
+ Log.e(TAG, "Error reporting job finish to system: binder has gone" +
"away.");
}
} else {
- Log.e(TAG, "finishTask() called for a nonexistent task id.");
+ Log.e(TAG, "finishJob() called for a nonexistent job id.");
}
break;
default:
@@ -159,34 +162,34 @@ public abstract class TaskService extends Service {
}
}
- private void ackStartMessage(TaskParams params, boolean workOngoing) {
- final ITaskCallback callback = params.getCallback();
- final int taskId = params.getTaskId();
+ private void ackStartMessage(JobParameters params, boolean workOngoing) {
+ final IJobCallback callback = params.getCallback();
+ final int jobId = params.getJobId();
if (callback != null) {
try {
- callback.acknowledgeStartMessage(taskId, workOngoing);
+ callback.acknowledgeStartMessage(jobId, workOngoing);
} catch(RemoteException e) {
- Log.e(TAG, "System unreachable for starting task.");
+ Log.e(TAG, "System unreachable for starting job.");
}
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Attempting to ack a task that has already been processed.");
+ Log.d(TAG, "Attempting to ack a job that has already been processed.");
}
}
}
- private void ackStopMessage(TaskParams params, boolean reschedule) {
- final ITaskCallback callback = params.getCallback();
- final int taskId = params.getTaskId();
+ private void ackStopMessage(JobParameters params, boolean reschedule) {
+ final IJobCallback callback = params.getCallback();
+ final int jobId = params.getJobId();
if (callback != null) {
try {
- callback.acknowledgeStopMessage(taskId, reschedule);
+ callback.acknowledgeStopMessage(jobId, reschedule);
} catch(RemoteException e) {
- Log.e(TAG, "System unreachable for stopping task.");
+ Log.e(TAG, "System unreachable for stopping job.");
}
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Attempting to ack a task that has already been processed.");
+ Log.d(TAG, "Attempting to ack a job that has already been processed.");
}
}
}
@@ -198,59 +201,59 @@ public abstract class TaskService extends Service {
}
/**
- * Override this method with the callback logic for your task. Any such logic needs to be
+ * Override this method with the callback logic for your job. Any such logic needs to be
* performed on a separate thread, as this function is executed on your application's main
* thread.
*
- * @param params Parameters specifying info about this task, including the extras bundle you
- * optionally provided at task-creation time.
+ * @param params Parameters specifying info about this job, including the extras bundle you
+ * optionally provided at job-creation time.
* @return True if your service needs to process the work (on a separate thread). False if
- * there's no more work to be done for this task.
+ * there's no more work to be done for this job.
*/
- public abstract boolean onStartTask(TaskParams params);
+ public abstract boolean onStartJob(JobParameters params);
/**
- * This method is called if the system has determined that you must stop execution of your task
- * even before you've had a chance to call {@link #taskFinished(TaskParams, boolean)}.
+ * This method is called if the system has determined that you must stop execution of your job
+ * even before you've had a chance to call {@link #jobFinished(JobParameters, boolean)}.
*
* <p>This will happen if the requirements specified at schedule time are no longer met. For
* example you may have requested WiFi with
- * {@link android.app.task.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
- * task was executing the user toggled WiFi. Another example is if you had specified
- * {@link android.app.task.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
+ * {@link android.app.job.JobInfo.Builder#setRequiredNetworkCapabilities(int)}, yet while your
+ * job was executing the user toggled WiFi. Another example is if you had specified
+ * {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
* idle maintenance window. You are solely responsible for the behaviour of your application
* upon receipt of this message; your app will likely start to misbehave if you ignore it. One
* immediate repercussion is that the system will cease holding a wakelock for you.</p>
*
- * @param params Parameters specifying info about this task.
- * @return True to indicate to the TaskManager whether you'd like to reschedule this task based
- * on the retry criteria provided at task creation-time. False to drop the task. Regardless of
- * the value returned, your task must stop executing.
+ * @param params Parameters specifying info about this job.
+ * @return True to indicate to the JobManager whether you'd like to reschedule this job based
+ * on the retry criteria provided at job creation-time. False to drop the job. Regardless of
+ * the value returned, your job must stop executing.
*/
- public abstract boolean onStopTask(TaskParams params);
+ public abstract boolean onStopJob(JobParameters params);
/**
- * Callback to inform the TaskManager you've finished executing. This can be called from any
+ * Callback to inform the JobManager you've finished executing. This can be called from any
* thread, as it will ultimately be run on your application's main thread. When the system
* receives this message it will release the wakelock being held.
* <p>
* You can specify post-execution behaviour to the scheduler here with
- * <code>needsReschedule </code>. This will apply a back-off timer to your task based on
+ * <code>needsReschedule </code>. This will apply a back-off timer to your job based on
* the default, or what was set with
- * {@link android.app.task.Task.Builder#setBackoffCriteria(long, int)}. The original
- * requirements are always honoured even for a backed-off task. Note that a task running in
- * idle mode will not be backed-off. Instead what will happen is the task will be re-added
+ * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}. The original
+ * requirements are always honoured even for a backed-off job. Note that a job running in
+ * idle mode will not be backed-off. Instead what will happen is the job will be re-added
* to the queue and re-executed within a future idle maintenance window.
* </p>
*
- * @param params Parameters specifying system-provided info about this task, this was given to
- * your application in {@link #onStartTask(TaskParams)}.
- * @param needsReschedule True if this task is complete, false if you want the TaskManager to
+ * @param params Parameters specifying system-provided info about this job, this was given to
+ * your application in {@link #onStartJob(JobParameters)}.
+ * @param needsReschedule True if this job is complete, false if you want the JobManager to
* reschedule you.
*/
- public final void taskFinished(TaskParams params, boolean needsReschedule) {
+ public final void jobFinished(JobParameters params, boolean needsReschedule) {
ensureHandler();
- Message m = Message.obtain(mHandler, MSG_TASK_FINISHED, params);
+ Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
m.arg2 = needsReschedule ? 1 : 0;
m.sendToTarget();
}
diff --git a/core/java/android/app/task/TaskManager.java b/core/java/android/app/task/TaskManager.java
deleted file mode 100644
index 00f57da..0000000
--- a/core/java/android/app/task/TaskManager.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.app.task;
-
-import java.util.List;
-
-import android.content.Context;
-
-/**
- * Class for scheduling various types of tasks with the scheduling framework on the device.
- *
- * <p>You do not
- * instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService
- * Context.getSystemService(Context.TASK_SERVICE)}.
- */
-public abstract class TaskManager {
- /*
- * Returned from {@link #schedule(Task)} when an invalid parameter was supplied. This can occur
- * if the run-time for your task is too short, or perhaps the system can't resolve the
- * requisite {@link TaskService} in your package.
- */
- public static final int RESULT_FAILURE = 0;
- /**
- * Returned from {@link #schedule(Task)} if this application has made too many requests for
- * work over too short a time.
- */
- // TODO: Determine if this is necessary.
- public static final int RESULT_SUCCESS = 1;
-
- /**
- * @param task The task you wish scheduled. See
- * {@link android.app.task.Task.Builder Task.Builder} for more detail on the sorts of tasks
- * you can schedule.
- * @return If >0, this int returns the taskId of the successfully scheduled task.
- * Otherwise you have to compare the return value to the error codes defined in this class.
- */
- public abstract int schedule(Task task);
-
- /**
- * Cancel a task that is pending in the TaskManager.
- * @param taskId unique identifier for this task. Obtain this value from the tasks returned by
- * {@link #getAllPendingTasks()}.
- * @return
- */
- public abstract void cancel(int taskId);
-
- /**
- * Cancel all tasks that have been registered with the TaskManager by this package.
- */
- public abstract void cancelAll();
-
- /**
- * @return a list of all the tasks registered by this package that have not yet been executed.
- */
- public abstract List<Task> getAllPendingTasks();
-
-}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9fe9bce..cdcfd2e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2059,7 +2059,7 @@ public abstract class Context {
PRINT_SERVICE,
MEDIA_SESSION_SERVICE,
BATTERY_SERVICE,
- TASK_SERVICE,
+ JOB_SCHEDULER_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -2116,8 +2116,8 @@ public abstract class Context {
* <dd> A {@link android.app.DownloadManager} for requesting HTTP downloads
* <dt> {@link #BATTERY_SERVICE} ("batterymanager")
* <dd> A {@link android.os.BatteryManager} for managing battery state
- * <dt> {@link #TASK_SERVICE} ("taskmanager")
- * <dd> A {@link android.app.task.TaskManager} for managing scheduled tasks
+ * <dt> {@link #JOB_SCHEDULER_SERVICE} ("taskmanager")
+ * <dd> A {@link android.app.job.JobScheduler} for managing scheduled tasks
* </dl>
*
* <p>Note: System services obtained via this API may be closely associated with
@@ -2171,8 +2171,8 @@ public abstract class Context {
* @see android.app.DownloadManager
* @see #BATTERY_SERVICE
* @see android.os.BatteryManager
- * @see #TASK_SERVICE
- * @see android.app.task.TaskManager
+ * @see #JOB_SCHEDULER_SERVICE
+ * @see android.app.job.JobScheduler
*/
public abstract Object getSystemService(@ServiceName @NonNull String name);
@@ -2761,12 +2761,12 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a {@link
- * android.app.task.TaskManager} instance for managing occasional
+ * android.app.job.JobScheduler} instance for managing occasional
* background tasks.
* @see #getSystemService
- * @see android.app.task.TaskManager
+ * @see android.app.job.JobScheduler
*/
- public static final String TASK_SERVICE = "task";
+ public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
/**
* Determine whether the given permission is allowed for a particular
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3696806..8768779 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1758,11 +1758,11 @@
<!-- Allows the system to bind to an application's task services
@hide -->
- <permission android:name="android.permission.BIND_TASK_SERVICE"
+ <permission android:name="android.permission.BIND_JOB_SERVICE"
android:protectionLevel="signature"
- android:label="@string/permlab_bindTaskService"
- android:description="@string/permdesc_bindTaskService" />
- <uses-permission android:name="android.permission.BIND_TASK_SERVICE"/>
+ android:label="@string/permlab_bindJobService"
+ android:description="@string/permdesc_bindJobService" />
+ <uses-permission android:name="android.permission.BIND_JOB_SERVICE"/>
<!-- ========================================= -->
<!-- Permissions for special development tools -->
@@ -2877,8 +2877,8 @@
</service>
<service android:name="com.android.server.MountServiceIdler"
- android:exported="false"
- android:permission="android.permission.BIND_TASK_SERVICE" >
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
</application>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d521746..a224cd5 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1261,10 +1261,10 @@
permission that an application must be granted by the user. Instead, it
is part of a mechanism that applications use to indicate to the system
that they want to do scheduled background work. -->
- <string name="permlab_bindTaskService">run the application\'s scheduled background work</string>
+ <string name="permlab_bindJobService">run the application\'s scheduled background work</string>
<!-- Description of an application permission, so that the user can understand
what is being done if they are curious. -->
- <string name="permdesc_bindTaskService">This permission allows the Android system to run the application in the background when requested.</string>
+ <string name="permdesc_bindJobService">This permission allows the Android system to run the application in the background when requested.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_diagnostic">read/write to resources owned by diag</string>
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index 6179082..bcb6e9e 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -18,32 +18,32 @@ package com.android.server;
import java.util.Calendar;
-import android.app.task.Task;
-import android.app.task.TaskManager;
-import android.app.task.TaskParams;
-import android.app.task.TaskService;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
import android.util.Slog;
-public class MountServiceIdler extends TaskService {
+public class MountServiceIdler extends JobService {
private static final String TAG = "MountServiceIdler";
private static ComponentName sIdleService =
new ComponentName(MountServiceIdler.class.getPackage().getName(),
MountServiceIdler.class.getName());
- private static int MOUNT_TASK_ID = 808;
+ private static int MOUNT_JOB_ID = 808;
private boolean mStarted;
- private TaskParams mTaskParams;
+ private JobParameters mJobParams;
private Runnable mFinishCallback = new Runnable() {
@Override
public void run() {
Slog.i(TAG, "Got mount service completion callback");
synchronized (mFinishCallback) {
if (mStarted) {
- taskFinished(mTaskParams, false);
+ jobFinished(mJobParams, false);
mStarted = false;
}
}
@@ -53,12 +53,12 @@ public class MountServiceIdler extends TaskService {
};
@Override
- public boolean onStartTask(TaskParams params) {
+ public boolean onStartJob(JobParameters params) {
// The mount service will run an fstrim operation asynchronously
// on a designated separate thread, so we provide it with a callback
// that lets us cleanly end our idle timeslice. It's safe to call
// finishIdle() from any thread.
- mTaskParams = params;
+ mJobParams = params;
MountService ms = MountService.sSelf;
if (ms != null) {
synchronized (mFinishCallback) {
@@ -70,9 +70,9 @@ public class MountServiceIdler extends TaskService {
}
@Override
- public boolean onStopTask(TaskParams params) {
+ public boolean onStopJob(JobParameters params) {
// Once we kick off the fstrim we aren't actually interruptible; just note
- // that we don't need to call taskFinished(), and let everything happen in
+ // that we don't need to call jobFinished(), and let everything happen in
// the callback from the mount service.
synchronized (mFinishCallback) {
mStarted = false;
@@ -84,12 +84,12 @@ public class MountServiceIdler extends TaskService {
* Schedule the idle job that will ping the mount service
*/
public static void scheduleIdlePass(Context context) {
- TaskManager tm = (TaskManager) context.getSystemService(Context.TASK_SERVICE);
+ JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
Calendar calendar = tomorrowMidnight();
final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis();
- Task.Builder builder = new Task.Builder(MOUNT_TASK_ID, sIdleService);
+ JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService);
builder.setRequiresDeviceIdle(true);
builder.setRequiresCharging(true);
builder.setMinimumLatency(timeToMidnight);
diff --git a/services/core/java/com/android/server/task/TaskCompletedListener.java b/services/core/java/com/android/server/job/JobCompletedListener.java
index c53f5ca..a7af9cd 100644
--- a/services/core/java/com/android/server/task/TaskCompletedListener.java
+++ b/services/core/java/com/android/server/job/JobCompletedListener.java
@@ -14,19 +14,19 @@
* limitations under the License
*/
-package com.android.server.task;
+package com.android.server.job;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
/**
- * Used for communication between {@link com.android.server.task.TaskServiceContext} and the
- * {@link com.android.server.task.TaskManagerService}.
+ * Used for communication between {@link com.android.server.job.JobServiceContext} and the
+ * {@link com.android.server.job.JobSchedulerService}.
*/
-public interface TaskCompletedListener {
+public interface JobCompletedListener {
/**
- * Callback for when a task is completed.
- * @param needsReschedule Whether the implementing class should reschedule this task.
+ * Callback for when a job is completed.
+ * @param needsReschedule Whether the implementing class should reschedule this job.
*/
- public void onTaskCompleted(TaskStatus taskStatus, boolean needsReschedule);
+ public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule);
}
diff --git a/services/core/java/com/android/server/task/TaskMapReadFinishedListener.java b/services/core/java/com/android/server/job/JobMapReadFinishedListener.java
index c68d8db..f3e77e6 100644
--- a/services/core/java/com/android/server/task/TaskMapReadFinishedListener.java
+++ b/services/core/java/com/android/server/job/JobMapReadFinishedListener.java
@@ -14,21 +14,21 @@
* limitations under the License
*/
-package com.android.server.task;
+package com.android.server.job;
import java.util.List;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
/**
- * Callback definition for I/O thread to let the TaskManagerService know when
+ * Callback definition for I/O thread to let the JobManagerService know when
* I/O read has completed. Done this way so we don't stall the main thread on
* boot.
*/
-public interface TaskMapReadFinishedListener {
+public interface JobMapReadFinishedListener {
/**
- * Called by the {@link TaskStore} at boot, when the disk read is finished.
+ * Called by the {@link JobStore} at boot, when the disk read is finished.
*/
- public void onTaskMapReadFinished(List<TaskStatus> tasks);
+ public void onJobMapReadFinished(List<JobStatus> jobs);
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
new file mode 100644
index 0000000..0e9a9cc
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -0,0 +1,764 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.job;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.app.job.IJobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.server.job.controllers.BatteryController;
+import com.android.server.job.controllers.ConnectivityController;
+import com.android.server.job.controllers.IdleController;
+import com.android.server.job.controllers.JobStatus;
+import com.android.server.job.controllers.StateController;
+import com.android.server.job.controllers.TimeController;
+
+import java.util.LinkedList;
+
+/**
+ * Responsible for taking jobs representing work to be performed by a client app, and determining
+ * based on the criteria specified when that job should be run against the client application's
+ * endpoint.
+ * Implements logic for scheduling, and rescheduling jobs. The JobSchedulerService knows nothing
+ * about constraints, or the state of active jobs. It receives callbacks from the various
+ * controllers and completed jobs and operates accordingly.
+ *
+ * Note on locking: Any operations that manipulate {@link #mJobs} need to lock on that object.
+ * Any function with the suffix 'Locked' also needs to lock on {@link #mJobs}.
+ * @hide
+ */
+public class JobSchedulerService extends com.android.server.SystemService
+ implements StateChangedListener, JobCompletedListener, JobMapReadFinishedListener {
+ // TODO: Switch this off for final version.
+ static final boolean DEBUG = true;
+ /** The number of concurrent jobs we run at one time. */
+ private static final int MAX_JOB_CONTEXTS_COUNT = 3;
+ static final String TAG = "JobManagerService";
+ /** Master list of jobs. */
+ private final JobStore mJobs;
+
+ static final int MSG_JOB_EXPIRED = 0;
+ static final int MSG_CHECK_JOB = 1;
+
+ // Policy constants
+ /**
+ * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
+ * early.
+ */
+ private static final int MIN_IDLE_COUNT = 1;
+ /**
+ * Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule
+ * things early.
+ */
+ private static final int MIN_CONNECTIVITY_COUNT = 2;
+ /**
+ * Minimum # of jobs (with no particular constraints) for which the JMS will be happy running
+ * some work early.
+ */
+ private static final int MIN_READY_JOBS_COUNT = 4;
+
+ /**
+ * Track Services that have currently active or pending jobs. The index is provided by
+ * {@link JobStatus#getServiceToken()}
+ */
+ private final List<JobServiceContext> mActiveServices = new LinkedList<JobServiceContext>();
+ /** List of controllers that will notify this service of updates to jobs. */
+ private List<StateController> mControllers;
+ /**
+ * Queue of pending jobs. The JobServiceContext class will receive jobs from this list
+ * when ready to execute them.
+ */
+ private final LinkedList<JobStatus> mPendingJobs = new LinkedList<JobStatus>();
+
+ private final JobHandler mHandler;
+ private final JobSchedulerStub mJobSchedulerStub;
+ /**
+ * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
+ * still clean up. On reinstall the package will have a new uid.
+ */
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Slog.d(TAG, "Receieved: " + intent.getAction());
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+ int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (DEBUG) {
+ Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+ }
+ cancelJobsForUid(uidRemoved);
+ } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ if (DEBUG) {
+ Slog.d(TAG, "Removing jobs for user: " + userId);
+ }
+ cancelJobsForUser(userId);
+ }
+ }
+ };
+
+ /**
+ * Entry point from client to schedule the provided job.
+ * This cancels the job if it's already been scheduled, and replaces it with the one provided.
+ * @param job JobInfo object containing execution parameters
+ * @param uId The package identifier of the application this job is for.
+ * @param canPersistJob Whether or not the client has the appropriate permissions for
+ * persisting this job.
+ * @return Result of this operation. See <code>JobScheduler#RESULT_*</code> return codes.
+ */
+ public int schedule(JobInfo job, int uId, boolean canPersistJob) {
+ JobStatus jobStatus = new JobStatus(job, uId, canPersistJob);
+ cancelJob(uId, job.getId());
+ startTrackingJob(jobStatus);
+ return JobScheduler.RESULT_SUCCESS;
+ }
+
+ public List<JobInfo> getPendingJobs(int uid) {
+ ArrayList<JobInfo> outList = new ArrayList<JobInfo>();
+ synchronized (mJobs) {
+ for (JobStatus job : mJobs.getJobs()) {
+ if (job.getUid() == uid) {
+ outList.add(job.getJob());
+ }
+ }
+ }
+ return outList;
+ }
+
+ private void cancelJobsForUser(int userHandle) {
+ synchronized (mJobs) {
+ List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
+ for (JobStatus toRemove : jobsForUser) {
+ if (DEBUG) {
+ Slog.d(TAG, "Cancelling: " + toRemove);
+ }
+ cancelJobLocked(toRemove);
+ }
+ }
+ }
+
+ /**
+ * Entry point from client to cancel all jobs originating from their uid.
+ * This will remove the job from the master list, and cancel the job if it was staged for
+ * execution or being executed.
+ * @param uid To check against for removal of a job.
+ */
+ public void cancelJobsForUid(int uid) {
+ // Remove from master list.
+ synchronized (mJobs) {
+ List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
+ for (JobStatus toRemove : jobsForUid) {
+ if (DEBUG) {
+ Slog.d(TAG, "Cancelling: " + toRemove);
+ }
+ cancelJobLocked(toRemove);
+ }
+ }
+ }
+
+ /**
+ * Entry point from client to cancel the job corresponding to the jobId provided.
+ * This will remove the job from the master list, and cancel the job if it was staged for
+ * execution or being executed.
+ * @param uid Uid of the calling client.
+ * @param jobId Id of the job, provided at schedule-time.
+ */
+ public void cancelJob(int uid, int jobId) {
+ JobStatus toCancel;
+ synchronized (mJobs) {
+ toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
+ if (toCancel != null) {
+ cancelJobLocked(toCancel);
+ }
+ }
+ }
+
+ private void cancelJobLocked(JobStatus cancelled) {
+ // Remove from store.
+ stopTrackingJob(cancelled);
+ // Remove from pending queue.
+ mPendingJobs.remove(cancelled);
+ // Cancel if running.
+ stopJobOnServiceContextLocked(cancelled);
+ }
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public JobSchedulerService(Context context) {
+ super(context);
+ // Create the controllers.
+ mControllers = new LinkedList<StateController>();
+ mControllers.add(ConnectivityController.get(this));
+ mControllers.add(TimeController.get(this));
+ mControllers.add(IdleController.get(this));
+ mControllers.add(BatteryController.get(this));
+
+ mHandler = new JobHandler(context.getMainLooper());
+ mJobSchedulerStub = new JobSchedulerStub();
+ // Create the "runners".
+ for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
+ mActiveServices.add(
+ new JobServiceContext(this, context.getMainLooper()));
+ }
+ mJobs = JobStore.initAndGet(this);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (PHASE_SYSTEM_SERVICES_READY == phase) {
+ // Register br for package removals and user removals.
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ getContext().registerReceiverAsUser(
+ mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+ final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+ getContext().registerReceiverAsUser(
+ mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+ }
+ }
+
+ /**
+ * Called when we have a job status object that we need to insert in our
+ * {@link com.android.server.job.JobStore}, and make sure all the relevant controllers know
+ * about.
+ */
+ private void startTrackingJob(JobStatus jobStatus) {
+ boolean update;
+ synchronized (mJobs) {
+ update = mJobs.add(jobStatus);
+ }
+ for (StateController controller : mControllers) {
+ if (update) {
+ controller.maybeStopTrackingJob(jobStatus);
+ }
+ controller.maybeStartTrackingJob(jobStatus);
+ }
+ }
+
+ /**
+ * Called when we want to remove a JobStatus object that we've finished executing. Returns the
+ * object removed.
+ */
+ private boolean stopTrackingJob(JobStatus jobStatus) {
+ boolean removed;
+ synchronized (mJobs) {
+ // Remove from store as well as controllers.
+ removed = mJobs.remove(jobStatus);
+ }
+ if (removed) {
+ for (StateController controller : mControllers) {
+ controller.maybeStopTrackingJob(jobStatus);
+ }
+ }
+ return removed;
+ }
+
+ private boolean stopJobOnServiceContextLocked(JobStatus job) {
+ for (JobServiceContext jsc : mActiveServices) {
+ final JobStatus executing = jsc.getRunningJob();
+ if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
+ jsc.cancelExecutingJob();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param job JobStatus we are querying against.
+ * @return Whether or not the job represented by the status object is currently being run or
+ * is pending.
+ */
+ private boolean isCurrentlyActiveLocked(JobStatus job) {
+ for (JobServiceContext serviceContext : mActiveServices) {
+ final JobStatus running = serviceContext.getRunningJob();
+ if (running != null && running.matches(job.getUid(), job.getJobId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A job is rescheduled with exponential back-off if the client requests this from their
+ * execution logic.
+ * A caveat is for idle-mode jobs, for which the idle-mode constraint will usurp the
+ * timeliness of the reschedule. For an idle-mode job, no deadline is given.
+ * @param failureToReschedule Provided job status that we will reschedule.
+ * @return A newly instantiated JobStatus with the same constraints as the last job except
+ * with adjusted timing constraints.
+ */
+ private JobStatus getRescheduleJobForFailure(JobStatus failureToReschedule) {
+ final long elapsedNowMillis = SystemClock.elapsedRealtime();
+ final JobInfo job = failureToReschedule.getJob();
+
+ final long initialBackoffMillis = job.getInitialBackoffMillis();
+ final int backoffAttempt = failureToReschedule.getNumFailures() + 1;
+ long newEarliestRuntimeElapsed = elapsedNowMillis;
+
+ switch (job.getBackoffPolicy()) {
+ case JobInfo.BackoffPolicy.LINEAR:
+ newEarliestRuntimeElapsed += initialBackoffMillis * backoffAttempt;
+ break;
+ default:
+ if (DEBUG) {
+ Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
+ }
+ case JobInfo.BackoffPolicy.EXPONENTIAL:
+ newEarliestRuntimeElapsed +=
+ Math.pow(initialBackoffMillis * 0.001, backoffAttempt) * 1000;
+ break;
+ }
+ newEarliestRuntimeElapsed =
+ Math.min(newEarliestRuntimeElapsed, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
+ return new JobStatus(failureToReschedule, newEarliestRuntimeElapsed,
+ JobStatus.NO_LATEST_RUNTIME, backoffAttempt);
+ }
+
+ /**
+ * Called after a periodic has executed so we can to re-add it. We take the last execution time
+ * of the job to be the time of completion (i.e. the time at which this function is called).
+ * This could be inaccurate b/c the job can run for as long as
+ * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
+ * to underscheduling at least, rather than if we had taken the last execution time to be the
+ * start of the execution.
+ * @return A new job representing the execution criteria for this instantiation of the
+ * recurring job.
+ */
+ private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) {
+ final long elapsedNow = SystemClock.elapsedRealtime();
+ // Compute how much of the period is remaining.
+ long runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0);
+ long newEarliestRunTimeElapsed = elapsedNow + runEarly;
+ long period = periodicToReschedule.getJob().getIntervalMillis();
+ long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
+
+ if (DEBUG) {
+ Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
+ newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
+ }
+ return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
+ newLatestRuntimeElapsed, 0 /* backoffAttempt */);
+ }
+
+ // JobCompletedListener implementations.
+
+ /**
+ * A job just finished executing. We fetch the
+ * {@link com.android.server.job.controllers.JobStatus} from the store and depending on
+ * whether we want to reschedule we readd it to the controllers.
+ * @param jobStatus Completed job.
+ * @param needsReschedule Whether the implementing class should reschedule this job.
+ */
+ @Override
+ public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule) {
+ if (DEBUG) {
+ Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
+ }
+ if (!stopTrackingJob(jobStatus)) {
+ if (DEBUG) {
+ Slog.e(TAG, "Error removing job: could not find job to remove. Was job " +
+ "removed while executing?");
+ }
+ return;
+ }
+ if (needsReschedule) {
+ JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
+ startTrackingJob(rescheduled);
+ } else if (jobStatus.getJob().isPeriodic()) {
+ JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
+ startTrackingJob(rescheduledPeriodic);
+ }
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+ }
+
+ // StateChangedListener implementations.
+
+ /**
+ * Off-board work to our handler thread as quickly as possible, b/c this call is probably being
+ * made on the main thread.
+ * For now this takes the job and if it's ready to run it will run it. In future we might not
+ * provide the job, so that the StateChangedListener has to run through its list of jobs to
+ * see which are ready. This will further decouple the controllers from the execution logic.
+ */
+ @Override
+ public void onControllerStateChanged() {
+ // Post a message to to run through the list of jobs and start/stop any that are eligible.
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+ }
+
+ @Override
+ public void onRunJobNow(JobStatus jobStatus) {
+ mHandler.obtainMessage(MSG_JOB_EXPIRED, jobStatus).sendToTarget();
+ }
+
+ /**
+ * Disk I/O is finished, take the list of jobs we read from disk and add them to our
+ * {@link JobStore}.
+ * This is run on the {@link com.android.server.IoThread} instance, which is a separate thread,
+ * and is called once at boot.
+ */
+ @Override
+ public void onJobMapReadFinished(List<JobStatus> jobs) {
+ synchronized (mJobs) {
+ for (JobStatus js : jobs) {
+ if (mJobs.containsJobIdForUid(js.getJobId(), js.getUid())) {
+ // An app with BOOT_COMPLETED *might* have decided to reschedule their job, in
+ // the same amount of time it took us to read it from disk. If this is the case
+ // we leave it be.
+ continue;
+ }
+ startTrackingJob(js);
+ }
+ }
+ }
+
+ private class JobHandler extends Handler {
+
+ public JobHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_JOB_EXPIRED:
+ synchronized (mJobs) {
+ JobStatus runNow = (JobStatus) message.obj;
+ if (!mPendingJobs.contains(runNow)) {
+ mPendingJobs.add(runNow);
+ }
+ }
+ queueReadyJobsForExecutionH();
+ break;
+ case MSG_CHECK_JOB:
+ // Check the list of jobs and run some of them if we feel inclined.
+ maybeQueueReadyJobsForExecutionH();
+ break;
+ }
+ maybeRunPendingJobsH();
+ // Don't remove JOB_EXPIRED in case one came along while processing the queue.
+ removeMessages(MSG_CHECK_JOB);
+ }
+
+ /**
+ * Run through list of jobs and execute all possible - at least one is expired so we do
+ * as many as we can.
+ */
+ private void queueReadyJobsForExecutionH() {
+ synchronized (mJobs) {
+ for (JobStatus job : mJobs.getJobs()) {
+ if (isReadyToBeExecutedLocked(job)) {
+ mPendingJobs.add(job);
+ } else if (isReadyToBeCancelledLocked(job)) {
+ stopJobOnServiceContextLocked(job);
+ }
+ }
+ }
+ }
+
+ /**
+ * The state of at least one job has changed. Here is where we could enforce various
+ * policies on when we want to execute jobs.
+ * Right now the policy is such:
+ * If >1 of the ready jobs is idle mode we send all of them off
+ * if more than 2 network connectivity jobs are ready we send them all off.
+ * If more than 4 jobs total are ready we send them all off.
+ * TODO: It would be nice to consolidate these sort of high-level policies somewhere.
+ */
+ private void maybeQueueReadyJobsForExecutionH() {
+ synchronized (mJobs) {
+ int idleCount = 0;
+ int backoffCount = 0;
+ int connectivityCount = 0;
+ List<JobStatus> runnableJobs = new ArrayList<JobStatus>();
+ for (JobStatus job : mJobs.getJobs()) {
+ if (isReadyToBeExecutedLocked(job)) {
+ if (job.getNumFailures() > 0) {
+ backoffCount++;
+ }
+ if (job.hasIdleConstraint()) {
+ idleCount++;
+ }
+ if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
+ connectivityCount++;
+ }
+ runnableJobs.add(job);
+ } else if (isReadyToBeCancelledLocked(job)) {
+ stopJobOnServiceContextLocked(job);
+ }
+ }
+ if (backoffCount > 0 || idleCount >= MIN_IDLE_COUNT ||
+ connectivityCount >= MIN_CONNECTIVITY_COUNT ||
+ runnableJobs.size() >= MIN_READY_JOBS_COUNT) {
+ for (JobStatus job : runnableJobs) {
+ mPendingJobs.add(job);
+ }
+ }
+ }
+ }
+
+ /**
+ * Criteria for moving a job into the pending queue:
+ * - It's ready.
+ * - It's not pending.
+ * - It's not already running on a JSC.
+ */
+ private boolean isReadyToBeExecutedLocked(JobStatus job) {
+ return job.isReady() && !mPendingJobs.contains(job) && !isCurrentlyActiveLocked(job);
+ }
+
+ /**
+ * Criteria for cancelling an active job:
+ * - It's not ready
+ * - It's running on a JSC.
+ */
+ private boolean isReadyToBeCancelledLocked(JobStatus job) {
+ return !job.isReady() && isCurrentlyActiveLocked(job);
+ }
+
+ /**
+ * Reconcile jobs in the pending queue against available execution contexts.
+ * A controller can force a job into the pending queue even if it's already running, but
+ * here is where we decide whether to actually execute it.
+ */
+ private void maybeRunPendingJobsH() {
+ synchronized (mJobs) {
+ Iterator<JobStatus> it = mPendingJobs.iterator();
+ while (it.hasNext()) {
+ JobStatus nextPending = it.next();
+ JobServiceContext availableContext = null;
+ for (JobServiceContext jsc : mActiveServices) {
+ final JobStatus running = jsc.getRunningJob();
+ if (running != null && running.matches(nextPending.getUid(),
+ nextPending.getJobId())) {
+ // Already running this tId for this uId, skip.
+ availableContext = null;
+ break;
+ }
+ if (jsc.isAvailable()) {
+ availableContext = jsc;
+ }
+ }
+ if (availableContext != null) {
+ if (!availableContext.executeRunnableJob(nextPending)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Error executing " + nextPending);
+ }
+ mJobs.remove(nextPending);
+ }
+ it.remove();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Binder stub trampoline implementation
+ */
+ final class JobSchedulerStub extends IJobScheduler.Stub {
+ /** Cache determination of whether a given app can persist jobs
+ * key is uid of the calling app; value is undetermined/true/false
+ */
+ private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
+
+ // Enforce that only the app itself (or shared uid participant) can schedule a
+ // job that runs one of the app's services, as well as verifying that the
+ // named service properly requires the BIND_JOB_SERVICE permission
+ private void enforceValidJobRequest(int uid, JobInfo job) {
+ final PackageManager pm = getContext().getPackageManager();
+ final ComponentName service = job.getService();
+ try {
+ ServiceInfo si = pm.getServiceInfo(service, 0);
+ if (si.applicationInfo.uid != uid) {
+ throw new IllegalArgumentException("uid " + uid +
+ " cannot schedule job in " + service.getPackageName());
+ }
+ if (!JobService.PERMISSION_BIND.equals(si.permission)) {
+ throw new IllegalArgumentException("Scheduled service " + service
+ + " does not require android.permission.BIND_JOB_SERVICE permission");
+ }
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException("No such service: " + service);
+ }
+ }
+
+ private boolean canPersistJobs(int pid, int uid) {
+ // If we get this far we're good to go; all we need to do now is check
+ // whether the app is allowed to persist its scheduled work.
+ final boolean canPersist;
+ synchronized (mPersistCache) {
+ Boolean cached = mPersistCache.get(uid);
+ if (cached != null) {
+ canPersist = cached.booleanValue();
+ } else {
+ // Persisting jobs is tantamount to running at boot, so we permit
+ // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
+ // permission
+ int result = getContext().checkPermission(
+ android.Manifest.permission.RECEIVE_BOOT_COMPLETED, pid, uid);
+ canPersist = (result == PackageManager.PERMISSION_GRANTED);
+ mPersistCache.put(uid, canPersist);
+ }
+ }
+ return canPersist;
+ }
+
+ // IJobScheduler implementation
+ @Override
+ public int schedule(JobInfo job) throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "Scheduling job: " + job);
+ }
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+
+ enforceValidJobRequest(uid, job);
+ final boolean canPersist = canPersistJobs(pid, uid);
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return JobSchedulerService.this.schedule(job, uid, canPersist);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public List<JobInfo> getAllPendingJobs() throws RemoteException {
+ final int uid = Binder.getCallingUid();
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return JobSchedulerService.this.getPendingJobs(uid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void cancelAll() throws RemoteException {
+ final int uid = Binder.getCallingUid();
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ JobSchedulerService.this.cancelJobsForUid(uid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void cancel(int jobId) throws RemoteException {
+ final int uid = Binder.getCallingUid();
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ JobSchedulerService.this.cancelJob(uid, jobId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * "dumpsys" infrastructure
+ */
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+ long identityToken = Binder.clearCallingIdentity();
+ try {
+ JobSchedulerService.this.dumpInternal(pw);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+ };
+
+ void dumpInternal(PrintWriter pw) {
+ synchronized (mJobs) {
+ pw.println("Registered jobs:");
+ if (mJobs.size() > 0) {
+ for (JobStatus job : mJobs.getJobs()) {
+ job.dump(pw, " ");
+ }
+ } else {
+ pw.println();
+ pw.println("No jobs scheduled.");
+ }
+ for (StateController controller : mControllers) {
+ pw.println();
+ controller.dumpControllerState(pw);
+ }
+ pw.println();
+ pw.println("Pending");
+ for (JobStatus jobStatus : mPendingJobs) {
+ pw.println(jobStatus.hashCode());
+ }
+ pw.println();
+ pw.println("Active jobs:");
+ for (JobServiceContext jsc : mActiveServices) {
+ if (jsc.isAvailable()) {
+ continue;
+ } else {
+ pw.println(jsc.getRunningJob().hashCode() + " for: " +
+ (SystemClock.elapsedRealtime()
+ - jsc.getExecutionStartTimeElapsed())/1000 + "s " +
+ "timeout: " + jsc.getTimeoutElapsed());
+ }
+ }
+ }
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index a21de88..92b643c 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -14,12 +14,12 @@
* limitations under the License
*/
-package com.android.server.task;
+package com.android.server.job;
import android.app.ActivityManager;
-import android.app.task.ITaskCallback;
-import android.app.task.ITaskService;
-import android.app.task.TaskParams;
+import android.app.job.JobParameters;
+import android.app.job.IJobCallback;
+import android.app.job.IJobService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -39,32 +39,32 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
import java.util.concurrent.atomic.AtomicBoolean;
/**
- * Handles client binding and lifecycle of a task. A task will only execute one at a time on an
+ * Handles client binding and lifecycle of a job. A job will only execute one at a time on an
* instance of this class.
*/
-public class TaskServiceContext extends ITaskCallback.Stub implements ServiceConnection {
+public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
private static final boolean DEBUG = true;
- private static final String TAG = "TaskServiceContext";
- /** Define the maximum # of tasks allowed to run on a service at once. */
- private static final int defaultMaxActiveTasksPerService =
+ private static final String TAG = "JobServiceContext";
+ /** Define the maximum # of jobs allowed to run on a service at once. */
+ private static final int defaultMaxActiveJobsPerService =
ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
- /** Amount of time a task is allowed to execute for before being considered timed-out. */
+ /** Amount of time a job is allowed to execute for before being considered timed-out. */
private static final long EXECUTING_TIMESLICE_MILLIS = 60 * 1000;
- /** Amount of time the TaskManager will wait for a response from an app for a message. */
+ /** Amount of time the JobScheduler will wait for a response from an app for a message. */
private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
/** String prefix for all wakelock names. */
- private static final String TM_WAKELOCK_PREFIX = "*task*/";
+ private static final String JS_WAKELOCK_PREFIX = "*job*/";
private static final String[] VERB_STRINGS = {
"VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_PENDING"
};
- // States that a task occupies while interacting with the client.
+ // States that a job occupies while interacting with the client.
static final int VERB_BINDING = 0;
static final int VERB_STARTING = 1;
static final int VERB_EXECUTING = 2;
@@ -75,30 +75,30 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
private static final int MSG_TIMEOUT = 0;
/** Received a callback from client. */
private static final int MSG_CALLBACK = 1;
- /** Run through list and start any ready tasks.*/
+ /** Run through list and start any ready jobs.*/
private static final int MSG_SERVICE_BOUND = 2;
- /** Cancel a task. */
+ /** Cancel a job. */
private static final int MSG_CANCEL = 3;
- /** Shutdown the Task. Used when the client crashes and we can't die gracefully.*/
+ /** Shutdown the job. Used when the client crashes and we can't die gracefully.*/
private static final int MSG_SHUTDOWN_EXECUTION = 4;
private final Handler mCallbackHandler;
- /** Make callbacks to {@link TaskManagerService} to inform on task completion status. */
- private final TaskCompletedListener mCompletedListener;
+ /** Make callbacks to {@link JobSchedulerService} to inform on job completion status. */
+ private final JobCompletedListener mCompletedListener;
/** Used for service binding, etc. */
private final Context mContext;
private PowerManager.WakeLock mWakeLock;
// Execution state.
- private TaskParams mParams;
+ private JobParameters mParams;
@VisibleForTesting
int mVerb;
private AtomicBoolean mCancelled = new AtomicBoolean();
- /** All the information maintained about the task currently being executed. */
- private TaskStatus mRunningTask;
+ /** All the information maintained about the job currently being executed. */
+ private JobStatus mRunningJob;
/** Binder to the client service. */
- ITaskService service;
+ IJobService service;
private final Object mLock = new Object();
/** Whether this context is free. */
@@ -109,45 +109,45 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
/** Track when job will timeout. */
private long mTimeoutElapsed;
- TaskServiceContext(TaskManagerService service, Looper looper) {
+ JobServiceContext(JobSchedulerService service, Looper looper) {
this(service.getContext(), service, looper);
}
@VisibleForTesting
- TaskServiceContext(Context context, TaskCompletedListener completedListener, Looper looper) {
+ JobServiceContext(Context context, JobCompletedListener completedListener, Looper looper) {
mContext = context;
- mCallbackHandler = new TaskServiceHandler(looper);
+ mCallbackHandler = new JobServiceHandler(looper);
mCompletedListener = completedListener;
mAvailable = true;
}
/**
- * Give a task to this context for execution. Callers must first check {@link #isAvailable()}
+ * Give a job to this context for execution. Callers must first check {@link #isAvailable()}
* to make sure this is a valid context.
- * @param ts The status of the task that we are going to run.
- * @return True if the task is valid and is running. False if the task cannot be executed.
+ * @param job The status of the job that we are going to run.
+ * @return True if the job is valid and is running. False if the job cannot be executed.
*/
- boolean executeRunnableTask(TaskStatus ts) {
+ boolean executeRunnableJob(JobStatus job) {
synchronized (mLock) {
if (!mAvailable) {
Slog.e(TAG, "Starting new runnable but context is unavailable > Error.");
return false;
}
- mRunningTask = ts;
- mParams = new TaskParams(ts.getTaskId(), ts.getExtras(), this);
+ mRunningJob = job;
+ mParams = new JobParameters(job.getJobId(), job.getExtras(), this);
mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
mVerb = VERB_BINDING;
- final Intent intent = new Intent().setComponent(ts.getServiceComponent());
+ final Intent intent = new Intent().setComponent(job.getServiceComponent());
boolean binding = mContext.bindServiceAsUser(intent, this,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
- new UserHandle(ts.getUserId()));
+ new UserHandle(job.getUserId()));
if (!binding) {
if (DEBUG) {
- Slog.d(TAG, ts.getServiceComponent().getShortClassName() + " unavailable.");
+ Slog.d(TAG, job.getServiceComponent().getShortClassName() + " unavailable.");
}
- mRunningTask = null;
+ mRunningJob = null;
mParams = null;
mExecutionStartTimeElapsed = 0L;
return false;
@@ -157,13 +157,13 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
}
}
- /** Used externally to query the running task. Will return null if there is no task running. */
- TaskStatus getRunningTask() {
- return mRunningTask;
+ /** Used externally to query the running job. Will return null if there is no job running. */
+ JobStatus getRunningJob() {
+ return mRunningJob;
}
- /** Called externally when a task that was scheduled for execution should be cancelled. */
- void cancelExecutingTask() {
+ /** Called externally when a job that was scheduled for execution should be cancelled. */
+ void cancelExecutingJob() {
mCallbackHandler.obtainMessage(MSG_CANCEL).sendToTarget();
}
@@ -185,29 +185,29 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
}
@Override
- public void taskFinished(int taskId, boolean reschedule) {
+ public void jobFinished(int jobId, boolean reschedule) {
if (!verifyCallingUid()) {
return;
}
- mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+ mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0)
.sendToTarget();
}
@Override
- public void acknowledgeStopMessage(int taskId, boolean reschedule) {
+ public void acknowledgeStopMessage(int jobId, boolean reschedule) {
if (!verifyCallingUid()) {
return;
}
- mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+ mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0)
.sendToTarget();
}
@Override
- public void acknowledgeStartMessage(int taskId, boolean ongoing) {
+ public void acknowledgeStartMessage(int jobId, boolean ongoing) {
if (!verifyCallingUid()) {
return;
}
- mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, ongoing ? 1 : 0).sendToTarget();
+ mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, ongoing ? 1 : 0).sendToTarget();
}
/**
@@ -219,25 +219,25 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- if (!name.equals(mRunningTask.getServiceComponent())) {
+ if (!name.equals(mRunningJob.getServiceComponent())) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
return;
}
- this.service = ITaskService.Stub.asInterface(service);
+ this.service = IJobService.Stub.asInterface(service);
// Remove all timeouts.
mCallbackHandler.removeMessages(MSG_TIMEOUT);
final PowerManager pm =
(PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- TM_WAKELOCK_PREFIX + mRunningTask.getServiceComponent().getPackageName());
- mWakeLock.setWorkSource(new WorkSource(mRunningTask.getUid()));
+ JS_WAKELOCK_PREFIX + mRunningJob.getServiceComponent().getPackageName());
+ mWakeLock.setWorkSource(new WorkSource(mRunningJob.getUid()));
mWakeLock.setReferenceCounted(false);
mWakeLock.acquire();
mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
}
/**
- * If the client service crashes we reschedule this task and clean up.
+ * If the client service crashes we reschedule this job and clean up.
* @param name The concrete component name of the service whose
*/
@Override
@@ -251,7 +251,7 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
* @return True if the binder calling is coming from the client we expect.
*/
private boolean verifyCallingUid() {
- if (mRunningTask == null || Binder.getCallingUid() != mRunningTask.getUid()) {
+ if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
if (DEBUG) {
Slog.d(TAG, "Stale callback received, ignoring.");
}
@@ -261,12 +261,12 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
}
/**
- * Handles the lifecycle of the TaskService binding/callbacks, etc. The convention within this
+ * Handles the lifecycle of the JobService binding/callbacks, etc. The convention within this
* class is to append 'H' to each function name that can only be called on this handler. This
* isn't strictly necessary because all of these functions are private, but helps clarity.
*/
- private class TaskServiceHandler extends Handler {
- TaskServiceHandler(Looper looper) {
+ private class JobServiceHandler extends Handler {
+ JobServiceHandler(Looper looper) {
super(looper);
}
@@ -278,7 +278,7 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
break;
case MSG_CALLBACK:
if (DEBUG) {
- Slog.d(TAG, "MSG_CALLBACK of : " + mRunningTask + " v:" +
+ Slog.d(TAG, "MSG_CALLBACK of : " + mRunningJob + " v:" +
VERB_STRINGS[mVerb]);
}
removeMessages(MSG_TIMEOUT);
@@ -292,7 +292,7 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
handleFinishedH(reschedule);
} else {
if (DEBUG) {
- Slog.d(TAG, "Unrecognised callback: " + mRunningTask);
+ Slog.d(TAG, "Unrecognised callback: " + mRunningJob);
}
}
break;
@@ -303,42 +303,42 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
handleOpTimeoutH();
break;
case MSG_SHUTDOWN_EXECUTION:
- closeAndCleanupTaskH(true /* needsReschedule */);
+ closeAndCleanupJobH(true /* needsReschedule */);
break;
default:
Log.e(TAG, "Unrecognised message: " + message);
}
}
- /** Start the task on the service. */
+ /** Start the job on the service. */
private void handleServiceBoundH() {
if (mVerb != VERB_BINDING) {
- Slog.e(TAG, "Sending onStartTask for a task that isn't pending. "
+ Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
+ VERB_STRINGS[mVerb]);
- closeAndCleanupTaskH(false /* reschedule */);
+ closeAndCleanupJobH(false /* reschedule */);
return;
}
if (mCancelled.get()) {
if (DEBUG) {
- Slog.d(TAG, "Task cancelled while waiting for bind to complete. "
- + mRunningTask);
+ Slog.d(TAG, "Job cancelled while waiting for bind to complete. "
+ + mRunningJob);
}
- closeAndCleanupTaskH(true /* reschedule */);
+ closeAndCleanupJobH(true /* reschedule */);
return;
}
try {
mVerb = VERB_STARTING;
scheduleOpTimeOut();
- service.startTask(mParams);
+ service.startJob(mParams);
} catch (RemoteException e) {
Log.e(TAG, "Error sending onStart message to '" +
- mRunningTask.getServiceComponent().getShortClassName() + "' ", e);
+ mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
}
}
/**
* State behaviours.
- * VERB_STARTING -> Successful start, change task to VERB_EXECUTING and post timeout.
+ * VERB_STARTING -> Successful start, change job to VERB_EXECUTING and post timeout.
* _PENDING -> Error
* _EXECUTING -> Error
* _STOPPING -> Error
@@ -348,7 +348,7 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
case VERB_STARTING:
mVerb = VERB_EXECUTING;
if (!workOngoing) {
- // Task is finished already so fast-forward to handleFinished.
+ // Job is finished already so fast-forward to handleFinished.
handleFinishedH(false);
return;
}
@@ -360,14 +360,14 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
scheduleOpTimeOut();
break;
default:
- Log.e(TAG, "Handling started task but task wasn't starting! Was "
+ Log.e(TAG, "Handling started job but job wasn't starting! Was "
+ VERB_STRINGS[mVerb] + ".");
return;
}
}
/**
- * VERB_EXECUTING -> Client called taskFinished(), clean up and notify done.
+ * VERB_EXECUTING -> Client called jobFinished(), clean up and notify done.
* _STOPPING -> Successful finish, clean up and notify done.
* _STARTING -> Error
* _PENDING -> Error
@@ -376,20 +376,20 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
switch (mVerb) {
case VERB_EXECUTING:
case VERB_STOPPING:
- closeAndCleanupTaskH(reschedule);
+ closeAndCleanupJobH(reschedule);
break;
default:
- Slog.e(TAG, "Got an execution complete message for a task that wasn't being" +
+ Slog.e(TAG, "Got an execution complete message for a job that wasn't being" +
"executed. Was " + VERB_STRINGS[mVerb] + ".");
}
}
/**
- * A task can be in various states when a cancel request comes in:
+ * A job can be in various states when a cancel request comes in:
* VERB_BINDING -> Cancelled before bind completed. Mark as cancelled and wait for
* {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)}
* _STARTING -> Mark as cancelled and wait for
- * {@link TaskServiceContext#acknowledgeStartMessage(int, boolean)}
+ * {@link JobServiceContext#acknowledgeStartMessage(int, boolean)}
* _EXECUTING -> call {@link #sendStopMessageH}}.
* _ENDING -> No point in doing anything here, so we ignore.
*/
@@ -406,48 +406,48 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
// Nada.
break;
default:
- Slog.e(TAG, "Cancelling a task without a valid verb: " + mVerb);
+ Slog.e(TAG, "Cancelling a job without a valid verb: " + mVerb);
break;
}
}
/** Process MSG_TIMEOUT here. */
private void handleOpTimeoutH() {
- if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+ if (Log.isLoggable(JobSchedulerService.TAG, Log.DEBUG)) {
Log.d(TAG, "MSG_TIMEOUT of " +
- mRunningTask.getServiceComponent().getShortClassName() + " : "
- + mParams.getTaskId());
+ mRunningJob.getServiceComponent().getShortClassName() + " : "
+ + mParams.getJobId());
}
- final int taskId = mParams.getTaskId();
+ final int jobId = mParams.getJobId();
switch (mVerb) {
case VERB_STARTING:
// Client unresponsive - wedged or failed to respond in time. We don't really
- // know what happened so let's log it and notify the TaskManager
+ // know what happened so let's log it and notify the JobScheduler
// FINISHED/NO-RETRY.
- Log.e(TAG, "No response from client for onStartTask '" +
- mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
- + taskId);
- closeAndCleanupTaskH(false /* needsReschedule */);
+ Log.e(TAG, "No response from client for onStartJob '" +
+ mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+ + jobId);
+ closeAndCleanupJobH(false /* needsReschedule */);
break;
case VERB_STOPPING:
- // At least we got somewhere, so fail but ask the TaskManager to reschedule.
- Log.e(TAG, "No response from client for onStopTask, '" +
- mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
- + taskId);
- closeAndCleanupTaskH(true /* needsReschedule */);
+ // At least we got somewhere, so fail but ask the JobScheduler to reschedule.
+ Log.e(TAG, "No response from client for onStopJob, '" +
+ mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+ + jobId);
+ closeAndCleanupJobH(true /* needsReschedule */);
break;
case VERB_EXECUTING:
// Not an error - client ran out of time.
- Log.i(TAG, "Client timed out while executing (no taskFinished received)." +
+ Log.i(TAG, "Client timed out while executing (no jobFinished received)." +
" sending onStop. " +
- mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
- + taskId);
+ mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+ + jobId);
sendStopMessageH();
break;
default:
- Log.e(TAG, "Handling timeout for an unknown active task state: "
- + mRunningTask);
+ Log.e(TAG, "Handling timeout for an unknown active job state: "
+ + mRunningJob);
return;
}
}
@@ -459,35 +459,35 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
private void sendStopMessageH() {
mCallbackHandler.removeMessages(MSG_TIMEOUT);
if (mVerb != VERB_EXECUTING) {
- Log.e(TAG, "Sending onStopTask for a task that isn't started. " + mRunningTask);
- closeAndCleanupTaskH(false /* reschedule */);
+ Log.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
+ closeAndCleanupJobH(false /* reschedule */);
return;
}
try {
mVerb = VERB_STOPPING;
scheduleOpTimeOut();
- service.stopTask(mParams);
+ service.stopJob(mParams);
} catch (RemoteException e) {
- Log.e(TAG, "Error sending onStopTask to client.", e);
- closeAndCleanupTaskH(false /* reschedule */);
+ Log.e(TAG, "Error sending onStopJob to client.", e);
+ closeAndCleanupJobH(false /* reschedule */);
}
}
/**
- * The provided task has finished, either by calling
- * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+ * The provided job has finished, either by calling
+ * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
* or from acknowledging the stop message we sent. Either way, we're done tracking it and
* we want to clean up internally.
*/
- private void closeAndCleanupTaskH(boolean reschedule) {
+ private void closeAndCleanupJobH(boolean reschedule) {
removeMessages(MSG_TIMEOUT);
synchronized (mLock) {
mWakeLock.release();
- mContext.unbindService(TaskServiceContext.this);
- mCompletedListener.onTaskCompleted(mRunningTask, reschedule);
+ mContext.unbindService(JobServiceContext.this);
+ mCompletedListener.onJobCompleted(mRunningJob, reschedule);
mWakeLock = null;
- mRunningTask = null;
+ mRunningJob = null;
mParams = null;
mVerb = -1;
mCancelled.set(false);
@@ -508,8 +508,8 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
if (DEBUG) {
Slog.d(TAG, "Scheduling time out for '" +
- mRunningTask.getServiceComponent().getShortClassName() + "' tId: " +
- mParams.getTaskId() + ", in " + (timeoutMillis / 1000) + " s");
+ mRunningJob.getServiceComponent().getShortClassName() + "' tId: " +
+ mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s");
}
Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT);
mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/job/JobStore.java
index 9e095e7..3ea7171 100644
--- a/services/core/java/com/android/server/task/TaskStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -14,10 +14,10 @@
* limitations under the License
*/
-package com.android.server.task;
+package com.android.server.job;
import android.content.ComponentName;
-import android.app.task.Task;
+import android.app.job.JobInfo;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
@@ -33,7 +33,7 @@ import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.IoThread;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -50,94 +50,94 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
/**
- * Maintain a list of classes, and accessor methods/logic for these tasks.
+ * Maintain a list of classes, and accessor methods/logic for these jobs.
* This class offers the following functionality:
- * - When a task is added, it will determine if the task requirements have changed (update) and
+ * - When a job is added, it will determine if the job requirements have changed (update) and
* whether the controllers need to be updated.
- * - Persists Tasks, figures out when to to rewrite the Task to disk.
- * - Handles rescheduling of tasks.
- * - When a periodic task is executed and must be re-added.
- * - When a task fails and the client requests that it be retried with backoff.
+ * - Persists JobInfos, figures out when to to rewrite the JobInfo to disk.
+ * - Handles rescheduling of jobs.
+ * - When a periodic job is executed and must be re-added.
+ * - When a job fails and the client requests that it be retried with backoff.
* - This class <strong>is not</strong> thread-safe.
*
* Note on locking:
* All callers to this class must <strong>lock on the class object they are calling</strong>.
- * This is important b/c {@link com.android.server.task.TaskStore.WriteTasksMapToDiskRunnable}
- * and {@link com.android.server.task.TaskStore.ReadTaskMapFromDiskRunnable} lock on that
+ * This is important b/c {@link com.android.server.job.JobStore.WriteJobsMapToDiskRunnable}
+ * and {@link com.android.server.job.JobStore.ReadJobMapFromDiskRunnable} lock on that
* object.
*/
-public class TaskStore {
- private static final String TAG = "TaskManagerStore";
- private static final boolean DEBUG = TaskManagerService.DEBUG;
+public class JobStore {
+ private static final String TAG = "JobStore";
+ private static final boolean DEBUG = JobSchedulerService.DEBUG;
/** Threshold to adjust how often we want to write to the db. */
private static final int MAX_OPS_BEFORE_WRITE = 1;
- final ArraySet<TaskStatus> mTasksSet;
+ final ArraySet<JobStatus> mJobSet;
final Context mContext;
private int mDirtyOperations;
private static final Object sSingletonLock = new Object();
- private final AtomicFile mTasksFile;
+ private final AtomicFile mJobsFile;
/** Handler backed by IoThread for writing to disk. */
private final Handler mIoHandler = IoThread.getHandler();
- private static TaskStore sSingleton;
+ private static JobStore sSingleton;
- /** Used by the {@Link TaskManagerService} to instantiate the TaskStore. */
- static TaskStore initAndGet(TaskManagerService taskManagerService) {
+ /** Used by the {@link JobSchedulerService} to instantiate the JobStore. */
+ static JobStore initAndGet(JobSchedulerService jobManagerService) {
synchronized (sSingletonLock) {
if (sSingleton == null) {
- sSingleton = new TaskStore(taskManagerService.getContext(),
- Environment.getDataDirectory(), taskManagerService);
+ sSingleton = new JobStore(jobManagerService.getContext(),
+ Environment.getDataDirectory(), jobManagerService);
}
return sSingleton;
}
}
@VisibleForTesting
- public static TaskStore initAndGetForTesting(Context context, File dataDir,
- TaskMapReadFinishedListener callback) {
- return new TaskStore(context, dataDir, callback);
+ public static JobStore initAndGetForTesting(Context context, File dataDir,
+ JobMapReadFinishedListener callback) {
+ return new JobStore(context, dataDir, callback);
}
- private TaskStore(Context context, File dataDir, TaskMapReadFinishedListener callback) {
+ private JobStore(Context context, File dataDir, JobMapReadFinishedListener callback) {
mContext = context;
mDirtyOperations = 0;
File systemDir = new File(dataDir, "system");
- File taskDir = new File(systemDir, "task");
- taskDir.mkdirs();
- mTasksFile = new AtomicFile(new File(taskDir, "tasks.xml"));
+ File jobDir = new File(systemDir, "job");
+ jobDir.mkdirs();
+ mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));
- mTasksSet = new ArraySet<TaskStatus>();
+ mJobSet = new ArraySet<JobStatus>();
- readTaskMapFromDiskAsync(callback);
+ readJobMapFromDiskAsync(callback);
}
/**
- * Add a task to the master list, persisting it if necessary. If the TaskStatus already exists,
+ * Add a job to the master list, persisting it if necessary. If the JobStatus already exists,
* it will be replaced.
- * @param taskStatus Task to add.
- * @return Whether or not an equivalent TaskStatus was replaced by this operation.
+ * @param jobStatus Job to add.
+ * @return Whether or not an equivalent JobStatus was replaced by this operation.
*/
- public boolean add(TaskStatus taskStatus) {
- boolean replaced = mTasksSet.remove(taskStatus);
- mTasksSet.add(taskStatus);
- if (taskStatus.isPersisted()) {
+ public boolean add(JobStatus jobStatus) {
+ boolean replaced = mJobSet.remove(jobStatus);
+ mJobSet.add(jobStatus);
+ if (jobStatus.isPersisted()) {
maybeWriteStatusToDiskAsync();
}
if (DEBUG) {
- Slog.d(TAG, "Added task status to store: " + taskStatus);
+ Slog.d(TAG, "Added job status to store: " + jobStatus);
}
return replaced;
}
/**
- * Whether this taskStatus object already exists in the TaskStore.
+ * Whether this jobStatus object already exists in the JobStore.
*/
- public boolean containsTaskIdForUid(int taskId, int uId) {
- for (TaskStatus ts : mTasksSet) {
- if (ts.getUid() == uId && ts.getTaskId() == taskId) {
+ public boolean containsJobIdForUid(int jobId, int uId) {
+ for (JobStatus ts : mJobSet) {
+ if (ts.getUid() == uId && ts.getJobId() == jobId) {
return true;
}
}
@@ -145,18 +145,18 @@ public class TaskStore {
}
public int size() {
- return mTasksSet.size();
+ return mJobSet.size();
}
/**
- * Remove the provided task. Will also delete the task if it was persisted.
- * @return Whether or not the task existed to be removed.
+ * Remove the provided job. Will also delete the job if it was persisted.
+ * @return Whether or not the job existed to be removed.
*/
- public boolean remove(TaskStatus taskStatus) {
- boolean removed = mTasksSet.remove(taskStatus);
+ public boolean remove(JobStatus jobStatus) {
+ boolean removed = mJobSet.remove(jobStatus);
if (!removed) {
if (DEBUG) {
- Slog.d(TAG, "Couldn't remove task: didn't exist: " + taskStatus);
+ Slog.d(TAG, "Couldn't remove job: didn't exist: " + jobStatus);
}
return false;
}
@@ -166,48 +166,48 @@ public class TaskStore {
@VisibleForTesting
public void clear() {
- mTasksSet.clear();
+ mJobSet.clear();
maybeWriteStatusToDiskAsync();
}
- public List<TaskStatus> getTasksByUser(int userHandle) {
- List<TaskStatus> matchingTasks = new ArrayList<TaskStatus>();
- Iterator<TaskStatus> it = mTasksSet.iterator();
+ public List<JobStatus> getJobsByUser(int userHandle) {
+ List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+ Iterator<JobStatus> it = mJobSet.iterator();
while (it.hasNext()) {
- TaskStatus ts = it.next();
+ JobStatus ts = it.next();
if (UserHandle.getUserId(ts.getUid()) == userHandle) {
- matchingTasks.add(ts);
+ matchingJobs.add(ts);
}
}
- return matchingTasks;
+ return matchingJobs;
}
/**
* @param uid Uid of the requesting app.
- * @return All TaskStatus objects for a given uid from the master list.
+ * @return All JobStatus objects for a given uid from the master list.
*/
- public List<TaskStatus> getTasksByUid(int uid) {
- List<TaskStatus> matchingTasks = new ArrayList<TaskStatus>();
- Iterator<TaskStatus> it = mTasksSet.iterator();
+ public List<JobStatus> getJobsByUid(int uid) {
+ List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+ Iterator<JobStatus> it = mJobSet.iterator();
while (it.hasNext()) {
- TaskStatus ts = it.next();
+ JobStatus ts = it.next();
if (ts.getUid() == uid) {
- matchingTasks.add(ts);
+ matchingJobs.add(ts);
}
}
- return matchingTasks;
+ return matchingJobs;
}
/**
* @param uid Uid of the requesting app.
- * @param taskId Task id, specified at schedule-time.
- * @return the TaskStatus that matches the provided uId and taskId, or null if none found.
+ * @param jobId Job id, specified at schedule-time.
+ * @return the JobStatus that matches the provided uId and jobId, or null if none found.
*/
- public TaskStatus getTaskByUidAndTaskId(int uid, int taskId) {
- Iterator<TaskStatus> it = mTasksSet.iterator();
+ public JobStatus getJobByUidAndJobId(int uid, int jobId) {
+ Iterator<JobStatus> it = mJobSet.iterator();
while (it.hasNext()) {
- TaskStatus ts = it.next();
- if (ts.getUid() == uid && ts.getTaskId() == taskId) {
+ JobStatus ts = it.next();
+ if (ts.getUid() == uid && ts.getJobId() == jobid) {
return ts;
}
}
@@ -215,15 +215,15 @@ public class TaskStore {
}
/**
- * @return The live array of TaskStatus objects.
+ * @return The live array of JobStatus objects.
*/
- public ArraySet<TaskStatus> getTasks() {
- return mTasksSet;
+ public ArraySet<JobStatus> getJobs() {
+ return mJobSet;
}
/** Version of the db schema. */
- private static final int TASKS_FILE_VERSION = 0;
- /** Tag corresponds to constraints this task needs. */
+ private static final int JOBS_FILE_VERSION = 0;
+ /** Tag corresponds to constraints this job needs. */
private static final String XML_TAG_PARAMS_CONSTRAINTS = "constraints";
/** Tag corresponds to execution parameters. */
private static final String XML_TAG_PERIODIC = "periodic";
@@ -231,7 +231,7 @@ public class TaskStore {
private static final String XML_TAG_EXTRAS = "extras";
/**
- * Every time the state changes we write all the tasks in one swathe, instead of trying to
+ * Every time the state changes we write all the jobs in one swath, instead of trying to
* track incremental changes.
* @return Whether the operation was successful. This will only fail for e.g. if the system is
* low on storage. If this happens, we continue as normal
@@ -240,38 +240,38 @@ public class TaskStore {
mDirtyOperations++;
if (mDirtyOperations >= MAX_OPS_BEFORE_WRITE) {
if (DEBUG) {
- Slog.v(TAG, "Writing tasks to disk.");
+ Slog.v(TAG, "Writing jobs to disk.");
}
- mIoHandler.post(new WriteTasksMapToDiskRunnable());
+ mIoHandler.post(new WriteJobsMapToDiskRunnable());
}
}
- private void readTaskMapFromDiskAsync(TaskMapReadFinishedListener callback) {
- mIoHandler.post(new ReadTaskMapFromDiskRunnable(callback));
+ private void readJobMapFromDiskAsync(JobMapReadFinishedListener callback) {
+ mIoHandler.post(new ReadJobMapFromDiskRunnable(callback));
}
- public void readTaskMapFromDisk(TaskMapReadFinishedListener callback) {
- new ReadTaskMapFromDiskRunnable(callback).run();
+ public void readJobMapFromDisk(JobMapReadFinishedListener callback) {
+ new ReadJobMapFromDiskRunnable(callback).run();
}
/**
- * Runnable that writes {@link #mTasksSet} out to xml.
- * NOTE: This Runnable locks on TaskStore.this
+ * Runnable that writes {@link #mJobSet} out to xml.
+ * NOTE: This Runnable locks on JobStore.this
*/
- private class WriteTasksMapToDiskRunnable implements Runnable {
+ private class WriteJobsMapToDiskRunnable implements Runnable {
@Override
public void run() {
final long startElapsed = SystemClock.elapsedRealtime();
- synchronized (TaskStore.this) {
- writeTasksMapImpl();
+ synchronized (JobStore.this) {
+ writeJobsMapImpl();
}
- if (TaskManagerService.DEBUG) {
+ if (JobSchedulerService.DEBUG) {
Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime()
- startElapsed) + "ms");
}
}
- private void writeTasksMapImpl() {
+ private void writeJobsMapImpl() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XmlSerializer out = new FastXmlSerializer();
@@ -279,31 +279,31 @@ public class TaskStore {
out.startDocument(null, true);
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- out.startTag(null, "task-info");
- out.attribute(null, "version", Integer.toString(TASKS_FILE_VERSION));
- for (int i = 0; i < mTasksSet.size(); i++) {
- final TaskStatus taskStatus = mTasksSet.valueAt(i);
+ out.startTag(null, "job-info");
+ out.attribute(null, "version", Integer.toString(JOBS_FILE_VERSION));
+ for (int i = 0; i < mJobSet.size(); i++) {
+ final JobStatus jobStatus = mJobSet.valueAt(i);
if (DEBUG) {
- Slog.d(TAG, "Saving task " + taskStatus.getTaskId());
+ Slog.d(TAG, "Saving job " + jobStatus.getJobId());
}
- out.startTag(null, "task");
- addIdentifierAttributesToTaskTag(out, taskStatus);
- writeConstraintsToXml(out, taskStatus);
- writeExecutionCriteriaToXml(out, taskStatus);
- writeBundleToXml(taskStatus.getExtras(), out);
- out.endTag(null, "task");
+ out.startTag(null, "job");
+ addIdentifierAttributesToJobTag(out, jobStatus);
+ writeConstraintsToXml(out, jobStatus);
+ writeExecutionCriteriaToXml(out, jobStatus);
+ writeBundleToXml(jobStatus.getExtras(), out);
+ out.endTag(null, "job");
}
- out.endTag(null, "task-info");
+ out.endTag(null, "job-info");
out.endDocument();
// Write out to disk in one fell sweep.
- FileOutputStream fos = mTasksFile.startWrite();
+ FileOutputStream fos = mJobsFile.startWrite();
fos.write(baos.toByteArray());
- mTasksFile.finishWrite(fos);
+ mJobsFile.finishWrite(fos);
mDirtyOperations = 0;
} catch (IOException e) {
if (DEBUG) {
- Slog.v(TAG, "Error writing out task data.", e);
+ Slog.v(TAG, "Error writing out job data.", e);
}
} catch (XmlPullParserException e) {
if (DEBUG) {
@@ -312,13 +312,13 @@ public class TaskStore {
}
}
- /** Write out a tag with data comprising the required fields of this task and its client. */
- private void addIdentifierAttributesToTaskTag(XmlSerializer out, TaskStatus taskStatus)
+ /** Write out a tag with data comprising the required fields of this job and its client. */
+ private void addIdentifierAttributesToJobTag(XmlSerializer out, JobStatus jobStatus)
throws IOException {
- out.attribute(null, "taskid", Integer.toString(taskStatus.getTaskId()));
- out.attribute(null, "package", taskStatus.getServiceComponent().getPackageName());
- out.attribute(null, "class", taskStatus.getServiceComponent().getClassName());
- out.attribute(null, "uid", Integer.toString(taskStatus.getUid()));
+ out.attribute(null, "jobid", Integer.toString(jobStatus.getJobId()));
+ out.attribute(null, "package", jobStatus.getServiceComponent().getPackageName());
+ out.attribute(null, "class", jobStatus.getServiceComponent().getClassName());
+ out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
}
private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
@@ -328,57 +328,57 @@ public class TaskStore {
out.endTag(null, XML_TAG_EXTRAS);
}
/**
- * Write out a tag with data identifying this tasks constraints. If the constraint isn't here
+ * Write out a tag with data identifying this job's constraints. If the constraint isn't here
* it doesn't apply.
*/
- private void writeConstraintsToXml(XmlSerializer out, TaskStatus taskStatus) throws IOException {
+ private void writeConstraintsToXml(XmlSerializer out, JobStatus jobStatus) throws IOException {
out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS);
- if (taskStatus.hasUnmeteredConstraint()) {
+ if (jobStatus.hasUnmeteredConstraint()) {
out.attribute(null, "unmetered", Boolean.toString(true));
}
- if (taskStatus.hasConnectivityConstraint()) {
+ if (jobStatus.hasConnectivityConstraint()) {
out.attribute(null, "connectivity", Boolean.toString(true));
}
- if (taskStatus.hasIdleConstraint()) {
+ if (jobStatus.hasIdleConstraint()) {
out.attribute(null, "idle", Boolean.toString(true));
}
- if (taskStatus.hasChargingConstraint()) {
+ if (jobStatus.hasChargingConstraint()) {
out.attribute(null, "charging", Boolean.toString(true));
}
out.endTag(null, XML_TAG_PARAMS_CONSTRAINTS);
}
- private void writeExecutionCriteriaToXml(XmlSerializer out, TaskStatus taskStatus)
+ private void writeExecutionCriteriaToXml(XmlSerializer out, JobStatus jobStatus)
throws IOException {
- final Task task = taskStatus.getTask();
- if (taskStatus.getTask().isPeriodic()) {
+ final JobInfo job = jobStatus.getJob();
+ if (jobStatus.getJob().isPeriodic()) {
out.startTag(null, XML_TAG_PERIODIC);
- out.attribute(null, "period", Long.toString(task.getIntervalMillis()));
+ out.attribute(null, "period", Long.toString(job.getIntervalMillis()));
} else {
out.startTag(null, XML_TAG_ONEOFF);
}
- if (taskStatus.hasDeadlineConstraint()) {
+ if (jobStatus.hasDeadlineConstraint()) {
// Wall clock deadline.
final long deadlineWallclock = System.currentTimeMillis() +
- (taskStatus.getLatestRunTimeElapsed() - SystemClock.elapsedRealtime());
+ (jobStatus.getLatestRunTimeElapsed() - SystemClock.elapsedRealtime());
out.attribute(null, "deadline", Long.toString(deadlineWallclock));
}
- if (taskStatus.hasTimingDelayConstraint()) {
+ if (jobStatus.hasTimingDelayConstraint()) {
final long delayWallclock = System.currentTimeMillis() +
- (taskStatus.getEarliestRunTime() - SystemClock.elapsedRealtime());
+ (jobStatus.getEarliestRunTime() - SystemClock.elapsedRealtime());
out.attribute(null, "delay", Long.toString(delayWallclock));
}
// Only write out back-off policy if it differs from the default.
- // This also helps the case where the task is idle -> these aren't allowed to specify
+ // This also helps the case where the job is idle -> these aren't allowed to specify
// back-off.
- if (taskStatus.getTask().getInitialBackoffMillis() != Task.DEFAULT_INITIAL_BACKOFF_MILLIS
- || taskStatus.getTask().getBackoffPolicy() != Task.DEFAULT_BACKOFF_POLICY) {
- out.attribute(null, "backoff-policy", Integer.toString(task.getBackoffPolicy()));
- out.attribute(null, "initial-backoff", Long.toString(task.getInitialBackoffMillis()));
+ if (jobStatus.getJob().getInitialBackoffMillis() != JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS
+ || jobStatus.getJob().getBackoffPolicy() != JobInfo.DEFAULT_BACKOFF_POLICY) {
+ out.attribute(null, "backoff-policy", Integer.toString(job.getBackoffPolicy()));
+ out.attribute(null, "initial-backoff", Long.toString(job.getInitialBackoffMillis()));
}
- if (task.isPeriodic()) {
+ if (job.isPeriodic()) {
out.endTag(null, XML_TAG_PERIODIC);
} else {
out.endTag(null, XML_TAG_ONEOFF);
@@ -387,43 +387,43 @@ public class TaskStore {
}
/**
- * Runnable that reads list of persisted task from xml.
- * NOTE: This Runnable locks on TaskStore.this
+ * Runnable that reads list of persisted job from xml.
+ * NOTE: This Runnable locks on JobStore.this
*/
- private class ReadTaskMapFromDiskRunnable implements Runnable {
- private TaskMapReadFinishedListener mCallback;
- public ReadTaskMapFromDiskRunnable(TaskMapReadFinishedListener callback) {
+ private class ReadJobMapFromDiskRunnable implements Runnable {
+ private JobMapReadFinishedListener mCallback;
+ public ReadJobMapFromDiskRunnable(JobMapReadFinishedListener callback) {
mCallback = callback;
}
@Override
public void run() {
try {
- List<TaskStatus> tasks;
- FileInputStream fis = mTasksFile.openRead();
- synchronized (TaskStore.this) {
- tasks = readTaskMapImpl(fis);
+ List<JobStatus> jobs;
+ FileInputStream fis = mJobsFile.openRead();
+ synchronized (JobStore.this) {
+ jobs = readJobMapImpl(fis);
}
fis.close();
- if (tasks != null) {
- mCallback.onTaskMapReadFinished(tasks);
+ if (jobs != null) {
+ mCallback.onJobMapReadFinished(jobs);
}
} catch (FileNotFoundException e) {
- if (TaskManagerService.DEBUG) {
- Slog.d(TAG, "Could not find tasks file, probably there was nothing to load.");
+ if (JobSchedulerService.DEBUG) {
+ Slog.d(TAG, "Could not find jobs file, probably there was nothing to load.");
}
} catch (XmlPullParserException e) {
- if (TaskManagerService.DEBUG) {
+ if (JobSchedulerService.DEBUG) {
Slog.d(TAG, "Error parsing xml.", e);
}
} catch (IOException e) {
- if (TaskManagerService.DEBUG) {
+ if (JobSchedulerService.DEBUG) {
Slog.d(TAG, "Error parsing xml.", e);
}
}
}
- private List<TaskStatus> readTaskMapImpl(FileInputStream fis) throws XmlPullParserException, IOException {
+ private List<JobStatus> readJobMapImpl(FileInputStream fis) throws XmlPullParserException, IOException {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(fis, null);
@@ -435,66 +435,66 @@ public class TaskStore {
}
if (eventType == XmlPullParser.END_DOCUMENT) {
if (DEBUG) {
- Slog.d(TAG, "No persisted tasks.");
+ Slog.d(TAG, "No persisted jobs.");
}
return null;
}
String tagName = parser.getName();
- if ("task-info".equals(tagName)) {
- final List<TaskStatus> tasks = new ArrayList<TaskStatus>();
+ if ("job-info".equals(tagName)) {
+ final List<JobStatus> jobs = new ArrayList<JobStatus>();
// Read in version info.
try {
int version = Integer.valueOf(parser.getAttributeValue(null, "version"));
- if (version != TASKS_FILE_VERSION) {
- Slog.d(TAG, "Invalid version number, aborting tasks file read.");
+ if (version != JOBS_FILE_VERSION) {
+ Slog.d(TAG, "Invalid version number, aborting jobs file read.");
return null;
}
} catch (NumberFormatException e) {
- Slog.e(TAG, "Invalid version number, aborting tasks file read.");
+ Slog.e(TAG, "Invalid version number, aborting jobs file read.");
return null;
}
eventType = parser.next();
do {
- // Read each <task/>
+ // Read each <job/>
if (eventType == XmlPullParser.START_TAG) {
tagName = parser.getName();
- // Start reading task.
- if ("task".equals(tagName)) {
- TaskStatus persistedTask = restoreTaskFromXml(parser);
- if (persistedTask != null) {
+ // Start reading job.
+ if ("job".equals(tagName)) {
+ JobStatus persistedJob = restoreJobFromXml(parser);
+ if (persistedJob != null) {
if (DEBUG) {
- Slog.d(TAG, "Read out " + persistedTask);
+ Slog.d(TAG, "Read out " + persistedJob);
}
- tasks.add(persistedTask);
+ jobs.add(persistedJob);
} else {
- Slog.d(TAG, "Error reading task from file.");
+ Slog.d(TAG, "Error reading job from file.");
}
}
}
eventType = parser.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
- return tasks;
+ return jobs;
}
return null;
}
/**
- * @param parser Xml parser at the beginning of a "<task/>" tag. The next "parser.next()" call
- * will take the parser into the body of the task tag.
- * @return Newly instantiated task holding all the information we just read out of the xml tag.
+ * @param parser Xml parser at the beginning of a "<job/>" tag. The next "parser.next()" call
+ * will take the parser into the body of the job tag.
+ * @return Newly instantiated job holding all the information we just read out of the xml tag.
*/
- private TaskStatus restoreTaskFromXml(XmlPullParser parser) throws XmlPullParserException,
+ private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException,
IOException {
- Task.Builder taskBuilder;
+ JobInfo.Builder jobBuilder;
int uid;
- // Read out task identifier attributes.
+ // Read out job identifier attributes.
try {
- taskBuilder = buildBuilderFromXml(parser);
+ jobBuilder = buildBuilderFromXml(parser);
uid = Integer.valueOf(parser.getAttributeValue(null, "uid"));
} catch (NumberFormatException e) {
- Slog.e(TAG, "Error parsing task's required fields, skipping");
+ Slog.e(TAG, "Error parsing job's required fields, skipping");
return null;
}
@@ -510,7 +510,7 @@ public class TaskStore {
return null;
}
try {
- buildConstraintsFromXml(taskBuilder, parser);
+ buildConstraintsFromXml(jobBuilder, parser);
} catch (NumberFormatException e) {
Slog.d(TAG, "Error reading constraints, skipping.");
return null;
@@ -538,22 +538,22 @@ public class TaskStore {
if (XML_TAG_PERIODIC.equals(parser.getName())) {
try {
String val = parser.getAttributeValue(null, "period");
- taskBuilder.setPeriodic(Long.valueOf(val));
+ jobBuilder.setPeriodic(Long.valueOf(val));
} catch (NumberFormatException e) {
Slog.d(TAG, "Error reading periodic execution criteria, skipping.");
return null;
}
} else if (XML_TAG_ONEOFF.equals(parser.getName())) {
try {
- if (runtimes.first != TaskStatus.NO_EARLIEST_RUNTIME) {
- taskBuilder.setMinimumLatency(runtimes.first - SystemClock.elapsedRealtime());
+ if (runtimes.first != JobStatus.NO_EARLIEST_RUNTIME) {
+ jobBuilder.setMinimumLatency(runtimes.first - SystemClock.elapsedRealtime());
}
- if (runtimes.second != TaskStatus.NO_LATEST_RUNTIME) {
- taskBuilder.setOverrideDeadline(
+ if (runtimes.second != JobStatus.NO_LATEST_RUNTIME) {
+ jobBuilder.setOverrideDeadline(
runtimes.second - SystemClock.elapsedRealtime());
}
} catch (NumberFormatException e) {
- Slog.d(TAG, "Error reading task execution criteria, skipping.");
+ Slog.d(TAG, "Error reading job execution criteria, skipping.");
return null;
}
} else {
@@ -563,7 +563,7 @@ public class TaskStore {
// Expecting a parameters start tag.
return null;
}
- maybeBuildBackoffPolicyFromXml(taskBuilder, parser);
+ maybeBuildBackoffPolicyFromXml(jobBuilder, parser);
parser.nextTag(); // Consume parameters end tag.
@@ -579,52 +579,52 @@ public class TaskStore {
}
PersistableBundle extras = PersistableBundle.restoreFromXml(parser);
- taskBuilder.setExtras(extras);
+ jobBuilder.setExtras(extras);
parser.nextTag(); // Consume </extras>
- return new TaskStatus(taskBuilder.build(), uid, runtimes.first, runtimes.second);
+ return new JobStatus(jobBuilder.build(), uid, runtimes.first, runtimes.second);
}
- private Task.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
- // Pull out required fields from <task> attributes.
- int taskId = Integer.valueOf(parser.getAttributeValue(null, "taskid"));
+ private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
+ // Pull out required fields from <job> attributes.
+ int jobId = Integer.valueOf(parser.getAttributeValue(null, "jobid"));
String packageName = parser.getAttributeValue(null, "package");
String className = parser.getAttributeValue(null, "class");
ComponentName cname = new ComponentName(packageName, className);
- return new Task.Builder(taskId, cname);
+ return new JobInfo.Builder(jobId, cname);
}
- private void buildConstraintsFromXml(Task.Builder taskBuilder, XmlPullParser parser) {
+ private void buildConstraintsFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) {
String val = parser.getAttributeValue(null, "unmetered");
if (val != null) {
- taskBuilder.setRequiredNetworkCapabilities(Task.NetworkType.UNMETERED);
+ jobBuilder.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED);
}
val = parser.getAttributeValue(null, "connectivity");
if (val != null) {
- taskBuilder.setRequiredNetworkCapabilities(Task.NetworkType.ANY);
+ jobBuilder.setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY);
}
val = parser.getAttributeValue(null, "idle");
if (val != null) {
- taskBuilder.setRequiresDeviceIdle(true);
+ jobBuilder.setRequiresDeviceIdle(true);
}
val = parser.getAttributeValue(null, "charging");
if (val != null) {
- taskBuilder.setRequiresCharging(true);
+ jobBuilder.setRequiresCharging(true);
}
}
/**
* Builds the back-off policy out of the params tag. These attributes may not exist, depending
- * on whether the back-off was set when the task was first scheduled.
+ * on whether the back-off was set when the job was first scheduled.
*/
- private void maybeBuildBackoffPolicyFromXml(Task.Builder taskBuilder, XmlPullParser parser) {
+ private void maybeBuildBackoffPolicyFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) {
String val = parser.getAttributeValue(null, "initial-backoff");
if (val != null) {
long initialBackoff = Long.valueOf(val);
val = parser.getAttributeValue(null, "backoff-policy");
int backoffPolicy = Integer.valueOf(val); // Will throw NFE which we catch higher up.
- taskBuilder.setBackoffCriteria(initialBackoff, backoffPolicy);
+ jobBuilder.setBackoffCriteria(initialBackoff, backoffPolicy);
}
}
@@ -640,8 +640,8 @@ public class TaskStore {
final long nowWallclock = System.currentTimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
- long earliestRunTimeElapsed = TaskStatus.NO_EARLIEST_RUNTIME;
- long latestRunTimeElapsed = TaskStatus.NO_LATEST_RUNTIME;
+ long earliestRunTimeElapsed = JobStatus.NO_EARLIEST_RUNTIME;
+ long latestRunTimeElapsed = JobStatus.NO_LATEST_RUNTIME;
String val = parser.getAttributeValue(null, "deadline");
if (val != null) {
long latestRuntimeWallclock = Long.valueOf(val);
diff --git a/services/core/java/com/android/server/task/StateChangedListener.java b/services/core/java/com/android/server/job/StateChangedListener.java
index ab5cc7c..90c203a 100644
--- a/services/core/java/com/android/server/task/StateChangedListener.java
+++ b/services/core/java/com/android/server/job/StateChangedListener.java
@@ -14,26 +14,26 @@
* limitations under the License
*/
-package com.android.server.task;
+package com.android.server.job;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
/**
- * Interface through which a {@link com.android.server.task.controllers.StateController} informs
- * the {@link com.android.server.task.TaskManagerService} that there are some tasks potentially
+ * Interface through which a {@link com.android.server.job.controllers.StateController} informs
+ * the {@link com.android.server.job.JobSchedulerService} that there are some tasks potentially
* ready to be run.
*/
public interface StateChangedListener {
/**
- * Called by the controller to notify the TaskManager that it should check on the state of a
+ * Called by the controller to notify the JobManager that it should check on the state of a
* task.
*/
public void onControllerStateChanged();
/**
- * Called by the controller to notify the TaskManager that regardless of the state of the task,
+ * Called by the controller to notify the JobManager that regardless of the state of the task,
* it must be run immediately.
- * @param taskStatus The state of the task which is to be run immediately.
+ * @param jobStatus The state of the task which is to be run immediately.
*/
- public void onRunTaskNow(TaskStatus taskStatus);
+ public void onRunJobNow(JobStatus jobStatus);
}
diff --git a/services/core/java/com/android/server/task/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index 443527f..010de5c 100644
--- a/services/core/java/com/android/server/task/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -32,8 +32,8 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.BatteryService;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -54,10 +54,10 @@ public class BatteryController extends StateController {
/** Wait this long after phone is plugged in before doing any work. */
private static final long STABLE_CHARGING_THRESHOLD_MILLIS = 2 * 60 * 1000; // 2 minutes.
- private List<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>();
+ private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
private ChargingTracker mChargeTracker;
- public static BatteryController get(TaskManagerService taskManagerService) {
+ public static BatteryController get(JobSchedulerService taskManagerService) {
synchronized (sCreationLock) {
if (sController == null) {
sController = new BatteryController(taskManagerService,
@@ -85,7 +85,7 @@ public class BatteryController extends StateController {
}
@Override
- public void maybeStartTrackingTask(TaskStatus taskStatus) {
+ public void maybeStartTrackingJob(JobStatus taskStatus) {
if (taskStatus.hasChargingConstraint()) {
synchronized (mTrackedTasks) {
mTrackedTasks.add(taskStatus);
@@ -96,7 +96,7 @@ public class BatteryController extends StateController {
}
@Override
- public void maybeStopTrackingTask(TaskStatus taskStatus) {
+ public void maybeStopTrackingJob(JobStatus taskStatus) {
if (taskStatus.hasChargingConstraint()) {
synchronized (mTrackedTasks) {
mTrackedTasks.remove(taskStatus);
@@ -108,7 +108,7 @@ public class BatteryController extends StateController {
final boolean stablePower = mChargeTracker.isOnStablePower();
boolean reportChange = false;
synchronized (mTrackedTasks) {
- for (TaskStatus ts : mTrackedTasks) {
+ for (JobStatus ts : mTrackedTasks) {
boolean previous = ts.chargingConstraintSatisfied.getAndSet(stablePower);
if (previous != stablePower) {
reportChange = true;
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index c1ab0f0..7e79ff7 100644
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
import android.content.BroadcastReceiver;
@@ -28,8 +28,8 @@ import android.os.UserHandle;
import android.util.Slog;
import com.android.server.ConnectivityService;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
import java.util.LinkedList;
@@ -42,9 +42,9 @@ import java.util.List;
*/
public class ConnectivityController extends StateController implements
ConnectivityManager.OnNetworkActiveListener {
- private static final String TAG = "TaskManager.Conn";
+ private static final String TAG = "JobScheduler.Conn";
- private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
+ private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
private final BroadcastReceiver mConnectivityChangedReceiver =
new ConnectivityChangedReceiver();
/** Singleton. */
@@ -55,10 +55,10 @@ public class ConnectivityController extends StateController implements
/** Track whether the latest active network is connected. */
private boolean mNetworkConnected;
- public static ConnectivityController get(TaskManagerService taskManager) {
+ public static ConnectivityController get(JobSchedulerService jms) {
synchronized (sCreationLock) {
if (mSingleton == null) {
- mSingleton = new ConnectivityController(taskManager, taskManager.getContext());
+ mSingleton = new ConnectivityController(jms, jms.getContext());
}
return mSingleton;
}
@@ -82,21 +82,21 @@ public class ConnectivityController extends StateController implements
}
@Override
- public void maybeStartTrackingTask(TaskStatus taskStatus) {
- if (taskStatus.hasConnectivityConstraint() || taskStatus.hasUnmeteredConstraint()) {
- synchronized (mTrackedTasks) {
- taskStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
- taskStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
- mTrackedTasks.add(taskStatus);
+ public void maybeStartTrackingJob(JobStatus jobStatus) {
+ if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
+ synchronized (mTrackedJobs) {
+ jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
+ jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
+ mTrackedJobs.add(jobStatus);
}
}
}
@Override
- public void maybeStopTrackingTask(TaskStatus taskStatus) {
- if (taskStatus.hasConnectivityConstraint() || taskStatus.hasUnmeteredConstraint()) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.remove(taskStatus);
+ public void maybeStopTrackingJob(JobStatus jobStatus) {
+ if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
+ synchronized (mTrackedJobs) {
+ mTrackedJobs.remove(jobStatus);
}
}
}
@@ -104,16 +104,16 @@ public class ConnectivityController extends StateController implements
/**
* @param userId Id of the user for whom we are updating the connectivity state.
*/
- private void updateTrackedTasks(int userId) {
- synchronized (mTrackedTasks) {
+ private void updateTrackedJobs(int userId) {
+ synchronized (mTrackedJobs) {
boolean changed = false;
- for (TaskStatus ts : mTrackedTasks) {
- if (ts.getUserId() != userId) {
+ for (JobStatus js : mTrackedJobs) {
+ if (js.getUserId() != userId) {
continue;
}
boolean prevIsConnected =
- ts.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
- boolean prevIsMetered = ts.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
+ js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
+ boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
changed = true;
}
@@ -125,16 +125,16 @@ public class ConnectivityController extends StateController implements
}
/**
- * We know the network has just come up. We want to run any tasks that are ready.
+ * We know the network has just come up. We want to run any jobs that are ready.
*/
public synchronized void onNetworkActive() {
- synchronized (mTrackedTasks) {
- for (TaskStatus ts : mTrackedTasks) {
- if (ts.isReady()) {
+ synchronized (mTrackedJobs) {
+ for (JobStatus js : mTrackedJobs) {
+ if (js.isReady()) {
if (DEBUG) {
- Slog.d(TAG, "Running " + ts + " due to network activity.");
+ Slog.d(TAG, "Running " + js + " due to network activity.");
}
- mStateChangedListener.onRunTaskNow(ts);
+ mStateChangedListener.onRunJobNow(js);
}
}
}
@@ -169,7 +169,7 @@ public class ConnectivityController extends StateController implements
if (activeNetwork == null) {
mNetworkUnmetered = false;
mNetworkConnected = false;
- updateTrackedTasks(userid);
+ updateTrackedJobs(userid);
} else if (activeNetwork.getType() == networkType) {
mNetworkUnmetered = false;
mNetworkConnected = !intent.getBooleanExtra(
@@ -177,7 +177,7 @@ public class ConnectivityController extends StateController implements
if (mNetworkConnected) { // No point making the call if we know there's no conn.
mNetworkUnmetered = !connManager.isActiveNetworkMetered();
}
- updateTrackedTasks(userid);
+ updateTrackedJobs(userid);
}
} else {
if (DEBUG) {
@@ -191,10 +191,10 @@ public class ConnectivityController extends StateController implements
public void dumpControllerState(PrintWriter pw) {
pw.println("Conn.");
pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
- for (TaskStatus ts: mTrackedTasks) {
- pw.println(String.valueOf(ts.hashCode()).substring(0, 3) + ".."
- + ": C=" + ts.hasConnectivityConstraint()
- + ", UM=" + ts.hasUnmeteredConstraint());
+ for (JobStatus js: mTrackedJobs) {
+ pw.println(String.valueOf(js.hashCode()).substring(0, 3) + ".."
+ + ": C=" + js.hasConnectivityConstraint()
+ + ", UM=" + js.hasUnmeteredConstraint());
}
}
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/task/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index e749b00..07ffe4d 100644
--- a/services/core/java/com/android/server/task/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -29,8 +29,8 @@ import android.content.IntentFilter;
import android.os.SystemClock;
import android.util.Slog;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
public class IdleController extends StateController {
private static final String TAG = "IdleController";
@@ -43,14 +43,14 @@ public class IdleController extends StateController {
private static final String ACTION_TRIGGER_IDLE =
"com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
- final ArrayList<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>();
+ final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
IdlenessTracker mIdleTracker;
// Singleton factory
private static Object sCreationLock = new Object();
private static volatile IdleController sController;
- public static IdleController get(TaskManagerService service) {
+ public static IdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
sController = new IdleController(service, service.getContext());
@@ -68,7 +68,7 @@ public class IdleController extends StateController {
* StateController interface
*/
@Override
- public void maybeStartTrackingTask(TaskStatus taskStatus) {
+ public void maybeStartTrackingJob(JobStatus taskStatus) {
if (taskStatus.hasIdleConstraint()) {
synchronized (mTrackedTasks) {
mTrackedTasks.add(taskStatus);
@@ -78,7 +78,7 @@ public class IdleController extends StateController {
}
@Override
- public void maybeStopTrackingTask(TaskStatus taskStatus) {
+ public void maybeStopTrackingJob(JobStatus taskStatus) {
synchronized (mTrackedTasks) {
mTrackedTasks.remove(taskStatus);
}
@@ -89,7 +89,7 @@ public class IdleController extends StateController {
*/
void reportNewIdleState(boolean isIdle) {
synchronized (mTrackedTasks) {
- for (TaskStatus task : mTrackedTasks) {
+ for (JobStatus task : mTrackedTasks) {
task.idleConstraintSatisfied.set(isIdle);
}
}
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index a286737..15a6b25 100644
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -14,9 +14,9 @@
* limitations under the License
*/
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
-import android.app.task.Task;
+import android.app.job.JobInfo;
import android.content.ComponentName;
import android.os.PersistableBundle;
import android.os.SystemClock;
@@ -26,9 +26,9 @@ import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicBoolean;
/**
- * Uniquely identifies a task internally.
- * Created from the public {@link android.app.task.Task} object when it lands on the scheduler.
- * Contains current state of the requirements of the task, as well as a function to evaluate
+ * Uniquely identifies a job internally.
+ * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
+ * Contains current state of the requirements of the job, as well as a function to evaluate
* whether it's ready to run.
* This object is shared among the various controllers - hence why the different fields are atomic.
* This isn't strictly necessary because each controller is only interested in a specific field,
@@ -36,14 +36,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
* but we don't enforce that so this is safer.
* @hide
*/
-public class TaskStatus {
+public class JobStatus {
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
public static final long NO_EARLIEST_RUNTIME = 0L;
- final Task task;
+ final JobInfo job;
final int uId;
- /** At reschedule time we need to know whether to update task on disk. */
+ /** At reschedule time we need to know whether to update job on disk. */
final boolean persisted;
// Constraints.
@@ -55,77 +55,77 @@ public class TaskStatus {
final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
/**
- * Earliest point in the future at which this task will be eligible to run. A value of 0
+ * Earliest point in the future at which this job will be eligible to run. A value of 0
* indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
*/
private long earliestRunTimeElapsedMillis;
/**
- * Latest point in the future at which this task must be run. A value of {@link Long#MAX_VALUE}
+ * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
* indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
*/
private long latestRunTimeElapsedMillis;
- /** How many times this task has failed, used to compute back-off. */
+ /** How many times this job has failed, used to compute back-off. */
private final int numFailures;
- /** Provide a handle to the service that this task will be run on. */
+ /** Provide a handle to the service that this job will be run on. */
public int getServiceToken() {
return uId;
}
- private TaskStatus(Task task, int uId, boolean persisted, int numFailures) {
- this.task = task;
+ private JobStatus(JobInfo job, int uId, boolean persisted, int numFailures) {
+ this.job = job;
this.uId = uId;
this.numFailures = numFailures;
this.persisted = persisted;
}
- /** Create a newly scheduled task. */
- public TaskStatus(Task task, int uId, boolean persisted) {
- this(task, uId, persisted, 0);
+ /** Create a newly scheduled job. */
+ public JobStatus(JobInfo job, int uId, boolean persisted) {
+ this(job, uId, persisted, 0);
final long elapsedNow = SystemClock.elapsedRealtime();
- if (task.isPeriodic()) {
+ if (job.isPeriodic()) {
earliestRunTimeElapsedMillis = elapsedNow;
- latestRunTimeElapsedMillis = elapsedNow + task.getIntervalMillis();
+ latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
} else {
- earliestRunTimeElapsedMillis = task.hasEarlyConstraint() ?
- elapsedNow + task.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
- latestRunTimeElapsedMillis = task.hasLateConstraint() ?
- elapsedNow + task.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
+ earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
+ elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
+ latestRunTimeElapsedMillis = job.hasLateConstraint() ?
+ elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
}
}
/**
- * Create a new TaskStatus that was loaded from disk. We ignore the provided
- * {@link android.app.task.Task} time criteria because we can load a persisted periodic task
- * from the {@link com.android.server.task.TaskStore} and still want to respect its
+ * Create a new JobStatus that was loaded from disk. We ignore the provided
+ * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
+ * from the {@link com.android.server.job.JobStore} and still want to respect its
* wallclock runtime rather than resetting it on every boot.
- * We consider a freshly loaded task to no longer be in back-off.
+ * We consider a freshly loaded job to no longer be in back-off.
*/
- public TaskStatus(Task task, int uId, long earliestRunTimeElapsedMillis,
+ public JobStatus(JobInfo job, int uId, long earliestRunTimeElapsedMillis,
long latestRunTimeElapsedMillis) {
- this(task, uId, true, 0);
+ this(job, uId, true, 0);
this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
}
- /** Create a new task to be rescheduled with the provided parameters. */
- public TaskStatus(TaskStatus rescheduling, long newEarliestRuntimeElapsedMillis,
+ /** Create a new job to be rescheduled with the provided parameters. */
+ public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
long newLatestRuntimeElapsedMillis, int backoffAttempt) {
- this(rescheduling.task, rescheduling.getUid(), rescheduling.isPersisted(), backoffAttempt);
+ this(rescheduling.job, rescheduling.getUid(), rescheduling.isPersisted(), backoffAttempt);
earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
}
- public Task getTask() {
- return task;
+ public JobInfo getJob() {
+ return job;
}
- public int getTaskId() {
- return task.getId();
+ public int getJobId() {
+ return job.getId();
}
public int getNumFailures() {
@@ -133,7 +133,7 @@ public class TaskStatus {
}
public ComponentName getServiceComponent() {
- return task.getService();
+ return job.getService();
}
public int getUserId() {
@@ -145,19 +145,19 @@ public class TaskStatus {
}
public PersistableBundle getExtras() {
- return task.getExtras();
+ return job.getExtras();
}
public boolean hasConnectivityConstraint() {
- return task.getNetworkCapabilities() == Task.NetworkType.ANY;
+ return job.getNetworkCapabilities() == JobInfo.NetworkType.ANY;
}
public boolean hasUnmeteredConstraint() {
- return task.getNetworkCapabilities() == Task.NetworkType.UNMETERED;
+ return job.getNetworkCapabilities() == JobInfo.NetworkType.UNMETERED;
}
public boolean hasChargingConstraint() {
- return task.isRequireCharging();
+ return job.isRequireCharging();
}
public boolean hasTimingDelayConstraint() {
@@ -169,7 +169,7 @@ public class TaskStatus {
}
public boolean hasIdleConstraint() {
- return task.isRequireDeviceIdle();
+ return job.isRequireDeviceIdle();
}
public long getEarliestRunTime() {
@@ -184,7 +184,7 @@ public class TaskStatus {
return persisted;
}
/**
- * @return Whether or not this task is ready to run, based on its requirements.
+ * @return Whether or not this job is ready to run, based on its requirements.
*/
public synchronized boolean isReady() {
return (!hasChargingConstraint() || chargingConstraintSatisfied.get())
@@ -196,36 +196,17 @@ public class TaskStatus {
|| (hasDeadlineConstraint() && deadlineConstraintSatisfied.get());
}
- /*@Override
- public int hashCode() {
- int result = getServiceComponent().hashCode();
- result = 31 * result + task.getId();
- result = 31 * result + uId;
- return result;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof TaskStatus)) return false;
-
- TaskStatus that = (TaskStatus) o;
- return ((task.getId() == that.task.getId())
- && (uId == that.uId)
- && (getServiceComponent().equals(that.getServiceComponent())));
- }*/
-
- public boolean matches(int uid, int taskId) {
- return this.task.getId() == taskId && this.uId == uid;
+ public boolean matches(int uid, int jobId) {
+ return this.job.getId() == jobId && this.uId == uid;
}
@Override
public String toString() {
return String.valueOf(hashCode()).substring(0, 3) + ".."
- + ":[" + task.getService().getPackageName() + ",tId=" + task.getId()
+ + ":[" + job.getService().getPackageName() + ",jId=" + job.getId()
+ ",R=(" + earliestRunTimeElapsedMillis + "," + latestRunTimeElapsedMillis + ")"
- + ",N=" + task.getNetworkCapabilities() + ",C=" + task.isRequireCharging()
- + ",I=" + task.isRequireDeviceIdle() + ",F=" + numFailures
+ + ",N=" + job.getNetworkCapabilities() + ",C=" + job.isRequireCharging()
+ + ",I=" + job.isRequireDeviceIdle() + ",F=" + numFailures
+ (isReady() ? "(READY)" : "")
+ "]";
}
diff --git a/services/core/java/com/android/server/task/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index a7f52f5..81658bf 100644
--- a/services/core/java/com/android/server/task/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -14,18 +14,18 @@
* limitations under the License
*/
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
import android.content.Context;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
/**
- * Incorporates shared controller logic between the various controllers of the TaskManager.
- * These are solely responsible for tracking a list of tasks, and notifying the TM when these
+ * Incorporates shared controller logic between the various controllers of the JobManager.
+ * These are solely responsible for tracking a list of jobs, and notifying the JM when these
* are ready to run, or whether they must be stopped.
*/
public abstract class StateController {
@@ -39,16 +39,16 @@ public abstract class StateController {
}
/**
- * Implement the logic here to decide whether a task should be tracked by this controller.
- * This logic is put here so the TaskManger can be completely agnostic of Controller logic.
+ * Implement the logic here to decide whether a job should be tracked by this controller.
+ * This logic is put here so the JobManger can be completely agnostic of Controller logic.
* Also called when updating a task, so implementing controllers have to be aware of
* preexisting tasks.
*/
- public abstract void maybeStartTrackingTask(TaskStatus taskStatus);
+ public abstract void maybeStartTrackingJob(JobStatus jobStatus);
/**
* Remove task - this will happen if the task is cancelled, completed, etc.
*/
- public abstract void maybeStopTrackingTask(TaskStatus taskStatus);
+ public abstract void maybeStopTrackingJob(JobStatus jobStatus);
public abstract void dumpControllerState(PrintWriter pw);
diff --git a/services/core/java/com/android/server/task/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index b75036c..e46226c 100644
--- a/services/core/java/com/android/server/task/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -25,8 +25,8 @@ import android.content.IntentFilter;
import android.os.SystemClock;
import android.util.Slog;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
import java.util.Iterator;
@@ -35,35 +35,35 @@ import java.util.List;
import java.util.ListIterator;
/**
- * This class sets an alarm for the next expiring task, and determines whether a task's minimum
+ * This class sets an alarm for the next expiring job, and determines whether a job's minimum
* delay has been satisfied.
*/
public class TimeController extends StateController {
- private static final String TAG = "TaskManager.Time";
- private static final String ACTION_TASK_EXPIRED =
- "android.content.taskmanager.TASK_DEADLINE_EXPIRED";
- private static final String ACTION_TASK_DELAY_EXPIRED =
- "android.content.taskmanager.TASK_DELAY_EXPIRED";
+ private static final String TAG = "JobScheduler.Time";
+ private static final String ACTION_JOB_EXPIRED =
+ "android.content.jobscheduler.JOB_DEADLINE_EXPIRED";
+ private static final String ACTION_JOB_DELAY_EXPIRED =
+ "android.content.jobscheduler.JOB_DELAY_EXPIRED";
- /** Set an alarm for the next task expiry. */
+ /** Set an alarm for the next job expiry. */
private final PendingIntent mDeadlineExpiredAlarmIntent;
- /** Set an alarm for the next task delay expiry. This*/
+ /** Set an alarm for the next job delay expiry. This*/
private final PendingIntent mNextDelayExpiredAlarmIntent;
/** Constant time determining how near in the future we'll set an alarm for. */
private static final long MIN_WAKEUP_INTERVAL_MILLIS = 15 * 1000;
- private long mNextTaskExpiredElapsedMillis;
+ private long mNextJobExpiredElapsedMillis;
private long mNextDelayExpiredElapsedMillis;
private AlarmManager mAlarmService = null;
- /** List of tracked tasks, sorted asc. by deadline */
- private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
+ /** List of tracked jobs, sorted asc. by deadline */
+ private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
/** Singleton. */
private static TimeController mSingleton;
- public static synchronized TimeController get(TaskManagerService taskManager) {
+ public static synchronized TimeController get(JobSchedulerService jms) {
if (mSingleton == null) {
- mSingleton = new TimeController(taskManager, taskManager.getContext());
+ mSingleton = new TimeController(jms, jms.getContext());
}
return mSingleton;
}
@@ -72,66 +72,66 @@ public class TimeController extends StateController {
super(stateChangedListener, context);
mDeadlineExpiredAlarmIntent =
PendingIntent.getBroadcast(mContext, 0 /* ignored */,
- new Intent(ACTION_TASK_EXPIRED), 0);
+ new Intent(ACTION_JOB_EXPIRED), 0);
mNextDelayExpiredAlarmIntent =
PendingIntent.getBroadcast(mContext, 0 /* ignored */,
- new Intent(ACTION_TASK_DELAY_EXPIRED), 0);
- mNextTaskExpiredElapsedMillis = Long.MAX_VALUE;
+ new Intent(ACTION_JOB_DELAY_EXPIRED), 0);
+ mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
// Register BR for these intents.
- IntentFilter intentFilter = new IntentFilter(ACTION_TASK_EXPIRED);
- intentFilter.addAction(ACTION_TASK_DELAY_EXPIRED);
+ IntentFilter intentFilter = new IntentFilter(ACTION_JOB_EXPIRED);
+ intentFilter.addAction(ACTION_JOB_DELAY_EXPIRED);
mContext.registerReceiver(mAlarmExpiredReceiver, intentFilter);
}
/**
- * Check if the task has a timing constraint, and if so determine where to insert it in our
+ * Check if the job has a timing constraint, and if so determine where to insert it in our
* list.
*/
@Override
- public synchronized void maybeStartTrackingTask(TaskStatus task) {
- if (task.hasTimingDelayConstraint() || task.hasDeadlineConstraint()) {
- maybeStopTrackingTask(task);
- ListIterator<TaskStatus> it = mTrackedTasks.listIterator(mTrackedTasks.size());
+ public synchronized void maybeStartTrackingJob(JobStatus job) {
+ if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
+ maybeStopTrackingJob(job);
+ ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
while (it.hasPrevious()) {
- TaskStatus ts = it.previous();
- if (ts.getLatestRunTimeElapsed() < task.getLatestRunTimeElapsed()) {
+ JobStatus ts = it.previous();
+ if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
// Insert
break;
}
}
- it.add(task);
+ it.add(job);
maybeUpdateAlarms(
- task.hasTimingDelayConstraint() ? task.getEarliestRunTime() : Long.MAX_VALUE,
- task.hasDeadlineConstraint() ? task.getLatestRunTimeElapsed() : Long.MAX_VALUE);
+ job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
+ job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE);
}
}
/**
- * When we stop tracking a task, we only need to update our alarms if the task we're no longer
+ * When we stop tracking a job, we only need to update our alarms if the job we're no longer
* tracking was the one our alarms were based off of.
* Really an == comparison should be enough, but why play with fate? We'll do <=.
*/
@Override
- public synchronized void maybeStopTrackingTask(TaskStatus taskStatus) {
- if (mTrackedTasks.remove(taskStatus)) {
+ public synchronized void maybeStopTrackingJob(JobStatus job) {
+ if (mTrackedJobs.remove(job)) {
checkExpiredDelaysAndResetAlarm();
checkExpiredDeadlinesAndResetAlarm();
}
}
/**
- * Determines whether this controller can stop tracking the given task.
- * The controller is no longer interested in a task once its time constraint is satisfied, and
- * the task's deadline is fulfilled - unlike other controllers a time constraint can't toggle
+ * Determines whether this controller can stop tracking the given job.
+ * The controller is no longer interested in a job once its time constraint is satisfied, and
+ * the job's deadline is fulfilled - unlike other controllers a time constraint can't toggle
* back and forth.
*/
- private boolean canStopTrackingTask(TaskStatus taskStatus) {
- return (!taskStatus.hasTimingDelayConstraint() ||
- taskStatus.timeDelayConstraintSatisfied.get()) &&
- (!taskStatus.hasDeadlineConstraint() ||
- taskStatus.deadlineConstraintSatisfied.get());
+ private boolean canStopTrackingJob(JobStatus job) {
+ return (!job.hasTimingDelayConstraint() ||
+ job.timeDelayConstraintSatisfied.get()) &&
+ (!job.hasDeadlineConstraint() ||
+ job.deadlineConstraintSatisfied.get());
}
private void ensureAlarmService() {
@@ -141,27 +141,27 @@ public class TimeController extends StateController {
}
/**
- * Checks list of tasks for ones that have an expired deadline, sending them to the TaskManager
+ * Checks list of jobs for ones that have an expired deadline, sending them to the JobScheduler
* if so, removing them from this list, and updating the alarm for the next expiry time.
*/
private synchronized void checkExpiredDeadlinesAndResetAlarm() {
long nextExpiryTime = Long.MAX_VALUE;
final long nowElapsedMillis = SystemClock.elapsedRealtime();
- Iterator<TaskStatus> it = mTrackedTasks.iterator();
+ Iterator<JobStatus> it = mTrackedJobs.iterator();
while (it.hasNext()) {
- TaskStatus ts = it.next();
- if (!ts.hasDeadlineConstraint()) {
+ JobStatus job = it.next();
+ if (!job.hasDeadlineConstraint()) {
continue;
}
- final long taskDeadline = ts.getLatestRunTimeElapsed();
+ final long jobDeadline = job.getLatestRunTimeElapsed();
- if (taskDeadline <= nowElapsedMillis) {
- ts.deadlineConstraintSatisfied.set(true);
- mStateChangedListener.onRunTaskNow(ts);
+ if (jobDeadline <= nowElapsedMillis) {
+ job.deadlineConstraintSatisfied.set(true);
+ mStateChangedListener.onRunJobNow(job);
it.remove();
} else { // Sorted by expiry time, so take the next one and stop.
- nextExpiryTime = taskDeadline;
+ nextExpiryTime = jobDeadline;
break;
}
}
@@ -169,31 +169,31 @@ public class TimeController extends StateController {
}
/**
- * Handles alarm that notifies us that a task's delay has expired. Iterates through the list of
- * tracked tasks and marks them as ready as appropriate.
+ * Handles alarm that notifies us that a job's delay has expired. Iterates through the list of
+ * tracked jobs and marks them as ready as appropriate.
*/
private synchronized void checkExpiredDelaysAndResetAlarm() {
final long nowElapsedMillis = SystemClock.elapsedRealtime();
long nextDelayTime = Long.MAX_VALUE;
boolean ready = false;
- Iterator<TaskStatus> it = mTrackedTasks.iterator();
+ Iterator<JobStatus> it = mTrackedJobs.iterator();
while (it.hasNext()) {
- final TaskStatus ts = it.next();
- if (!ts.hasTimingDelayConstraint()) {
+ final JobStatus job = it.next();
+ if (!job.hasTimingDelayConstraint()) {
continue;
}
- final long taskDelayTime = ts.getEarliestRunTime();
- if (taskDelayTime <= nowElapsedMillis) {
- ts.timeDelayConstraintSatisfied.set(true);
- if (canStopTrackingTask(ts)) {
+ final long jobDelayTime = job.getEarliestRunTime();
+ if (jobDelayTime <= nowElapsedMillis) {
+ job.timeDelayConstraintSatisfied.set(true);
+ if (canStopTrackingJob(job)) {
it.remove();
}
- if (ts.isReady()) {
+ if (job.isReady()) {
ready = true;
}
} else { // Keep going through list to get next delay time.
- if (nextDelayTime > taskDelayTime) {
- nextDelayTime = taskDelayTime;
+ if (nextDelayTime > jobDelayTime) {
+ nextDelayTime = jobDelayTime;
}
}
}
@@ -207,13 +207,13 @@ public class TimeController extends StateController {
if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
setDelayExpiredAlarm(delayExpiredElapsed);
}
- if (deadlineExpiredElapsed < mNextTaskExpiredElapsedMillis) {
+ if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
setDeadlineExpiredAlarm(deadlineExpiredElapsed);
}
}
/**
- * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
+ * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
* delay will expire.
* This alarm <b>will not</b> wake up the phone.
*/
@@ -228,7 +228,7 @@ public class TimeController extends StateController {
}
/**
- * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
+ * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
* deadline will expire.
* This alarm <b>will</b> wake up the phone.
*/
@@ -238,8 +238,8 @@ public class TimeController extends StateController {
if (alarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
alarmTimeElapsedMillis = earliestWakeupTimeElapsed;
}
- mNextTaskExpiredElapsedMillis = alarmTimeElapsedMillis;
- updateAlarmWithPendingIntent(mDeadlineExpiredAlarmIntent, mNextTaskExpiredElapsedMillis);
+ mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
+ updateAlarmWithPendingIntent(mDeadlineExpiredAlarmIntent, mNextJobExpiredElapsedMillis);
}
private void updateAlarmWithPendingIntent(PendingIntent pi, long alarmTimeElapsed) {
@@ -260,11 +260,11 @@ public class TimeController extends StateController {
if (DEBUG) {
Slog.d(TAG, "Just received alarm: " + intent.getAction());
}
- // An task has just expired, so we run through the list of tasks that we have and
+ // A job has just expired, so we run through the list of jobs that we have and
// notify our StateChangedListener.
- if (ACTION_TASK_EXPIRED.equals(intent.getAction())) {
+ if (ACTION_JOB_EXPIRED.equals(intent.getAction())) {
checkExpiredDeadlinesAndResetAlarm();
- } else if (ACTION_TASK_DELAY_EXPIRED.equals(intent.getAction())) {
+ } else if (ACTION_JOB_DELAY_EXPIRED.equals(intent.getAction())) {
checkExpiredDelaysAndResetAlarm();
}
}
@@ -276,10 +276,10 @@ public class TimeController extends StateController {
pw.println("Alarms (" + SystemClock.elapsedRealtime() + ")");
pw.println(
"Next delay alarm in " + (mNextDelayExpiredElapsedMillis - nowElapsed)/1000 + "s");
- pw.println("Next deadline alarm in " + (mNextTaskExpiredElapsedMillis - nowElapsed)/1000
+ pw.println("Next deadline alarm in " + (mNextJobExpiredElapsedMillis - nowElapsed)/1000
+ "s");
pw.println("Tracking:");
- for (TaskStatus ts : mTrackedTasks) {
+ for (JobStatus ts : mTrackedJobs) {
pw.println(String.valueOf(ts.hashCode()).substring(0, 3) + ".."
+ ": (" + (ts.hasTimingDelayConstraint() ? ts.getEarliestRunTime() : "N/A")
+ ", " + (ts.hasDeadlineConstraint() ?ts.getLatestRunTimeElapsed() : "N/A")
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
deleted file mode 100644
index 0c55a1d..0000000
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.task;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import android.app.task.ITaskManager;
-import android.app.task.Task;
-import android.app.task.TaskManager;
-import android.content.BroadcastReceiver;
-import android.app.task.TaskService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ServiceInfo;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.server.task.controllers.BatteryController;
-import com.android.server.task.controllers.ConnectivityController;
-import com.android.server.task.controllers.IdleController;
-import com.android.server.task.controllers.StateController;
-import com.android.server.task.controllers.TaskStatus;
-import com.android.server.task.controllers.TimeController;
-
-import java.util.LinkedList;
-
-/**
- * Responsible for taking tasks representing work to be performed by a client app, and determining
- * based on the criteria specified when that task should be run against the client application's
- * endpoint.
- * Implements logic for scheduling, and rescheduling tasks. The TaskManagerService knows nothing
- * about constraints, or the state of active tasks. It receives callbacks from the various
- * controllers and completed tasks and operates accordingly.
- *
- * Note on locking: Any operations that manipulate {@link #mTasks} need to lock on that object.
- * Any function with the suffix 'Locked' also needs to lock on {@link #mTasks}.
- * @hide
- */
-public class TaskManagerService extends com.android.server.SystemService
- implements StateChangedListener, TaskCompletedListener, TaskMapReadFinishedListener {
- // TODO: Switch this off for final version.
- static final boolean DEBUG = true;
- /** The number of concurrent tasks we run at one time. */
- private static final int MAX_TASK_CONTEXTS_COUNT = 3;
- static final String TAG = "TaskManager";
- /** Master list of tasks. */
- private final TaskStore mTasks;
-
- static final int MSG_TASK_EXPIRED = 0;
- static final int MSG_CHECK_TASKS = 1;
-
- // Policy constants
- /**
- * Minimum # of idle tasks that must be ready in order to force the TM to schedule things
- * early.
- */
- private static final int MIN_IDLE_COUNT = 1;
- /**
- * Minimum # of connectivity tasks that must be ready in order to force the TM to schedule
- * things early.
- */
- private static final int MIN_CONNECTIVITY_COUNT = 2;
- /**
- * Minimum # of tasks (with no particular constraints) for which the TM will be happy running
- * some work early.
- */
- private static final int MIN_READY_TASKS_COUNT = 4;
-
- /**
- * Track Services that have currently active or pending tasks. The index is provided by
- * {@link TaskStatus#getServiceToken()}
- */
- private final List<TaskServiceContext> mActiveServices = new LinkedList<TaskServiceContext>();
- /** List of controllers that will notify this service of updates to tasks. */
- private List<StateController> mControllers;
- /**
- * Queue of pending tasks. The TaskServiceContext class will receive tasks from this list
- * when ready to execute them.
- */
- private final LinkedList<TaskStatus> mPendingTasks = new LinkedList<TaskStatus>();
-
- private final TaskHandler mHandler;
- private final TaskManagerStub mTaskManagerStub;
- /**
- * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
- * still clean up. On reinstall the package will have a new uid.
- */
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Slog.d(TAG, "Receieved: " + intent.getAction());
- if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
- int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
- if (DEBUG) {
- Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
- }
- cancelTasksForUid(uidRemoved);
- } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- if (DEBUG) {
- Slog.d(TAG, "Removing jobs for user: " + userId);
- }
- cancelTasksForUser(userId);
- }
- }
- };
-
- /**
- * Entry point from client to schedule the provided task.
- * This cancels the task if it's already been scheduled, and replaces it with the one provided.
- * @param task Task object containing execution parameters
- * @param uId The package identifier of the application this task is for.
- * @param canPersistTask Whether or not the client has the appropriate permissions for
- * persisting this task.
- * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
- */
- public int schedule(Task task, int uId, boolean canPersistTask) {
- TaskStatus taskStatus = new TaskStatus(task, uId, canPersistTask);
- cancelTask(uId, task.getId());
- startTrackingTask(taskStatus);
- return TaskManager.RESULT_SUCCESS;
- }
-
- public List<Task> getPendingTasks(int uid) {
- ArrayList<Task> outList = new ArrayList<Task>();
- synchronized (mTasks) {
- for (TaskStatus ts : mTasks.getTasks()) {
- if (ts.getUid() == uid) {
- outList.add(ts.getTask());
- }
- }
- }
- return outList;
- }
-
- private void cancelTasksForUser(int userHandle) {
- synchronized (mTasks) {
- List<TaskStatus> tasksForUser = mTasks.getTasksByUser(userHandle);
- for (TaskStatus toRemove : tasksForUser) {
- if (DEBUG) {
- Slog.d(TAG, "Cancelling: " + toRemove);
- }
- cancelTaskLocked(toRemove);
- }
- }
- }
-
- /**
- * Entry point from client to cancel all tasks originating from their uid.
- * This will remove the task from the master list, and cancel the task if it was staged for
- * execution or being executed.
- * @param uid To check against for removal of a task.
- */
- public void cancelTasksForUid(int uid) {
- // Remove from master list.
- synchronized (mTasks) {
- List<TaskStatus> tasksForUid = mTasks.getTasksByUid(uid);
- for (TaskStatus toRemove : tasksForUid) {
- if (DEBUG) {
- Slog.d(TAG, "Cancelling: " + toRemove);
- }
- cancelTaskLocked(toRemove);
- }
- }
- }
-
- /**
- * Entry point from client to cancel the task corresponding to the taskId provided.
- * This will remove the task from the master list, and cancel the task if it was staged for
- * execution or being executed.
- * @param uid Uid of the calling client.
- * @param taskId Id of the task, provided at schedule-time.
- */
- public void cancelTask(int uid, int taskId) {
- TaskStatus toCancel;
- synchronized (mTasks) {
- toCancel = mTasks.getTaskByUidAndTaskId(uid, taskId);
- if (toCancel != null) {
- cancelTaskLocked(toCancel);
- }
- }
- }
-
- private void cancelTaskLocked(TaskStatus cancelled) {
- // Remove from store.
- stopTrackingTask(cancelled);
- // Remove from pending queue.
- mPendingTasks.remove(cancelled);
- // Cancel if running.
- stopTaskOnServiceContextLocked(cancelled);
- }
-
- /**
- * Initializes the system service.
- * <p>
- * Subclasses must define a single argument constructor that accepts the context
- * and passes it to super.
- * </p>
- *
- * @param context The system server context.
- */
- public TaskManagerService(Context context) {
- super(context);
- // Create the controllers.
- mControllers = new LinkedList<StateController>();
- mControllers.add(ConnectivityController.get(this));
- mControllers.add(TimeController.get(this));
- mControllers.add(IdleController.get(this));
- mControllers.add(BatteryController.get(this));
-
- mHandler = new TaskHandler(context.getMainLooper());
- mTaskManagerStub = new TaskManagerStub();
- // Create the "runners".
- for (int i = 0; i < MAX_TASK_CONTEXTS_COUNT; i++) {
- mActiveServices.add(
- new TaskServiceContext(this, context.getMainLooper()));
- }
- mTasks = TaskStore.initAndGet(this);
- }
-
- @Override
- public void onStart() {
- publishBinderService(Context.TASK_SERVICE, mTaskManagerStub);
- }
-
- @Override
- public void onBootPhase(int phase) {
- if (PHASE_SYSTEM_SERVICES_READY == phase) {
- // Register br for package removals and user removals.
- final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- getContext().registerReceiverAsUser(
- mBroadcastReceiver, UserHandle.ALL, filter, null, null);
- final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
- getContext().registerReceiverAsUser(
- mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
- }
- }
-
- /**
- * Called when we have a task status object that we need to insert in our
- * {@link com.android.server.task.TaskStore}, and make sure all the relevant controllers know
- * about.
- */
- private void startTrackingTask(TaskStatus taskStatus) {
- boolean update;
- synchronized (mTasks) {
- update = mTasks.add(taskStatus);
- }
- for (StateController controller : mControllers) {
- if (update) {
- controller.maybeStopTrackingTask(taskStatus);
- }
- controller.maybeStartTrackingTask(taskStatus);
- }
- }
-
- /**
- * Called when we want to remove a TaskStatus object that we've finished executing. Returns the
- * object removed.
- */
- private boolean stopTrackingTask(TaskStatus taskStatus) {
- boolean removed;
- synchronized (mTasks) {
- // Remove from store as well as controllers.
- removed = mTasks.remove(taskStatus);
- }
- if (removed) {
- for (StateController controller : mControllers) {
- controller.maybeStopTrackingTask(taskStatus);
- }
- }
- return removed;
- }
-
- private boolean stopTaskOnServiceContextLocked(TaskStatus ts) {
- for (TaskServiceContext tsc : mActiveServices) {
- final TaskStatus executing = tsc.getRunningTask();
- if (executing != null && executing.matches(ts.getUid(), ts.getTaskId())) {
- tsc.cancelExecutingTask();
- return true;
- }
- }
- return false;
- }
-
- /**
- * @param ts TaskStatus we are querying against.
- * @return Whether or not the task represented by the status object is currently being run or
- * is pending.
- */
- private boolean isCurrentlyActiveLocked(TaskStatus ts) {
- for (TaskServiceContext serviceContext : mActiveServices) {
- final TaskStatus running = serviceContext.getRunningTask();
- if (running != null && running.matches(ts.getUid(), ts.getTaskId())) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * A task is rescheduled with exponential back-off if the client requests this from their
- * execution logic.
- * A caveat is for idle-mode tasks, for which the idle-mode constraint will usurp the
- * timeliness of the reschedule. For an idle-mode task, no deadline is given.
- * @param failureToReschedule Provided task status that we will reschedule.
- * @return A newly instantiated TaskStatus with the same constraints as the last task except
- * with adjusted timing constraints.
- */
- private TaskStatus getRescheduleTaskForFailure(TaskStatus failureToReschedule) {
- final long elapsedNowMillis = SystemClock.elapsedRealtime();
- final Task task = failureToReschedule.getTask();
-
- final long initialBackoffMillis = task.getInitialBackoffMillis();
- final int backoffAttempt = failureToReschedule.getNumFailures() + 1;
- long newEarliestRuntimeElapsed = elapsedNowMillis;
-
- switch (task.getBackoffPolicy()) {
- case Task.BackoffPolicy.LINEAR:
- newEarliestRuntimeElapsed += initialBackoffMillis * backoffAttempt;
- break;
- default:
- if (DEBUG) {
- Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
- }
- case Task.BackoffPolicy.EXPONENTIAL:
- newEarliestRuntimeElapsed +=
- Math.pow(initialBackoffMillis * 0.001, backoffAttempt) * 1000;
- break;
- }
- newEarliestRuntimeElapsed =
- Math.min(newEarliestRuntimeElapsed, Task.MAX_BACKOFF_DELAY_MILLIS);
- return new TaskStatus(failureToReschedule, newEarliestRuntimeElapsed,
- TaskStatus.NO_LATEST_RUNTIME, backoffAttempt);
- }
-
- /**
- * Called after a periodic has executed so we can to re-add it. We take the last execution time
- * of the task to be the time of completion (i.e. the time at which this function is called).
- * This could be inaccurate b/c the task can run for as long as
- * {@link com.android.server.task.TaskServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
- * to underscheduling at least, rather than if we had taken the last execution time to be the
- * start of the execution.
- * @return A new task representing the execution criteria for this instantiation of the
- * recurring task.
- */
- private TaskStatus getRescheduleTaskForPeriodic(TaskStatus periodicToReschedule) {
- final long elapsedNow = SystemClock.elapsedRealtime();
- // Compute how much of the period is remaining.
- long runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0);
- long newEarliestRunTimeElapsed = elapsedNow + runEarly;
- long period = periodicToReschedule.getTask().getIntervalMillis();
- long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
-
- if (DEBUG) {
- Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
- newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
- }
- return new TaskStatus(periodicToReschedule, newEarliestRunTimeElapsed,
- newLatestRuntimeElapsed, 0 /* backoffAttempt */);
- }
-
- // TaskCompletedListener implementations.
-
- /**
- * A task just finished executing. We fetch the
- * {@link com.android.server.task.controllers.TaskStatus} from the store and depending on
- * whether we want to reschedule we readd it to the controllers.
- * @param taskStatus Completed task.
- * @param needsReschedule Whether the implementing class should reschedule this task.
- */
- @Override
- public void onTaskCompleted(TaskStatus taskStatus, boolean needsReschedule) {
- if (DEBUG) {
- Slog.d(TAG, "Completed " + taskStatus + ", reschedule=" + needsReschedule);
- }
- if (!stopTrackingTask(taskStatus)) {
- if (DEBUG) {
- Slog.e(TAG, "Error removing task: could not find task to remove. Was task " +
- "removed while executing?");
- }
- return;
- }
- if (needsReschedule) {
- TaskStatus rescheduled = getRescheduleTaskForFailure(taskStatus);
- startTrackingTask(rescheduled);
- } else if (taskStatus.getTask().isPeriodic()) {
- TaskStatus rescheduledPeriodic = getRescheduleTaskForPeriodic(taskStatus);
- startTrackingTask(rescheduledPeriodic);
- }
- mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
- }
-
- // StateChangedListener implementations.
-
- /**
- * Off-board work to our handler thread as quickly as possible, b/c this call is probably being
- * made on the main thread.
- * For now this takes the task and if it's ready to run it will run it. In future we might not
- * provide the task, so that the StateChangedListener has to run through its list of tasks to
- * see which are ready. This will further decouple the controllers from the execution logic.
- */
- @Override
- public void onControllerStateChanged() {
- // Post a message to to run through the list of tasks and start/stop any that are eligible.
- mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
- }
-
- @Override
- public void onRunTaskNow(TaskStatus taskStatus) {
- mHandler.obtainMessage(MSG_TASK_EXPIRED, taskStatus).sendToTarget();
- }
-
- /**
- * Disk I/O is finished, take the list of tasks we read from disk and add them to our
- * {@link TaskStore}.
- * This is run on the {@link com.android.server.IoThread} instance, which is a separate thread,
- * and is called once at boot.
- */
- @Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
- synchronized (mTasks) {
- for (TaskStatus ts : tasks) {
- if (mTasks.containsTaskIdForUid(ts.getTaskId(), ts.getUid())) {
- // An app with BOOT_COMPLETED *might* have decided to reschedule their task, in
- // the same amount of time it took us to read it from disk. If this is the case
- // we leave it be.
- continue;
- }
- startTrackingTask(ts);
- }
- }
- }
-
- private class TaskHandler extends Handler {
-
- public TaskHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case MSG_TASK_EXPIRED:
- synchronized (mTasks) {
- TaskStatus runNow = (TaskStatus) message.obj;
- if (!mPendingTasks.contains(runNow)) {
- mPendingTasks.add(runNow);
- }
- }
- queueReadyTasksForExecutionH();
- break;
- case MSG_CHECK_TASKS:
- // Check the list of tasks and run some of them if we feel inclined.
- maybeQueueReadyTasksForExecutionH();
- break;
- }
- maybeRunPendingTasksH();
- // Don't remove TASK_EXPIRED in case one came along while processing the queue.
- removeMessages(MSG_CHECK_TASKS);
- }
-
- /**
- * Run through list of tasks and execute all possible - at least one is expired so we do
- * as many as we can.
- */
- private void queueReadyTasksForExecutionH() {
- synchronized (mTasks) {
- for (TaskStatus ts : mTasks.getTasks()) {
- if (isReadyToBeExecutedLocked(ts)) {
- mPendingTasks.add(ts);
- } else if (isReadyToBeCancelledLocked(ts)) {
- stopTaskOnServiceContextLocked(ts);
- }
- }
- }
- }
-
- /**
- * The state of at least one task has changed. Here is where we could enforce various
- * policies on when we want to execute tasks.
- * Right now the policy is such:
- * If >1 of the ready tasks is idle mode we send all of them off
- * if more than 2 network connectivity tasks are ready we send them all off.
- * If more than 4 tasks total are ready we send them all off.
- * TODO: It would be nice to consolidate these sort of high-level policies somewhere.
- */
- private void maybeQueueReadyTasksForExecutionH() {
- synchronized (mTasks) {
- int idleCount = 0;
- int backoffCount = 0;
- int connectivityCount = 0;
- List<TaskStatus> runnableTasks = new ArrayList<TaskStatus>();
- for (TaskStatus ts : mTasks.getTasks()) {
- if (isReadyToBeExecutedLocked(ts)) {
- if (ts.getNumFailures() > 0) {
- backoffCount++;
- }
- if (ts.hasIdleConstraint()) {
- idleCount++;
- }
- if (ts.hasConnectivityConstraint() || ts.hasUnmeteredConstraint()) {
- connectivityCount++;
- }
- runnableTasks.add(ts);
- } else if (isReadyToBeCancelledLocked(ts)) {
- stopTaskOnServiceContextLocked(ts);
- }
- }
- if (backoffCount > 0 || idleCount >= MIN_IDLE_COUNT ||
- connectivityCount >= MIN_CONNECTIVITY_COUNT ||
- runnableTasks.size() >= MIN_READY_TASKS_COUNT) {
- for (TaskStatus ts : runnableTasks) {
- mPendingTasks.add(ts);
- }
- }
- }
- }
-
- /**
- * Criteria for moving a job into the pending queue:
- * - It's ready.
- * - It's not pending.
- * - It's not already running on a TSC.
- */
- private boolean isReadyToBeExecutedLocked(TaskStatus ts) {
- return ts.isReady() && !mPendingTasks.contains(ts) && !isCurrentlyActiveLocked(ts);
- }
-
- /**
- * Criteria for cancelling an active job:
- * - It's not ready
- * - It's running on a TSC.
- */
- private boolean isReadyToBeCancelledLocked(TaskStatus ts) {
- return !ts.isReady() && isCurrentlyActiveLocked(ts);
- }
-
- /**
- * Reconcile jobs in the pending queue against available execution contexts.
- * A controller can force a task into the pending queue even if it's already running, but
- * here is where we decide whether to actually execute it.
- */
- private void maybeRunPendingTasksH() {
- synchronized (mTasks) {
- Iterator<TaskStatus> it = mPendingTasks.iterator();
- while (it.hasNext()) {
- TaskStatus nextPending = it.next();
- TaskServiceContext availableContext = null;
- for (TaskServiceContext tsc : mActiveServices) {
- final TaskStatus running = tsc.getRunningTask();
- if (running != null && running.matches(nextPending.getUid(),
- nextPending.getTaskId())) {
- // Already running this tId for this uId, skip.
- availableContext = null;
- break;
- }
- if (tsc.isAvailable()) {
- availableContext = tsc;
- }
- }
- if (availableContext != null) {
- if (!availableContext.executeRunnableTask(nextPending)) {
- if (DEBUG) {
- Slog.d(TAG, "Error executing " + nextPending);
- }
- mTasks.remove(nextPending);
- }
- it.remove();
- }
- }
- }
- }
- }
-
- /**
- * Binder stub trampoline implementation
- */
- final class TaskManagerStub extends ITaskManager.Stub {
- /** Cache determination of whether a given app can persist tasks
- * key is uid of the calling app; value is undetermined/true/false
- */
- private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
-
- // Enforce that only the app itself (or shared uid participant) can schedule a
- // task that runs one of the app's services, as well as verifying that the
- // named service properly requires the BIND_TASK_SERVICE permission
- private void enforceValidJobRequest(int uid, Task job) {
- final PackageManager pm = getContext().getPackageManager();
- final ComponentName service = job.getService();
- try {
- ServiceInfo si = pm.getServiceInfo(service, 0);
- if (si.applicationInfo.uid != uid) {
- throw new IllegalArgumentException("uid " + uid +
- " cannot schedule job in " + service.getPackageName());
- }
- if (!TaskService.PERMISSION_BIND.equals(si.permission)) {
- throw new IllegalArgumentException("Scheduled service " + service
- + " does not require android.permission.BIND_TASK_SERVICE permission");
- }
- } catch (NameNotFoundException e) {
- throw new IllegalArgumentException("No such service: " + service);
- }
- }
-
- private boolean canPersistJobs(int pid, int uid) {
- // If we get this far we're good to go; all we need to do now is check
- // whether the app is allowed to persist its scheduled work.
- final boolean canPersist;
- synchronized (mPersistCache) {
- Boolean cached = mPersistCache.get(uid);
- if (cached != null) {
- canPersist = cached.booleanValue();
- } else {
- // Persisting tasks is tantamount to running at boot, so we permit
- // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
- // permission
- int result = getContext().checkPermission(
- android.Manifest.permission.RECEIVE_BOOT_COMPLETED, pid, uid);
- canPersist = (result == PackageManager.PERMISSION_GRANTED);
- mPersistCache.put(uid, canPersist);
- }
- }
- return canPersist;
- }
-
- // ITaskManager implementation
- @Override
- public int schedule(Task task) throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "Scheduling task: " + task);
- }
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
-
- enforceValidJobRequest(uid, task);
- final boolean canPersist = canPersistJobs(pid, uid);
-
- long ident = Binder.clearCallingIdentity();
- try {
- return TaskManagerService.this.schedule(task, uid, canPersist);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public List<Task> getAllPendingTasks() throws RemoteException {
- final int uid = Binder.getCallingUid();
-
- long ident = Binder.clearCallingIdentity();
- try {
- return TaskManagerService.this.getPendingTasks(uid);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public void cancelAll() throws RemoteException {
- final int uid = Binder.getCallingUid();
-
- long ident = Binder.clearCallingIdentity();
- try {
- TaskManagerService.this.cancelTasksForUid(uid);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public void cancel(int taskId) throws RemoteException {
- final int uid = Binder.getCallingUid();
-
- long ident = Binder.clearCallingIdentity();
- try {
- TaskManagerService.this.cancelTask(uid, taskId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- /**
- * "dumpsys" infrastructure
- */
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
- long identityToken = Binder.clearCallingIdentity();
- try {
- TaskManagerService.this.dumpInternal(pw);
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
- };
-
- void dumpInternal(PrintWriter pw) {
- synchronized (mTasks) {
- pw.println("Registered tasks:");
- if (mTasks.size() > 0) {
- for (TaskStatus ts : mTasks.getTasks()) {
- ts.dump(pw, " ");
- }
- } else {
- pw.println();
- pw.println("No tasks scheduled.");
- }
- for (StateController controller : mControllers) {
- pw.println();
- controller.dumpControllerState(pw);
- }
- pw.println();
- pw.println("Pending");
- for (TaskStatus taskStatus : mPendingTasks) {
- pw.println(taskStatus.hashCode());
- }
- pw.println();
- pw.println("Active jobs:");
- for (TaskServiceContext tsc : mActiveServices) {
- if (tsc.isAvailable()) {
- continue;
- } else {
- pw.println(tsc.getRunningTask().hashCode() + " for: " +
- (SystemClock.elapsedRealtime()
- - tsc.getExecutionStartTimeElapsed())/1000 + "s " +
- "timeout: " + tsc.getTimeoutElapsed());
- }
- }
- }
- pw.println();
- }
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2aa1220..db8c7a6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -65,6 +65,7 @@ import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.input.InputManagerService;
+import com.android.server.job.JobSchedulerService;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LightsService;
import com.android.server.media.MediaRouterService;
@@ -83,7 +84,6 @@ import com.android.server.power.ShutdownThread;
import com.android.server.search.SearchManagerService;
import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.storage.DeviceStorageMonitorService;
-import com.android.server.task.TaskManagerService;
import com.android.server.trust.TrustManagerService;
import com.android.server.tv.TvInputManagerService;
import com.android.server.twilight.TwilightService;
@@ -131,8 +131,8 @@ public final class SystemServer {
"com.android.server.wifi.p2p.WifiP2pService";
private static final String ETHERNET_SERVICE_CLASS =
"com.android.server.ethernet.EthernetService";
- private static final String TASK_SERVICE_CLASS =
- "com.android.server.task.TaskManagerService";
+ private static final String JOB_SCHEDULER_SERVICE_CLASS =
+ "com.android.server.job.JobSchedulerService";
private final int mFactoryTestMode;
private Timer mProfilerSnapshotTimer;
@@ -832,7 +832,7 @@ public final class SystemServer {
mSystemServiceManager.startService(UiModeManagerService.class);
- mSystemServiceManager.startService(TaskManagerService.class);
+ mSystemServiceManager.startService(JobSchedulerService.class);
if (!disableNonCoreServices) {
try {
diff --git a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java b/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
index e7f9ca0..23ea174 100644
--- a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
@@ -3,18 +3,20 @@ package com.android.server.task;
import android.content.ComponentName;
import android.content.Context;
-import android.app.task.Task;
-import android.app.task.Task.Builder;
+import android.app.job.JobInfo;
+import android.app.job.JobInfo.Builder;
import android.os.PersistableBundle;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.util.Log;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.JobMapReadFinishedListener;
+import com.android.server.job.JobStore;
+import com.android.server.job.controllers.JobStatus;
import java.util.List;
-import static com.android.server.task.TaskStore.initAndGet;
+import static com.android.server.job.JobStore.initAndGet;
/**
* Test reading and writing correctly from file.
*/
@@ -26,12 +28,12 @@ public class TaskStoreTest extends AndroidTestCase {
private ComponentName mComponent;
private static final long IO_WAIT = 600L;
- TaskStore mTaskStoreUnderTest;
+ JobStore mTaskStoreUnderTest;
Context mTestContext;
- TaskMapReadFinishedListener mTaskMapReadFinishedListenerStub =
- new TaskMapReadFinishedListener() {
+ JobMapReadFinishedListener mTaskMapReadFinishedListenerStub =
+ new JobMapReadFinishedListener() {
@Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+ public void onJobMapReadFinished(List<JobStatus> tasks) {
// do nothing.
}
};
@@ -40,7 +42,7 @@ public class TaskStoreTest extends AndroidTestCase {
public void setUp() throws Exception {
mTestContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX);
Log.d(TAG, "Saving tasks to '" + mTestContext.getFilesDir() + "'");
- mTaskStoreUnderTest = TaskStore.initAndGetForTesting(mTestContext,
+ mTaskStoreUnderTest = JobStore.initAndGetForTesting(mTestContext,
mTestContext.getFilesDir(), mTaskMapReadFinishedListenerStub);
mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName());
}
@@ -56,23 +58,23 @@ public class TaskStoreTest extends AndroidTestCase {
long runFromMillis = 2000L; // 2s
long initialBackoff = 10000L; // 10s
- final Task task = new Builder(taskId, mComponent)
+ final JobInfo task = new Builder(taskId, mComponent)
.setRequiresCharging(true)
- .setRequiredNetworkCapabilities(Task.NetworkType.ANY)
- .setBackoffCriteria(initialBackoff, Task.BackoffPolicy.EXPONENTIAL)
+ .setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY)
+ .setBackoffCriteria(initialBackoff, JobInfo.BackoffPolicy.EXPONENTIAL)
.setOverrideDeadline(runByMillis)
.setMinimumLatency(runFromMillis)
.build();
- final TaskStatus ts = new TaskStatus(task, SOME_UID, true /* persisted */);
+ final JobStatus ts = new JobStatus(task, SOME_UID, true /* persisted */);
mTaskStoreUnderTest.add(ts);
Thread.sleep(IO_WAIT);
// Manually load tasks from xml file.
- mTaskStoreUnderTest.readTaskMapFromDisk(new TaskMapReadFinishedListener() {
+ mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
@Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+ public void onJobMapReadFinished(List<JobStatus> tasks) {
assertEquals("Didn't get expected number of persisted tasks.", 1, tasks.size());
- TaskStatus loadedTaskStatus = tasks.get(0);
- assertTasksEqual(task, loadedTaskStatus.getTask());
+ JobStatus loadedTaskStatus = tasks.get(0);
+ assertTasksEqual(task, loadedTaskStatus.getJob());
assertEquals("Different uids.", SOME_UID, tasks.get(0).getUid());
compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime());
@@ -84,30 +86,30 @@ public class TaskStoreTest extends AndroidTestCase {
}
public void testWritingTwoFilesToDisk() throws Exception {
- final Task task1 = new Builder(8, mComponent)
+ final JobInfo task1 = new Builder(8, mComponent)
.setRequiresDeviceIdle(true)
.setPeriodic(10000L)
.setRequiresCharging(true)
.build();
- final Task task2 = new Builder(12, mComponent)
+ final JobInfo task2 = new Builder(12, mComponent)
.setMinimumLatency(5000L)
- .setBackoffCriteria(15000L, Task.BackoffPolicy.LINEAR)
+ .setBackoffCriteria(15000L, JobInfo.BackoffPolicy.LINEAR)
.setOverrideDeadline(30000L)
- .setRequiredNetworkCapabilities(Task.NetworkType.UNMETERED)
+ .setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED)
.build();
- final TaskStatus taskStatus1 = new TaskStatus(task1, SOME_UID, true /* persisted */);
- final TaskStatus taskStatus2 = new TaskStatus(task2, SOME_UID, true /* persisted */);
+ final JobStatus taskStatus1 = new JobStatus(task1, SOME_UID, true /* persisted */);
+ final JobStatus taskStatus2 = new JobStatus(task2, SOME_UID, true /* persisted */);
mTaskStoreUnderTest.add(taskStatus1);
mTaskStoreUnderTest.add(taskStatus2);
Thread.sleep(IO_WAIT);
- mTaskStoreUnderTest.readTaskMapFromDisk(new TaskMapReadFinishedListener() {
+ mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
@Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+ public void onJobMapReadFinished(List<JobStatus> tasks) {
assertEquals("Incorrect # of persisted tasks.", 2, tasks.size());
- TaskStatus loaded1 = tasks.get(0);
- TaskStatus loaded2 = tasks.get(1);
- assertTasksEqual(task1, loaded1.getTask());
- assertTasksEqual(task2, loaded2.getTask());
+ JobStatus loaded1 = tasks.get(0);
+ JobStatus loaded2 = tasks.get(1);
+ assertTasksEqual(task1, loaded1.getJob());
+ assertTasksEqual(task2, loaded2.getJob());
// Check that the loaded task has the correct runtimes.
compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
@@ -124,7 +126,7 @@ public class TaskStoreTest extends AndroidTestCase {
}
public void testWritingTaskWithExtras() throws Exception {
- Task.Builder b = new Builder(8, mComponent)
+ JobInfo.Builder b = new Builder(8, mComponent)
.setRequiresDeviceIdle(true)
.setPeriodic(10000L)
.setRequiresCharging(true);
@@ -134,17 +136,17 @@ public class TaskStoreTest extends AndroidTestCase {
extras.putString("hi", "there");
extras.putInt("into", 3);
b.setExtras(extras);
- final Task task = b.build();
- TaskStatus taskStatus = new TaskStatus(task, SOME_UID, true /* persisted */);
+ final JobInfo task = b.build();
+ JobStatus taskStatus = new JobStatus(task, SOME_UID, true /* persisted */);
mTaskStoreUnderTest.add(taskStatus);
Thread.sleep(IO_WAIT);
- mTaskStoreUnderTest.readTaskMapFromDisk(new TaskMapReadFinishedListener() {
+ mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
@Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+ public void onJobMapReadFinished(List<JobStatus> tasks) {
assertEquals("Incorrect # of persisted tasks.", 1, tasks.size());
- TaskStatus loaded = tasks.get(0);
- assertTasksEqual(task, loaded.getTask());
+ JobStatus loaded = tasks.get(0);
+ assertTasksEqual(task, loaded.getJob());
}
});
@@ -153,7 +155,7 @@ public class TaskStoreTest extends AndroidTestCase {
/**
* Helper function to throw an error if the provided task and TaskStatus objects are not equal.
*/
- private void assertTasksEqual(Task first, Task second) {
+ private void assertTasksEqual(JobInfo first, JobInfo second) {
assertEquals("Different task ids.", first.getId(), second.getId());
assertEquals("Different components.", first.getService(), second.getService());
assertEquals("Different periodic status.", first.isPeriodic(), second.isPeriodic());
@@ -168,11 +170,11 @@ public class TaskStoreTest extends AndroidTestCase {
assertEquals("Invalid idle constraint.", first.isRequireDeviceIdle(),
second.isRequireDeviceIdle());
assertEquals("Invalid unmetered constraint.",
- first.getNetworkCapabilities() == Task.NetworkType.UNMETERED,
- second.getNetworkCapabilities() == Task.NetworkType.UNMETERED);
+ first.getNetworkCapabilities() == JobInfo.NetworkType.UNMETERED,
+ second.getNetworkCapabilities() == JobInfo.NetworkType.UNMETERED);
assertEquals("Invalid connectivity constraint.",
- first.getNetworkCapabilities() == Task.NetworkType.ANY,
- second.getNetworkCapabilities() == Task.NetworkType.ANY);
+ first.getNetworkCapabilities() == JobInfo.NetworkType.ANY,
+ second.getNetworkCapabilities() == JobInfo.NetworkType.ANY);
assertEquals("Invalid deadline constraint.",
first.hasLateConstraint(),
second.hasLateConstraint());
diff --git a/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java b/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java
index 6617a05..9754e8c 100644
--- a/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java
@@ -21,9 +21,11 @@ import android.content.ComponentName;
import android.content.Intent;
import android.test.AndroidTestCase;
-import com.android.server.task.StateChangedListener;
+import com.android.server.job.StateChangedListener;
+import com.android.server.job.controllers.BatteryController;
+import com.android.server.job.controllers.JobStatus;
-import static com.android.server.task.controllers.BatteryController.getForTesting;
+import static com.android.server.job.controllers.BatteryController.getForTesting;
import static org.mockito.Mockito.*;
@@ -40,7 +42,7 @@ public class BatteryControllerTest extends AndroidTestCase {
}
@Override
- public void onRunTaskNow(TaskStatus taskStatus) {
+ public void onRunJobNow(JobStatus taskStatus) {
}
};
diff --git a/tests/JobSchedulerTestApp/AndroidManifest.xml b/tests/JobSchedulerTestApp/AndroidManifest.xml
index 7431737..9654197 100644
--- a/tests/JobSchedulerTestApp/AndroidManifest.xml
+++ b/tests/JobSchedulerTestApp/AndroidManifest.xml
@@ -25,6 +25,7 @@
<service
android:name=".service.TestJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"/>
</application>
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
index 393c594..15050ef 100644
--- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
@@ -17,8 +17,8 @@
package com.android.demo.jobSchedulerApp;
import android.app.Activity;
-import android.app.task.Task;
-import android.app.task.TaskParams;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
import android.content.ComponentName;
import android.content.Intent;
import android.content.res.Resources;
@@ -80,10 +80,10 @@ public class MainActivity extends Activity {
RadioButton mWiFiConnectivityRadioButton;
RadioButton mAnyConnectivityRadioButton;
ComponentName mServiceComponent;
- /** Service object to interact scheduled tasks. */
+ /** Service object to interact scheduled jobs. */
TestJobService mTestService;
- private static int kTaskId = 0;
+ private static int kJobId = 0;
Handler mHandler = new Handler(/* default looper */) {
@Override
@@ -112,7 +112,7 @@ public class MainActivity extends Activity {
}
/**
- * UI onclick listener to schedule a task. What this task is is defined in
+ * UI onclick listener to schedule a job. What this job is is defined in
* TestJobService#scheduleJob()
*/
public void scheduleJob(View v) {
@@ -120,7 +120,7 @@ public class MainActivity extends Activity {
return;
}
- Task.Builder builder = new Task.Builder(kTaskId++, mServiceComponent);
+ JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent);
String delay = mDelayEditText.getText().toString();
if (delay != null && !TextUtils.isEmpty(delay)) {
@@ -133,9 +133,9 @@ public class MainActivity extends Activity {
boolean requiresUnmetered = mWiFiConnectivityRadioButton.isSelected();
boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isSelected();
if (requiresUnmetered) {
- builder.setRequiredNetworkCapabilities(Task.NetworkType.UNMETERED);
+ builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED);
} else if (requiresAnyConnectivity) {
- builder.setRequiredNetworkCapabilities(Task.NetworkType.ANY);
+ builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY);
}
mTestService.scheduleJob(builder.build());
@@ -143,24 +143,24 @@ public class MainActivity extends Activity {
}
/**
- * UI onclick listener to call taskFinished() in our service.
+ * UI onclick listener to call jobFinished() in our service.
*/
public void finishJob(View v) {
if (!ensureTestService()) {
return;
}
- mTestService.callTaskFinished();
+ mTestService.callJobFinished();
mParamsTextView.setText("");
}
- public void onReceivedStartTask(TaskParams params) {
+ public void onReceivedStartJob(JobParameters params) {
mShowStartView.setBackgroundColor(startJobColor);
Message m = Message.obtain(mHandler, MSG_UNCOLOUR_START);
mHandler.sendMessageDelayed(m, 1000L); // uncolour in 1 second.
- mParamsTextView.setText("Executing: " + params.getTaskId() + " " + params.getExtras());
+ mParamsTextView.setText("Executing: " + params.getJobId() + " " + params.getExtras());
}
- public void onReceivedStopTask() {
+ public void onReceivedStopJob() {
mShowStopView.setBackgroundColor(stopJobColor);
Message m = Message.obtain(mHandler, MSG_UNCOLOUR_STOP);
mHandler.sendMessageDelayed(m, 2000L); // uncolour in 1 second.
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
index 7dd3cf1..bf8e887 100644
--- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
@@ -16,28 +16,20 @@
package com.android.demo.jobSchedulerApp.service;
-import android.app.Service;
-import android.app.task.Task;
-import android.app.task.TaskManager;
-import android.app.task.TaskParams;
-import android.app.task.TaskService;
-import android.content.ComponentName;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
import android.content.Context;
import android.content.Intent;
-import android.os.Binder;
-import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
-import android.os.PersistableBundle;
import android.os.RemoteException;
import android.util.Log;
import com.android.demo.jobSchedulerApp.MainActivity;
-import java.util.ArrayList;
-import java.util.HashMap;
import java.util.LinkedList;
-import java.util.List;
/**
@@ -52,7 +44,7 @@ import java.util.List;
* lifecycle of our and provide a handle to said SyncAdapter to the OS on
* request.
*/
-public class TestJobService extends TaskService {
+public class TestJobService extends JobService {
private static final String TAG = "SyncService";
@Override
@@ -82,44 +74,44 @@ public class TestJobService extends TaskService {
}
@Override
- public boolean onStartTask(TaskParams params) {
- taskParamsMap.add(params);
+ public boolean onStartJob(JobParameters params) {
+ jobParamsMap.add(params);
if (mActivity != null) {
- mActivity.onReceivedStartTask(params);
+ mActivity.onReceivedStartJob(params);
}
- Log.i(TAG, "on start task: " + params.getTaskId());
+ Log.i(TAG, "on start job: " + params.getJobId());
return true;
}
@Override
- public boolean onStopTask(TaskParams params) {
- taskParamsMap.remove(params);
- mActivity.onReceivedStopTask();
- Log.i(TAG, "on stop task: " + params.getTaskId());
+ public boolean onStopJob(JobParameters params) {
+ jobParamsMap.remove(params);
+ mActivity.onReceivedStopJob();
+ Log.i(TAG, "on stop job: " + params.getJobId());
return true;
}
MainActivity mActivity;
- private final LinkedList<TaskParams> taskParamsMap = new LinkedList<TaskParams>();
+ private final LinkedList<JobParameters> jobParamsMap = new LinkedList<JobParameters>();
public void setUiCallback(MainActivity activity) {
mActivity = activity;
}
/** Send job to the JobScheduler. */
- public void scheduleJob(Task t) {
+ public void scheduleJob(JobInfo t) {
Log.d(TAG, "Scheduling job");
- TaskManager tm =
- (TaskManager) getSystemService(Context.TASK_SERVICE);
+ JobScheduler tm =
+ (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
tm.schedule(t);
}
- public boolean callTaskFinished() {
- TaskParams params = taskParamsMap.poll();
+ public boolean callJobFinished() {
+ JobParameters params = jobParamsMap.poll();
if (params == null) {
return false;
} else {
- taskFinished(params, false);
+ jobFinished(params, false);
return true;
}
}