JobScheduler, Job IDs, and Libraries

TL;DR: If you write an Android library, and it uses JobScheduler to schedule jobs, make sure that the job IDs that you use are configurable by the app that is using your library.

Ori Wasserman asked a damn good question this morning (my time) on Stack Overflow:

According to the documentation, jobs must have a unique Job ID per uid. If I use a 3rd party library which also schedules jobs, does this mean I can’t use the same Job ID as theirs? If so, how can I avoid these kind of collisions?

(“aw, crap” moments like this are better than caffeine for waking me up…)

When you create a JobInfo via a JobInfo.Builder, you provide an int that serves as a unique ID for that job within all apps associated with your Linux user ID. For most developers, that means that the ID is unique within your app. The “associated with your Linux user ID” part is for developers who are using android:sharedUserId, which I sincerely hope is not being used all that much outside of custom ROM developers.

However, since that ID is unique for the app, that would include being unique across both the app’s own code and the code from any library that the app uses. And that’s where the problem arises. I cannot see a good way to have everybody coordinate as to what the IDs are. And even if there is such a way, there is no requirement for all libraries to use that coordination point.

For example, you might think that we could use the id resource trick: define a custom id resource for the job ID, and that id value is guaranteed to be unique within the resource identifier space. However:

  • The docs point out that the id needs to be stable across app updates, and therefore an id resource is unsuitable

  • There is nothing forcing library authors to use an id resource, anyway

If you are writing a library, while you are welcome to default the job IDs to something (to simplify integration of your library), be sure to have some means to allow the app to change those IDs. App developers, in turn, need to look for library APIs related to job IDs and use them, if you are also using JobScheduler elsewhere (in your app code or via yet more libraries).

As problems go, this one is not unique (pun intended). We also need unique int values for Notification IDs, for example. Similarly, if your library raises a Notification, while you might default your notification ID to some value, be sure to allow app developers to change that value to something else, to avoid conflicts with other notification IDs used elsewhere in the app.

Historically, the JobScheduler job ID issue was not a big deal. Partially, that is because JobScheduler is new to Android 5.0, and only recently has Android 5.0+ gotten to over 50% market share. Partially, that is because only so many apps and libraries needed to schedule jobs.

However, with the continued War on Background Processing by way of Android O, JobScheduler becomes increasingly important:

  • You may find yourself using a job instead of an IntentService for background work that might take more than a minute, but less than ten minutes, and for which you would prefer not to use a foreground service

  • JobScheduler has been touted as an alternative to implicit broadcasts, though in truth that only works in a few cases

I half expect O Developer Preview 3 to show how JobScheduler can be used both as a floor wax and as a dessert topping.

Regardless, the number of libraries needing JobScheduler should climb steadily, and with that comes the issue of job ID conflicts.

In general, anywhere in Android that requires some sort of app-defined unique identifier, library developers should consider offering control over those identifiers to the consumers of the library.