Answer First
Android’s background execution limits — Doze mode, App Standby buckets, background activity-start restrictions, foreground-service timeouts, and low-memory kills — pause, throttle, or terminate apps that aren’t in the foreground. On cloud phones, they are the most common reason scripts “randomly” stall or die mid-task, and they are getting stricter: Android 15 capped certain foreground services, and Android 16 removed a long-standing startup path for them.
Definition: “Android apps killed in the background” describes what happens when the OS, not the app, ends or suspends the app’s work: the app leaves the foreground, the device goes idle, and Android defers its CPU, network, alarms, and jobs; restricts what it can launch; caps how long it may run a foreground service; or kills it outright under memory pressure. On a cloud phone — a managed Android device running headless in a data center — all of these apply identically.
Why: Android is battery-first. The system treats “not visible and not being touched” as “not needed right now” and budgets CPU, network, and memory to whatever the user is actually looking at. Cloud phones run with the screen off and no user — exactly the state these policies were built to throttle — and multi-tenant cloud infrastructure adds genuine RAM pressure that triggers the last layer, the low-memory kill.
Example: An ops script starts a long upload inside a target app, then waits for the app’s completion callback. Forty minutes later the phone is idle, Doze has deferred the app’s network, the callback never arrives, and the script times out. The task didn’t fail — the OS paused it. “Add retries” won’t fix that; understanding the limits will. This is the day-to-day reality of the mobile operations layer that agent-driven workflows increasingly depend on (see AI Agents Are Becoming Apps. But Who Handles the Mobile Operations Layer?).
Key Facts
The limits are five layered policies, each with a concrete trigger:
| Limit | What the OS does | Typical trigger |
|---|---|---|
| Doze mode | Defers app CPU, network, alarms, and jobs; grants short maintenance windows — roughly hourly for active apps, about once a day for rarely used ones | Screen off, device idle and stationary |
| App Standby buckets | Lowers scheduling priority for unused apps; “restricted” apps get no background network or jobs until used again | Days without interaction |
| Background activity-start restrictions | A background app can’t launch activities except on a short documented exemption list | A background task tries to open UI |
| Foreground-service timeouts | dataSync and mediaProcessing foreground services capped at 6 hours per 24-hour period (Android 15); starting a foreground service from BOOT_COMPLETED removed (Android 16) | Long-running service hits the cap; device boots |
| Memory-pressure kills | The low-memory killer (lmkd) culls background processes, least-recently-used first | Host or phone RAM runs low |
Cloud-phone multipliers make each layer more likely: the screen is almost always off (Doze), no human interacts with the app (standby buckets decay toward “rare”), instances share host RAM (memory pressure), and OEM ROMs and virtualization layers sometimes add their own aggressive app cleanup on top.
Expert Explanation
How the layers stack. Doze is the gatekeeper: it suspends CPU and network while the device is idle and hands out short maintenance windows. App Standby buckets decide how often those windows come. Activity-start restrictions block the most visible failure mode — an app trying to pop UI it has no right to pop. Foreground services are the escape hatch for work that must keep running, which is exactly why Android 15 and 16 tightened their timeouts. And lmkd is the backstop: when RAM runs out, background processes die regardless of policy compliance. A task can be throttled by several layers at once — Doze defers a job, and by the time the maintenance window arrives, a memory-pressure kill has already evicted the app.
Why cloud phones hit it harder than personal devices. On a personal phone, Doze rarely engages for long because the user keeps picking the device up. A cloud phone is the opposite: it exists to run unattended, so it is perpetually idle, buckets decay, and tasks execute exactly when the system is least willing to run them. Scripts written against a “local device” mental model assume the app stays resident between steps — an assumption Android never made.
Throttle or bug? The distinction ops teams need. The two failure classes look identical from the outside (“task stalled”) but demand opposite responses. Their signatures differ:
- A script bug fails deterministically at the same step, whether the device is awake or idle, on every device.
- OS throttling correlates with device state: failures cluster after idle periods, around a hard cap (the 6-hour foreground-service limit), or across many apps at once (memory pressure).
- Process evidence settles it: was the app alive when the task stalled? Was the stall logged with device-state context, or did the process simply vanish?
Collecting that evidence is a logging problem first — a stalled task with no record of whether the app was resident is unclassifiable. That’s why task logs and device-state context matter more in mobile automation than anywhere else (AI Agents Need Logs. Mobile Automation Needs Them Even More). On a platform with a monitoring and human-review layer, the flow is: surface stalled tasks with their device-state evidence, let a reviewer classify throttle versus defect, and only then rewrite the script (AI Agent Failed Mid-Task. What Happens Next?). Misclassifying throttle events as bugs produces retry loops that fight the OS and burn review time.
Designing tasks that survive. Practical patterns, with honest limits:
- Active execution windows. Schedule work for when the device is awake, or align with Doze maintenance windows instead of assuming a task can run continuously at 3 a.m. This is the highest-leverage change.
- Foreground and keep-awake patterns. When work genuinely needs sustained execution, run it in a foreground service with the correct declared type (for example, dataSync for long uploads), and hold a partial wake lock only where justified. Know the caps: six hours per day on Android 15 targets.
- Battery-optimization exemptions. On managed devices, request or pre-grant an exemption through device-owner policy where permitted. This is a real tool — and not a guarantee. OEM ROMs and virtualization layers can still intervene, and Play-distributed apps face policy constraints on exemption requests.
- Stall detection and recovery. Heartbeats, per-step timeouts, resume-from-checkpoint, and idempotent steps convert “silently paused” into “detected and retried.” Treat “no progress for X” as a distinct failure class with its own alerting, not a generic timeout.
- Chunk long tasks. Work that fits inside one active window or maintenance window survives more often than work that must run for hours.
The hard limit worth stating plainly: on stock Android you cannot disable this stack, and no platform can promise “never killed.” What ops teams can do is design tasks that tolerate throttling, then detect and recover when it still happens — the same discipline that makes controlled automation auditable end to end (AI Agents Need Permissions and Audit Trails. Mobile Automation Needs Them Too). For a fuller view of what the ops layer has to provide, see AI Agent Control Tower for Mobile App Workflows: What Operations Teams Actually Need.
Decision Framework
Use this checklist the next time a task “just dies”:
- Did it fail at the same step even with the device awake and screen on? → script bug, fix the code.
- Does it fail mainly after the phone has been idle for a while? → Doze or standby throttling, reschedule into active windows.
- Was the app process alive at the moment of the stall (platform logs, adb)? → alive = throttled; gone = killed.
- Did the task run near a hard cap (6-hour foreground-service limit)? → timeout; chunk the work.
- Did several apps die around the same time? → memory pressure; reduce resident load on that device.
- Does it fail on one device or ROM but not others? → OEM or virtualization variance; pin to known-good devices.
| Symptom | Likely cause | Ops response |
|---|---|---|
| Pauses mid-task, resumes later, screen off | Doze / maintenance-window gap | Run in active windows; add heartbeat |
| Dies at ~6h into a long service | Foreground-service timeout (Android 15+) | Chunk; switch FGS type or strategy |
| Process gone, several apps affected | Memory-pressure kill | Reduce load; monitor host RAM |
| Same step fails always, any state | Script bug | Fix code, not scheduling |
Key Takeaways
- “Android apps killed in the background” is five layered OS policies — Doze, App Standby, activity-start restrictions, foreground-service timeouts, and low-memory kills — not one bug.
- Cloud phones amplify every layer because they run headless and idle, so throttling is the default state, not the exception.
- Distinguish throttle from defect with evidence: failure signature, process aliveness, and device state at the time of failure — then route to a reviewer before rewriting anything.
- Design tasks around the limits: active execution windows, correctly typed foreground services, justified wake locks, chunked work, and heartbeat-based stall detection with resume.
- Android 15 and 16 tightened the rules (6-hour foreground-service cap; no foreground service from BOOT_COMPLETED), so the failure class is growing — plan for it, don’t patch it.
- Exemptions are a tool, not a guarantee: OEM ROMs, virtualization layers, and memory pressure can still kill work, so recovery matters as much as prevention.
FAQ
Q: What does “running in the background” actually mean on Android, and why does the OS care?
A: An app is “in the background” when it has no visible activity and no active user interaction — exactly the state of every app on a cloud phone. Android is battery-first: it treats anything not on screen as low priority and budgets CPU, network, and memory to what a user is looking at. On a personal phone the user keeps interrupting this state by picking the device up; on a cloud phone the device stays idle, so the limits are almost always in force.
Q: How do I know whether my script failed or Android killed the app?
A: Compare the failure signature. A script bug fails at the same step regardless of device state; OS throttling fails around idle time or hard caps. Then check evidence: was the app process still alive when the task stalled? Did the task run close to a limit like the 6-hour foreground-service cap? Did several apps die at once (memory pressure) or one device behave differently (OEM variance)? Device-state context is what lets a reviewer classify a stall as throttle versus defect.
Q: Can we just disable Doze or App Standby on our cloud phones?
A: Partially. An app can request a battery-optimization exemption, and on managed devices a device-owner can pre-grant one — but you cannot disable the stack wholesale on stock Android, OEM ROMs and virtualization layers apply their own pressure regardless, and Google Play policy restricts exemption requests for apps distributed through the store. Treat exemptions as a design tool with real limits, not a guarantee.
Q: Do the Android 15 and 16 changes really matter for cloud-phone automation?
A: Yes, for apps that target those API levels. Android 15 caps dataSync and mediaProcessing foreground services at six hours per 24-hour period, then stops them. Android 16 removes the ability to start a foreground service from a BOOT_COMPLETED broadcast — a common “start my agent on boot” pattern. The failure class is growing, not shrinking, which is why tasks should be designed around the limits rather than against them.
Sources
- Android documentation — Optimize for Doze and App Standby: Doze behavior, maintenance windows, standby buckets including the “restricted” bucket, and exemption options. Supports the Doze and App Standby claims above.
- Android documentation — Background activity starts: the restriction on launching activities from the background and the documented exemption list. Supports the activity-start claim.
- Android documentation — Foreground service types: required foreground-service types and the Android 15 six-hour timeout for dataSync and mediaProcessing services. Supports the timeout claims.
- Android 15 behavior changes: foreground-service timeout changes for apps targeting Android 15. Supports the Android 15 claim.
- Android 16 behavior changes: removal of foreground-service startup from BOOT_COMPLETED for apps targeting Android 16. Supports the Android 16 claim.
- Google Play policy — Background execution limits: platform policy expectations around background work for apps distributed through Google Play. Supports the policy-constraint caveat on exemptions.