summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/current.txt101
-rw-r--r--core/java/android/app/ContextImpl.java8
-rw-r--r--core/java/android/app/TaskManagerImpl.java62
-rw-r--r--core/java/android/app/task/ITaskManager.aidl30
-rw-r--r--core/java/android/app/task/Task.aidl20
-rw-r--r--core/java/android/app/task/Task.java (renamed from core/java/android/content/Task.java)16
-rw-r--r--core/java/android/app/task/TaskManager.java (renamed from core/java/android/content/TaskManager.java)23
-rw-r--r--core/java/android/app/task/TaskParams.java2
-rw-r--r--core/java/android/app/task/TaskService.java8
-rw-r--r--core/java/android/content/Context.java14
-rw-r--r--services/core/java/com/android/server/task/TaskManagerService.java171
-rw-r--r--services/core/java/com/android/server/task/TaskServiceContext.java2
-rw-r--r--services/core/java/com/android/server/task/TaskStore.java9
-rw-r--r--services/core/java/com/android/server/task/controllers/ConnectivityController.java10
-rw-r--r--services/core/java/com/android/server/task/controllers/TaskStatus.java39
-rw-r--r--services/java/com/android/server/SystemServer.java5
17 files changed, 403 insertions, 118 deletions
diff --git a/Android.mk b/Android.mk
index a4673f3..8603d99 100644
--- a/Android.mk
+++ b/Android.mk
@@ -78,6 +78,7 @@ LOCAL_SRC_FILES += \
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/IThumbnailRetriever.aidl \
core/java/android/app/ITransientNotification.aidl \
diff --git a/api/current.txt b/api/current.txt
index 96e83f7..5c931f9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5351,6 +5351,57 @@ package android.app.maintenance {
package android.app.task {
+ public class Task implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getBackoffPolicy();
+ method public android.os.Bundle getExtras();
+ method public long getInitialBackoffMillis();
+ method public long getIntervalMillis();
+ method public long getMaxExecutionDelayMillis();
+ method public long getMinLatencyMillis();
+ method public int getNetworkCapabilities();
+ method public android.content.ComponentName getService();
+ method public int getTaskId();
+ method public boolean isPeriodic();
+ method public boolean isRequireCharging();
+ method public boolean isRequireDeviceIdle();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public static abstract interface Task.BackoffPolicy {
+ field public static final int EXPONENTIAL = 1; // 0x1
+ field public static final int LINEAR = 0; // 0x0
+ }
+
+ public 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.Bundle);
+ 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 abstract interface Task.NetworkType {
+ field public static final int ANY = 0; // 0x0
+ field public static final int UNMETERED = 1; // 0x1
+ }
+
+ public abstract class TaskManager {
+ ctor public TaskManager();
+ 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);
+ field public static final int RESULT_INVALID_PARAMETERS = -1; // 0xffffffff
+ field public static final int RESULT_OVER_QUOTA = -2; // 0xfffffffe
+ }
+
public class TaskParams implements android.os.Parcelable {
method public int describeContents();
method public android.os.Bundle getExtras();
@@ -6974,6 +7025,7 @@ 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";
@@ -7912,55 +7964,6 @@ package android.content {
method public abstract void onStatusChanged(int);
}
- public class Task implements android.os.Parcelable {
- method public int describeContents();
- method public int getBackoffPolicy();
- method public android.os.Bundle getExtras();
- method public long getInitialBackoffMillis();
- method public long getIntervalMillis();
- method public long getMaxExecutionDelayMillis();
- method public long getMinLatencyMillis();
- method public int getNetworkCapabilities();
- method public android.content.ComponentName getService();
- method public int getTaskId();
- method public boolean isPeriodic();
- method public boolean isRequireCharging();
- method public boolean isRequireDeviceIdle();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public static abstract interface Task.BackoffPolicy {
- field public static final int EXPONENTIAL = 1; // 0x1
- field public static final int LINEAR = 0; // 0x0
- }
-
- public final class Task.Builder {
- ctor public Task.Builder(int, android.content.ComponentName);
- method public android.content.Task build();
- method public android.content.Task.Builder setBackoffCriteria(long, int);
- method public android.content.Task.Builder setExtras(android.os.Bundle);
- method public android.content.Task.Builder setMinimumLatency(long);
- method public android.content.Task.Builder setOverrideDeadline(long);
- method public android.content.Task.Builder setPeriodic(long);
- method public android.content.Task.Builder setRequiredNetworkCapabilities(int);
- method public android.content.Task.Builder setRequiresCharging(boolean);
- method public android.content.Task.Builder setRequiresDeviceIdle(boolean);
- }
-
- public static abstract interface Task.NetworkType {
- field public static final int ANY = 0; // 0x0
- field public static final int UNMETERED = 1; // 0x1
- }
-
- public abstract class TaskManager {
- ctor public TaskManager();
- method public abstract void cancel(int);
- method public abstract void cancelAll();
- method public abstract java.util.List<android.content.Task> getAllPendingTasks();
- method public abstract int schedule(android.content.Task);
- }
-
public class UriMatcher {
ctor public UriMatcher(int);
method public void addURI(java.lang.String, java.lang.String, int);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1634d11..ff8688d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -133,10 +133,12 @@ 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.trust.TrustManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.appwidget.IAppWidgetService.Stub;
import com.android.internal.os.IDropBoxManagerService;
import java.io.File;
@@ -693,6 +695,12 @@ class ContextImpl extends Context {
public Object createService(ContextImpl ctx) {
return new UsageStatsManager(ctx.getOuterContext());
}});
+
+ registerService(TASK_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(TASK_SERVICE);
+ return new TaskManagerImpl(ITaskManager.Stub.asInterface(b));
+ }});
}
static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/app/TaskManagerImpl.java b/core/java/android/app/TaskManagerImpl.java
new file mode 100644
index 0000000..f42839e
--- /dev/null
+++ b/core/java/android/app/TaskManagerImpl.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+// 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 java.util.List;
+
+
+/**
+ * Concrete implementation of the TaskManager interface
+ * @hide
+ */
+public class TaskManagerImpl extends TaskManager {
+ ITaskManager mBinder;
+
+ /* package */ TaskManagerImpl(ITaskManager binder) {
+ mBinder = binder;
+ }
+
+ @Override
+ public int schedule(Task task) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public void cancel(int taskId) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void cancelAll() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public List<Task> getAllPendingTasks() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/core/java/android/app/task/ITaskManager.aidl b/core/java/android/app/task/ITaskManager.aidl
new file mode 100644
index 0000000..b56c78a
--- /dev/null
+++ b/core/java/android/app/task/ITaskManager.aidl
@@ -0,0 +1,30 @@
+/**
+ * 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 android.app.task.Task;
+
+ /**
+ * IPC interface that supports the app-facing {@link #TaskManager} api.
+ * {@hide}
+ */
+interface ITaskManager {
+ int schedule(in Task task);
+ void cancel(int taskId);
+ void cancelAll();
+ List<Task> getAllPendingTasks();
+}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/app/task/Task.aidl
new file mode 100644
index 0000000..1f25439
--- /dev/null
+++ b/core/java/android/app/task/Task.aidl
@@ -0,0 +1,20 @@
+/**
+ * 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;
+
+parcelable Task;
+ \ No newline at end of file
diff --git a/core/java/android/content/Task.java b/core/java/android/app/task/Task.java
index 407880f..dd184a5 100644
--- a/core/java/android/content/Task.java
+++ b/core/java/android/app/task/Task.java
@@ -14,15 +14,15 @@
* limitations under the License
*/
-package android.content;
+package android.app.task;
-import android.app.task.TaskService;
+import android.content.ComponentName;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
/**
- * Container of data passed to the {@link android.content.TaskManager} fully encapsulating the
+ * Container of data passed to the {@link android.app.task.TaskManager} fully encapsulating the
* parameters required to schedule work against the calling application. These are constructed
* using the {@link Task.Builder}.
*/
@@ -92,7 +92,7 @@ public class Task implements Parcelable {
}
/**
- * See {@link android.content.Task.NetworkType} for a description of this value.
+ * See {@link android.app.task.Task.NetworkType} for a description of this value.
*/
public int getNetworkCapabilities() {
return networkCapabilities;
@@ -139,7 +139,7 @@ public class Task implements Parcelable {
}
/**
- * See {@link android.content.Task.BackoffPolicy} for an explanation of the values this field
+ * See {@link android.app.task.Task.BackoffPolicy} for an explanation of the values this field
* can take. This defaults to exponential.
*/
public int getBackoffPolicy() {
@@ -255,7 +255,7 @@ 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.content.Task.NetworkType}.
+ * will be a parameter defined in {@link android.app.task.Task.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
@@ -314,7 +314,7 @@ 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
* throw an {@link java.lang.IllegalArgumentException} when
- * {@link android.content.Task.Builder#build()} is called.
+ * {@link android.app.task.Task.Builder#build()} is called.
* @param minLatencyMillis Milliseconds before which this task will not be considered for
* execution.
*/
@@ -328,7 +328,7 @@ public class Task implements Parcelable {
* 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
* {@link java.lang.IllegalArgumentException} when
- * {@link android.content.Task.Builder#build()} is called.
+ * {@link android.app.task.Task.Builder#build()} is called.
*/
public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
mMaxExecutionDelayMillis = maxExecutionDelayMillis;
diff --git a/core/java/android/content/TaskManager.java b/core/java/android/app/task/TaskManager.java
index d28d78a..0fbe37d 100644
--- a/core/java/android/content/TaskManager.java
+++ b/core/java/android/app/task/TaskManager.java
@@ -14,14 +14,19 @@
* limitations under the License
*/
-package android.content;
+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.
*
- * Get an instance of this class through {@link Context#getSystemService(String)}.
+ * <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 {
/*
@@ -29,18 +34,20 @@ public abstract class TaskManager {
* if the run-time for your task is too short, or perhaps the system can't resolve the
* requisite {@link TaskService} in your package.
*/
- static final int RESULT_INVALID_PARAMETERS = -1;
+ public static final int RESULT_INVALID_PARAMETERS = -1;
+
/**
* 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.
- static final int RESULT_OVER_QUOTA = -2;
+ public static final int RESULT_OVER_QUOTA = -2;
- /*
- * @param task The task you wish scheduled. See {@link Task#TaskBuilder} for more detail on
- * the sorts of tasks you can schedule.
- * @return If >0, this int corresponds to the taskId of the successfully scheduled task.
+ /**
+ * @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);
diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/task/TaskParams.java
index 0351082..dacb348 100644
--- a/core/java/android/app/task/TaskParams.java
+++ b/core/java/android/app/task/TaskParams.java
@@ -47,7 +47,7 @@ public class TaskParams implements Parcelable {
/**
* @return The extras you passed in when constructing this task with
- * {@link android.content.Task.Builder#setExtras(android.os.Bundle)}. This will
+ * {@link android.app.task.Task.Builder#setExtras(android.os.Bundle)}. This will
* never be null. If you did not set any extras this will be an empty bundle.
*/
public Bundle getExtras() {
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
index ab1a565..8ce4484 100644
--- a/core/java/android/app/task/TaskService.java
+++ b/core/java/android/app/task/TaskService.java
@@ -28,7 +28,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
/**
- * <p>Entry point for the callback from the {@link android.content.TaskManager}.</p>
+ * <p>Entry point for the callback from the {@link android.app.task.TaskManager}.</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>
@@ -215,9 +215,9 @@ public abstract class TaskService extends Service {
*
* <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.content.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
+ * {@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.content.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
+ * {@link android.app.task.Task.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>
@@ -237,7 +237,7 @@ public abstract class TaskService extends Service {
* 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
* the default, or what was set with
- * {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The original
+ * {@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
* to the queue and re-executed within a future idle maintenance window.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6ae006c..b0673b5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2023,6 +2023,7 @@ public abstract class Context {
PRINT_SERVICE,
MEDIA_SESSION_SERVICE,
BATTERY_SERVICE,
+ TASK_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -2079,6 +2080,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
* </dl>
*
* <p>Note: System services obtained via this API may be closely associated with
@@ -2134,6 +2137,8 @@ public abstract class Context {
* @see android.app.DownloadManager
* @see #BATTERY_SERVICE
* @see android.os.BatteryManager
+ * @see #TASK_SERVICE
+ * @see android.app.task.TaskManager
*/
public abstract Object getSystemService(@ServiceName @NonNull String name);
@@ -2728,6 +2733,15 @@ public abstract class Context {
public static final String USAGE_STATS_SERVICE = "usagestats";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.app.task.TaskManager} instance for managing occasional
+ * background tasks.
+ * @see #getSystemService
+ * @see android.app.task.TaskManager
+ */
+ public static final String TASK_SERVICE = "task";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
index 6d208ff..80030b4 100644
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ b/services/core/java/com/android/server/task/TaskManagerService.java
@@ -16,12 +16,22 @@
package com.android.server.task;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.task.ITaskManager;
+import android.app.task.Task;
import android.content.Context;
-import android.content.Task;
+import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.util.Log;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.server.task.controllers.TaskStatus;
@@ -39,13 +49,6 @@ public class TaskManagerService extends com.android.server.SystemService
/** Master list of tasks. */
private final TaskStore mTasks;
- /** Check the pending queue and start any tasks. */
- static final int MSG_RUN_PENDING = 0;
- /** Initiate the stop task flow. */
- static final int MSG_STOP_TASK = 1;
- /** */
- static final int MSG_CHECK_TASKS = 2;
-
/**
* Track Services that have currently active or pending tasks. The index is provided by
* {@link TaskStatus#getServiceToken()}
@@ -54,6 +57,14 @@ public class TaskManagerService extends com.android.server.SystemService
new SparseArray<TaskServiceContext>();
private final TaskHandler mHandler;
+ private final TaskManagerStub mTaskManagerStub;
+
+ /** Check the pending queue and start any tasks. */
+ static final int MSG_RUN_PENDING = 0;
+ /** Initiate the stop task flow. */
+ static final int MSG_STOP_TASK = 1;
+ /** */
+ static final int MSG_CHECK_TASKS = 2;
private class TaskHandler extends Handler {
@@ -94,21 +105,6 @@ public class TaskManagerService extends com.android.server.SystemService
}
/**
- * Entry point from client to schedule the provided task.
- * This will add the task to the
- * @param task Task object containing execution parameters
- * @param userId The id of the user this task is for.
- * @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
- * of this task.
- * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
- */
- public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
- TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
- return 0;
- }
-
- /**
* Initializes the system service.
* <p>
* Subclasses must define a single argument constructor that accepts the context
@@ -121,11 +117,42 @@ public class TaskManagerService extends com.android.server.SystemService
super(context);
mTasks = new TaskStore(context);
mHandler = new TaskHandler(context.getMainLooper());
+ mTaskManagerStub = new TaskManagerStub();
}
@Override
public void onStart() {
+ publishBinderService(Context.TASK_SERVICE, mTaskManagerStub);
+ }
+
+ /**
+ * Entry point from client to schedule the provided task.
+ * This will add the task to the
+ * @param task Task object containing execution parameters
+ * @param userId The id of the user this task is for.
+ * @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 of this task.
+ * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
+ */
+ public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
+ TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
+ return 0;
+ }
+ public List<Task> getPendingTasks(int uid) {
+ ArrayList<Task> outList = new ArrayList<Task>(3);
+ synchronized (mTasks) {
+ final SparseArray<TaskStatus> tasks = mTasks.getTasks();
+ final int N = tasks.size();
+ for (int i = 0; i < N; i++) {
+ TaskStatus ts = tasks.get(i);
+ if (ts.getUid() == uid) {
+ outList.add(ts.getTask());
+ }
+ }
+ }
+ return outList;
}
// StateChangedListener implementations.
@@ -162,7 +189,7 @@ public class TaskManagerService extends com.android.server.SystemService
public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule) {
final TaskServiceContext serviceContext = mActiveServices.get(serviceToken);
if (serviceContext == null) {
- Log.e(TAG, "Task completed for invalid service context; " + serviceToken);
+ Slog.e(TAG, "Task completed for invalid service context; " + serviceToken);
return;
}
@@ -203,4 +230,98 @@ public class TaskManagerService extends com.android.server.SystemService
private void postCheckTasksMessage() {
mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
}
+
+ /**
+ * 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>();
+
+ // Determine whether the caller is allowed to persist tasks, with a small cache
+ // because the lookup is expensive enough that we'd like to avoid repeating it.
+ // This must be called from within the calling app's binder identity!
+ private boolean canCallerPersistTasks() {
+ final boolean canPersist;
+ final int callingUid = Binder.getCallingUid();
+ synchronized (mPersistCache) {
+ Boolean cached = mPersistCache.get(callingUid);
+ if (cached) {
+ 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().checkCallingPermission(
+ android.Manifest.permission.RECEIVE_BOOT_COMPLETED);
+ canPersist = (result == PackageManager.PERMISSION_GRANTED);
+ mPersistCache.put(callingUid, canPersist);
+ }
+ }
+ return canPersist;
+ }
+
+ // ITaskManager implementation
+ @Override
+ public int schedule(Task task) throws RemoteException {
+ final boolean canPersist = canCallerPersistTasks();
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getCallingUserId();
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return TaskManagerService.this.schedule(task, userId, uid, canPersist);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public List<Task> getAllPendingTasks() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public void cancelAll() throws RemoteException {
+ }
+
+ @Override
+ public void cancel(int taskId) throws RemoteException {
+ }
+
+ /**
+ * "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.print("Registered tasks:");
+ if (mTasks.size() > 0) {
+ SparseArray<TaskStatus> tasks = mTasks.getTasks();
+ for (int i = 0; i < tasks.size(); i++) {
+ TaskStatus ts = tasks.get(i);
+ pw.println();
+ ts.dump(pw, " ");
+ }
+ } else {
+ pw.println();
+ pw.println("No tasks scheduled.");
+ }
+ }
+ pw.println();
+ }
}
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java
index b51cbb3..165445a 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/task/TaskServiceContext.java
@@ -45,7 +45,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* is reused to start concurrent tasks on the TaskService. Information here is unique
* to the service.
* Functionality provided by this class:
- * - Managages wakelock for the service.
+ * - Manages wakelock for the service.
* - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks.
* -
*/
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java
index 3bfc8a5..81187c8 100644
--- a/services/core/java/com/android/server/task/TaskStore.java
+++ b/services/core/java/com/android/server/task/TaskStore.java
@@ -16,8 +16,8 @@
package com.android.server.task;
+import android.app.task.Task;
import android.content.Context;
-import android.content.Task;
import android.util.SparseArray;
import com.android.server.task.controllers.TaskStatus;
@@ -95,6 +95,13 @@ public class TaskStore {
}
/**
+ * @return the number of tasks in the store
+ */
+ public int size() {
+ return mTasks.size();
+ }
+
+ /**
* @return The live array of TaskStatus objects.
*/
public SparseArray<TaskStatus> getTasks() {
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
index 6a4e1f3..a0038c5 100644
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
@@ -70,13 +70,10 @@ public class ConnectivityController extends StateController {
}
/**
- * @param userId Id of the user for whom we are updating the connectivity state.
+ *
*/
- private void updateTrackedTasks(int userId) {
+ private void updateTrackedTasks() {
for (TaskStatus ts : mTrackedTasks) {
- if (ts.userId != userId) {
- continue;
- }
boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(mConnectivity);
boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(mMetered);
if (prevIsConnected != mConnectivity || prevIsMetered != mMetered) {
@@ -107,14 +104,13 @@ public class ConnectivityController extends StateController {
final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
// This broadcast gets sent a lot, only update if the active network has changed.
if (activeNetwork.getType() == networkType) {
- final int userid = context.getUserId();
mMetered = false;
mConnectivity =
!intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (mConnectivity) { // No point making the call if we know there's no conn.
mMetered = connManager.isActiveNetworkMetered();
}
- updateTrackedTasks(userid);
+ updateTrackedTasks();
}
} else {
Log.w(TAG, "Unrecognised action in intent: " + action);
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
index d96fedc..d270016 100644
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java
@@ -16,17 +16,19 @@
package com.android.server.task.controllers;
+import android.app.task.Task;
import android.content.ComponentName;
-import android.content.Task;
import android.content.pm.PackageParser;
import android.os.Bundle;
import android.os.SystemClock;
+import android.os.UserHandle;
+import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Uniquely identifies a task internally.
- * Created from the public {@link android.content.Task} object when it lands on the scheduler.
+ * 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
* whether it's ready to run.
* This object is shared among the various controllers - hence why the different fields are atomic.
@@ -36,10 +38,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @hide
*/
public class TaskStatus {
+ final Task task;
final int taskId;
- final int userId;
final int uId;
- final ComponentName component;
final Bundle extras;
final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
@@ -57,9 +58,9 @@ public class TaskStatus {
private long earliestRunTimeElapsedMillis;
private long latestRunTimeElapsedMillis;
- /** Provide a unique handle to the service that this task will be run on. */
+ /** Provide a handle to the service that this task will be run on. */
public int getServiceToken() {
- return component.hashCode() + userId;
+ return uId;
}
/** Generate a TaskStatus object for a given task and uid. */
@@ -70,9 +71,8 @@ public class TaskStatus {
/** Set up the state of a newly scheduled task. */
TaskStatus(Task task, int userId, int uId) {
+ this.task = task;
this.taskId = task.getTaskId();
- this.userId = userId;
- this.component = task.getService();
this.extras = task.getExtras();
this.uId = uId;
@@ -100,16 +100,20 @@ public class TaskStatus {
hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY;
}
+ public Task getTask() {
+ return task;
+ }
+
public int getTaskId() {
return taskId;
}
public ComponentName getServiceComponent() {
- return component;
+ return task.getService();
}
public int getUserId() {
- return userId;
+ return UserHandle.getUserId(uId);
}
public int getUid() {
@@ -161,9 +165,9 @@ public class TaskStatus {
@Override
public int hashCode() {
- int result = component.hashCode();
+ int result = getServiceComponent().hashCode();
result = 31 * result + taskId;
- result = 31 * result + userId;
+ result = 31 * result + uId;
return result;
}
@@ -174,7 +178,14 @@ public class TaskStatus {
TaskStatus that = (TaskStatus) o;
return ((taskId == that.taskId)
- && (userId == that.userId)
- && (component.equals(that.component)));
+ && (uId == that.uId)
+ && (getServiceComponent().equals(that.getServiceComponent())));
+ }
+
+ // Dumpsys infrastructure
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("Task "); pw.println(taskId);
+ pw.print(prefix); pw.print("uid="); pw.println(uId);
+ pw.print(prefix); pw.print("component="); pw.println(task.getService());
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index de46b16..bc34e0e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -83,6 +83,7 @@ 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;
@@ -132,6 +133,8 @@ public final class SystemServer {
"com.android.server.hdmi.HdmiCecService";
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 final int mFactoryTestMode;
private Timer mProfilerSnapshotTimer;
@@ -831,6 +834,8 @@ public final class SystemServer {
mSystemServiceManager.startService(UiModeManagerService.class);
+ mSystemServiceManager.startService(TaskManagerService.class);
+
if (!disableNonCoreServices) {
try {
if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {