Zygote
Background workintermediate

The history of background work

For ten years Android let apps run background services forever. Then the battery data came in, and the platform spent a decade adding restriction after restriction — each one closing a door the previous one opened.

12 minAPI 1–37 · 17interactivequizverified 2026-10-27

Every restriction in this module is a fix for a specific abuse. Understanding which abuse explains why the API you have is shaped the way it is — and why the obvious workaround is usually the next thing that got restricted.

TL;DR#

  • 2008–2015: a started service runs until stopped. Apps keep one alive forever, hold wake locks, and poll on a repeating alarm.
  • 2013–2014: alarms become inexact by default; JobScheduler arrives as the system's answer to "let me defer this".
  • 2015: Doze and App Standby defer network, jobs and alarms when the device is idle.
  • 2017–2018: the big wave. Background services are stopped after the app leaves the foreground, most implicit broadcasts are banned from the manifest, and WorkManager appears as the supported replacement.
  • 2018–2021: standby buckets, background activity start restrictions, background location as a separate grant, and foreground service launch restrictions.
  • 2023–2024: foreground service types are mandatory, and some types have time limits.

Mental model#

Picture a hotel that slowly discovers its guests are running industrial machinery in their rooms.

The first decade has no rules. Guests plug in whatever they like, and the hotel's electricity bill is everyone's problem. Some guests run a factory overnight, because nothing stops them.

The first rules are about the building's own systems: the lifts slow down at night (Doze), and guests who have not left their room in days get a smaller power allowance (App Standby).

The second wave is about the rooms themselves: you may not run a factory unless you put a sign on the door saying so (a foreground service notification). The sign is the deal — you get power, the hotel gets the right to tell the guest what is happening.

The third wave is about the sign: it must say what kind of factory it is (a foreground service type), and some kinds have a closing time.

The fourth wave is about the front desk: you cannot check in a factory from the lobby any more. You must ask in advance, from inside your room (background activity starts, FGS launch restrictions).

Where the analogy breaks#

A hotel can renegotiate with a guest. Android cannot: the app was installed by the user, and the platform's only tools are restriction and revocation. That asymmetry is why the rules accumulated rather than being redesigned — each release could take away a capability, but none could take back a promise an app had already relied on.

The big picture#

Loading diagram…
Text description of this diagram

A restriction timeline from Android 4.4 (API 19, 2013) to Android 15 (API 35, 2024), with eight restriction layers: background services, network and sync, alarms, implicit broadcasts, background activity starts, background location, foreground services, and job and work quotas. Each wave adds restrictions on top of earlier ones. API 19 makes alarms inexact. API 21 introduces JobScheduler. API 23 adds Doze, deferring network, alarms and jobs. API 26 adds background execution limits, banning manifest implicit broadcasts and stopping background services. API 28 adds standby buckets and the foreground service permission. API 29 blocks background activity starts. API 30 separates background location into its own grant. API 31 restricts starting foreground services from the background and requires a permission for exact alarms. API 34 requires foreground service types and their permissions. API 35 adds a dataSync timeout. A replay panel shows a hypothetical 2012 polling app, with seven behaviours — a started service, a sixty-second poll, a repeating alarm, a manifest connectivity receiver, a background activity start, continuous background location, and a foreground service escape hatch — each marked as working, degraded or blocked at the selected API level.

Scrub the slider. The replay panel is the point: the same code is not fighting one rule at API 35, it is fighting a stack of them, and each layer was added by a different release for a different reason.

Deep dive#

The wild west, 2008–2014#

The original model was simple and honest. startService() starts a service; the service runs until stopService() or until the system kills the process for memory. A wakelock keeps the CPU awake. An AlarmManager repeating alarm wakes the device on a schedule.

Nothing in that model knows what the app is for. A music player and a flashlight app that pings an analytics endpoint every 40 seconds get identical treatment. The Android 4.4 release notes describe the first correction: set() and setRepeating() become inexact for apps targeting KitKat, so the system can batch alarms from many apps into one wakeup.1

JobScheduler, added in Android 5.0, was the first API designed for the system rather than the app. Instead of "wake me in 60 seconds", an app says "run this when there is network and the device is charging". The system can then run every app's job in a single window, when it is already awake for other reasons.2

2015: Doze#

Doze is what happens when the phone is stationary, unplugged and the screen has been off for a while. The device enters a deep idle state and defers network access, jobs and alarms until a maintenance window. Windows are spaced further apart the longer the device stays idle.3

Two escapes were deliberately left:

  • High-priority FCM messages can wake the device briefly.
  • setExactAndAllowWhileIdle fires an alarm even in Doze, but sparingly.

The design intent is visible in the escapes: Doze is not trying to stop urgent work, it is stopping periodic work that could have waited.

2017–2018: background execution limits#

Android 8.0 is the release that broke the most apps, and the mechanism is worth stating precisely.

  • A started background service is stopped a few minutes after the app leaves the foreground. It is not paused; it is stopped, and the process may be killed.
  • Most implicit broadcasts cannot be declared in the manifest. A CONNECTIVITY_CHANGE receiver in the manifest simply is not delivered. It must be registered at runtime, which means the app must already be running.
  • Background location updates are throttled.4

The replacement offered was JobScheduler, and for apps that needed to be compatible with older devices, Firebase JobDispatcher — which was itself replaced by WorkManager.

2018–2019: buckets and background activity starts#

App Standby Buckets (Android 9) sorts apps into tiers based on how the user actually uses them. An app in the "rare" bucket gets far fewer jobs and alarms per day than one in "active". Unlike Doze, this is not about the device state; it is about the app's standing.5

Background activity starts (Android 10) closed the "wake the user up with a screen" loophole. An app in the background cannot launch an activity without an exemption. The exemption that remained — a full-screen intent notification — was itself restricted later.6

2020–2021: location and foreground services#

Android 11 split background location into its own grant, requested separately and separately refusable. It also added one-time permissions and permission auto-reset. For background work, the important consequence is that a location-tracking background service can no longer assume it has location: the grant may be foreground-only or absent.7

Android 12 went after the escape hatch itself: an app cannot start a foreground service from the background without an exemption, and exact alarms require a permission.8

That is the moment the previous decade's workaround stopped working. From 2017 onward, "use a foreground service" was the answer to background limits. From 2021, you cannot always start one.

2023–2024: types and timeouts#

Android 14 made foreground service types mandatory: every foreground service declares what it is for (dataSync, location, mediaPlayback, camera, and others), and each type has a matching permission. Some types cannot be started from the background at all.9

Android 15 added a time limit for the dataSync type, pushing long syncs towards WorkManager or user-initiated transfer jobs.10

Android 16 changed JobScheduler quota accounting, and Android 13 added battery resource utilisation restrictions for apps that burn CPU or hold wake locks.11

The pattern behind the restrictions#

Read the releases in order and a design philosophy emerges, stated more clearly each time.

Batch what can be batched. Inexact alarms and JobScheduler both let the system align one app's work with another's, so the radio and the CPU wake once instead of fifty times.

Defer what can be deferred. Doze and standby buckets distinguish between work that must happen now and work that merely wants to. Both are enforced with a state machine, not a permission.

Make the visible exception explicit. The foreground service is the escape hatch, and the notification is the price of using it. The system does not forbid long-running work; it requires the user to be told.

Close the escape hatch when it becomes the norm. FGS launch restrictions and mandatory types are the platform noticing that "use a foreground service" had become the universal workaround, and narrowing it to the cases it was designed for.

That sequence is a reasonable template for how any mobile platform rations a shared resource.

How it evolved#

2008–2013Wild westservices forever, wake locks, polling alarms
2013–2017Scheduling APIsinexact alarms, JobScheduler, Doze, standby
2017–2021Execution limitsbackground service stop, broadcast bans, buckets
2021–nowTyped foregroundFGS launch rules, types, permissions, timeouts
Background and power changes12 releases
APIVersionWhat changed
11.0
  • The original android.* SDK: Activity, Service, BroadcastReceiver, ContentProvider
174.2 Jelly Bean
  • Daydream service
194.4 KitKat
  • AlarmManager becomes inexact by default for targeting apps
215.0 Lollipop
  • JobScheduler
  • Implicit service intents restricted for targeting apps
268.0 Oreo
  • Background service limits
289 Pie
  • Foreground service permission
2910
  • Background activity starts restricted
3011
  • Background location requires a second request
3112
  • Exact alarms need SCHEDULE_EXACT_ALARM
  • Foreground service launch restrictions from the background
3414 Upside Down Cake
  • Foreground service types required when targeting 34
  • User-initiated data transfer jobs
3515 Vanilla Ice Cream
  • Deprecated APIs: WindowInsetsController hiding, elevate the importance of foreground services
3616 Baklava
  • JobScheduler quota changes

Under the hood#

The enforcement lives in a small number of system_server components:

Curiosity corner#

  • Doze was not in the original Android 6.0 plan. It shipped as a late addition and became the template for every later restriction: define a state, defer work in it, and leave a narrow escape hatch.
  • The "rare" standby bucket is the single biggest determinant of background reliability for an app the user opens once a month, and no API can opt out of it.
  • A foreground service notification is not a trick to avoid the rules. It is the contract: the user is told what is running, and the system holds you to what you declared.

Try it#

See the current Doze state

adb shell dumpsys deviceidle

Example output
mDeviceIdleMode=false
mLightIdleMode=false
mState=ACTIVE
Put the device into Doze

adb shell dumpsys deviceidle force-idle adb shell dumpsys deviceidle unforce

Example output
Now forced into idle mode
Check an app's standby bucket

adb shell am get-standby-bucket com.example.app

Example output
Uid: 10123  Bucket: 10 (rare)
Inspect scheduled jobs

adb shell dumpsys jobscheduler | head -40

Example output
Registered 3 jobs.  Job #1001: com.example.app/.SyncJob

Build it#

Install an app with a background service, use it, then press Home and watch adb shell dumpsys activity services — on a device targeting API 26 or higher, the service stops within a few minutes. That observation, more than any documentation, explains why WorkManager exists.

Check yourself#

Check yourself

1 / 12

Put these background restrictions in the order they were introduced.

Drag, or use the arrows to reorder.

  1. 1Background activity starts are blocked (API 29)
  2. 2Background services are stopped after the app leaves the foreground (API 26)
  3. 3Alarms become inexact by default (API 19)
  4. 4Foreground service types become mandatory (API 34)
  5. 5Doze defers network, jobs and alarms (API 23)
0 answered · 0 correct

Sources#

Sources

Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.

  1. docsAndroid 4.4 APIsdeveloper.android.comaccessed 2026-10-27↩
  2. docsSchedule alarmsdeveloper.android.comaccessed 2026-10-27↩
  3. docsOptimize for Doze and App Standbydeveloper.android.comaccessed 2026-10-27↩
  4. docsPerubahan Perilaku Android 8.0developer.android.comaccessed 2026-10-27↩
  5. docsStandby bucketsdeveloper.android.comaccessed 2026-10-27↩
  6. docsBehavior changes: Apps targeting Android 10developer.android.comaccessed 2026-10-27↩
  7. docsBehavior changes: Apps targeting Android 11developer.android.comaccessed 2026-10-27↩
  8. docsBehavior changes: Apps targeting Android 12developer.android.comaccessed 2026-10-27↩
  9. docsBehavior changes: Apps targeting Android 14developer.android.comaccessed 2026-10-27↩
  10. docsBehavior changes: Apps targeting Android 15 or higherdeveloper.android.comaccessed 2026-10-27↩
  11. docsBehavior changes: Apps targeting Android 13 or higherdeveloper.android.comaccessed 2026-10-27↩
  12. docsBackground tasks overview | Background workdeveloper.android.comaccessed 2026-10-27↩
  13. docsServices overview | Background workdeveloper.android.comaccessed 2026-10-27↩
  14. docsBroadcasts overview | Background workdeveloper.android.comaccessed 2026-10-27↩
  15. docsWorkmanagerdeveloper.android.comaccessed 2026-10-27↩
  16. docsPerubahan perilaku: aplikasi yang menargetkan API level 28+developer.android.comaccessed 2026-10-27↩
  17. docsFirebase Cloud Messagingfirebase.google.comaccessed 2026-10-27↩