AOSP Foundations
5 min read

The Vendor Ramdisk

Understand how the vendor ramdisk handles the highly specialized early-boot tasks before handing control to the generic framework.

The Catch-22 of Booting Android

How does the kernel read from the flash storage if the drivers to read it are stored on the flash storage? The Linux kernel does not include proprietary storage drivers for UFS or eMMC hardware by default. It relies on loadable kernel modules to communicate with these components. Those modules live on the physical system partition. You need the key to open the safe, but the key is locked inside the safe.

A temporary in-memory filesystem solves this exact problem. The bootloader loads an initial ramdisk directly into RAM before the Linux kernel even starts. This ramdisk acts like a spare key taped to the outside of the safe by the manufacturer. If a bootloader tries to launch the kernel without this ramdisk, the boot fails instantly. The kernel panics because it cannot open the root device. Now that we know we need a temporary filesystem, let's look at how modern Android architectures split this spare key into two halves.

The Merged Ramdisk: Separating Generic from Proprietary

Why does Android use two separate ramdisks now instead of one? The Generic Kernel Image requirement forced the separation of generic init logic from vendor-specific drivers. A modern Android device requires a standardized init_boot partition and a hardware-specific vendor_boot partition. The bootloader merges these two pieces into a single ramdisk at boot time. This is exactly like buying a generic car frame and bolting on custom wheels before turning the ignition. The generic init_boot remains identical across devices, while the vendor_boot shrinks to contain only the specific kernel modules required for that exact hardware.

Warning: Do not confuse the physical /vendor partition with the in-memory vendor_boot ramdisk.

The diagram below shows the bootloader combining the two distinct partitions into a single in-memory filesystem. This separation allows the core system to remain generic while still loading the proprietary drivers needed for early boot.

This combination creates the merged ramdisk that the kernel will use to boot the device. With the merged ramdisk successfully sitting in memory, the kernel can finally execute the very first Android user-space process.

First Stage Init: Setting the Stage

What exactly happens in those first few milliseconds after the kernel loads the ramdisk? The kernel executes the /init binary found inside the merged ramdisk. This triggers the First Stage init process. The setup is minimal and focuses entirely on preparing the environment to mount the physical partitions. It scans the ramdisk for loadable kernel modules and loads the proprietary storage drivers into the kernel.

With drivers loaded, the system can finally see the physical flash memory. It reads the vendor-provided fstab and mounts /system, /vendor, and /product as read-only.

The sequence diagram below traces the precise cause and effect chain during these first milliseconds. It shows how the kernel initiates the process, loads drivers, mounts storage, and applies security policies.

First Stage init executes, sequentially loading modules, reading the filesystem table, and mounting the physical partitions. It finishes by loading the initial SELinux policy rules from those mounted partitions to enforce mandatory access control.

// Simplified First Stage init flow
int main(int argc, char** argv) {
    DoFirstStageMount();
    SetInitEnv();
    LoadSelinuxPolicy();
    // Proceed to pivot root
}

Engineers often make the mistake of thinking this First Stage init launches system services like Zygote or SurfaceFlinger. It only builds the foundation, walls, and roof of the house. The process does not move the furniture in. Once the physical partitions are visible and secured, the tiny ramdisk's job is completely finished and it needs to get out of the way.

The Pivot Root: Swapping the World

How does Android switch from the temporary ramdisk to the real OS without crashing? The init process executes a crucial system call called pivot_root. This call instantly swaps the temporary ramdisk with the physical /system partition. The /system partition becomes the new permanent root of the file system. Afterward, the kernel unmounts the old ramdisk and returns its memory to the system pool. Think of the ramdisk as the booster stage of a space rocket.

It gets the OS off the ground, but once in orbit, it detaches and falls away so the main engine can take over.

Tip: Older Android versions used the chroot system call instead of pivot_root for this transition.

The state diagram below illustrates the exact transition point where the temporary root is discarded in favor of the permanent storage. This mechanism ensures zero downtime during the handoff.

Transitioning from the temporary RamdiskRoot state through the PivotRoot syscall lands the system in the permanent SystemRoot state. To verify this handoff in real-time on a device, you need to read the early boot logs. The following command queries the kernel ring buffer and filters for init messages, outputting the exact timestamps and milestones of the transition.

adb shell dmesg | grep "init:"

A common beginner mistake is believing the ramdisk stays in memory forever, perpetually eating up valuable RAM. This memory footprint is strictly temporary. The bootloader handed off a memory chunk, the system mounted the physical partitions, and the memory-saving pivot discarded the temporary files. With the permanent file system established and the ramdisk memory freed, Android is finally ready to start launching the actual operating system services. Now that we are executing /system/bin/init from the permanent flash storage, how does Android bring up Zygote, SurfaceFlinger, and the rest of the world?