Loading core/java/android/app/task/ITaskCallback.aidl +5 −2 Original line number Diff line number Diff line Loading @@ -34,14 +34,17 @@ interface ITaskCallback { * 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 * complete */ void acknowledgeStartMessage(int taskId); void acknowledgeStartMessage(int taskId, 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. */ void acknowledgeStopMessage(int taskId); void acknowledgeStopMessage(int taskId, boolean reschedule); /* * Tell the task 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. Loading core/java/android/app/task/TaskService.java +39 −42 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package android.app.task; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; Loading Loading @@ -124,22 +123,20 @@ public abstract class TaskService extends Service { switch (msg.what) { case MSG_EXECUTE_TASK: try { TaskService.this.onStartTask(params); boolean workOngoing = TaskService.this.onStartTask(params); ackStartMessage(params, workOngoing); } catch (Exception e) { Log.e(TAG, "Error while executing task: " + params.getTaskId()); throw new RuntimeException(e); } finally { maybeAckMessageReceived(params, MSG_EXECUTE_TASK); } break; case MSG_STOP_TASK: try { TaskService.this.onStopTask(params); boolean ret = TaskService.this.onStopTask(params); ackStopMessage(params, ret); } catch (Exception e) { Log.e(TAG, "Application unable to handle onStopTask.", e); throw new RuntimeException(e); } finally { maybeAckMessageReceived(params, MSG_STOP_TASK); } break; case MSG_TASK_FINISHED: Loading @@ -162,30 +159,34 @@ public abstract class TaskService extends Service { } } /** * Messages come in on the application's main thread, so rather than run the risk of * waiting for an app that may be doing something foolhardy, we ack to the system after * processing a message. This allows us to throw up an ANR dialogue as quickly as possible. * @param params id of the task we're acking. * @param state Information about what message we're acking. */ private void maybeAckMessageReceived(TaskParams params, int state) { private void ackStartMessage(TaskParams params, boolean workOngoing) { final ITaskCallback callback = params.getCallback(); final int taskId = params.getTaskId(); if (callback != null) { try { if (state == MSG_EXECUTE_TASK) { callback.acknowledgeStartMessage(taskId); } else if (state == MSG_STOP_TASK) { callback.acknowledgeStopMessage(taskId); } callback.acknowledgeStartMessage(taskId, workOngoing); } catch(RemoteException e) { Log.e(TAG, "System unreachable for starting task."); } } else { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, state + ": Attempting to ack a task that has already been" + "processed."); Log.d(TAG, "Attempting to ack a task that has already been processed."); } } } private void ackStopMessage(TaskParams params, boolean reschedule) { final ITaskCallback callback = params.getCallback(); final int taskId = params.getTaskId(); if (callback != null) { try { callback.acknowledgeStopMessage(taskId, reschedule); } catch(RemoteException e) { Log.e(TAG, "System unreachable for stopping task."); } } else { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Attempting to ack a task that has already been processed."); } } } Loading @@ -203,12 +204,14 @@ public abstract class TaskService extends Service { * * @param params Parameters specifying info about this task, including the extras bundle you * optionally provided at task-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. */ public abstract void onStartTask(TaskParams params); public abstract boolean onStartTask(TaskParams params); /** * This method is called if your task should be stopped even before you've called * {@link #taskFinished(TaskParams, boolean)}. * 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)}. * * <p>This will happen if the requirements specified at schedule time are no longer met. For * example you may have requested WiFi with Loading @@ -217,33 +220,27 @@ public abstract class TaskService extends Service { * {@link android.content.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 * repercussion is that the system will cease to hold a wakelock for you.</p> * * <p>After you've done your clean-up you are still expected to call * {@link #taskFinished(TaskParams, boolean)} this will inform the TaskManager that all is well, and * allow you to reschedule your task as it is probably uncompleted. Until you call * taskFinished() you will not receive any newly scheduled tasks with the given task id as the * TaskManager will consider the task to be in an error state.</p> * 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 criteria provided at task creation-time. False to drop the task. Regardless of the * value returned, your task must stop executing. * on the retry criteria provided at task creation-time. False to drop the task. Regardless of * the value returned, your task must stop executing. */ public abstract boolean onStopTask(TaskParams params); /** * Callback to inform the TaskManager you have completed execution. This can be called from any * Callback to inform the TaskManager 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 the default, or what was * set with {@link android.content.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. * 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 * 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. * </p> * * @param params Parameters specifying system-provided info about this task, this was given to Loading services/core/java/com/android/server/task/TaskCompletedListener.java 0 → 100644 +38 −0 Original line number Diff line number Diff line /* * 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; /** * Used for communication between {@link com.android.server.task.TaskServiceContext} and the * {@link com.android.server.task.TaskManagerService}. */ public interface TaskCompletedListener { /** * Callback for when a task is completed. * @param needsReschedule Whether the implementing class should reschedule this task. */ public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule); /** * Callback for when the implementing class needs to clean up the * {@link com.android.server.task.TaskServiceContext}. The scheduler can get this callback * several times if the TaskServiceContext got into a bad state (for e.g. the client crashed * and it needs to clean up). */ public void onAllTasksCompleted(int serviceToken); } services/core/java/com/android/server/task/TaskManagerService.java +105 −26 Original line number Diff line number Diff line Loading @@ -17,16 +17,15 @@ package com.android.server.task; import android.content.Context; import android.content.Task; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.util.SparseArray; import com.android.server.task.controllers.TaskStatus; import java.util.ArrayList; import java.util.List; /** * 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 Loading @@ -34,25 +33,29 @@ import java.util.List; * @hide */ public class TaskManagerService extends com.android.server.SystemService implements StateChangedListener { implements StateChangedListener, TaskCompletedListener { static final String TAG = "TaskManager"; /** Master list of tasks. */ private final TaskList mTaskList; 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()} */ private final SparseArray<TaskServiceContext> mPendingTaskServices = private final SparseArray<TaskServiceContext> mActiveServices = new SparseArray<TaskServiceContext>(); private final TaskHandler mHandler; private class TaskHandler extends Handler { /** 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; public TaskHandler(Looper looper) { super(looper); Loading @@ -66,24 +69,45 @@ public class TaskManagerService extends com.android.server.SystemService break; case MSG_STOP_TASK: break; case MSG_CHECK_TASKS: checkTasks(); break; } } /** * Helper to post a message to this handler that will run through the pending queue and * start any tasks it can. * Called when we need to run through the list of all tasks and start/stop executing one or * more of them. */ void sendRunPendingTasksMessage() { Message m = Message.obtain(this, MSG_RUN_PENDING); m.sendToTarget(); private void checkTasks() { synchronized (mTasks) { final SparseArray<TaskStatus> tasks = mTasks.getTasks(); for (int i = 0; i < tasks.size(); i++) { TaskStatus ts = tasks.valueAt(i); if (ts.isReady() && ! isCurrentlyActive(ts)) { assignTaskToServiceContext(ts); } } } void sendOnStopMessage(TaskStatus taskStatus) { } } /** * 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> Loading @@ -95,7 +119,7 @@ public class TaskManagerService extends com.android.server.SystemService */ public TaskManagerService(Context context) { super(context); mTaskList = new TaskList(); mTasks = new TaskStore(context); mHandler = new TaskHandler(context.getMainLooper()); } Loading @@ -104,25 +128,80 @@ public class TaskManagerService extends com.android.server.SystemService } // StateChangedListener implementations. /** * Offboard work to our handler thread as quickly as possible, b/c this call is probably being * 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. * @param taskStatus The state of the task which has changed. */ @Override public void onTaskStateChanged(TaskStatus taskStatus) { if (taskStatus.isReady()) { postCheckTasksMessage(); } else { if (mPendingTaskServices.get(taskStatus.getServiceToken()) != null) { // The task is either pending or being executed, which we have to cancel. } @Override public void onTaskDeadlineExpired(TaskStatus taskStatus) { } // 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 serviceToken key for the service context in {@link #mActiveServices}. * @param taskId Id of the task that is complete. * @param needsReschedule Whether the implementing class should reschedule this task. */ @Override 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); return; } } @Override public void onTaskDeadlineExpired(TaskStatus taskStatus) { public void onClientExecutionCompleted(int serviceToken) { } private void assignTaskToServiceContext(TaskStatus ts) { TaskServiceContext serviceContext = mActiveServices.get(ts.getServiceToken()); if (serviceContext == null) { serviceContext = new TaskServiceContext(this, mHandler.getLooper(), ts); mActiveServices.put(ts.getServiceToken(), serviceContext); } serviceContext.addPendingTask(ts); } /** * @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 isCurrentlyActive(TaskStatus ts) { TaskServiceContext serviceContext = mActiveServices.get(ts.getServiceToken()); if (serviceContext == null) { return false; } return serviceContext.hasTaskPending(ts); } /** * Post a message to {@link #mHandler} to run through the list of tasks and start/stop any that * are eligible. */ private void postCheckTasksMessage() { mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget(); } } services/core/java/com/android/server/task/TaskServiceContext.java +440 −19 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/app/task/ITaskCallback.aidl +5 −2 Original line number Diff line number Diff line Loading @@ -34,14 +34,17 @@ interface ITaskCallback { * 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 * complete */ void acknowledgeStartMessage(int taskId); void acknowledgeStartMessage(int taskId, 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. */ void acknowledgeStopMessage(int taskId); void acknowledgeStopMessage(int taskId, boolean reschedule); /* * Tell the task 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. Loading
core/java/android/app/task/TaskService.java +39 −42 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package android.app.task; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; Loading Loading @@ -124,22 +123,20 @@ public abstract class TaskService extends Service { switch (msg.what) { case MSG_EXECUTE_TASK: try { TaskService.this.onStartTask(params); boolean workOngoing = TaskService.this.onStartTask(params); ackStartMessage(params, workOngoing); } catch (Exception e) { Log.e(TAG, "Error while executing task: " + params.getTaskId()); throw new RuntimeException(e); } finally { maybeAckMessageReceived(params, MSG_EXECUTE_TASK); } break; case MSG_STOP_TASK: try { TaskService.this.onStopTask(params); boolean ret = TaskService.this.onStopTask(params); ackStopMessage(params, ret); } catch (Exception e) { Log.e(TAG, "Application unable to handle onStopTask.", e); throw new RuntimeException(e); } finally { maybeAckMessageReceived(params, MSG_STOP_TASK); } break; case MSG_TASK_FINISHED: Loading @@ -162,30 +159,34 @@ public abstract class TaskService extends Service { } } /** * Messages come in on the application's main thread, so rather than run the risk of * waiting for an app that may be doing something foolhardy, we ack to the system after * processing a message. This allows us to throw up an ANR dialogue as quickly as possible. * @param params id of the task we're acking. * @param state Information about what message we're acking. */ private void maybeAckMessageReceived(TaskParams params, int state) { private void ackStartMessage(TaskParams params, boolean workOngoing) { final ITaskCallback callback = params.getCallback(); final int taskId = params.getTaskId(); if (callback != null) { try { if (state == MSG_EXECUTE_TASK) { callback.acknowledgeStartMessage(taskId); } else if (state == MSG_STOP_TASK) { callback.acknowledgeStopMessage(taskId); } callback.acknowledgeStartMessage(taskId, workOngoing); } catch(RemoteException e) { Log.e(TAG, "System unreachable for starting task."); } } else { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, state + ": Attempting to ack a task that has already been" + "processed."); Log.d(TAG, "Attempting to ack a task that has already been processed."); } } } private void ackStopMessage(TaskParams params, boolean reschedule) { final ITaskCallback callback = params.getCallback(); final int taskId = params.getTaskId(); if (callback != null) { try { callback.acknowledgeStopMessage(taskId, reschedule); } catch(RemoteException e) { Log.e(TAG, "System unreachable for stopping task."); } } else { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Attempting to ack a task that has already been processed."); } } } Loading @@ -203,12 +204,14 @@ public abstract class TaskService extends Service { * * @param params Parameters specifying info about this task, including the extras bundle you * optionally provided at task-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. */ public abstract void onStartTask(TaskParams params); public abstract boolean onStartTask(TaskParams params); /** * This method is called if your task should be stopped even before you've called * {@link #taskFinished(TaskParams, boolean)}. * 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)}. * * <p>This will happen if the requirements specified at schedule time are no longer met. For * example you may have requested WiFi with Loading @@ -217,33 +220,27 @@ public abstract class TaskService extends Service { * {@link android.content.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 * repercussion is that the system will cease to hold a wakelock for you.</p> * * <p>After you've done your clean-up you are still expected to call * {@link #taskFinished(TaskParams, boolean)} this will inform the TaskManager that all is well, and * allow you to reschedule your task as it is probably uncompleted. Until you call * taskFinished() you will not receive any newly scheduled tasks with the given task id as the * TaskManager will consider the task to be in an error state.</p> * 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 criteria provided at task creation-time. False to drop the task. Regardless of the * value returned, your task must stop executing. * on the retry criteria provided at task creation-time. False to drop the task. Regardless of * the value returned, your task must stop executing. */ public abstract boolean onStopTask(TaskParams params); /** * Callback to inform the TaskManager you have completed execution. This can be called from any * Callback to inform the TaskManager 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 the default, or what was * set with {@link android.content.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. * 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 * 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. * </p> * * @param params Parameters specifying system-provided info about this task, this was given to Loading
services/core/java/com/android/server/task/TaskCompletedListener.java 0 → 100644 +38 −0 Original line number Diff line number Diff line /* * 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; /** * Used for communication between {@link com.android.server.task.TaskServiceContext} and the * {@link com.android.server.task.TaskManagerService}. */ public interface TaskCompletedListener { /** * Callback for when a task is completed. * @param needsReschedule Whether the implementing class should reschedule this task. */ public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule); /** * Callback for when the implementing class needs to clean up the * {@link com.android.server.task.TaskServiceContext}. The scheduler can get this callback * several times if the TaskServiceContext got into a bad state (for e.g. the client crashed * and it needs to clean up). */ public void onAllTasksCompleted(int serviceToken); }
services/core/java/com/android/server/task/TaskManagerService.java +105 −26 Original line number Diff line number Diff line Loading @@ -17,16 +17,15 @@ package com.android.server.task; import android.content.Context; import android.content.Task; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.util.SparseArray; import com.android.server.task.controllers.TaskStatus; import java.util.ArrayList; import java.util.List; /** * 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 Loading @@ -34,25 +33,29 @@ import java.util.List; * @hide */ public class TaskManagerService extends com.android.server.SystemService implements StateChangedListener { implements StateChangedListener, TaskCompletedListener { static final String TAG = "TaskManager"; /** Master list of tasks. */ private final TaskList mTaskList; 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()} */ private final SparseArray<TaskServiceContext> mPendingTaskServices = private final SparseArray<TaskServiceContext> mActiveServices = new SparseArray<TaskServiceContext>(); private final TaskHandler mHandler; private class TaskHandler extends Handler { /** 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; public TaskHandler(Looper looper) { super(looper); Loading @@ -66,24 +69,45 @@ public class TaskManagerService extends com.android.server.SystemService break; case MSG_STOP_TASK: break; case MSG_CHECK_TASKS: checkTasks(); break; } } /** * Helper to post a message to this handler that will run through the pending queue and * start any tasks it can. * Called when we need to run through the list of all tasks and start/stop executing one or * more of them. */ void sendRunPendingTasksMessage() { Message m = Message.obtain(this, MSG_RUN_PENDING); m.sendToTarget(); private void checkTasks() { synchronized (mTasks) { final SparseArray<TaskStatus> tasks = mTasks.getTasks(); for (int i = 0; i < tasks.size(); i++) { TaskStatus ts = tasks.valueAt(i); if (ts.isReady() && ! isCurrentlyActive(ts)) { assignTaskToServiceContext(ts); } } } void sendOnStopMessage(TaskStatus taskStatus) { } } /** * 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> Loading @@ -95,7 +119,7 @@ public class TaskManagerService extends com.android.server.SystemService */ public TaskManagerService(Context context) { super(context); mTaskList = new TaskList(); mTasks = new TaskStore(context); mHandler = new TaskHandler(context.getMainLooper()); } Loading @@ -104,25 +128,80 @@ public class TaskManagerService extends com.android.server.SystemService } // StateChangedListener implementations. /** * Offboard work to our handler thread as quickly as possible, b/c this call is probably being * 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. * @param taskStatus The state of the task which has changed. */ @Override public void onTaskStateChanged(TaskStatus taskStatus) { if (taskStatus.isReady()) { postCheckTasksMessage(); } else { if (mPendingTaskServices.get(taskStatus.getServiceToken()) != null) { // The task is either pending or being executed, which we have to cancel. } @Override public void onTaskDeadlineExpired(TaskStatus taskStatus) { } // 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 serviceToken key for the service context in {@link #mActiveServices}. * @param taskId Id of the task that is complete. * @param needsReschedule Whether the implementing class should reschedule this task. */ @Override 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); return; } } @Override public void onTaskDeadlineExpired(TaskStatus taskStatus) { public void onClientExecutionCompleted(int serviceToken) { } private void assignTaskToServiceContext(TaskStatus ts) { TaskServiceContext serviceContext = mActiveServices.get(ts.getServiceToken()); if (serviceContext == null) { serviceContext = new TaskServiceContext(this, mHandler.getLooper(), ts); mActiveServices.put(ts.getServiceToken(), serviceContext); } serviceContext.addPendingTask(ts); } /** * @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 isCurrentlyActive(TaskStatus ts) { TaskServiceContext serviceContext = mActiveServices.get(ts.getServiceToken()); if (serviceContext == null) { return false; } return serviceContext.hasTaskPending(ts); } /** * Post a message to {@link #mHandler} to run through the list of tasks and start/stop any that * are eligible. */ private void postCheckTasksMessage() { mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget(); } }
services/core/java/com/android/server/task/TaskServiceContext.java +440 −19 File changed.Preview size limit exceeded, changes collapsed. Show changes