332 – Android init Process: The First Userspace Process
Series Navigation: 330-Boot Overview | 331-Bootloader | 333-Zygote
Two articles ago, we covered how the Bootloader loads the kernel. Last time, we covered how the kernel decompresses, initializes hardware, and jumps to execute userspace code.
Now we arrive at a pivotal role in the Android boot chain — init.
init is the first userspace process to run after the Linux kernel boots (PID 1). In Android, it is much simpler than the standard Linux systemd/sysvinit, but it performs several highly customized tasks:
- Parse and execute
init.rc(configuration language) - Manage the property service
- Load SELinux security policy
- Spawn Zygote
What Is init
In Linux, PID 1 is the ancestor of all processes. After completing initialization, the kernel attempts to run /sbin/init (or the init program specified on the kernel command line). If it can’t be found, the kernel panics.
Android’s init is a standalone project under system/core/init/, written in C++ and compiled into an executable:
# Android device's init
/system/bin/init
# or
/sbin/initIts source code structure:
system/core/init/
├── init.cpp # Main entry, parses command line, calls Parser
├── parser.cpp # init.rc parser
├── ast.cpp # Abstract syntax tree (Section/Trigger/Service)
├── builtins.cpp # Built-in command implementations (mount, mkdir, write...)
├── property_service.cpp # Property service server implementation
├── selinux.cpp # SELinux policy loading
├── devices.cpp # Device node management (ueventd)
├── keychords.cpp # Key chord detection (lock screen)
└── init.rc # Main configuration fileWhat Is init.rc
init.rc is init’s configuration file, using a declarative domain-specific language (DSL) describing all behaviors during the boot process.
Linux’s init system (systemd) uses unit files (INI format). Android invented its own format — a trigger-based configuration language.
init.rc Basic Structure
# Part 1: Import other configuration files
import /init.usb.configfs.rc
import /init.${ro.hardware}.rc # Device-specific configuration
import /init.trace.rc
import /init.kernel.modules.rc
# Part 2: on triggers (event-driven service startup)
on late-init
# Trigger condition: late_initcall, kernel is ready
trigger late-init
on late-init
# Mount filesystems
mount tmpfs tmpfs /sys/fs/cgroup nosuid nodev noexec
chmod 0775 /sys/fs/cgroup
mkdir /sys/fs/cgroup/freezer 0755 root root
mount cgroup cgroup /sys/fs/cgroup/freezer freezer
# Restore user data (if needed)
exec_background /system/bin/e2fsck -f -y /dev/block/bootdevice/by-name/userdata
# Set kernel variables
write /proc/sys/kernel/random/boot_id ${ro.boot.serialno}
# Part 3: Service definitions
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
# Part 4: Triggers for specific events
on property:sys.boot_completed=1
# Boot completed notification
bootchart stopinit’s Main Responsibilities
1. Parse and execute init.rc:
- Read init.rc and all imported files
- Execute on-boot triggers in order
- Track property changes and trigger actions
2. Property Service:
- Key-value store shared by all processes
- /dev/__properties__ (shared memory)
- Bionic libc reads properties via this shared memory
- setprop/getprop commands
3. SELinux policy:
- Load SELinux security policy at boot
- Set security contexts for all files and processes
- Ensure MAC (Mandatory Access Control) enforcement
4. Device node management (ueventd):
- Listen for uevents from the kernel
- Create device nodes in /dev
- Set permissions and SELinux contexts
5. Service lifecycle:
- Start core services (zygote, servicemanager, surfaceflinger)
- Restart services on crash (onrestart)
- Track service state (running/stopped/restarting)
Comments