AOSP Foundations
6 min read

The init Process (Overview)

An introduction to PID 1, the absolute root of the Android user space process tree.

The Empty Operating System: Why We Need a Master Orchestrator

After the kernel finishes booting, your phone screen remains completely blank. The CPU is running, but the device is entirely silent and useless. Connecting a serial console at this exact millisecond reveals only a blinking cursor. There is no graphical interface, no touch input, and no Java framework loaded. A Linux kernel alone does not provide a working smartphone. It only provides low level hardware management.

Common Mistake: Beginners often assume the kernel directly starts the Android UI or the Java framework. The kernel actually has no knowledge of Android specific components.

A kernel acts like a construction crew that lays the foundation and installs the plumbing for a building. The physical structure exists, but the interior is entirely empty. We need a general contractor to arrive with blueprints and start hiring electricians, painters, and decorators. Android requires a first user space process to bootstrap everything else. To fill this empty void, the kernel explicitly summons a single universally powerful program to take control.

PID 1: The Absolute Root of the Android User Space

The moment the kernel pivots to user space, it starts the init binary. This executable is explicitly assigned Process ID 1 (PID 1). It sits directly at the top of the process hierarchy as the parent of all other processes. Every single application and service on your phone is a direct descendant of this master process.

Tip: You can verify this structure yourself. Run adb shell ps -A in your terminal to see the process tree and confirm that init runs as root on PID 1.

Because it forms the absolute root of the system, its survival is critical. If you force kill this process, the Linux kernel instantly panics and reboots the entire device to protect itself. Beginners often mistake Zygote for this root process because it spawns Java applications. Zygote only manages the Java layer, whereas PID 1 is the root of the entire operating system.

Before we visualize this hierarchy, we need to understand how the components relate to one another. This flowchart maps the direct lineage from the system level down to an individual application. Notice how the single orchestrator acts as the sole bridge between the kernel and the rest of user space.

The kernel bootstraps the first process. This process then forks native services like the graphics compositor alongside platform foundations like Zygote. Zygote then forks individual application processes.

Did You Know: Android uses a custom built binary for this task. It completely replaces standard Linux initialization systems like systemd or SysVinit.

But this orchestrator is just a single C++ binary. How does it know how to start the thousands of components that make up Android?

The Android Init Language: Following the Master Script

The binary itself does not contain any hardcoded logic for the boot sequence. It acts purely as a dynamic parser. Execution relies entirely on plain text configuration files written in the Android Init Language. These files use the .rc extension and contain exact instructions.

The master file is located at /system/etc/init/hw/init.rc. You can think of the binary as a theatrical stage manager. The manager does not perform the play directly. Instead, they read a script and cue the actors to go on stage at the exact right moment.

Warning: Do not assume these .rc files are standard shell scripts. They use a highly restricted custom syntax parsed directly by the C++ binary.

Let us look at a typical example of this syntax. You will often see commands grouped under specific triggers.

on boot
    write /sys/power/wake_lock 1
    start netd

When the system reads the trigger event, it executes the subsequent actions in order. The primary job here is to parse these files and spawn the background C++ daemons that make up the native layer. These background services include logd for system logs, servicemanager for IPC communication, and audioserver for mixing sound streams.

To clarify how these instructions become running services, we can trace the flow of execution. This flowchart illustrates the relationship between the configuration file and the spawned daemons. Observe how the single configuration file dictates the creation of multiple distinct services.

The parser reads the text file from the filesystem. It then interprets the text commands and spawns individual daemon processes. These daemons immediately begin running in the background to handle system tasks.

Once the script is fully parsed and all daemons are running, you might assume the job is done. However, its most important role is just beginning.

The Eternal Babysitter: Why init Never Sleeps

A modern smartphone cannot simply crash and force the user to pull the battery out. If a critical daemon encounters a fatal bug, the system must recover gracefully. This is why the primary process stays alive indefinitely as a background daemon itself. It continuously monitors all of its child processes to ensure they remain functional.

When a native service crashes, the Linux kernel sends a SIGCHLD signal back to the parent process. The orchestrator catches this signal, checks the configuration script, and instantly respawns the dead service. If a developer accidentally pushes a bug that crashes the audio server, the sound might cut out for a single second. The system immediately spins up a fresh instance to prevent a full device reboot.

Tip: Application crashes are handled entirely by ActivityManager and Zygote. This root monitor only babysits native system daemons.

We can visualize this automatic recovery loop in action. The sequence below demonstrates what happens when a critical service fails unexpectedly. Notice how quickly the system detects the failure and restores functionality.

The graphics compositor encounters a fatal error and terminates. Our kernel alerts the parent process about the death of its child. This parent immediately executes a new instance to restore the visual interface.

This single C++ binary successfully bridges the gap between a raw kernel and a fully graphical environment. It accomplishes this while permanently monitoring the background services that keep the device stable. We know what this orchestrator does, but how does it execute thousands of instructions in mere milliseconds? Next, we examine the exact mechanics of init.