AOSP Framework & Internals
2 min read

Zygote Forks System Server

Learn about Zygote Forks System Server.

The system_server process is the beating heart of Android. It hosts almost all core system services (ActivityManager, PackageManager, WindowManager, etc.). However, it does not start from a standard init script like native daemons. Instead, it is the very first process forked by Zygote.

ZygoteInit.forkSystemServer()

When Android boots, the init process starts the Zygote daemon (app_process). Zygote initializes the Dalvik/ART virtual machine, preloads common Java classes and resources into memory, and then calls ZygoteInit.main().

The first meaningful action ZygoteInit.main() takes is calling forkSystemServer().

// Simplified snippet from ZygoteInit.java
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
    r.run(); // Runs in the newly forked system_server process
    return;
}

This fork is identical to how user applications are launched later, but with special privileges. Because it is forked, system_server inherits the preloaded ART VM and classes, ensuring a rapid startup.

UID and GID Assignment to system_server

A crucial part of forkSystemServer() is assigning the correct Linux identity. It parses arguments specifying the UID, GID, and supplementary groups.

The system_server is assigned a fixed UID of 1000 (defined as AID_SYSTEM). It is also granted numerous supplementary GIDs (like AID_AUDIO, AID_CAMERA, AID_NET_ADMIN) allowing it to bypass standard file and device node permissions to interact directly with hardware drivers and network interfaces.

Capabilities Assigned to system_server

In addition to standard Linux UIDs/GIDs, Android utilizes Linux Capabilities to grant fine-grained root-like privileges without running the process as full root (UID 0).

During the fork, Zygote grants system_server specific capabilities such as CAP_SYS_NICE (to change thread priorities for other processes), CAP_NET_ADMIN (to configure network interfaces), and CAP_BLOCK_SUSPEND (to acquire wake locks and prevent the CPU from sleeping).

system_server Process Initialization

Once the native fork() completes:

  1. Zygote State Cleanup: The child process (now system_server) closes the Zygote listening socket, as it should not accept app launch requests.
  2. Native Setup: It calls nativeZygoteInit() to establish the Binder thread pool. This is critical; without it, system_server cannot receive IPC calls from native daemons or future apps.
  3. Java Entry: Finally, it uses reflection to locate com.android.server.SystemServer.main() and executes it, transferring control to the main Java initialization sequence.