What system_server is
One Java process hosts most of the framework's services, is forked from Zygote at boot, and takes the whole UI down with it when it dies. This is what lives inside it and why it is shaped that way.
Every Android app that calls getSystemService() is talking to a process it never names. That
process is system_server: a single Java/Kotlin process, started at boot, hosting the services that
decide what runs, what is visible, what is installed and who may do what.
TL;DR#
system_serveris one process that hosts roughly a hundred framework services. It is forked from at boot, not started from scratch.- Each service is a Binder object published under a name in . Apps never address the process; they address a service.
- It runs with the
systemUID and a privileged SELinux domain, which is why compromising it is equivalent to compromising the platform. - A crash is not an app crash. The framework state is gone, so the system performs a soft reboot that restarts the framework without rebooting the kernel.
- The thread kills the process when a critical service stops making progress, which is the same path taken by a deadlock.
Mental model#
Think of a city's municipal building.
Every department — planning, licensing, utilities, records — sits in one building, but citizens do not walk into "the building". They go to a counter with a name on it: permits, water, records. The building is an address; the counter is the interface.
That is system_server and its services. The process is the building. ActivityManager,
PackageManager, WindowManager are the counters. When you call
context.getSystemService(Context.ACTIVITY_SERVICE), you are not getting the building; you are
getting a phone line to one counter.
The departments share a building for a reason: they constantly need each other's records. Planning needs the licensing register; utilities needs the planning map. Putting them in one process makes those conversations cheap, because they become method calls rather than Binder transactions.
Where the analogy breaks#
A municipal building is robust: one department can close for renovation. system_server is not.
Its services share one heap and one main thread, so a deadlock in the notification service can stop
the activity manager from ever handling the next launch. The building is also not merely an address:
it holds the authoritative in-memory state of the running system. There is no database to fall
back on. That is why the recovery strategy is not "restart the department" but "restart the
municipality" — the soft reboot.
The big picture#
system_server is best understood as a neighbourhood rather than a list. The services cluster by the
question they answer.
Text description of this diagram
A treemap of system_server's services grouped into seven areas: activity and windows (ActivityTaskManager, ActivityManager, WindowManager, InputManager, DisplayManager, InputMethodManager, DreamManager, WallpaperManager, AccessibilityManager), packages and users (PackageManager, PermissionManager, UserManager, LauncherApps, ShortcutManager, AppWidgetService, DevicePolicyManager, CredentialManager, LocaleManager), power and time (PowerManager, AlarmManager, JobScheduler, BatteryStats, NetworkPolicy, DeviceStateManager, ThermalService), media and audio (AudioManager, MediaSessionService, MediaProjectionManager, CameraService, MidiService, SoundTrigger, PrintManager), connectivity (ConnectivityService, WifiService, TelephonyManager, BluetoothManager, Vpn, NetworkStats, NfcService), security and identity (KeyStoreService, BiometricService, FingerprintService, TrustManager, KeyguardServiceDelegate, AppOpsService, IncidentManager), and system and diagnostics (StorageManagerService, UsbService, ClipboardService, DropBoxManager, BugreportManager, StatsCompanion, UsageStatsService, HardwarePropertiesManager, VibratorManager). Each block is one registered Binder service; its size is its share of the catalogue, not of the process's memory.
The grouping matters more than the inventory. The services that answer "what is running" and the services that answer "what is installed" are the two poles the rest of the platform revolves around. Everything else — power, media, connectivity, security — is a specialist that both poles consult.
Where the process comes from#
system_server is not launched by init the way surfaceflinger or audioserver are. It is
forked by Zygote, which means it starts life as a copy of a process that has already loaded the
framework classes and initialised ART. The sequence is worth knowing because it explains both its
speed and its privilege.1
initstartszygotefrom an.rcfile.- Zygote preloads classes and resources, then listens on a Unix socket.
initstarts thesystem_serverservice, which connects to that socket and asks Zygote to fork.- The child runs
SystemServer'smain, which spawns the services.
The fork is why system_server does not pay seconds of class-loading at every boot, and why its
heap starts with a large shared read-only region inherited from Zygote. It is also why a bug in a
preloaded class affects every process on the device.
The boot phases#
SystemServer.java reports progress through a small set of phase constants. They are the single
best map of what has to happen before a phone is usable, and they appear in logcat and in
dumpsys timing output.
Text description of this diagram
A timeline of system_server's boot phases plotted against the numeric phase constants used in SystemServer.java. PHASE_WAIT_FOR_DEFAULT_DISPLAY is 100: the process waits for a display to exist. PHASE_WAIT_FOR_SENSOR_SERVICE is 200: it waits for the sensor service. PHASE_LOCK_SETTINGS_READY is 480: credential and keystore state can be read. PHASE_SYSTEM_SERVICES_READY is 500: the framework's own services are registered. PHASE_DEVICE_SPECIFIC_SERVICES_READY is 520: OEM and vendor services have hooked in. PHASE_ACTIVITY_MANAGER_READY is 550: activities can be launched. PHASE_THIRD_PARTY_APPS_CAN_START is 600: the lock screen is up and ordinary apps may start. PHASE_BOOT_COMPLETED is 1000: BOOT_COMPLETED broadcasts are delivered. The large gap between 200 and 480 is where the native services and HALs are brought up.
Two things are easy to miss in that list.
The first is that PHASE_DEVICE_SPECIFIC_SERVICES_READY exists at all. There is a documented seam
where an OEM can add services to the boot sequence without forking SystemServer.java. That seam is
a compromise: vendor code needs to run at boot, and the platform would rather give it a hook than a
fork.
The second is the ordering constraint at 480. Lock settings must be ready before user and keyguard services can do anything meaningful, because their state lives behind the user's credential. On a device with File-Based Encryption, that is the moment the framework can begin reasoning about credential-encrypted storage at all.
Deep dive#
One process, many services#
The class that starts everything is
SystemServer.java.1 Its run()
method is a long sequence of startService-style calls, most of which follow the same shape: build
a *Service object, register it with ServiceManager, and keep a static reference for in-process
callers.
Registration is by name, and the name is what matters. ActivityManagerService is published as
"activity". WindowManagerService is "window". PackageManagerService is "package".1 Those
strings are the keys that <G id="binder">Binder</G> clients use, and they are stable in a way the
Java class names are not — services get renamed and split, but the binder name has to keep working
or every app on the device breaks.
The mapping from a Context constant to a binder name is in
SystemServiceRegistry.java. That file is a
static block with one registerService call per service. It is the closest thing to an official
inventory, and it is where you look when you want to know what getSystemService will actually
return for a given constant.22
The privilege question#
system_server runs as the system user, not as root. That surprises people who assume the
framework is omnipotent.3 It has a great many permissions and a
privileged SELinux domain, but it still goes through the same kernel checks as anything else. When
a framework service reads an app's file, SELinux is consulted exactly as it would be for another
app.
This is deliberate. The design goal is that a compromise of the framework is bad but not unbounded: the kernel and the secure hardware are still in front of the keys. It is the same defence-in-depth argument that puts a TEE in front of Keystore, applied one layer up.
What happens when it crashes#
If system_server dies, every service it hosted dies with it. Binder proxies held by apps become
dead objects. Windows lose their owner. The activity stack, the package state and the notification
state are gone.
The recovery path is the soft reboot: the framework restarts while the kernel and the native services keep running. On modern Android this is implemented as a controlled restart of the framework rather than a full device reboot, which is why you sometimes see a phone return to the lock screen in a few seconds without the boot logo.4
It is worth being precise about what survives. The kernel survives. surfaceflinger, audioserver
and the HALs survive. What does not survive is every process that held a Binder reference to a
framework service: in practice, that means every app. That is why a soft reboot feels like a
reboot even though the uptime counter keeps climbing.
The Watchdog#
The is a thread inside system_server that periodically checks
whether the main thread and a set of critical services are making progress. It uses a
HandlerChecker per monitored thread and a monotonic clock, and it is deliberately dumb: it does
not try to diagnose, it tries to notice.
If a monitored thread fails to respond within its timeout, the Watchdog logs a trace and kills the
process. The kill is the point: a hung system_server is worse than a restarting one, because a
hung one holds the locks that every other service needs.
What is not in the process#
A useful sanity check on the mental model: several things that feel like framework services are not in this process.
- SurfaceFlinger is a native process.
WindowManagerServicedecides where windows go; SurfaceFlinger does the composition. - audioserver does the mixing.
AudioManagerinsystem_serveris policy and routing. - The camera provider is a vendor HAL process.
CameraServicearbitrates between clients. - vold is a native daemon that mounts storage.
StorageManagerServiceis the policy layer. - MediaCodec runs in app processes via
mediaserverand vendor codecs.
The pattern is consistent: system_server holds policy and bookkeeping, and the heavy or
device-specific work happens elsewhere. That division is why a framework restart can leave audio
playing for a moment, and why a camera HAL crash does not take the launcher with it.
How it evolved#
The process has been continuously debloated. Services are split out when they get too large, moved into Mainline modules when they need to update independently, and occasionally moved out of the process entirely.
| API | Version | What changed |
|---|---|---|
| 1 | 1.0 |
|
| 4 | 1.6 Donut |
|
| 5 | 2.0 Eclair |
|
| 8 | 2.2 Froyo |
|
| 9 | 2.3 Gingerbread |
|
| 11 | 3.0 Honeycomb |
|
| 13 | 3.2 Honeycomb |
|
| 14 | 4.0 Ice Cream Sandwich |
|
| 16 | 4.1 Jelly Bean |
|
| 17 | 4.2 Jelly Bean |
|
| 18 | 4.3 Jelly Bean |
|
| 19 | 4.4 KitKat |
|
| 20 | 4.4W KitKat (Wear) |
|
| 21 | 5.0 Lollipop |
|
| 22 | 5.1 Lollipop |
|
| 23 | 6.0 Marshmallow |
|
| 24 | 7.0 Nougat |
|
| 26 | 8.0 Oreo |
|
| 27 | 8.1 Oreo |
|
| 28 | 9 Pie |
|
| 29 | 10 |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 32 | 12L |
|
| 33 | 13 Tiramisu |
|
| 34 | 14 Upside Down Cake |
|
| 35 | 15 Vanilla Ice Cream |
|
| 36 | 16 Baklava |
|
| 37 | 17 Cinnamon Bun |
|
Two splits are worth knowing by name. ActivityTaskManagerService was carved out of
ActivityManagerService in Android 10 to separate activity/task management from process
management. PermissionManagerService was carved out of PackageManagerService in Android 11 to
separate permission policy from package state. Both are the same story: a class that had grown to
do two jobs was cut along the seam between them.
Under the hood#
- SystemServer.javathe boot sequence, the phase constants, and the order services are started in
- SystemServiceManager.javathe lifecycle every system service implements: start, phase callbacks, boot phase
- SystemServiceRegistry.javathe Context constant → manager object map, which is the client side of every service
- Watchdog.javathe liveness monitor that reboots the framework when a critical thread stalls
Curiosity corner#
system_serveris the largest Java heap on an idle phone. Its heap is dominated by the activity stack, the package database and the resource caches, not by your apps. That is whydumpsys meminfoshows it near the top even when nothing is happening.- The process has a fixed name, but not a fixed contents list. Services have been added, split
and moved out for seventeen API levels; the name
system_serverhas not changed since Android 1.0. - The soft reboot has a user-visible tell. If your phone returns to the lock screen without the boot animation, you probably just watched the framework restart after a Watchdog kill.
Try it#
adb shell ps -A -o USER,PID,PPID,NAME | grep -E "system_server|zygote"
adb shell service list | head -20
Example output
system 863 610 system_server
root 610 1 zygote64The second command prints every registered Binder service with its interface descriptor. It is the
closest thing to system_server's table of contents, and it is the list getSystemService is
ultimately indexing.
Check yourself#
Check yourself
How does system_server's process come into existence at boot?
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.
- docsAndroid platform architecture (AOSP)source.android.comaccessed 2026-10-27↩
- docsContext | API referencedeveloper.android.comaccessed 2026-10-27↩
- docsApplication sandboxsource.android.comaccessed 2026-10-27↩
- docsSoft restartsource.android.comaccessed 2026-10-27↩
- docsProcesses and threads overview | App qualitydeveloper.android.comaccessed 2026-10-27↩
- docsZygotesource.android.comaccessed 2026-10-27↩