Chromium Code Reviews| Index: components/background_task_scheduler/README.md |
| diff --git a/components/background_task_scheduler/README.md b/components/background_task_scheduler/README.md |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b3da5df8416175d421e60ebc665847ffd8325743 |
| --- /dev/null |
| +++ b/components/background_task_scheduler/README.md |
| @@ -0,0 +1,163 @@ |
| +# Quick Start Guide to using BackgroundTaskScheduler |
| + |
| +## Background |
| + |
| +In Android M+ it is encouraged to use `JobScheduler` for all background jobs, |
| +instead of using things like `IntentService` or polling using alarms. Using the |
| +system API is beneficial as it has a full view of what goes on in the system and |
| +can schedule jobs accordingly. |
| + |
| +However, this functionality was introduced in Android L, and |
| +the API has been very stable since Android M. This means that we also need a |
| +similar framework for older versions of Android, which is provided by |
| +Google Play services. We prefer system APIs, since they do not require including |
| +external libraries which bloats the APK size of Chrome and adds unnecessary |
| +complexity. The GcmNetworkManager isonly used when the system API is not |
|
David Trainor- moved to gerrit
2017/02/24 07:19:46
isonly -> is only
nyquist
2017/02/24 23:41:11
Done.
|
| +available. |
| + |
| +The `background_task_scheduler` component provides a new framework for use |
| +within chromium to schedule and execute background jobs using the frameworks |
| +available on a given version of Android. |
| +The public API of the framework is similar to that of the Android |
| +`JobScheduler`, but it is backed by either the system `JobScheduler` API or by |
| +GcmNetworkManager. What service is used to back the framework remains unknown to |
| +callers of the API. |
| + |
| +## What is a task |
| + |
| +A task is defined as a class that implements the `BackgroundTask` interface, |
| +which looks like this: |
| + |
| +```java |
| +interface BackgroundTask { |
| + interface TaskFinishedCallback { |
| + void taskFinished(boolean needsReSchedule); |
| + } |
| + |
| + boolean onStartTask(Context context, |
| + TaskParameters taskParameters, |
| + TaskFinishedCallback callback); |
| + boolean onStopTask(Context context, |
| + TaskParameters taskParameters); |
| +} |
| +``` |
| + |
| +**Any class implementing this interface must have a public constructor which takes |
|
David Trainor- moved to gerrit
2017/02/24 07:19:47
Should we assert this at register time?
nyquist
2017/02/24 23:41:11
Done.
|
| +no arguments.** |
| + |
| +A task must also have a unique ID, and it must be listed in `TaskIds` to ensure |
| +there is no overlap between different tasks. |
| + |
| +## How to schedule a task |
| + |
| +A task is scheduled by creating an object containing information about the task, |
| +such as when to run it, whether it requires battery, and other similar |
| +constraints. This object is called `TaskInfo` and has a builder you can use |
| +to set all the relevant fields. |
| + |
| +There are two main types of tasks; one-off tasks and periodic tasks. One-off |
| +tasks are only executed once, whereas periodic tasks are executed once per |
| +a defined interval. |
| + |
| +As an example for how to create a one-off task that executes in 200 minutes, |
| +you can do the following: |
| + |
| +```java |
| +TaskInfo.createOneOffTask(42, |
|
nyquist
2017/02/22 18:24:12
Self-review: Change to use TaskIds.YOUR_FEATURE
nyquist
2017/02/24 23:41:11
Done.
|
| + MyBackgroundTask.class, |
| + TimeUnit.MINUTES.toMillis(200)).build(); |
| +``` |
| + |
| +For a periodic task that executes every 200 minutes, you can call: |
| + |
| +```java |
| +TaskInfo.createPeriodicTask(42, |
| + MyBackgroundTask.class, |
| + TimeUnit.MINUTES.toMillis(200)).build(); |
| +``` |
| + |
| +Typically you will also set other required parameters such as what type of |
| +network conditions are necessary and whether the task requires the device to |
| +be charging. They can be set on the builder like this: |
| + |
| +```java |
| +TaskInfo.createOneOffTask(42, |
| + MyBackgroundTask.class, |
| + TimeUnit.MINUTES.toMillis(100) |
| + TimeUnit.MINUTES.toMillis(200)) |
| + .setRequiresCharging(true) |
| + .setRequiredNetworkType(TaskInfo.NETWORK_TYPE_UNMETERED) |
| + .build(); |
| +``` |
| + |
| +When the task is ready for scheduling, you use the |
| +`BackgroundTaskSchedulerFactory` to get the current instance of the |
| +`BackgroundTaskScheduler` and use it to schedule the job. |
| + |
| +```java |
| +BackgroundTaskScheduleFactory.getScheduler().schedule(myTaskInfo); |
| +``` |
| + |
| +If you ever need to cancel a task, you can do that by calling `cancel`, and |
| +passing in the task ID: |
| + |
| +```java |
| +BackgroundTaskScheduleFactory.getScheduler().cancel(42); |
| +``` |
| + |
| +## Passing task arguments |
| + |
| +A `TaskInfo` supports passing in arguments through a `Bundle`, but only values |
| +that can be part of an Android `BaseBundle` are allowed. You can pass them in |
| +using the `TaskInfo.Builder`: |
| + |
| +```java |
| +Bundle myBundle = new Bundle(); |
| +myBundle.putString("foo", "bar"); |
| +myBundle.putLong("number", 1337L); |
|
Peter Beverloo
2017/02/24 18:07:09
This is awesome, no more Bundle/PersistableBundle
nyquist
2017/02/24 23:41:11
Yeah, at least we only have to write that horrible
|
| + |
| +TaskInfo.createOneOffTask(42, |
| + MyBackgroundTask.class, |
| + TimeUnit.MINUTES.toMillis(100) |
| + TimeUnit.MINUTES.toMillis(200)) |
| + .setExtras(myBundle) |
| + .build(); |
| +``` |
| + |
| +These arguments will be readable for the task through the `TaskParameters` |
| +object that is passed to both `onStartTask(...)` and `onStopTask(...)`, by |
| +doing the following: |
| + |
| +```java |
| +boolean onStartTask(Context context, |
| + TaskParameters taskParameters, |
| + TaskFinishedCallback callback) { |
| + Bundle myExtras = taskParameters.getExtras(); |
| + // Use |myExtras|. |
| + ... |
| +} |
| +``` |
| + |
| +## Background processing |
| + |
| +Even though the `BackgroundTaskScheduler` provides functionality for invoking |
| +code while the application is in the background, the `BackgroundTask` instance |
| +is still invoked on the application main thread. |
| + |
| +This means that unless the operation is extremely quick, processing must happen |
| +asynchronously, and the call to `onStartJob(...)` must return before the task |
| +has finished processing. In that case, `onStartJob(...)` must return true, and |
| +instead invoke the `TaskFinishedCallback` when the processing is finished, which |
| +typically happens on a different `Thread`, `Handler` or using an `AsyncTask`. |
|
Peter Beverloo
2017/02/24 18:07:08
What if a feature cannot invoke yet TaskFinishedCa
nyquist
2017/02/24 23:41:11
That would be something we have to think about I b
|
| + |
| +If the task finishes while still being on the main thread, `onStartJob(...)` |
| +should return false, indicating that no further processsing is required. |
| + |
| +If at any time the constraints given through the `TaskInfo` object does not |
| +hold anymore, or if the system deems it necessary, `onStopTask(...)` will be |
| +invoked, requiring all activity to cease immediately. The task can return true |
| +if the task needs to be rescheduled since it was canceled, or false otherwise. |
| + |
| +**The system will hold a wakelock from the time `onStartTask(...)` is invoked |
| +until either the task itself invokes the `TaskFinishedCallback`, or |
| +`onStopTask(...)` is invoked.** |