Android Platform

Android Boot Process

Everything that happens between pressing the power button and seeing the home screen: the ROM bootloader, the Qualcomm XBL and ABL stages, verified boot, A/B slots, the Linux kernel, init, Zygote and system_server. It is one of the most common platform interview openers, and knowing where each stage can fail is the key to debugging devices that will not boot.

~110 min read 0 interview questions
In 30 seconds
  • Boot is a relay race: PMIC → PBL (ROM) → XBL/SBL → ABL → Linux kernel → init → Zygote → system_server → Launcher and BOOT_COMPLETED.
  • Each stage is small, brings up just enough hardware for the next, verifies the next stage's signature, and jumps to it.
  • Trust is anchored in a public-key hash burned into eFuses (QFPROM); AVB extends it to boot/vbmeta and dm-verity extends it to /system and /vendor at runtime.
  • A/B slots (and virtual A/B snapshots) let OTAs install in the background and roll back automatically if the new build does not boot.
  • Debugging starts by locating the stage that died: no logo, logo only, stuck boot animation, or a crash loop after the animation.

The big picture

Booting a phone is a relay race of bootloaders. Right after power-on almost nothing works: there is no main memory (DRAM), no storage driver, no display. So each stage is deliberately small, initializes just enough hardware to load the next (bigger, more capable) stage, checks that the next stage is genuine, and hands over control. The pieces grow from a few kilobytes of code etched into the chip up to the full Android framework.

Analogy

Think of opening a secure office building in the morning. The night guard (code baked into the chip) unlocks the front door and checks the receptionist's ID. The receptionist powers the lifts and checks the floor manager's badge. The floor manager turns on the lights and verifies each department head. Only when every badge checks out do the employees (apps) start working. The night guard is the PBL, the receptionist is XBL, the floor manager is ABL, the department heads are the kernel and init, and the badge checks are signature verification - each level trusts the next only after verifying it, which is the chain of trust.

Two stories you must be able to tell

The loading story (who loads whom)

Power → PBL (chip ROM) → XBL/SBL → ABL (Android bootloader) → Linux kernel → init → Zygote → system_server → Launcher. Each stage copies the next from storage into memory and jumps to it.

The trust story (who verifies whom)

A hash of the OEM public key fused into the SoC (root of trust) lets PBL verify XBL; XBL verifies TrustZone and ABL; ABL verifies vbmeta, boot, dtbo with Android Verified Boot (AVB); the kernel verifies /system and /vendor block by block with dm-verity. Break any link and boot stops or warns.

The whole chain on one screen

  +---------+
  |  POWER  |  PMIC ramps rails in sequence, starts XO clock, releases CPU reset
  +----+----+
       v
  [1] PBL   Primary Boot Loader - SoC mask ROM, runs from IMEM/SRAM   -- verifies -->
  [2] XBL   eXtensible Boot Loader (older: SBL) - trains DDR,
            loads TrustZone/QTEE, hypervisor, AOP firmware             -- verifies -->
  [3] ABL   Android Boot Loader (UEFI app; older: LK/aboot)
            boot mode, A/B slot, AVB, fastboot                         -- verifies (AVB) -->
  [4] Linux kernel  (boot.img kernel + ramdisks from init_boot/vendor_boot + DTB/DTBO)
            decompress, start_kernel(), drivers, mount ramdisk         -- dm-verity -->
  [5] init  PID 1: first stage -> SELinux setup -> second stage, *.rc
  [6] Zygote  app_process: ART, preload classes/resources, fork
  [7] system_server  ~100 services: AMS, PMS, WMS, PowerMS, Telephony ...
  [8] SystemUI + Launcher, boot animation exits, BOOT_COMPLETED

  Secure world (TrustZone / QTEE) runs alongside Android from XBL onward.
#StageRuns fromMain jobLoads / startsArtifact
0PMIC power-onHardwarePower rails, XO clock, release resetCPU reset vectorPMIC OTP sequence
1PBLBoot ROM, IMEM/SRAMFind boot media, verify XBLXBLMask ROM (not a file)
2XBL/SBLSRAM, then DDRDDR training, PMIC, secure worldTZ/QTEE, hyp, AOP, ABLxbl.elf, xbl_config, tz.mbn, hyp.mbn
3ABLDDRBoot mode, slot, AVB, fastbootKernel + ramdisk + DTabl.elf
4KernelDDRMMU, scheduler, drivers, DT/initboot.img, vendor_boot, dtbo
5initUser space, PID 1Mount, SELinux, properties, servicesueventd, servicemanager, HALs, Zygoteinit.rc and *.rc
6ZygoteUser spaceWarm ART processsystem_server and every appapp_process64
7system_serverUser spaceFramework servicesSystemUI, Launcherservices.jar
8Boot completeUser spaceSignal appsBoot receiverssys.boot_completed=1

Why so many stages?

Hardware is not ready all at once. The ROM code must be tiny (silicon area, and it can never be patched, so fewer lines means fewer permanent bugs) and it only has on-chip SRAM. DRAM needs a complex training routine that is far too big and too board-specific to put in ROM. So the immutable ROM does the minimum (verify and load), and updatable, signed stages do the complex work. This split is good for bring-up (fixable in software), for security (a small immutable root), and for flexibility (OEMs customize ABL, not the ROM).

Note The same pattern exists on every SoC, only the names change. Qualcomm: PBL → XBL → ABL. MediaTek: BootROM → Preloader → TF-A/TEE → LK → kernel. Generic Arm Trusted Firmware: BL1 (ROM) → BL2 (trusted boot, DRAM init) → BL31 (EL3 secure monitor) → BL32 (secure OS) → BL33 (non-secure bootloader such as U-Boot or UEFI).
Interview angle The opener is almost always "Trace what happens from pressing power to seeing the launcher." A strong answer names every stage and the artifact it loads, separates the loading path from the trust path, and adds A/B slot selection at the bootloader and dm-verity at runtime. Then expect a follow-up that drills into whichever stage matches the role: PBL/XBL for BSP roles, init/SELinux for platform roles, Zygote/system_server for framework roles.

Power-on, PMIC and the PBL

When you press power (or plug in a charger, or a reset fires), the PMIC (Power Management IC) runs a hard-coded power-up sequence: it ramps the SoC voltage rails (VDD_CORE, VDD_CPU, VDD_MEM, VDD_IO) in the right order, starts the reference clock, waits for everything to be stable, and then releases the CPU reset line. The PMIC also records why the device powered on (power key, USB/charger insertion, RTC alarm, watchdog or warm reset); this "PON reason" later shows up as the boot reason.

The first code to run is the PBL (Primary Boot Loader), also called the Boot ROM. It is burned into the SoC's mask ROM at manufacture. It cannot be flashed, erased or patched, and that immutability is exactly why it can serve as the hardware root of trust.

Analogy

The PBL is like the instructions engraved on the inside of a bank vault door: nobody can edit them, and all they say is "read the combination card from drawer 1, check it against the master seal, and if it matches, open the next door." The engraving is the mask ROM, drawer 1 is the boot partition on UFS/eMMC, the master seal is the key hash in the eFuses, and the next door is XBL.

PBL execution, step by step

  1. Reset vector fetch The primary CPU core comes out of reset and fetches its first instruction from a hard-wired reset vector that maps to the Boot ROM (the exact address is SoC-specific). On Qualcomm AArch64 parts the PBL runs at the highest privilege level, EL3.
  2. Basic clocks The CPU starts on the raw 19.2 MHz XO (crystal oscillator). PBL configures a few basic PLLs to raise the core clock into the low hundreds of MHz (for example 300-600 MHz), bypassing the full clock tree.
  3. IMEM / SRAM setup PBL maps the small on-chip SRAM (Qualcomm calls it IMEM or OCIMEM) for its stack, heap, crypto scratch buffers and the buffer where XBL will be loaded. DRAM is not usable yet.
  4. Fuses and crypto engine PBL reads the QFPROM eFuses (secure-boot enable, OEM public-key hash, anti-rollback version, debug/JTAG disable, boot-device configuration) and powers up the hardware crypto engines (SHA-256, RSA/ECC).
  5. Boot media detection Using boot-configuration strap pins and fuses, PBL decides where to boot from: the UFS boot LUN or the eMMC boot partition, and it parses the GPT to find xbl, xbl_config (and later stages will find abl). If the primary medium is blank or unreadable it tries a secondary source and finally falls back to USB EDL.
  6. Load and hash PBL loads the xbl/xbl_sec image into IMEM and streams it through the SHA hardware engine to compute its digest.
  7. Authenticate It checks the image's certificate chain against the OEM PK hash in QFPROM, verifies the RSA/ECC signature over the image hash, and compares the image's anti-rollback version against the fuse counter.
  8. Hand over or fail On success it sets up the stack for the target exception level, cleans caches and pipelines, and branches to the XBL entry point in SRAM. On failure it halts or enters EDL (Qualcomm HS-USB QDLoader 9008).

Why the PBL uses SRAM, not DDR

SRAM (IMEM) usePurpose
StackFunction calls in the ROM code
Heap / work buffersTemporary variables and GPT parsing
Crypto bufferSHA calculation and signature math
XBL bufferDestination for loading the next stage

SRAM (static RAM) needs no calibration: it works the instant it has power. LPDDR, by contrast, needs PHY impedance calibration, command/address (CA) training, Vref tuning, DQS/DQ timing alignment and temperature compensation before it can hold a single byte reliably. That code is large and board-specific, so it lives in XBL, not in the ROM.

  SoC memory map during early boot
  +----------------------+
  | Boot ROM (PBL)       |  available at reset, read-only
  +----------------------+
  | IMEM / SRAM          |  available at reset, small (hundreds of KB)
  +----------------------+
  | LPDDR (DRAM)         |  unusable until XBL finishes DDR training
  +----------------------+
  | UFS / eMMC storage   |  holds xbl, abl, boot, super ... (read via minimal driver)
  +----------------------+

QFPROM and eFuses: the root of trust

QFPROM (Qualcomm Fuse Programmable ROM) is the SoC's block of one-time-programmable (OTP) eFuses. Blowing a fuse is permanent, so values written here cannot be changed later, even by an attacker with full software control.

Fuse fieldPurpose
Secure boot enableTurns on mandatory image authentication. On a "secure" production part every stage must be signed.
OEM PK hashHash of the OEM root public key (or root certificate). This is the root of trust. Storing a hash instead of the key saves fuse space and is equally secure.
Anti-rollback versionMinimum allowed firmware version; blocks downgrades to old, vulnerable but validly signed images.
Debug disableLocks JTAG and other debug ports on production devices.
Boot configurationPreferred boot device and boot options (together with strap pins).

Secure boot: signing and verification

At the factory / build server (signing)

  • Compute the SHA-256 hash of the image.
  • Sign the hash with the OEM private key (kept in an HSM, never on the device).
  • Attach an X.509 certificate chain (root CA → attestation CA → attestation certificate) and the signature to the image.
  • Burn the hash of the root public key into QFPROM once, at provisioning.

On the device every boot (verification)

  • Read the image and compute its SHA-256 hash in hardware.
  • Hash the root certificate in the image and compare it with the OEM PK hash fuse.
  • Walk the certificate chain, then verify the RSA/ECC signature over the image hash using the attestation public key.
  • Check the anti-rollback version, then jump. Any mismatch: halt or EDL.
Read XBL --> SHA-256 digest --> cert chain vs OEM PK hash (QFPROM) --> RSA/ECC signature check
         --> anti-rollback version check --> jump to XBL       (fail at any step: halt or EDL 9008)

Key terms: RSA (Rivest-Shamir-Adleman) and ECC (elliptic-curve) are asymmetric algorithms where the private key signs and the public key verifies. SHA (Secure Hash Algorithm, e.g. SHA-256) gives a fixed-size fingerprint of the image. An X.509 certificate binds a public key to an identity and is itself signed by a higher CA.

EDL - Emergency Download mode (9008)

When the PBL cannot boot (authentication failed, boot media blank or corrupt, or it was forced by a test point, key combination or adb reboot edl on devices that allow it), it exposes a USB device called Qualcomm HS-USB QDLoader 9008 (USB ID 05c6:9008). A host tool uses the Sahara protocol to upload a Firehose programmer into SRAM; the programmer then speaks the Firehose (XML) protocol to read and write storage. Even in EDL the PBL verifies the programmer's signature on secure devices, so EDL is a rescue path, not a security bypass. MediaTek's equivalent is BROM mode.

Common pitfall Some notes describe IMEM/internal SRAM as "static ROM". It is static RAM: volatile, writable, fast, and calibration-free. The ROM is the separate Boot ROM that holds the PBL code.
Interview angle BSP interviewers ask "Where is PBL stored, why can't it be updated, why does it run from SRAM, and what happens if XBL verification fails?" Strong answers mention mask ROM, EL3, the 19.2 MHz XO, IMEM, QFPROM fields (secure boot, PK hash, anti-rollback, JTAG disable), boot media detection via straps/fuses, and EDL 9008 with a signed Firehose programmer.

Boot media: eMMC vs UFS

The PBL and XBL must read the bootloaders from flash storage. Phones use either eMMC (embedded MultiMediaCard) or UFS (Universal Flash Storage). Both package NAND flash with a controller, but the interfaces are very different.

Analogy

eMMC is a single-lane road where cars take turns driving in either direction; UFS is a divided highway with separate lanes each way and a traffic controller that can queue many trips at once. The single lane is eMMC's half-duplex parallel bus, the divided highway is UFS's full-duplex serial M-PHY lanes, and the traffic controller is UFS's deep SCSI command queue.

FeatureeMMC 5.1UFS 3.1UFS 4.0
Physical interfaceParallel bus: 8-bit DAT0-DAT7, CMD, CLKSerial differential (M-PHY + UniPro)Serial differential (M-PHY 5.0 + UniPro 2.0)
DuplexHalf duplexFull duplexFull duplex
Command queueBasic (single queue, CMDQ since 5.1)Deep SCSI command queueDeep SCSI command queue, multi-lane
Peak throughput~400 MB/s (HS400)~2.1 GB/s (HS-Gear 4, 2 lanes)~4.2 GB/s (HS-Gear 5, 2 lanes)
Where the bootloader livesHardware boot partitions (boot1/boot2)Boot LUN (well-known boot W-LUN points to LUN A or B)Boot LUN
Typical useWearables (often ePoP), low-cost IoT, entry devicesMid-range and older flagship phonesCurrent flagship phones

eMMC speed modes

ModeSpecBus clockData ratePeak
HS200eMMC 4.5200 MHzSDR (one transfer per clock)~200 MB/s
HS400eMMC 5.0 / 5.1200 MHzDDR (both clock edges)~400 MB/s

SDR (single data rate) transfers once per clock cycle; DDR (double data rate) transfers on both the rising and falling edge, doubling throughput at the same clock. The same idea gives LPDDR memory its name.

Common pitfall There is no "eMMC 5.5"; the last major eMMC spec is 5.1 (HS400 plus command queuing). Also, a UFS "boot LUN" is a dedicated logical unit, whereas eMMC boot partitions are separate hardware areas of the chip - which is why PBL's detection logic differs per medium.
Interview angle Expect "eMMC vs UFS - why does it matter for boot?" Mention parallel vs serial, half vs full duplex, command queue depth, boot partitions vs boot LUN, and that faster storage directly shortens bootloader loading, kernel/ramdisk loading and first-boot dexopt. On a wearable, eMMC is still common because of cost, power and package size.

XBL / SBL: DDR training and the secure world

The XBL (eXtensible Boot Loader), called SBL (Secondary Boot Loader) on older Qualcomm SoCs, is the "real bootloader brain". It is built on UEFI (the XBL core is a UEFI firmware environment) and does the heavy hardware bring-up the ROM could not. On modern chips the first piece to run is XBL_SEC, which sets up the secure environment at EL3 before the main XBL loader continues.

Analogy

If the PBL is the night guard who opens the front door, XBL is the facilities manager who switches on the main power, calibrates the lifts, and opens the bank vault on the ground floor before anyone else arrives. Main power and lifts are DDR and clocks, the calibration is DDR training, and the vault is TrustZone - it is opened once at boot and then guards keys for the rest of the day.

What XBL does

  1. DDR training and initialization The single most important job. XBL calibrates the LPDDR PHY: impedance (ZQ) calibration, CA (command/address) training, Vref tuning, DQS/DQ read and write alignment, write leveling, and temperature compensation. Results are often cached in a partition (for example ddr/DDR training data) so later boots are faster. After this, gigabytes of DRAM are available.
  2. Full PMIC and clock setup Configures the PMIC rails for full operation, sets up PLLs, bus clocks and thermal limits.
  3. Storage and peripherals Brings up the full UFS/eMMC driver, basic USB, and sometimes the display for the splash logo.
  4. Load and authenticate the secure world Loads and verifies TrustZone images: the EL3 secure monitor and QTEE (Qualcomm Trusted Execution Environment, the secure OS in tz.mbn), plus trusted apps like KeyMint and fingerprint later loaded on demand.
  5. Load other firmware Loads the hypervisor (hyp.mbn, Qualcomm's EL2 hypervisor, Gunyah on newer chips) and firmware for helper processors such as the AOP (Always-On Processor, formerly RPM) that manages power resources, plus configuration images like devcfg.
  6. Load and verify ABL Loads abl.elf into DDR, authenticates it against the same OEM root, and jumps to it in the non-secure world.

TrustZone, TEE and exception levels

Arm TrustZone is a hardware feature that splits the SoC into two worlds: a normal world (Android, the Linux kernel, bootloaders like ABL) and a secure world (the TEE). Memory, peripherals and interrupts can be marked secure so normal-world software, even the kernel, cannot touch them. A TEE (Trusted Execution Environment) is the small secure OS that runs there (QTEE on Qualcomm, Trusty on Pixel, OP-TEE upstream, Kinibi/TEEGRIS elsewhere).

                 Normal world                         Secure world
  EL0     apps, native daemons                   trusted apps (KeyMint, Gatekeeper, fingerprint, DRM)
  EL1     Linux kernel (and ABL at boot)         TEE OS (QTEE / Trusty / OP-TEE)
  EL2     hypervisor (Qualcomm hyp / Gunyah / pKVM)
  EL3     ------------- secure monitor (from XBL_SEC / TZ) -------------  switches worlds via SMC

The kernel talks to the secure world through SMC (Secure Monitor Call) instructions, usually via a driver such as qseecom/smcinvoke on Qualcomm. The TEE holds keys (Keymaster/KeyMint), matches fingerprints, runs DRM (Widevine L1), and stores rollback counters in RPMB (Replay Protected Memory Block) on UFS/eMMC.

Responsibility matrix

ResponsibilityPBLXBLABL
Stored inSoC mask ROMUFS boot LUN / eMMC boot partitionUFS user LUN / eMMC user area (GPT partition abl)
Executes fromInternal SRAMSRAM, then LPDDRLPDDR
Memory initializationNone (SRAM only)Full DDR PHY trainingUses working DDR
Crypto roleAuthenticates XBL against QFPROMAuthenticates TZ, hyp, AOP, ABLVerifies vbmeta/boot/dtbo with AVB
PeripheralsTimers, minimal storage bus, USB for EDLFull UFS, PMIC, clocks, thermalsDisplay, fastboot over USB, simple menus
FastbootNoNoYes
Next stageJumps to XBL in SRAMStarts TZ at EL3/S-EL1, hands off to ABLBoots the Linux kernel (Image)
Common pitfall TrustZone is not a "brain" or a separate chip; it is an Arm CPU security extension. XBL only starts the secure world. The secure world then keeps running for the whole session alongside Android.
Interview angle "What's the most important thing XBL does?" The answer is DDR training. Follow-ups: why not do it in PBL (size, immutability, board-specific tuning), what else XBL loads (TZ/QTEE, hypervisor, AOP firmware, ABL), and what a DDR-training failure looks like (hang before the logo, often after a bad flash or on marginal hardware, sometimes falling back to EDL).

ABL, LK, UEFI and fastboot

The ABL (Android Boot Loader) is the Android-aware bootloader and the one users and developers interact with. On current Qualcomm platforms ABL is a UEFI application (built from edk2-based code; the Android logic lives in LinuxLoader) that runs on top of the XBL UEFI core. Older Qualcomm devices used LK (Little Kernel), flashed as the aboot partition. Other vendors use LK (MediaTek), U-Boot, or their own bootloaders; the Android-facing duties are the same.

Analogy

ABL is the airport check-in desk. It decides which flight you take (normal boot, recovery, fastboot, charger), which of two identical planes to board (slot A or B), checks your passport (verified boot), and finally loads your luggage (kernel, ramdisk, device tree) before sending you to the gate. The service counter where staff can change your booking is fastboot.

What ABL does

  1. Pick the boot mode Normal, recovery, fastboot (bootloader), charger (off-mode charging when powered on by USB insertion), or ramdump/crash-dump collection. Inputs: key combinations, the PMIC PON reason, and a reboot reason left in memory or the misc partition by adb reboot <target>.
  2. Pick the A/B slot Reads slot metadata (active, priority, retry count, successful flag) from the GPT attributes or misc, decrements the retry counter, and selects _a or _b.
  3. Verified boot Runs libavb (avb_slot_verify()) over vbmeta, boot, init_boot, vendor_boot, dtbo. Shows the boot-state warning screen when unlocked or verified with a custom key.
  4. Pass the root of trust to the TEE Sends the lock state, verified-boot state, vbmeta digest, OS version and patch level to the TEE so KeyMint can bind keys to them and key attestation can report them.
  5. Build the kernel command line / bootconfig Adds androidboot.* parameters (slot suffix, verified-boot state, serial number, hardware revision, boot reason). On Android 12+ these go in bootconfig; they become ro.boot.* properties in user space.
  6. Load and jump Loads the kernel, the ramdisks (concatenating vendor, then generic ramdisk) and the device tree (DTB with DTBO overlays applied) into DDR, then jumps to the kernel entry point with the DTB address in a register.

Boot modes and how you reach them

ModePurposeHow to enter
NormalBoot AndroidPower key
Fastboot (bootloader)Flash, unlock, query variables over USBadb reboot bootloader, key combo (often Power + Vol Down)
fastbootdUser-space fastboot inside recovery, needed to flash logical partitions in super (Android 10+)adb reboot fastboot or fastboot reboot fastboot
RecoverySideload OTA, factory reset, wipe cacheadb reboot recovery, key combo, or automatically after repeated failures
ChargerOff-mode charging animation; init starts only the charger classPlug USB while powered off (androidboot.mode=charger)
Ramdump / crash dumpCollect memory after a crash for offline analysisAutomatic after a kernel/TZ crash when enabled
EDLPBL-level rescue flashing (not an ABL mode)Test point, key combo, adb reboot edl where supported

Fastboot essentials

# query
fastboot devices
fastboot getvar all
fastboot getvar current-slot
fastboot getvar unlocked

# flash and boot
fastboot flash boot boot.img              # flashes the current slot's boot
fastboot flash boot_b boot.img            # explicit slot
fastboot flashall                         # flash everything from $ANDROID_PRODUCT_OUT
fastboot boot boot.img                    # RAM-boot an image without flashing it
fastboot --set-active=b                   # switch the active slot
fastboot reboot fastboot                  # go to fastbootd for super/logical partitions

# lock state
fastboot flashing get_unlock_ability      # 1 only if "OEM unlocking" is enabled in Settings
fastboot flashing unlock                  # wipes userdata, boot state becomes ORANGE
fastboot flashing lock                    # wipes userdata again, back to enforced verification

# debug builds: disable AVB checks via the vbmeta flags
fastboot --disable-verity --disable-verification flash vbmeta vbmeta.img
Tip Logo on screen means ABL ran. On Qualcomm the splash is normally drawn by XBL/ABL from the splash partition, so "no logo at all" points to PBL, XBL or very early ABL; "logo but no boot animation" points to kernel or early init.
Interview angle Interviewers check that you know the difference between fastboot (bootloader USB flashing), fastbootd (user-space fastboot for dynamic partitions), recovery (OTA/sideload/factory reset) and EDL (ROM-level rescue). Mention that ABL also passes the boot state to the TEE for key attestation and turns androidboot.* into ro.boot.* properties.

Android Verified Boot (AVB 2.0) and dm-verity

Android Verified Boot makes sure every byte of executable code and read-only data on the device comes from a trusted source. It extends the hardware chain of trust (PBL → XBL → ABL) into Android's own partitions. AVB 2.0 (reference library libavb, tool avbtool) replaced the Android 7 era "verified boot 1.0" starting with Android 8.

Analogy

vbmeta is like the signed packing list stapled to a shipping container. The customs officer (ABL) checks the signature on the list, then weighs each small box against the list (hash descriptors for boot and dtbo). The huge crates (system, vendor) are too big to weigh at the dock, so each item is spot-checked the moment it is unpacked (dm-verity checks each block when it is read). The rollback index is the list's version number: an older list, even genuinely signed, is refused.

The vbmeta structure

The vbmeta partition holds a signed VBMeta struct: a header, the public key and signature, a rollback index, flags, and a list of descriptors.

DescriptorUsed forWhat it contains
Hash descriptorSmall partitions loaded by the bootloader: boot, init_boot, vendor_boot, dtboSalted SHA-256 of the whole image. ABL hashes the image and compares.
Hashtree descriptorLarge partitions mounted by the kernel: system, vendor, product, odmRoot hash, salt and parameters of a Merkle hash tree (plus FEC data). Passed to the kernel for dm-verity.
Chain partition descriptorDelegating trust to another vbmeta, e.g. vbmeta_system, or a partition with its own footerPartition name, rollback index location, and the public key allowed to sign it. Lets different teams sign independently.
Kernel cmdline descriptorAdding verity parameters to the kernel command lineCommand-line fragments
Property descriptorMetadataKey/value pairs, e.g. OS version
  vbmeta (signed by OEM key, rollback index N)
    |-- hash      : boot, init_boot, vendor_boot, dtbo       (checked by ABL before jump)
    |-- chain     : vbmeta_system  (key K2, rollback location 1)
    |                 |-- hashtree : system, system_ext, product  (root hash -> dm-verity)
    |-- hashtree  : vendor, odm                             (root hash -> dm-verity)

Verification flow

  1. Verify vbmeta ABL checks the vbmeta signature against the OEM key embedded in (and verified with) the bootloader, or against a user-set custom key when locked with one.
  2. Rollback check Each vbmeta carries a rollback index; ABL compares it with the stored value in tamper-evident storage (usually RPMB, managed through the TEE). Lower index means refuse to boot.
  3. Hash small partitions For each hash descriptor, hash the image and compare. Mismatch on a locked device means boot fails (RED).
  4. Pass hashtree info Root hashes and salts go to the kernel via the command line or androidboot.* / fstab (avb flag) so init can set up dm-verity.
  5. Update rollback index Only after the slot is marked successful does the bootloader raise the stored rollback index, so a failed OTA can still roll back to the previous slot.

dm-verity: runtime integrity

dm-verity is a Linux device-mapper target. The partition is split into 4 KB blocks, each block is hashed, the hashes are hashed again level by level into a Merkle tree, and only the root hash needs to be trusted (it comes from signed vbmeta). When any block is read, the kernel hashes it and checks it against the tree; a single flipped bit is caught. Verification is lazy (on read), so there is no big boot-time cost of hashing gigabytes up front.

  • FEC (forward error correction) data lets dm-verity repair a small amount of flash corruption instead of failing.
  • Error modes: restart (reboot on corruption; the default on user builds), eio (return I/O errors, used after a corruption-triggered restart so the device can warn the user), and logging (debug only). Check ro.boot.veritymode.
  • Because system partitions are verified block by block, they must be read-only. adb remount on a debug build works by disabling verity and using overlayfs.

Lock states and boot-state colors

StateMeaningUser sees
GREENDevice locked, everything verified with the OEM keyNormal boot, no warning
YELLOWDevice locked, but verified with a user-installed custom root key (fastboot flash avb_custom_key)Warning screen showing the key fingerprint
ORANGEBootloader unlocked; verification runs but failures are allowed"Your device software can't be checked" warning, pause, then boot
REDLocked device and verification failed (or dm-verity found corruption)"Device is corrupt" screen; boot stops or waits for user action
adb shell getprop ro.boot.verifiedbootstate     # green / yellow / orange
adb shell getprop ro.boot.vbmeta.device_state   # locked / unlocked
adb shell getprop ro.boot.flash.locked          # 1 = locked
adb shell getprop ro.boot.veritymode            # enforcing / eio / logging
avbtool info_image --image vbmeta.img           # dump descriptors, rollback index, flags
avbtool verify_image --image vbmeta.img --key oem_key.pem

Unlocking the bootloader

  • Requires "OEM unlocking" in Developer Options (stored in a persistent partition protected by Factory Reset Protection) and physical access to run fastboot flashing unlock.
  • Wipes userdata on unlock and lock, so a thief cannot unlock to read data.
  • Boot state becomes ORANGE; the TEE is told the device is unlocked, so key attestation reports it and apps relying on strong integrity (payment, DRM L1) may stop working. Some vendors also blow a permanent warranty fuse.
Common pitfall "ORANGE means no verification" is not quite right: the bootloader still verifies, it just does not enforce the result. And rollback protection has two layers: QFPROM anti-rollback fuses for the SoC firmware (XBL, TZ, ABL) and AVB rollback indexes in RPMB for Android partitions.
Interview angle The classic probe is "AVB vs dm-verity". AVB verifies at boot in the bootloader (vbmeta signature, hash descriptors, rollback index); dm-verity verifies at runtime in the kernel, block by block, using a hash tree whose root hash came from vbmeta. Strong candidates also explain chained vbmeta partitions, why the rollback index is updated only after a successful boot, and how verified-boot state reaches KeyMint for attestation.

Partitions, boot images and dynamic partitions

Storage is divided by a GPT (GUID Partition Table). Knowing which partition holds what is essential for flashing, OTA design and debugging. Modern Android also splits Google's generic pieces from vendor-specific pieces (Project Treble and the Generic Kernel Image, GKI) so they can be updated independently.

Analogy

The partition table is like a building's floor directory. Some floors are fixed-size rooms (boot, dtbo, vbmeta), while super is an open-plan floor with movable partitions that can be resized between renovations. The fixed rooms are the physical GPT partitions, the open-plan floor is the super partition, and the movable walls are the dynamic partition metadata that the OTA can rewrite.

Key partitions

PartitionHoldsA/B?
xbl, xbl_configXBL loader and its configuration (DDR, platform settings)Yes (on A/B devices)
tz, hyp, aop, devcfg, keymaster/kmSecure world, hypervisor, power-processor firmware, TZ configYes
ablAndroid bootloader (older: aboot with LK)Yes
bootKernel (GKI) plus, before Android 13, the generic ramdiskYes
init_bootGeneric ramdisk containing first-stage /init (devices launching with Android 13+)Yes
vendor_bootVendor ramdisk (vendor fstab, first-stage kernel modules), DTB, vendor cmdline/bootconfig (Android 11+)Yes
dtboDevice-tree overlays for board variantsYes
vbmeta, vbmeta_systemAVB metadata, signatures, rollback indexesYes
superLogical partitions: system, system_ext, vendor, product, odm, vendor_dlkm, system_dlkmContains both slots (A/B) or snapshots (virtual A/B)
recoveryRecovery image (only on non-A/B devices; on A/B the recovery ramdisk lives inside boot or vendor_boot)No
miscBootloader control block: reboot target, recovery commands, virtual A/B merge statusNo
metadataMetadata encryption keys and OTA snapshot stateNo
userdataApps and user data (/data), file-based encryptedNo
modem, dsp, bluetoothFirmware for the modem, audio/compute DSPs and connectivity chipsYes
persist, frpCalibration data; Factory Reset Protection flag incl. the OEM-unlock bitNo

Boot image header versions

HeaderAndroidChange
v0Legacykernel + ramdisk + optional second-stage image in one boot.img
v19Adds recovery_dtbo for non-A/B recovery
v210Adds a DTB section to boot.img
v311Introduces vendor_boot; DTB and vendor ramdisk move there; boot.img becomes generic
v412Multiple vendor ramdisk fragments and bootconfig (replaces androidboot.* on the kernel command line)
init_boot13Generic ramdisk moved out of boot into init_boot, so boot contains only the GKI kernel
# inspect and repack
unpack_bootimg --boot_img boot.img --out out/
mkbootimg --header_version 4 --kernel Image --ramdisk ramdisk.img -o boot.img
unpack_bootimg --boot_img vendor_boot.img --out vb/

Dynamic partitions and super

Since Android 10, system, vendor, product and friends are logical partitions inside one physical super partition. The layout is described by LP metadata (liblp) at the start of super; first-stage init reads it and creates dm-linear device-mapper devices for each logical partition. Benefits: OTAs can resize partitions, and unused space is shared. Consequence: logical partitions can only be flashed from fastbootd (user space), not from the bootloader fastboot.

adb shell lpdump                       # show super layout and groups
adb shell ls -l /dev/block/mapper/     # dm devices for system_a, vendor_a ...
lpunpack super.img out/                # host-side: extract logical images
Interview angle Expect "What is init_boot / vendor_boot and why were they added?" The answer is GKI: Google ships one generic kernel (boot) and one generic ramdisk (init_boot), while vendor-specific ramdisk content, kernel modules and DTB live in vendor_boot, vendor_dlkm and dtbo. This lets the kernel and core be updated without the vendor rebuilding everything.

A/B slots, virtual A/B and OTA

A/B (seamless) updates, introduced in Android 7, keep two copies of every updatable partition: slot _a and slot _b. The OTA installs to the inactive slot in the background while the user keeps using the active one, and the bootloader switches slots on the next reboot. If the new slot fails to boot, the device falls back to the old one automatically.

Analogy

A/B is like repainting a spare room while you keep living in the current one, then moving in only once the paint is dry. If the new room turns out to have a problem, you just move back. Virtual A/B is the cheaper version: instead of owning two full rooms, you keep one room and a sheet of tracing paper recording every change; once you are happy with the change you trace it permanently onto the walls (merge), and if not, you throw the paper away (rollback). The two rooms are the physical A and B slots, and the tracing paper is the copy-on-write snapshot.

Slot metadata and the boot control HAL

Each slot has three attributes kept by the bootloader (GPT attributes or the misc partition): priority (which slot to try first), tries remaining (a retry counter, typically 7 or fewer), and successful (the slot has booted fully at least once). User space manipulates them through the boot control HAL (IBootControl) and the bootctl tool.

  1. Download and verify update_engine downloads the payload (full or delta), verifies its signature, and writes the new images to the inactive slot (for example boot_b, vendor_boot_b, and system_b in super).
  2. Post-install Runs the optional post-install step, including background dexopt (compiling apps for the new build) via otapreopt.
  3. Switch slot update_engine calls setActiveBootSlot(b): slot B gets the highest priority, full tries remaining, and successful = false.
  4. Reboot and try ABL picks B, decrements its tries counter, and verifies and boots it (the slot suffix reaches user space as ro.boot.slot_suffix).
  5. Mark successful After boot completes, update_verifier checks dm-verity partitions and markBootSuccessful() sets successful = true. Only now is the AVB rollback index raised.
  6. Automatic rollback If B keeps failing before it is marked successful, the tries counter reaches 0, B becomes unbootable, and ABL falls back to A.
OTA server --> update_engine verifies payload signature
  --> writes INACTIVE slot: boot_b, vendor_boot_b, dtbo_b, vbmeta_b, system_b/vendor_b (in super)
  --> post-install (otapreopt) --> setActiveBootSlot(B)
  --> reboot --> ABL selects B (tries--) --> AVB verifies B --> kernel --> init --> ... --> boot completed
  --> update_verifier + markBootSuccessful(B) --> rollback index updated
  (B fails N times before success --> tries = 0 --> ABL boots A again)
adb shell bootctl get-current-slot           # 0 = a, 1 = b
adb shell bootctl get-suffix 1               # _b
adb shell bootctl is-slot-marked-successful 1
adb shell getprop ro.boot.slot_suffix
fastboot getvar current-slot
fastboot getvar slot-retry-count:b
fastboot --set-active=a

Virtual A/B (Android 11+)

Full A/B doubles the storage cost of every partition. Virtual A/B keeps A/B semantics for the small bootloader-loaded partitions (boot, vendor_boot, dtbo, vbmeta stay physically duplicated) but stores only one physical copy of the large dynamic partitions in super. The OTA writes changes as copy-on-write (COW) snapshots, typically stored in free space in super or in files on /data.

  • After reboot, first-stage init maps the new slot as a dm-snapshot view (base partition + COW), managed by snapuserd with compressed COW (Virtual A/B Compression, Android 12+, via dm-user; newer kernels move back to in-kernel handling).
  • Once the new build is marked successful, a background merge folds the snapshot into the base partitions. During the merge, the old version no longer exists, so rollback is no longer possible; merge state is tracked in metadata/misc so it survives reboots.
  • If the new build fails before merge, the snapshot is discarded and the old slot boots.

Non-A/B (legacy)

  • One copy of each partition plus a recovery partition.
  • Device reboots into recovery to apply the update; phone is unusable for minutes.
  • A failed update can brick the device.
  • Lowest storage cost.

A/B and virtual A/B

  • Update in the background, one quick reboot.
  • Automatic rollback if the new slot fails.
  • Full A/B: about twice the system storage. Virtual A/B: extra space only for the COW snapshot, plus merge time and I/O after the update.
  • Required for new devices on recent Android releases (virtual A/B).
Common pitfall The bootloader does not flip slot_successful; it only selects the slot and decrements tries. User space (update_verifier / boot control HAL) marks the slot successful after a complete boot. Another pitfall: A/B protects against a bad OTA, not against corrupt userdata - both slots share /data, so a data-format problem can still bootloop both.
Interview angle Interviewers ask "How is an OTA applied without bricking?" and then "How does virtual A/B save space?" Walk the slot attributes, update_engine, tries counter, markBootSuccessful, rollback, and the snapshot-then-merge flow. Bonus: explain why the rollback index must be raised only after success, and that the merge window is when rollback is no longer possible.

Kernel start: from Image to /init

ABL jumps to the kernel entry point with the physical address of the DTB in register x0 (AArch64). From there the kernel goes from a raw binary to a running operating system and finally starts the first user-space program.

Analogy

Starting the kernel is like a new building manager arriving with a floor plan. They unpack their toolkit, read the plan to learn which rooms and machines exist, hire a specialist for each machine, and then hand the keys to the first tenant. The toolkit unpacking is decompression and early setup, the floor plan is the device tree, the specialists are drivers probing devices, and the first tenant is /init (PID 1).

  1. Decompress (if needed) The image may be compressed (gzip/LZ4). On arm64 the bootloader usually decompresses it; Image is raw, Image.lz4/Image.gz are compressed.
  2. Assembly entry arch/arm64/kernel/head.S sets the exception level, builds early page tables, enables the MMU and jumps to C code.
  3. start_kernel() In init/main.c: early memory setup (memblock), parse the device tree (unflatten the FDT), parse the command line and bootconfig, set up the page allocator, the scheduler, interrupts (GIC), timers, the console, RCU, and workqueues.
  4. initcalls rest_init() starts kernel_init; built-in drivers and subsystems register at initcall levels (early, core, postcore, arch, subsys, fs, device, late). Drivers probe against DT nodes by compatible string; missing dependencies (a regulator or clock not ready yet) cause deferred probe, retried later.
  5. Ramdisk The kernel unpacks the concatenated ramdisks (vendor ramdisk from vendor_boot + generic ramdisk from init_boot/boot) into an initramfs rootfs.
  6. Run init The kernel frees init memory ("Freeing unused kernel memory" in the log) and executes /init as PID 1. If it cannot find or run init, it panics.

Device tree in one paragraph

A device tree is a data structure (.dts source compiled to .dtb binary) that describes the hardware: CPUs, memory, buses, interrupts, clocks, regulators, GPIOs and peripherals. It lets one kernel binary run on many boards without hard-coded board files. DTBO overlays patch the base DTB for board variants (display panel, SKU, hardware revision); the bootloader selects and applies them using IDs such as msm-id and board-id.

adb shell cat /proc/cmdline            # kernel command line
adb shell cat /proc/bootconfig         # androidboot.* parameters (Android 12+)
adb shell ls /proc/device-tree/        # live device tree
dtc -I dtb -O dts -o out.dts board.dtb # decompile a DTB

GKI and kernel modules

Under GKI (Generic Kernel Image, Android 12+ with kernel 5.10+), the core kernel is built by Google and identical across devices of the same kernel version. Vendor drivers ship as loadable modules against a stable symbol list (KMI, Kernel Module Interface). Modules needed early (storage, display, clocks) are in the vendor_boot ramdisk and are loaded by first-stage init from modules.load; the rest are in vendor_dlkm and loaded later (often by a vendor modprobe service).

Peripheral subsystems (modem, DSPs)

On Qualcomm SoCs, the modem, audio DSP (ADSP), compute DSP (CDSP) and sensor DSP are separate processors. The kernel's remoteproc (formerly PIL, Peripheral Image Loader) driver loads their firmware from the modem/firmware partitions, and TrustZone authenticates each image (PAS, Peripheral Authentication Service) before releasing it from reset. Subsystem restart (SSR) can restart a crashed modem without rebooting Android.

Common pitfall "Unable to mount root fs" on modern Android usually does not mean the kernel is broken. Root is the ramdisk, so this points to a missing or corrupt ramdisk, a wrong vendor_boot/init_boot combination, or a command-line mismatch - check which images were flashed together.
Interview angle "What does the kernel do between the bootloader jump and /init?" A crisp answer: head.S and MMU, start_kernel(), device tree parsing, scheduler/IRQ/timer setup, initcalls and driver probe (with deferred probe), unpack the ramdisk, exec /init as PID 1. For BSP roles, expect follow-ups on DT compatible matching, deferred probe, GKI modules and initcall_debug.

init: first stage, SELinux and second stage

Android's init (source in system/core/init) is PID 1, the ancestor of every user-space process. It runs in three phases, each a fresh exec of the init binary.

Analogy

init is a theatre stage manager holding a cue sheet. First they set up the stage floor (mount the partitions), then the security guards take their posts (SELinux policy loaded), and then the show runs from the cue sheet: "at curtain, start lights; when the actor is ready, start music; if an actor collapses, restart them." The cue sheet is the .rc files, the cues are triggers, the actors are services, and "restart them" is init's service supervision.

The three phases

  1. First stage (FirstStageMain) Runs from the ramdisk. Mounts /dev, /proc, /sys; loads first-stage kernel modules from vendor_boot; reads the first-stage fstab (from the vendor ramdisk / DT); maps logical partitions from super with dm-linear (and virtual A/B snapshots); sets up dm-verity using AVB hashtree data; mounts /system, /vendor, /product, /odm; switches root to /system.
  2. SELinux setup (selinux_setup) Loads the SELinux policy: the platform policy (plat_sepolicy.cil) plus vendor policy, compiled on the device with secilc or taken from a precompiled_sepolicy when hashes match. Sets enforcing mode (permissive only if allowed on userdebug/eng via androidboot.selinux=permissive), restores labels, then re-executes init in the u:r:init:s0 domain.
  3. Second stage (SecondStageMain) Initializes the property service and loads build properties, parses all .rc files, and runs the action queue: early-init → init → late-init (which triggers early-fs, fs, post-fs, late-fs, post-fs-data, zygote-start, early-boot, boot). It then supervises services forever, reaping children and restarting them per policy.

What second stage starts, in order of importance

  • ueventd - creates /dev nodes (early-init).
  • servicemanager, hwservicemanager, vndservicemanager - Binder registries (init).
  • logd, lmkd, vold (storage, FBE and /data mounting), keystore2, apexd (activates APEX modules so ART and other mainline modules are available).
  • Vendor HALs - health, power, sensors, graphics composer, audio, radio - usually class hal or class main.
  • surfaceflinger and bootanim - display compositor and boot animation.
  • Zygote - on zygote-start, after /data is mounted (device-encrypted storage is available; credential-encrypted storage stays locked until the user unlocks).

The .rc language

init reads /system/etc/init/hw/init.rc and all .rc files in /{system,system_ext,vendor,odm,product}/etc/init/. Four kinds of statement: actions (on <trigger> followed by commands), services (programs init starts and supervises), imports, and options that modify services.

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart surfaceflinger
    task_profiles ProcessCapacityHigh MaxPerformance
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

service vendor.foo-hal /vendor/bin/hw/vendor.foo-service
    class hal
    user system
    group system
    # crash more than 4 times in 4 minutes -> reboot to bootloader (or target)
    critical

on post-fs-data
    mkdir /data/vendor/foo 0770 system system

on property:sys.boot_completed=1
    write /sys/class/foo/boot_done 1
    start vendor.foo-late
Service optionMeaning
classGroup started together: core, hal, main, late_start, charger
user / group / capabilitiesDrop privileges before exec
seclabelExplicit SELinux domain (normally derived from the file label)
oneshotDo not restart on exit
disabledNot started by its class; must be started explicitly (start or ctl.start)
criticalIf it crashes more than 4 times in 4 minutes, reboot into the bootloader (or a configured target)
onrestartCommand to run when the service restarts
socketCreate a Unix socket in /dev/socket and pass it to the service
task_profiles / priority / ioprioCgroup, CPU and I/O scheduling settings

The property service

Properties are a system-wide key/value store in shared memory, readable by everyone (subject to SELinux) and writable only through init's property service.

PrefixBehaviorExample
ro.*Read-only, set once (from build.prop files or ro.boot.* from the bootloader)ro.build.fingerprint, ro.boot.slot_suffix
persist.*Survives reboot (stored in /data/property/persistent_properties, available after /data is up)persist.sys.timezone
sys.*, vendor.*Runtime statesys.boot_completed
ctl.*Control commands to initsetprop ctl.start bootanim
init.svc.*Service state published by initinit.svc.zygote=running
ro.boottime.*Timestamp (ns) when each service startedro.boottime.zygote

Access is controlled by property_contexts: each property prefix has an SELinux label, and a process needs set permission on that label to write it.

SELinux in the boot path

SELinux is mandatory access control: every process runs in a domain and every file, socket and property has a type; only explicitly allowed interactions succeed. Since Android 5 all domains are enforcing. A new daemon or HAL with no policy, a mislabeled file, or a missing allow rule causes an avc: denied message and the operation fails, which can stall boot if the daemon is critical.

avc: denied { read } for pid=512 comm="foo-hal" name="calib.bin" dev="sda12"
    scontext=u:r:hal_foo_default:s0 tcontext=u:object_r:vendor_data_file:s0 tclass=file permissive=0

# find denials
adb shell dmesg | grep avc
adb logcat -b all | grep avc
# suggest rules (review them - never paste blindly)
audit2allow -i denials.txt

Fix denials by giving the file the right label (file_contexts), putting the daemon in its own domain (init_daemon_domain(hal_foo_default)), and adding the minimal allow rule in the vendor .te file. Never ship permissive, and avoid broad rules that neverallow checks and CTS will reject.

Common pitfall Several notes say second-stage init "loads SELinux policy". The policy is actually loaded in the separate selinux_setup phase between first and second stage. Also, persist.* properties are not available before /data is mounted, so early services must not depend on them.
Interview angle Platform interviewers ask you to write or read an .rc snippet, explain class/oneshot/critical, list the trigger order (early-init, init, late-init, post-fs-data, zygote-start, boot), and debug an avc: denied line by naming the source domain, target type, class and permission. Knowing that init restarts services and that critical reboots the device is a common differentiator.

ueventd and the service managers

Before any framework code can run, two pieces of plumbing must exist: device nodes in /dev so processes can open hardware, and a Binder registry so processes can find each other.

Analogy

ueventd is the building's locksmith: whenever a new room appears, it installs a door with the right lock and hands keys only to the right people. servicemanager is the reception switchboard: services register their extension, and callers ask reception to connect them by name. The new rooms are kernel devices announced by uevents, the locks and keys are the owner and permission rules in ueventd.rc, and the extensions are Binder handles.

ueventd

  • Started very early (in early-init). It is actually the init binary running in ueventd mode.
  • Listens on a netlink socket for kernel uevents (device add/remove) and creates /dev nodes with owner, group, mode and SELinux label from ueventd.rc files (/system/etc/ueventd.rc, /vendor/etc/ueventd.rc).
  • At start it performs coldboot: walks /sys and replays uevents for devices that were probed before it started, then init waits for /dev/.coldboot_done.
  • Serves firmware loading requests from drivers (request_firmware()) by copying files from /vendor/firmware, /odm/firmware and similar paths.
  • A wrong ueventd.rc entry leads to "permission denied" when a HAL opens its device node - a classic boot or bring-up issue.
# ueventd.rc: node  mode  owner  group
/dev/foo_sensor   0660   system   system
subsystem foo
    devname uevent_devname
    dirname /dev/foo

servicemanager and friends

RegistryBinder deviceUsed by
servicemanager/dev/binderFramework and AIDL services (including stable AIDL vendor HALs)
hwservicemanager/dev/hwbinderLegacy HIDL HALs
vndservicemanager/dev/vndbinderVendor-to-vendor services

servicemanager becomes the Binder context manager (handle 0), the one Binder object every process can reach without a lookup. Services call addService(name, binder); clients call getService/waitForService. It checks SELinux service_contexts for who may register and find each name, and checks VINTF manifests for declared HALs. It must start before system_server so that the framework services can register. Lazy HALs can be started on demand when a client asks for them.

adb shell service list            # registered Binder services
adb shell lshal                   # HIDL HALs
adb shell dumpsys -l              # services that support dumpsys
Interview angle "What is servicemanager's role at boot?" Answer: Binder context manager at handle 0, the name directory for services, gated by SELinux service contexts; started by init early because system_server and HALs register with it. For ueventd, mention coldboot, ueventd.rc permissions and firmware loading.

Zygote: the app factory

init starts Zygote on the zygote-start trigger by running app_process64 with --zygote --start-system-server. The init service is named zygote even on 64-bit devices (the rc file is init.zygote64.rc or init.zygote64_32.rc; that "64" is the binary, not the service name). On mixed-ABI devices a second service named zygote_secondary runs app_process32 and listens on /dev/socket/zygote_secondary. Zygote's job is to create a warm, pre-initialized ART process that can be cloned very cheaply.

Analogy

Zygote is like a bakery that keeps a batch of dough already mixed, proofed and ready. When an order arrives, the baker tears off a portion and shapes it, instead of milling flour for every loaf. The ready dough is the preloaded ART runtime with classes and resources, tearing off a portion is fork(), and the fact that portions share the same starter until reshaped is copy-on-write memory.

Zygote startup sequence

  1. app_process and AndroidRuntime Native app_process creates AndroidRuntime, which starts the ART VM (JNI_CreateJavaVM), maps the boot image (boot.art/boot.oat precompiled framework code from the ART APEX and /system/framework) and registers JNI methods.
  2. ZygoteInit.main() Enters Java: com.android.internal.os.ZygoteInit creates the zygote server socket (/dev/socket/zygote).
  3. Preload preload() loads classes listed in /system/etc/preloaded-classes, common resources and drawables, shared native libraries (for example libandroid, libjnigraphics), OpenGL/graphics drivers, WebView and text resources. The logcat event boot_progress_preload_start/_end brackets this step.
  4. Fork system_server forkSystemServer() forks the first child with uid 1000 (system), fixed capabilities and GIDs, and runs com.android.server.SystemServer.main() in it.
  5. Wait for requests runSelectLoop() listens on the socket. When ActivityManagerService needs a new app process, ZygoteProcess sends the arguments (uid, gids, SELinux info, app data dir, entry class android.app.ActivityThread) and Zygote forks. Android 10+ can also keep a pool of pre-forked USAP (unspecialized app process) children to cut fork latency.

Why fork instead of starting fresh?

  • Speed: VM startup and class loading take seconds; fork takes milliseconds.
  • Memory: preloaded classes, the boot image and resources are shared copy-on-write across all apps; physical pages are only duplicated when written.
  • Consistency: every app starts from the same known-good runtime state.
  • Trade-off: the preload list affects boot time and every app's memory footprint. Too much preload slows boot; too little slows every app start.
Common pitfall Zygote is single-threaded at fork time by design: forking a multi-threaded process copies only the calling thread and can leave locks held by vanished threads. That is why Zygote stops its helper threads (such as the heap task daemon) before each fork and why preloaded code must not start threads.
Interview angle "Why does Android use Zygote?" is a staple. Strong answers cover preload + fork + copy-on-write, the socket protocol from AMS, that Zygote also forks system_server, the 64/32-bit zygotes, USAP pool, and what happens if Zygote dies: init restarts it, and its onrestart lines restart dependent services, which appears as a soft reboot (the framework restarts but the kernel does not).

system_server, boot animation and BOOT_COMPLETED

system_server is the single process that hosts most Android framework services as threads: ActivityManagerService (AMS), PackageManagerService (PMS), WindowManagerService (WMS), PowerManagerService, DisplayManagerService, InputManagerService, ConnectivityService, SensorService and about a hundred more.

Analogy

system_server is the head office of a company that opens department by department: first the executives and the payroll office (bootstrap services), then the essential support teams (core services), then everyone else (other services). A PA announces each milestone to the whole office ("phones are working", "customers may now enter"), and the doors open only at the final announcement. The departments are system services, the milestones are boot phases, and "customers may enter" is BOOT_COMPLETED.

SystemServer.run()

  1. Prepare Sets up the main Looper, loads libandroid_servers, creates the system context and SystemServiceManager.
  2. startBootstrapServices() Services everything else depends on: Watchdog, Installer (connection to installd), ActivityManagerService and ActivityTaskManagerService, PowerManagerService, DisplayManagerService, PackageManagerService (scans all packages - traditionally the slowest part, boot_progress_pms_start/_ready), UserManager, sensor privacy, overlay manager.
  3. startCoreServices() BatteryService, UsageStatsService, WebViewUpdateService, BinderCallsStats and similar.
  4. startOtherServices() WindowManagerService, InputManagerService, ConnectivityService and networking, Telephony registry, AudioService, NotificationManager, LocationManager, and many more. Then AMS.systemReady().
  5. startApexServices() (Android 13+) Services that live in mainline APEX modules.
  6. Boot phases SystemServiceManager.startBootPhase() notifies every service as milestones are reached (see table).
  7. Home and SystemUI In systemReady() AMS starts SystemUI and persistent apps (for example com.android.phone), then launches the Home activity (Launcher, or on first boot the setup wizard).
Boot phase constantValueMeaning
PHASE_WAIT_FOR_DEFAULT_DISPLAY100Default display is available
PHASE_LOCK_SETTINGS_READY480Lock settings data can be read
PHASE_SYSTEM_SERVICES_READY500Core services can be safely called
PHASE_DEVICE_SPECIFIC_SERVICES_READY520OEM/device services are ready
PHASE_ACTIVITY_MANAGER_READY550AMS is ready to broadcast
PHASE_THIRD_PARTY_APPS_CAN_START600Apps may be started and bind to services
PHASE_BOOT_COMPLETED1000System services are told boot is complete (Home is up). This is not the same instant as ACTION_BOOT_COMPLETED on an FBE device with a lock screen

The boot animation

The bootanim service (/system/bin/bootanimation) is a native process that draws through SurfaceFlinger. It is started once SurfaceFlinger is up (SurfaceFlinger sets ctl.start bootanim) and plays bootanimation.zip from /product/media or /system/media (a desc.txt plus folders of frames). When the Launcher has drawn its first frame, WindowManagerService's performEnableScreen() sets service.bootanim.exit=1, the animation finishes its current loop and exits, and the screen shows Home.

Because the animation is native and independent of Java, an animation that plays forever means SurfaceFlinger and the kernel are fine but the framework never reached the point of showing Home: Zygote, system_server, PMS, or a required service is crashing or blocked.

BOOT_COMPLETED and Direct Boot

  • With file-based encryption (FBE), storage has two classes: device-encrypted (DE), available right after boot, and credential-encrypted (CE), available only after the user unlocks with PIN/pattern/password.
  • When system_server finishes booting, AMS sends ACTION_LOCKED_BOOT_COMPLETED to Direct Boot-aware apps (alarm clock, telephony, accessibility) that can run with DE storage.
  • The property sys.boot_completed=1 is set when the system user finishes booting (around the locked-boot point), even if the screen is still locked, so scripts that wait for it work on a locked device.
  • After the first user unlock, CE storage is unlocked and AMS sends ACTION_BOOT_COMPLETED to all apps with a boot receiver.
  • Older full-disk encryption (FDE) required a password before the framework could even start fully; it was deprecated in Android 10 and removed in Android 13.
adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done'
adb logcat -b events -d | grep boot_progress
#  boot_progress_start           (Zygote begins)
#  boot_progress_preload_start / _end
#  boot_progress_system_run      (SystemServer.run)
#  boot_progress_pms_start / _system_scan_start / _data_scan_start / _scan_end / _ready
#  boot_progress_ams_ready
#  boot_progress_enable_screen   (boot animation about to exit)
Common pitfall The source notes sometimes say BOOT_COMPLETED fires as soon as the Launcher is visible. On FBE devices with a lock screen, apps that are not Direct Boot-aware only receive it after the user unlocks. Apps doing heavy work in BOOT_COMPLETED receivers also slow down the post-boot experience.
Interview angle Expect "What lives in system_server and why is it one process?" (cheap in-process calls, shared memory from Zygote, at the cost of a large blast radius: if it crashes, the whole framework restarts). Deeper probes: the three start*Services methods, boot phases, the Watchdog that kills system_server when a core thread hangs, how the boot animation is stopped, and the difference between LOCKED_BOOT_COMPLETED and BOOT_COMPLETED.

Debugging no-boot and bootloops

The first question is always "which stage died?" The visible symptom tells you roughly where to look, and each stage has its own logs.

Analogy

Debugging a no-boot is like finding where a relay race broke down by asking which runner last held the baton. If nobody left the starting blocks, look at the first runner; if the baton reached the third runner and was dropped, you ignore the first two. Each runner is a boot stage, the baton is control flow, and the "who last held it" clue is the visible symptom (no logo, logo only, endless animation) plus the last log line.

Symptom to stage

SymptomLikely stageTypical causesWhere to look
Completely dead, no vibration, no logo; PC sees 9008PBL / XBLCorrupt or unsigned XBL, wrong-SoC or wrong-key image, blank storage, anti-rollback violationEDL, Firehose logs, UART
Dead, not even EDLHardware / PMICPower rail fault, battery, PMIC, SoCCurrent draw on bench supply, PMIC PON/fault registers
Hangs before logo, sometimes randomXBLDDR training failure, bad xbl_config, marginal memoryXBL UART log, DDR training logs
Logo, then drops to fastbootABLNo bootable slot, both slots exhausted tries, boot image missingfastboot getvar all, slot attributes
"Device is corrupt" / red screenABL AVB or dm-veritySignature or hash mismatch, rollback index too low, verity corruptionavbtool info_image, ABL log, ro.boot.veritymode
Logo, then reboot (no boot animation)Kernel / early initKernel panic, DT mismatch, driver probe crash, cannot mount system, missing first-stage moduleUART console, /sys/fs/pstore/console-ramoops-0, last_kmsg
Logo stuck, no rebootKernel / first-stage initWaiting for a block device that never appears, deadlocked driverUART, dmesg via early adb if available
Boot animation foreverZygote / system_serverZygote crash, system_server exception, PMS failure, missing HAL that a service waits on, SELinux denial of a critical daemonadb logcat -b all, boot_progress events, tombstones
Animation, reboots, repeatssystem_server or critical serviceWatchdog kill, crash loop, a critical service crashinglogcat crash buffer, /data/system/dropbox, sys.boot.reason
Boots to recovery with "Try again / Factory reset"Rescue PartyRepeated crashes of system_server or persistent appsRecovery log, dropbox
Boots after OTA on the old versionA/B rollbackNew slot failed before markBootSuccessfulbootctl, update_engine logs

Logs and tools per stage

StageEvidence
PBL / XBL / ABLUART serial console (needs a debug board or test points), fastboot variables, ABL logs saved to a partition or IMEM, EDL Firehose logs
KernelUART with console=, dmesg, pstore/ramoops (/sys/fs/pstore/), /proc/last_kmsg on older devices, initcall_debug, ramdumps (Qualcomm: analyse with QCAP/crash tools)
initdmesg | grep init: (init logs to kmsg), getprop | grep init.svc, ro.boottime.*
Native servicestombstones in /data/tombstones, debuggerd, logcat crash buffer
Frameworkadb logcat -b all, -b events (boot_progress_*, am_crash), /data/system/dropbox, /data/anr, Watchdog traces
Boot reasongetprop sys.boot.reason, ro.boot.bootreason, persist.sys.boot.reason.history
adb wait-for-device
adb shell dmesg -w                         # live kernel + init log
adb logcat -b all -v threadtime > boot.txt
adb shell cat /sys/fs/pstore/console-ramoops-0   # log from the previous (crashed) boot
adb shell getprop sys.boot.reason
adb shell getprop | grep -E "init.svc|boottime"
adb bugreport bugreport.zip                # everything, once adb works
fastboot getvar all                        # slot + lock state from the bootloader

A systematic approach

  1. Locate the stage Use the symptom table; get a UART log if adb is not available yet. Establish the last good log line.
  2. Classify the failure Kernel panic vs init service crash loop vs SELinux denial vs system_server exception vs verified-boot rejection. Each has a distinct signature: Kernel panic - not syncing, init: Service 'x' ... exited with status, avc: denied, FATAL EXCEPTION IN SYSTEM PROCESS, AVB error strings.
  3. Diff against known-good What changed: kernel config, DT/DTBO, a new driver or module, SELinux policy, an .rc file, a vendor/system mismatch after a partial flash? A/B helps: does the other slot still boot?
  4. Bisect Flash only one image at a time (boot, vendor_boot, vendor, system) to see which image breaks boot; fastboot boot a test kernel without flashing.
  5. Get more visibility Temporarily enable androidboot.selinux=permissive on a userdebug build to confirm a policy issue; add initcall_debug, ignore_loglevel; disable verity on debug builds to test a modified partition.
  6. Fix and prevent Fix the root cause, then add a test (boot test in CI, CTS/VTS, SELinux neverallow checks) so it does not return.

Bootloop protection built into Android

  • init critical services: more than 4 crashes in 4 minutes reboots to the bootloader or recovery instead of looping forever.
  • Watchdog in system_server: if a core thread (for example the main thread or a lock monitor) is blocked for about 60 seconds, it dumps stacks and kills system_server, which restarts the framework.
  • Rescue Party: detects repeated crashes of system_server or persistent apps and escalates - reset untrusted settings, reset all settings, then reboot into recovery offering a factory reset.
  • A/B tries counter: an OTA slot that never completes boot is abandoned automatically.
  • APEX rollback: a mainline module update that causes a crash loop is rolled back by the package watchdog.
Tip Always record the kernel log from the previous boot (pstore/ramoops) when chasing a reboot loop, because by the time adb is up, the crash that caused the reboot is gone from dmesg. Enable ramoops in the DT (reserved-memory node) early in bring-up.
Interview angle Scenario questions dominate here: "Device stuck at the logo after a kernel change", "boot animation forever after a vendor HAL update", "bootloop only on some units". Interviewers want the stage-first method, the right logs per stage, the signature strings, bisecting with A/B and single-image flashes, and a note about prevention. Avoid jumping straight to a fix without evidence.

Boot-time optimization

Boot time matters for user experience, factory throughput and OTA reboots. The rule is measure first, per stage, then attack the biggest block.

Analogy

Speeding up boot is like shortening a morning routine: first time each step with a stopwatch, then do things in parallel (make coffee while showering), skip what can wait until later (read the news on the train), and prepare the night before (lay out clothes). The stopwatch is bootchart/Perfetto, parallelism is async probing and concurrent init services, deferring is lazy HALs and deferred initcalls, and preparing the night before is caching DDR training and precompiling apps.

Measure

# kernel: timestamps and slow initcalls
adb shell dmesg | grep -E "Freeing unused kernel|init: "
# add to cmdline on a debug build:  initcall_debug printk.time=1

# init services: start times in ns since boot
adb shell getprop | grep ro.boottime

# framework milestones
adb logcat -b events -d | grep boot_progress

# bootchart (userspace CPU/disk per process)
adb shell touch /data/bootchart/enabled
adb reboot
system/core/init/grab-bootchart.sh

# Perfetto boot trace (Android 14+)
adb shell setprop persist.debug.perfetto.boottrace 1
# push a config to /data/misc/perfetto-configs/boottrace.pbtxt, reboot, pull the trace

Where time goes and what to do

StageCommon costsOptimizations
BootloadersDDR training, verbose UART logging, display init, loading large images, hashingCache DDR training results, reduce UART logging on user builds, use hardware crypto, avoid unneeded peripheral init, keep boot images small (LZ4)
KernelSynchronous driver probes, slow console on UART, many built-in drivers, deferred-probe stormsAsync probe (PROBE_PREFER_ASYNCHRONOUS), move non-critical drivers to modules loaded later, quiet console, fix probe ordering (fw_devlink), LZ4 kernel
First-stage initLoading many modules serially, waiting for block devicesLoad only boot-critical modules from vendor_boot, parallel module loading, correct modules.load order
init / nativeBlocking exec/wait commands in .rc, services started too early, slow HALsRemove blocking commands, start non-critical services on sys.boot_completed, lazy HALs, set task_profiles/priorities
ZygotePreloading classes and resourcesTune the preloaded-classes list with profiles; keep boot image and profiles up to date
system_serverPMS package scanning, services doing I/O on the boot pathMove work off the critical path (post BOOT_COMPLETED or background threads), cache package scan results, trim OEM services
First boot / after OTAdexopt of all apps, FBE key setup, APEX activationPre-compiled apps via cloud profiles, otapreopt during A/B install, fast UFS
Common pitfall Optimizing the wrong thing. A 200 ms kernel win means nothing if PMS scanning takes 6 seconds. Also, "faster" measured on a warm, previously booted device is not the same as the first boot after a factory reset or an OTA.
Interview angle "How would you reduce boot time by 30%?" Answer as a process: define the metric (power key to boot_completed or to Home drawn), measure per stage with the right tools, pick the largest blocks, apply stage-specific fixes, and guard the result with an automated boot-time regression test.

Boot on Wear OS

Wear OS runs the same Android boot chain (PBL → XBL → ABL → kernel → init → Zygote → system_server → home/watch face) with the same verified boot, SELinux and A/B or virtual A/B updates. The differences come from the hardware and the tight power budget.

Analogy

A watch booting is like opening a small corner shop instead of a department store: same opening checklist, fewer shelves, and a night-shift assistant who never goes home. The checklist is the identical boot chain, the fewer shelves are the smaller image and RAM, and the night-shift assistant is the always-on co-processor that keeps simple functions running while the main processor sleeps.

Dual-processor design

Snapdragon W-series platforms pair the main application processor with an always-on (AON) low-power co-processor or sensor hub (for example the QCC5100 on W5+ Gen 1). The co-processor has its own firmware and boot, and handles ambient display, step counting and sensor batching while the AP sleeps. Boot and power management must coordinate both.

Power-budgeted boot

A tiny battery makes cold boot, first-boot dexopt and resume from deep sleep real power costs. Fast resume matters more than on a phone, and boot time and idle residency are tracked KPIs.

Smaller image

Less RAM and flash, eMMC (often ePoP, stacked on the SoC) rather than UFS, a trimmed framework and watch-specific HALs (sensors, display, haptics, health). Zygote preload and system_server services are tuned down accordingly.

Charger mode matters

Watches spend a lot of time on the charger. Off-mode charging (androidboot.mode=charger) and a correct transition from charger mode to full boot are frequent bring-up issues.

OTA windows

Same A/B or virtual A/B mechanism, but installs are gated by battery level, charging and connectivity (typically "update overnight while charging on Wi-Fi").

Boot to watch face

The "home" is the watch face and Tiles, not a phone launcher. Pairing and Data Layer sync with the companion phone start after boot and are not part of boot completion.

Interview angle For wearable roles, say "It's the same Android boot chain; the integration challenge is coordinating the always-on co-processor firmware with the AP, keeping cold boot and resume within a tight power budget, and handling charger-mode and OTA constraints." Then be ready to go into any standard stage.

Userspace reboot

A full reboot walks the whole chain again (PMIC, PBL, XBL, ABL, kernel). From Android 11, the system can instead restart only userspace: init re-execs itself, tears down and restarts every native service, Zygote and system_server, and the kernel and hardware keep running. The screen goes through a boot animation, but you skip bootloader and kernel bring-up, so it is much faster than a cold reboot.

  • Triggered by sys.powerctl=reboot,userspace (what adb reboot userspace / some Rescue Party and module-update paths use).
  • init kills services, unmounts what it can, then execs a new init that re-runs second-stage bring-up. The kernel, loaded modules and most drivers stay as they were.
  • Use it when the failure is in the framework or a userspace daemon (a bad Mainline module, a stuck system_server) and the kernel is healthy. Do not use it to recover from a kernel or driver hang — that still needs a real reboot or a watchdog reset.
  • Debugging a userspace reboot looks like a soft reboot: you will see init restart and boot_progress_* again, but dmesg will not show a new kernel start, and sys.boot.reason / reboot history will say userspace.
Common pitfall Calling every framework restart a "userspace reboot". A Zygote/system_server crash is a soft reboot of the Java world only (init keeps running). A userspace reboot restarts init itself and every native daemon as well. A Watchdog kill of system_server is the former; adb reboot userspace is the latter.
Interview angle "What is the difference between a kernel reboot, a userspace reboot and a system_server crash?" Three different blast radii: hardware+kernel+userspace; userspace only; Java framework only. Name who restarts and who does not in each case.

Quick revision

  • Boot chain: PMIC → PBL → XBL/SBL → ABL → kernel → init → Zygote → system_server → SystemUI/Launcher → BOOT_COMPLETED.
  • Trust chain: OEM PK hash in QFPROM → PBL verifies XBL → XBL verifies TZ/hyp/ABL → ABL runs AVB on vbmeta/boot/dtbo → kernel dm-verity on system/vendor.
  • The PMIC sequences the rails, starts the clock, releases CPU reset and records the power-on reason.
  • PBL lives in SoC mask ROM, runs at EL3 from IMEM/SRAM on the 19.2 MHz XO, and can never be updated - that is why it is the root of trust.
  • PBL uses SRAM because DDR is untrained; DDR training is too large and board-specific for ROM.
  • QFPROM eFuses hold secure-boot enable, OEM PK hash, anti-rollback version and JTAG disable.
  • PBL finds XBL via strap pins and fuses: UFS boot LUN or eMMC boot partition.
  • Verification failure in PBL means halt or EDL (QDLoader 9008, USB 05c6:9008), which still requires a signed Firehose programmer.
  • eMMC: parallel, half duplex, ~400 MB/s HS400. UFS: serial M-PHY/UniPro, full duplex, deep SCSI queue, ~2.1 GB/s (3.1) to ~4.2 GB/s (4.0).
  • XBL's key job is DDR training; it also sets up PMIC/clocks and loads TrustZone/QTEE, the hypervisor, AOP firmware and ABL.
  • TrustZone splits normal and secure worlds; the kernel reaches the TEE through SMC calls; EL3 is the secure monitor.
  • ABL (UEFI app, older LK/aboot) picks boot mode and A/B slot, runs AVB, passes boot state to the TEE, builds bootconfig and loads kernel + ramdisks + DTB.
  • fastboot = bootloader flashing; fastbootd = user-space flashing for super; recovery = OTA/sideload/reset; EDL = ROM-level rescue.
  • vbmeta contains hash descriptors (small images), hashtree descriptors (dm-verity root hashes), chain descriptors (delegated keys) and a rollback index.
  • AVB rollback indexes live in RPMB and are raised only after the new slot is marked successful.
  • dm-verity checks each 4 KB block on read against a Merkle tree whose root hash comes from signed vbmeta; modes restart/eio/logging.
  • Boot states: GREEN locked + OEM key, YELLOW locked + custom key, ORANGE unlocked, RED verification failed.
  • Unlocking requires OEM unlocking enabled, wipes userdata, and is reported to KeyMint attestation.
  • GKI split: boot = generic kernel, init_boot = generic ramdisk (Android 13+), vendor_boot = vendor ramdisk + DTB + early modules, vendor_dlkm = other modules.
  • super holds logical partitions (system, vendor, product ...) mapped with dm-linear from LP metadata.
  • A/B: update inactive slot, setActiveBootSlot, tries counter decremented by the bootloader, markBootSuccessful by user space, automatic rollback.
  • Virtual A/B keeps one copy of dynamic partitions and writes COW snapshots, merged after a successful boot; rollback is impossible once the merge starts.
  • Kernel: head.S enables MMU, start_kernel() parses DT and sets up scheduler/IRQs, initcalls probe drivers (with deferred probe), ramdisk unpacked, /init runs as PID 1.
  • init phases: first stage (mount, dm-verity, super) → selinux_setup (load policy, enforce) → second stage (properties, .rc, services).
  • Trigger order: early-init, init, late-init (fs, post-fs, post-fs-data, zygote-start, boot).
  • critical service: more than 4 crashes in 4 minutes reboots to bootloader/recovery.
  • ueventd creates /dev nodes from ueventd.rc, does coldboot and loads firmware; servicemanager is Binder handle 0.
  • Zygote: the init service is named zygote (binary app_process64); a 32-bit helper is zygote_secondary. It preloads ART/classes, forks system_server, then forks apps (copy-on-write, optional USAP pool).
  • system_server: startBootstrapServices, startCoreServices, startOtherServices, boot phases 100 to 1000, then systemReady starts SystemUI and Home.
  • Boot animation is native; WMS sets service.bootanim.exit=1 when Home is drawn. Endless animation means a framework-level failure.
  • FBE: LOCKED_BOOT_COMPLETED for Direct Boot apps with DE storage; BOOT_COMPLETED after the user unlocks CE storage.
  • Debug by stage: no logo = bootloader, logo only = kernel/early init, endless animation = Zygote/system_server, recovery prompt = Rescue Party.
  • Previous-boot kernel log: pstore/ramoops; framework: logcat -b all, boot_progress events, tombstones, dropbox, sys.boot.reason.
  • Boot-time work: measure per stage (dmesg, ro.boottime, bootchart, Perfetto), then async probe, defer non-critical work, trim preloads and PMS work.
  • Wear OS: same chain plus AON co-processor coordination, eMMC, smaller image, charger mode and power-gated OTAs.
  • Userspace reboot (Android 11+): init re-execs and restarts all userspace; the kernel stays up. Different from a system_server crash (soft reboot of the Java world only) and from a full kernel reboot.

Glossary

A/B slots
Two copies (_a, _b) of updatable partitions so an OTA can install to the inactive copy and roll back on failure.
ABL
Android Boot Loader. Qualcomm's Android-aware bootloader (a UEFI application) that handles boot modes, slots, AVB and fastboot.
AOP
Always-On Processor. A small Qualcomm core that manages power resources such as rails and clocks; its firmware is loaded by XBL.
AVB
Android Verified Boot 2.0. The system that verifies vbmeta, boot images and partition hash trees before and during boot.
bootconfig
Android 12+ mechanism for passing androidboot.* parameters from the bootloader to the kernel, separate from the kernel command line.
Boot control HAL
The IBootControl interface used by update_engine and bootctl to read and set slot attributes.
Chain of trust
A sequence where each boot stage verifies the next before running it, anchored in an immutable hardware root.
Copy-on-write (COW)
Memory or storage pages are shared until someone writes, then a private copy is made. Used by Zygote forks and virtual A/B snapshots.
DDR training
Calibration of the LPDDR interface (impedance, CA training, Vref, DQS timing) done by XBL before DRAM can be used.
Device tree (DTB/DTBO)
A data structure describing the board's hardware for the kernel; DTBO overlays patch it for variants.
dm-verity
Device-mapper target that verifies each block of a read-only partition against a hash tree at read time.
EDL
Emergency Download mode. Qualcomm ROM-level USB rescue mode (QDLoader 9008) that accepts a signed Firehose programmer.
eFuse / QFPROM
One-time-programmable fuses in the SoC that store the OEM key hash, secure-boot enable, anti-rollback and debug settings.
eMMC
embedded MultiMediaCard. Parallel, half-duplex managed NAND storage, up to about 400 MB/s.
Exception level (EL0-EL3)
Arm privilege levels: apps (EL0), kernel (EL1), hypervisor (EL2), secure monitor (EL3).
Fastboot
USB protocol and bootloader mode for flashing partitions, switching slots and changing the lock state.
fastbootd
User-space fastboot running in recovery, required for flashing logical partitions inside super.
FBE
File-Based Encryption. Per-file encryption with device-encrypted and credential-encrypted storage, enabling Direct Boot.
Firehose
Signed Qualcomm programmer loaded in EDL mode that reads and writes flash using an XML protocol.
GKI
Generic Kernel Image. Google-built common kernel with vendor code in loadable modules against a stable KMI.
IMEM / SRAM
Small on-chip static RAM usable immediately after reset; used by PBL and early XBL before DDR works.
init
PID 1. Mounts partitions, loads SELinux policy, runs the property service and starts and supervises all native services.
init_boot
Partition holding the generic ramdisk with first-stage init (devices launching with Android 13+).
KeyMint
TEE-backed key management HAL (successor to Keymaster) that binds keys to the verified-boot state.
LK
Little Kernel. A small embedded OS used as the base of older Qualcomm (aboot) and MediaTek bootloaders.
Mask ROM
Read-only memory whose content is fixed during chip manufacture; holds the PBL.
PBL
Primary Boot Loader. The first code executed after reset, stored in SoC ROM; loads and verifies XBL.
PMIC
Power Management IC. Sequences voltage rails, releases CPU reset, handles charging and records the power-on reason.
Property service
init's system-wide key/value store (ro.*, persist.*, sys.*) protected by SELinux property contexts.
QTEE
Qualcomm Trusted Execution Environment. The secure OS in TrustZone that hosts trusted apps.
Rescue Party
Framework mechanism that detects crash loops and escalates from resetting settings to offering a factory reset.
Rollback index
Version number in vbmeta compared with a value in tamper-evident storage to block downgrades.
RPMB
Replay Protected Memory Block. Authenticated storage area in UFS/eMMC used by the TEE for rollback counters and secrets.
SELinux
Mandatory access control in the kernel; Android runs all domains in enforcing mode, and denials appear as avc: denied.
servicemanager
Binder context manager (handle 0) where services register by name and clients look them up.
super
Physical partition that contains resizable logical partitions such as system, vendor and product.
system_server
The process, forked from Zygote, that hosts most Android framework services.
TrustZone
Arm hardware security extension that isolates a secure world from the normal world.
ueventd
Daemon that creates /dev nodes from kernel uevents, applies permissions and serves firmware requests.
Userspace reboot
Android 11+ restart of init and all userspace without bringing down the kernel (faster than a cold reboot).
UFS
Universal Flash Storage. Serial, full-duplex storage with a SCSI command queue, much faster than eMMC.
vbmeta
Signed AVB metadata partition with descriptors for every verified partition.
vendor_boot
Partition with the vendor ramdisk, DTB, early kernel modules and vendor bootconfig (Android 11+).
Virtual A/B
A/B updates using copy-on-write snapshots of a single copy of dynamic partitions, merged after success.
XBL / SBL
eXtensible (formerly Secondary) Boot Loader. Trains DDR, loads the secure world and ABL.
Zygote
Pre-initialized ART process that preloads framework code and forks system_server and every app. The init service is named zygote; a 32-bit helper is zygote_secondary.

Interview questions

Fundamentals

Trace everything that happens from pressing the power button to seeing the launcher.
  1. The PMIC sequences the power rails, starts the 19.2 MHz clock and releases the CPU reset.
  2. The PBL (in SoC ROM) sets up SRAM and basic clocks, finds XBL on UFS/eMMC, verifies its signature against the key hash in eFuses, and jumps to it.
  3. XBL trains DDR, configures PMIC and clocks, loads and verifies TrustZone/QTEE, the hypervisor and ABL.
  4. ABL picks the boot mode and the A/B slot, runs AVB on vbmeta/boot/dtbo, and loads the kernel, ramdisks and device tree into DDR.
  5. The kernel sets up the MMU, scheduler and interrupts, parses the device tree, probes drivers, unpacks the ramdisk and runs /init as PID 1.
  6. init mounts the partitions with dm-verity, loads SELinux policy, starts the property service, ueventd, servicemanager, HALs and daemons, then Zygote.
  7. Zygote starts ART, preloads classes and forks system_server.
  8. system_server starts about a hundred services, then SystemUI and the Launcher. The boot animation exits, sys.boot_completed=1 is set and LOCKED_BOOT_COMPLETED is sent to Direct Boot apps. BOOT_COMPLETED waits for the user to unlock CE storage on an FBE device with a lock screen.
What is the chain of trust and where is it anchored?

Each boot stage cryptographically verifies the signature of the next stage before executing it. The anchor (root of trust) is the immutable PBL in ROM together with a hash of the OEM root public key burned into one-time-programmable eFuses (QFPROM), so the start of the chain cannot be forged or changed by software. The chain continues PBL → XBL → TZ/ABL → vbmeta/boot via AVB → system/vendor via dm-verity at runtime.

What is the difference between the loading path and the trust path?

The loading path is who copies whom into memory and jumps to it: PBL → XBL → ABL → kernel → init → Zygote → system_server. The trust path is who verifies whom: eFuse key hash → XBL → ABL → AVB → dm-verity. They happen together but are different concepts - for example Zygote and system_server are part of loading but do not verify anything; their integrity comes from dm-verity protecting /system. Interviewers like candidates who separate them.

What is the PMIC's role at power-on?

The Power Management IC applies the SoC's voltage rails in the correct order and at the correct levels, starts the reference clock, waits for stability and then de-asserts the CPU reset. It also records the power-on reason (power key, charger insertion, RTC alarm, watchdog or warm reset), which later becomes part of the boot reason and can make the bootloader choose charger mode. Later stages (XBL, kernel regulator drivers) configure the rest of its rails, charging and battery monitoring.

What is the PBL and where is it stored?

The Primary Boot Loader is the first code the CPU executes after reset. It is stored in the SoC's Boot ROM (mask ROM), written into the silicon at manufacture. It sets up minimal clocks and on-chip SRAM, reads the security fuses, detects the boot device, loads XBL into SRAM, verifies it and jumps to it. If anything fails it halts or enters EDL.

Why can't the PBL be updated, and why is that a good thing?

It is physically part of the chip's mask ROM, so it cannot be flashed, erased or patched. That immutability is what makes it trustworthy as the root: no software attack can modify the first verifier. The downside is that a bug in PBL is permanent for that silicon revision, which is why ROM code is kept as small and simple as possible and all complex logic is pushed into signed, updatable later stages.

Why does the PBL run from SRAM instead of DDR?

At reset the DDR is not usable. LPDDR needs PHY impedance calibration, command/address training, Vref tuning, DQS timing alignment and temperature compensation first, which is complex, board-specific code. On-chip SRAM (IMEM) works immediately without calibration, so PBL uses it for its stack, heap, crypto buffers and as the load buffer for XBL. XBL then trains DDR.

What clock does the SoC start on?

The CPU starts on the external 19.2 MHz crystal oscillator (XO) on Qualcomm platforms. PBL configures a few basic PLLs to raise the core frequency into the low hundreds of MHz so loading and hashing XBL is fast enough. The full clock tree with all PLLs and bus clocks is set up later by XBL and the kernel's clock drivers.

What is QFPROM and what does it store?

QFPROM (Qualcomm Fuse Programmable ROM) is the block of one-time-programmable eFuses in the SoC. It stores the secure-boot enable bit, the hash of the OEM root public key (the root of trust), anti-rollback version counters, debug/JTAG disable bits and boot configuration. Because fuses can only be blown once, these values cannot be reversed by software.

What is the single most important thing XBL/SBL does?

DDR training and initialization - bringing up the main memory. Before XBL only a few hundred KB of on-chip SRAM exist. XBL also configures the PMIC and clocks, brings up full storage drivers, loads and starts the TrustZone secure world (QTEE), the hypervisor and helper firmware such as AOP, and then loads and verifies ABL.

What does ABL do that the earlier bootloaders do not?

ABL is the Android-aware stage. It selects the boot mode (normal, recovery, fastboot, charger, ramdump), picks the A/B slot, runs Android Verified Boot on vbmeta/boot/init_boot/vendor_boot/dtbo and shows the boot-state warning, passes the boot state to the TEE, builds the kernel command line and bootconfig, loads the kernel, ramdisks and device tree into DDR and jumps to the kernel. It also implements the fastboot protocol.

What is the difference between fastboot, fastbootd, recovery and EDL?
  • fastboot: a bootloader (ABL) mode for flashing physical partitions, switching slots and locking/unlocking over USB.
  • fastbootd: fastboot implemented in user space inside recovery (Android 10+), needed to flash logical partitions in super.
  • recovery: a minimal Android environment for applying OTAs, sideloading and factory reset.
  • EDL: Qualcomm's ROM-level emergency download mode (QDLoader 9008) for reflashing a bricked device with a signed Firehose programmer.
What is in boot.img?

A header (with the header version, sizes, load addresses and command line) plus the kernel image. Before Android 13 it also contained the generic ramdisk. On devices launching with Android 13+ with GKI, boot contains only the kernel; the generic ramdisk with /init is in init_boot, and the vendor ramdisk, DTB and early modules are in vendor_boot. Device-tree overlays are in dtbo.

What is the device tree and why does Android use it?

A device tree is a data structure (.dts compiled to .dtb) that describes the hardware - CPUs, memory, buses, interrupts, clocks, regulators, GPIOs and peripherals - so the kernel does not hard-code board details. One kernel binary can run on many boards, and drivers bind to nodes by their compatible string. DTBO overlays adjust the base tree for board variants and are selected and applied by the bootloader.

What is PID 1 on Android and what are init's stages?

PID 1 is /init, the first user-space process and the ancestor of all others. First stage mounts /dev, /proc, /sys, loads early modules, maps super, sets up dm-verity and mounts system/vendor. The selinux_setup phase loads SELinux policy and switches to enforcing. Second stage starts the property service, parses the .rc files, runs triggers and starts and supervises services including ueventd, servicemanager, HALs and Zygote.

What is Zygote and why fork instead of starting each app fresh?

Zygote is a warm ART process started by init via app_process. The init service is always named zygote (the 64-bit binary is app_process64; do not call the service zygote64). On mixed-ABI devices a second service zygote_secondary runs the 32-bit binary. It preloads common framework classes, resources and libraries once. New app processes are created by forking Zygote, so they inherit that state instantly and share its memory pages copy-on-write. This makes app start fast (milliseconds instead of seconds) and saves RAM because the framework is loaded once for all apps. Zygote also forks system_server.

What lives in system_server?

Most Android framework services, running as threads in one process: ActivityManagerService, ActivityTaskManagerService, PackageManagerService, WindowManagerService, PowerManagerService, DisplayManagerService, InputManagerService, ConnectivityService, AudioService, NotificationManagerService and many more. They register with servicemanager and clients reach them over Binder. When they are ready, system_server starts SystemUI and the Launcher.

What does BOOT_COMPLETED mean and when does it fire?

ACTION_BOOT_COMPLETED is the broadcast telling apps the system has fully booted and they may start background work. On file-based-encryption devices, ACTION_LOCKED_BOOT_COMPLETED is sent first to Direct Boot-aware apps while credential storage is still locked; BOOT_COMPLETED follows after the user unlocks. The property sys.boot_completed=1 is the usual script-level marker that the system user has finished booting.

What are A/B (seamless) updates?

The device has two copies of each updatable partition, slot _a and _b. An OTA installs to the inactive slot in the background while the user keeps using the active one; on reboot the bootloader boots the updated slot. If the new slot boots fully it is marked successful; if it fails repeatedly its retry counter runs out and the bootloader falls back to the old slot. Benefits: minimal downtime and no brick from a bad update; cost: extra storage.

What do the GREEN, YELLOW, ORANGE and RED boot states mean?
  • GREEN: locked, everything verified with the OEM key.
  • YELLOW: locked, verified with a user-installed custom root key; a warning shows the key fingerprint.
  • ORANGE: bootloader unlocked; verification results are not enforced; a warning is shown.
  • RED: locked and verification failed (or dm-verity corruption); the device refuses to boot or requires user action.
What is EDL / 9008 mode?

Emergency Download mode is a Qualcomm PBL feature. When the PBL cannot load a valid XBL, or when forced by a test point or command, it enumerates over USB as "Qualcomm HS-USB QDLoader 9008" (ID 05c6:9008). A host tool uploads a Firehose programmer using the Sahara protocol, and the programmer then reads and writes flash. On secure devices the PBL verifies the programmer's signature, so EDL cannot be used to run arbitrary code.

What is the difference between eMMC and UFS?

eMMC uses a parallel 8-bit bus, is half duplex, has a basic command queue and tops out at about 400 MB/s (HS400). UFS uses serial differential lanes (M-PHY with the UniPro protocol), is full duplex, has a deep SCSI command queue and reaches about 2.1 GB/s (UFS 3.1) to 4.2 GB/s (UFS 4.0). The bootloader lives in eMMC hardware boot partitions or in a UFS boot LUN. UFS dominates phones; eMMC remains common in wearables and low-cost devices.

What does ueventd do?

ueventd listens for kernel uevents and creates the /dev device nodes with the owner, group, mode and SELinux label defined in ueventd.rc files. At startup it does a coldboot pass, replaying uevents for devices that probed before it ran. It also serves firmware requests from drivers by loading files from the firmware directories. Wrong entries lead to permission errors when HALs open their devices.

What is servicemanager's role at boot?

servicemanager is the Binder context manager, reachable by every process as handle 0. Services register themselves by name with it and clients look them up, subject to SELinux service_contexts checks. init starts it early because system_server, HALs and native daemons all register with it. Its siblings are hwservicemanager (HIDL, /dev/hwbinder) and vndservicemanager (vendor, /dev/vndbinder).

What is dm-verity in one sentence, and why are system partitions read-only?

dm-verity is a kernel device-mapper target that checks every block of a partition against a signed hash tree when the block is read, so any modification is detected at runtime. The partitions must be read-only because any write would change a block's hash and immediately fail verification; changing them requires building and signing a new image (or disabling verity on a debug build).

Why are there so many bootloader stages instead of one?

Because hardware becomes available step by step. The first stage has only ROM and a little SRAM, so it must be tiny; its job is just to verify and load the next stage. Each later stage initializes more hardware (DDR, PMIC, storage, display, USB) to make room for a bigger, more capable next stage. It also keeps the immutable ROM minimal while complex, board-specific logic lives in signed, updatable images, which is better for both bring-up and security.

Going deeper

Walk through the PBL's steps in order.
  1. Fetch from the reset vector in Boot ROM (EL3 on Qualcomm AArch64).
  2. Run on the 19.2 MHz XO and raise the clock with basic PLLs.
  3. Set up IMEM/SRAM for stack, heap and buffers.
  4. Read QFPROM fuses and power up the SHA and RSA/ECC crypto engines.
  5. Detect the boot device via straps/fuses (UFS boot LUN or eMMC boot partition) and parse the GPT.
  6. Load XBL into SRAM and hash it in hardware.
  7. Verify the certificate chain against the OEM PK hash, the signature, and the anti-rollback version.
  8. Jump to XBL, or halt/enter EDL on failure.
How is an image signed and verified in Qualcomm secure boot?

At build time the image hash (SHA-256 over its segments) is signed with the OEM private key held in an HSM, and an X.509 certificate chain (root, attestation CA, attestation certificate) is attached. On the device the verifier hashes the image in hardware, hashes the root certificate and compares it with the OEM PK hash in QFPROM, walks the certificate chain, verifies the RSA or ECC signature over the image hash with the attestation public key, and checks the anti-rollback version. Only if all checks pass does it jump.

Why store a hash of the public key in fuses instead of the key itself?

Fuses are expensive in silicon area, and an RSA-4096 key is 512 bytes while a SHA-256 hash is 32 bytes. The full public key (or root certificate) is shipped with the image, and the verifier checks that its hash matches the fuses; an attacker cannot find a different key with the same hash, so security is equivalent. Some SoCs support several key-hash slots so a compromised key can be revoked.

What is anti-rollback protection and where is it enforced?

Anti-rollback prevents booting an older image that is validly signed but has known vulnerabilities. It exists at two levels. For SoC firmware (XBL, TZ, ABL), each image has a version compared with a fuse counter in QFPROM; the fuse is blown forward after an update. For Android partitions, AVB compares each vbmeta's rollback index with a value in tamper-evident storage (RPMB via the TEE), raised only after the new slot is marked successful.

What does DDR training actually involve?

It calibrates the physical interface between the SoC's memory controller and LPDDR: output driver and termination impedance (ZQ calibration), command/address training, write leveling, read and write DQ/DQS eye centering, Vref tuning, and clock-domain crossing calibration, plus temperature compensation settings. Results depend on the board layout and the memory part, which is why XBL does it and often caches the result in a partition to speed later boots.

What are TrustZone and a TEE, and what runs there?

TrustZone is an Arm hardware extension that splits the SoC into a normal world and a secure world, with memory and peripherals that can be restricted to the secure world. A TEE is the secure OS that runs there (QTEE on Qualcomm, Trusty on Pixel, OP-TEE upstream). It hosts trusted apps for key storage (KeyMint), Gatekeeper, biometric matching, DRM (Widevine L1) and rollback counters in RPMB. Even a fully compromised Android kernel cannot read those secrets.

What are the Arm exception levels and which boot component runs at each?

EL3 is the secure monitor (PBL and XBL_SEC/TZ monitor code), which switches between worlds on SMC calls. EL2 is the hypervisor (Qualcomm hyp/Gunyah or pKVM). EL1 runs OS kernels: the Linux kernel (and bootloaders such as ABL at boot) in the normal world and the TEE OS in the secure world (S-EL1). EL0 runs apps and trusted apps.

How does ABL decide which mode to boot into?

It combines several inputs: key combinations held at power-on, the PMIC power-on reason (for example charger insertion leads to charger mode), a reboot reason written before reboot (adb reboot bootloader/recovery writes to memory or the misc partition's bootloader message), recovery commands in misc, and crash state that triggers ramdump mode. The result is passed on as androidboot.mode and the boot reason.

What is inside vbmeta?

A signed header with the algorithm, the public key, the signature, a rollback index and flags (for example the flags that disable verity or verification), plus descriptors: hash descriptors for small bootloader-loaded images (boot, init_boot, vendor_boot, dtbo), hashtree descriptors with dm-verity root hashes and salts for large partitions (system, vendor, product), chain partition descriptors that delegate to another vbmeta or partition signed by a different key, and kernel command-line and property descriptors.

Explain AVB vs dm-verity.

AVB runs in the bootloader before the kernel: it verifies the vbmeta signature and rollback index and fully hashes the small images such as boot and dtbo. For large partitions it cannot hash gigabytes at boot, so it hands the kernel the signed root hash of each partition's Merkle tree. dm-verity then verifies each block lazily when it is read, at runtime. AVB answers "is what we are about to boot genuine"; dm-verity answers "has the filesystem been tampered with while running".

What are chained vbmeta partitions and why use them?

A chain partition descriptor in the main vbmeta names another partition (for example vbmeta_system) along with the public key allowed to sign it and its own rollback index location. This lets different parties sign independently: the SoC vendor or OEM can sign vendor images while Google's generic system image or the system partitions have a separate key, and each can be updated and rolled forward separately without re-signing everything.

What does unlocking the bootloader change?

It must first be allowed by "OEM unlocking" in Developer Options, and then fastboot flashing unlock is run with physical access. It wipes userdata (so an attacker cannot unlock to read data), switches the boot state to ORANGE so unsigned images can boot, and tells the TEE the device is unlocked. Key attestation then reports an unlocked device, so apps needing strong integrity may refuse to run, and some vendors blow a permanent fuse. Relocking wipes data again.

What is the super partition and how does first-stage init use it?

super is a single physical partition containing logical partitions (system, system_ext, vendor, product, odm, vendor_dlkm ...), described by LP metadata at its start. First-stage init reads the metadata and creates dm-linear device-mapper devices for the current slot's partitions under /dev/block/mapper/, then applies dm-verity on top and mounts them. OTAs can resize logical partitions, and they are flashed through fastbootd.

Why were init_boot and vendor_boot introduced?

For the Generic Kernel Image. vendor_boot (Android 11, boot header v3) moved the vendor ramdisk, DTB and vendor command line out of boot, so boot became generic. init_boot (Android 13) moved the generic ramdisk out of boot, so boot now holds only the GKI kernel. Google's kernel, Google's ramdisk and vendor content can therefore be built, signed and updated independently.

What is GKI and why does it matter for boot?

The Generic Kernel Image is a common kernel built by Google per kernel version and architecture. Vendor-specific drivers are loadable modules built against a stable Kernel Module Interface; boot-critical modules are loaded by first-stage init from vendor_boot, and the rest from vendor_dlkm. It reduces fragmentation and lets kernel security fixes ship without every vendor rebuilding. For boot, it means module load order and missing modules become common failure points.

Walk through an A/B OTA end to end.
  1. update_engine downloads the payload and verifies its signature.
  2. It writes the new images to the inactive slot (boot_b, vendor_boot_b, dtbo_b, vbmeta_b, logical partitions in super).
  3. Post-install runs, including otapreopt to compile apps for the new build.
  4. It calls setActiveBootSlot(B): highest priority, full retry count, not successful.
  5. On reboot, ABL picks B, decrements its tries and runs AVB.
  6. After a full boot, update_verifier checks the verity partitions and markBootSuccessful() is called; the rollback index is raised.
  7. If B fails until tries reach 0, ABL boots A again.
What are the slot attributes and who changes them?

Each slot has a priority, a tries-remaining counter and a successful flag, stored in GPT attributes or the misc partition. update_engine uses the boot control HAL to set the new slot active (high priority, full tries, unsuccessful). The bootloader decrements tries on every attempt and treats a slot with zero tries and not successful as unbootable. User space marks the slot successful after a complete boot. You can inspect them with bootctl or fastboot getvar.

How does virtual A/B differ from classic A/B?

Classic A/B keeps two full physical copies of every partition. Virtual A/B keeps two physical copies only of small bootloader-loaded partitions (boot, vendor_boot, dtbo, vbmeta) and a single copy of the large dynamic partitions. The OTA writes the changes as copy-on-write snapshots; after reboot the new slot is a dm-snapshot view of base + COW (handled by snapuserd, compressed since Android 12). After a successful boot, the snapshot is merged into the base; before the merge rollback just discards the snapshot, but after the merge starts rollback is impossible.

What does the kernel do between start_kernel() and running /init?

head.S first sets up early page tables and enables the MMU. start_kernel() then sets up memory (memblock, page allocator), unflattens the device tree, parses the command line and bootconfig, initializes the scheduler, interrupt controller (GIC), timers, console, RCU and workqueues. rest_init() starts kernel_init, which runs the initcalls that register and probe built-in drivers, unpacks the initramfs from the ramdisks, frees init memory and executes /init as PID 1.

What is deferred probe?

When a driver's probe needs a resource that is not ready yet (a regulator, clock, GPIO, PHY or interrupt controller from another driver), it returns -EPROBE_DEFER. The driver core puts it on a deferred list and retries whenever another driver binds successfully. It avoids strict ordering of initcalls, but long deferral chains slow boot and a missing dependency means a device that never appears. /sys/kernel/debug/devices_deferred lists the stuck devices.

Explain the .rc language with an example.

.rc files contain actions, services, imports and options. An action is on <trigger> followed by commands; a service is a program init launches and supervises, with options.

service foo /vendor/bin/foo
    class main
    user system
    group system
    oneshot

on property:sys.boot_completed=1
    start foo

Here foo belongs to the main class, drops to the system user, is not restarted when it exits, and is also started once boot has completed.

In what order does init run its main triggers?

early-init (ueventd, cgroups), init (basic filesystem setup, servicemanager), then late-init, which triggers early-fs, fs (mount remaining partitions), post-fs, late-fs (HALs needed for decryption), post-fs-data (/data mounted; vold unlocks device-encrypted keys — CE stays locked until the user authenticates), zygote-start, early-boot and boot (class main and late_start). Property triggers such as on property:sys.boot_completed=1 fire whenever their condition becomes true.

What are the property prefixes and how are properties protected?

ro.* are set once and read-only (from build.prop files or ro.boot.* from bootloader parameters). persist.* survive reboots, stored under /data/property and available only once /data is mounted. sys.*, vendor.* and others are runtime state. ctl.* sends start/stop commands to init, and init.svc.* reflects service state. Writes go through init's property service, which checks the SELinux label of the property from property_contexts.

How does the Zygote fork request work?

When AMS needs a new process, it calls Process.start(), and ZygoteProcess writes the arguments (uid, gids, runtime flags, SELinux info, app data directory, target SDK, entry class android.app.ActivityThread) to the zygote socket in /dev/socket. Zygote's runSelectLoop() reads them, forks, and in the child specializes the process (sets uid/gid, capabilities, SELinux context, mount namespace) and calls ActivityThread.main(). The parent returns the pid to AMS. With the USAP pool, a pre-forked child is specialized instead of forking on demand.

Advanced

How does the PBL detect the boot medium, and what is the difference between an eMMC boot partition and a UFS boot LUN?

PBL reads boot-configuration strap pins and fuse bits that select the primary device and fallbacks (for example UFS, then eMMC or SD, then USB EDL). On eMMC, the chip has dedicated hardware boot partitions (boot1/boot2) separate from the user area, selected with a partition config register. On UFS, there are logical units; a well-known boot W-LUN is mapped by the device configuration to one of two boot LUNs (A or B), which also allows switching the XBL copy. PBL initializes only a minimal driver for the chosen medium, reads the partition table to find xbl/xbl_config, and if nothing valid is found it falls back to EDL.

What is XBL_SEC and why is it separate from the XBL loader?

On recent Qualcomm SoCs, XBL_SEC is the first image PBL authenticates and runs; it sets up the secure environment at EL3 (secure monitor setup, memory protection, security configuration) before the rest of XBL runs with lower privilege. Splitting it keeps the highest-privilege code small and auditable, and lets the main XBL loader, which contains complex DDR and peripheral code, run with fewer privileges. It is a least-privilege design inside the bootloader itself.

How does the verified-boot state reach the TEE, and why does it matter?

After AVB, the bootloader passes the root-of-trust information to the TEE before the normal world can tamper with it: the verified-boot key (hash of the key used to sign vbmeta), the lock state, the boot state color, the vbmeta digest, and the OS version and security patch level. KeyMint binds hardware-backed keys to these values, so keys created on a locked GREEN device are unusable if the device later boots differently, and key attestation certificates report them to remote servers. This is how banking apps or Play Integrity can trust that a device runs verified software.

How is a dm-verity hash tree built and verified?

The partition is split into 4 KB data blocks. Each block is hashed (salted SHA-256), the hashes are packed into 4 KB hash blocks, and those blocks are hashed again, level by level, until a single root hash remains. The tree is appended to the partition and the root hash plus salt are stored in the signed vbmeta hashtree descriptor. At runtime, reading a data block triggers hashing it and checking the path up to already-verified tree nodes; verified nodes are cached. Because only the root hash must be trusted, the whole partition is protected with one signature, and verification cost is paid lazily per read.

What happens when dm-verity detects corruption?

First, if FEC data is present, dm-verity tries to correct the block using forward error correction. If it cannot, behavior depends on mode: in restart mode (default on user builds) the device reboots, and the bootloader is told a verity error occurred; on the next boot it switches to eio mode, where corrupted reads return I/O errors so the device can boot enough to warn the user rather than loop. logging mode only logs and is for debugging. The mode is visible in ro.boot.veritymode.

Why must the AVB rollback index be updated only after a successful boot?

If the bootloader raised the stored rollback index as soon as it booted a new slot, the old slot (with a lower index) would become unbootable. If the new build then failed, A/B rollback could not fall back and the device would be bricked. So the stored index is raised only once the new slot is marked successful, and each vbmeta may use its own rollback index location so independent partitions can move forward separately.

What is the full first-stage init flow on a GKI, virtual A/B device?
  1. Kernel runs /init from the combined ramdisk (vendor_boot + init_boot).
  2. Mount tmpfs, proc, sysfs, devpts, selinuxfs; create early device nodes.
  3. Load kernel modules listed in modules.load from the vendor ramdisk (storage, clocks, display).
  4. Read the first-stage fstab and wait for the super block device.
  5. Read LP metadata, and if a virtual A/B update is pending, start snapuserd and create dm-snapshot devices; otherwise create dm-linear devices.
  6. Set up dm-verity using the AVB hashtree data and mount system, vendor, product, odm.
  7. Switch root to /system and exec init selinux_setup.
How does SELinux policy get loaded and why is it split between system and vendor?

In the selinux_setup phase, init loads the platform policy (plat_sepolicy.cil), the mapping files for the vendor's policy version, and the vendor/odm policy. If a precompiled_sepolicy in vendor matches the hashes of the system policy, it is loaded directly; otherwise init compiles the CIL on the device with secilc. The split exists for Treble: system and vendor can be updated independently, and the mapping files keep old vendor policy compatible with a newer platform policy.

Explain the SystemServer boot phases and why they exist.

SystemServiceManager.startBootPhase() tells every registered SystemService when a milestone is reached, via onBootPhase(): 100 default display ready, 480 lock settings ready, 500 system services ready (safe to call core services), 520 device-specific services ready, 550 activity manager ready (broadcasts possible), 600 third-party apps can start, 1000 boot completed. Services start in a strict order, but many need other services to be fully ready before doing some work; phases let them defer that work without hard-coded dependencies.

What is the system_server Watchdog and how can it cause a reboot loop?

The Watchdog thread in system_server periodically checks that key threads and monitors (main thread, UI, I/O, display, lock monitors in AMS/WMS/PMS) respond. If one is blocked for about 60 seconds, it dumps stack traces (/data/anr, dropbox) and kills system_server. init/Zygote then restart the framework (a soft reboot). If the blocking condition repeats at every boot, for example a HAL call that never returns during service start, the device loops, and eventually Rescue Party escalates.

What happens when Zygote or system_server crashes?

system_server is a child of Zygote; if it dies, Zygote kills itself so the two stay consistent. init sees Zygote exit and restarts it; the zygote service's onrestart lines restart dependent services such as audioserver, cameraserver and surfaceflinger. The framework comes back without a kernel reboot, a "soft reboot" visible as the boot animation again. This is not a userspace reboot: init and other native daemons keep running. Repeated crashes can trigger the zygote critical window, Rescue Party, and finally recovery.

What is a userspace reboot, and how does it differ from a system_server crash?

A userspace reboot (Android 11+) restarts init and every userspace process; the kernel and hardware stay up. It is what adb reboot userspace and some Rescue Party / Mainline-module recovery paths do. A system_server (or Zygote) crash is a smaller blast radius: init keeps running and only the Java framework and the daemons listed in Zygote's onrestart are restarted. A full reboot walks PBL → XBL → ABL → kernel again. Use userspace reboot when the kernel is healthy and you need a clean userspace; use a real reboot for kernel or driver failures.

How does the boot animation start and stop?

SurfaceFlinger, after it initializes the display, starts the bootanim service through ctl.start. The bootanimation process plays bootanimation.zip (a desc.txt describing size, fps and parts, plus frame folders) or the default Android logo. When the Home activity draws its first frame, WMS calls performEnableScreen(), which sets service.bootanim.exit=1; the animation finishes its current part and exits, and SurfaceFlinger shows the real UI. The boot_progress_enable_screen event marks this.

How does Project Treble relate to boot?

Treble separates the Android framework from the vendor implementation behind stable interfaces: HALs defined in HIDL/AIDL, a vendor interface object (VINTF) with manifests and compatibility matrices, and separate system and vendor partitions and SELinux policies. During boot, init loads both policy halves, the service managers check HAL registrations against VINTF manifests, and a mismatch between the framework compatibility matrix and the vendor manifest can block an OTA or cause missing HALs. The result is that a generic system image can boot on compliant vendor images.

How do the modem and DSPs boot on a Qualcomm device?

They are separate processors with their own firmware. After the Linux kernel is up, the remoteproc (formerly PIL) drivers load their firmware images from the modem/DSP partitions (mounted under paths like /vendor/firmware_mnt), place them in reserved memory, and ask TrustZone's Peripheral Authentication Service to verify the signatures and lock the memory. Only then are the subsystems released from reset. They communicate with the AP over shared memory (QMI/glink), and subsystem restart can recover a crashed modem without rebooting Android.

What are FBE, metadata encryption and Direct Boot, and how do they affect boot order?

File-based encryption encrypts files with per-user keys: device-encrypted (DE) storage is unlocked at boot using keys protected by the TEE and tied to verified boot, while credential-encrypted (CE) storage needs the user's lock-screen credential. Metadata encryption encrypts everything not covered by FBE (file sizes, names, permissions) with a key stored in the metadata partition. During post-fs-data, vold sets up the keys so /data can be mounted; Zygote waits for that. Direct Boot-aware apps run after LOCKED_BOOT_COMPLETED using DE storage; others wait for unlock and BOOT_COMPLETED.

What is bootconfig and how do androidboot parameters become properties?

Before Android 12, the bootloader appended parameters like androidboot.slot_suffix=_a to the kernel command line. Android 12 introduced bootconfig: the bootloader appends a structured key/value block to the ramdisk, readable at /proc/bootconfig, keeping Android settings out of the kernel command line. Early in init, every androidboot.X key is turned into a read-only ro.boot.X property, for example ro.boot.verifiedbootstate and ro.boot.hardware.

How are kernel modules loaded during boot on GKI devices?

Modules needed to reach the second stage (storage, UFS PHY, clocks, pinctrl, early display) live in the vendor ramdisk (/lib/modules) and are loaded by first-stage init in the order of modules.load, respecting modules.dep. The remaining modules are in vendor_dlkm (and system_dlkm for Google-built modules) and are loaded later, usually by a vendor modprobe oneshot service in an early trigger. A module in the wrong list leads either to a boot hang (needed too early) or to slower boot (loaded too early unnecessarily).

What is the USAP pool and why was it added?

The Unspecialized App Process pool (Android 10+) keeps a few children that Zygote has already forked but not yet specialized to an app. When AMS asks for a process, a USAP reads the request, specializes (uid, SELinux context, mount namespace) and runs, avoiding the fork latency on the critical path of app start. The pool is refilled in the background. It trades some memory and idle work for faster cold start.

What is Rescue Party and what does it escalate through?

Rescue Party is part of the package watchdog in system_server. It counts crashes of system_server and persistent system apps within a time window. When a threshold is reached it escalates step by step: reset settings changed by untrusted apps, reset all non-default settings, and finally reboot into recovery with a prompt to try again or factory reset. APEX and staged mainline updates that trigger the loop are rolled back first. It prevents endless bootloops from bad settings or updates.

How does off-mode charging work in the boot flow?

If the PMIC power-on reason is charger insertion and the power key was not pressed, the bootloader sets androidboot.mode=charger. The kernel boots normally, but init sees the mode and triggers the charger action instead of the normal late-init, starting only services in the charger class (the charger UI, health HAL, minimal display). Pressing the power key long enough then triggers a reboot into normal boot. Bugs here, like the charger UI crashing or not handing over to full boot, are common bring-up issues, especially on wearables.

How would you design verified boot for a new device from scratch?
  • Provision fuses at the factory: enable secure boot, burn the OEM PK hash, set anti-rollback, disable JTAG on production units.
  • Sign all SoC firmware with keys in an HSM and a certificate chain; plan key revocation slots.
  • Use AVB 2.0 with vbmeta, hash descriptors for boot images, hashtree descriptors for system partitions, and chained vbmeta for independently signed parts.
  • Store rollback indexes in RPMB and raise them only after successful boot.
  • Pass boot state to the TEE for KeyMint and attestation.
  • Define a lock/unlock policy (OEM unlocking, data wipe, warnings) and dm-verity error behavior (restart then eio).
  • Test with fuse-blown units early, since signing mistakes found late brick hardware.

Scenario & debugging

A device will not boot. How do you narrow down the failing stage?

Start from the visible symptom. Completely dead with a 9008 USB device means PBL could not load XBL. No logo and no EDL means hardware/PMIC or early XBL (DDR). Logo then fastboot means ABL found no bootable slot. A red "corrupt" screen is AVB. Logo followed by a reboot or hang means kernel or first-stage init. Boot animation forever means Zygote/system_server. Recovery prompt means Rescue Party. Then collect the matching logs: UART for bootloaders, pstore/ramoops for the kernel, dmesg for init, and logcat -b all for the framework, and check the active slot and verified-boot state.

The phone is stuck on the boot animation. What are the likely causes and how do you debug it?

The animation is native, so the kernel, init and SurfaceFlinger are working; the framework never reached Home. Likely causes: Zygote failing to start (ART or boot image problem, missing APEX), system_server throwing during service start (FATAL EXCEPTION IN SYSTEM PROCESS), a service blocked on a HAL that never registers (waitForService hanging, then Watchdog), PMS failing on a corrupted package database, a vendor/system mismatch after a partial flash, or an SELinux denial on a daemon the framework needs. Debug with adb logcat -b all, the boot_progress events to see the last milestone, getprop | grep init.svc for crashing services, and tombstones.

After a kernel change, the device shows the logo and then reboots. How do you approach it?

Logo means the bootloaders are fine, so suspect the kernel or first-stage init. Get the previous boot's log from pstore (/sys/fs/pstore/console-ramoops-0) or a UART console. Look for the panic string and backtrace: a NULL dereference in a driver probe, a device tree mismatch, "VFS: Unable to mount root fs", "init: ... Failed to mount", or a missing first-stage module. Compare the defconfig, DT and module lists with the last good build; test the kernel without flashing using fastboot boot; and if needed revert changes one by one. Once fixed, add a CI boot test.

You see "Kernel panic - not syncing: VFS: Unable to mount root fs". What do you check?

On modern Android, root is the ramdisk, so first check that a ramdisk is present and correct: were boot, init_boot and vendor_boot flashed from the same build, and does the boot header version match what the bootloader expects? Check that the kernel has initramfs support and the decompressor for the ramdisk format (LZ4/gzip). On older system-as-root devices, check the root device in the command line, that the storage driver probed (UFS/eMMC modules or built-in), and dm-verity parameters.

A new vendor HAL was added and now boot hangs. How do you debug it?

Check whether the HAL starts: getprop init.svc.vendor.foo-hal and dmesg | grep init: for exits and restarts. Look for avc: denied lines for its domain - a missing domain (no init_daemon_domain), wrong file labels or missing allow rules are the most common cause. Check ueventd.rc permissions on its device node, its VINTF manifest entry (a declared but not running HAL makes waitForService block), and whether it is marked critical. Test with permissive on a userdebug build to confirm a policy issue, then write the minimal proper policy.

How do you debug an avc denial that blocks boot?

Read the denial fields: the permission in braces, scontext (the process domain), tcontext (the target type), tclass (file, socket, property ...), and the path or name. Decide whether the access is legitimate. If the target is mislabeled, fix file_contexts/genfs_contexts; if the process runs in the wrong domain, give it its own domain and label its executable; otherwise add a minimal allow rule in the vendor .te file using macros. audit2allow can suggest rules but must be reviewed. Verify there are no neverallow violations, rebuild, and never ship permissive.

After an OTA, the device booted but is running the old version. What happened?

That is A/B rollback. The new slot was set active, but it failed to complete boot before being marked successful, so its tries counter reached zero and the bootloader fell back to the old slot. Check bootctl slot state and fastboot getvar retry counts, update_engine logs, and the previous boot's kernel and logcat logs (pstore, dropbox) to find why the new build crashed - for example a vendor/system incompatibility, an SELinux denial, or a dm-verity error in update_verifier.

A device shows "Your device is corrupt" (RED) after flashing a custom boot image. Why and how do you fix it?

The device is locked, and the boot image hash no longer matches the hash descriptor in the signed vbmeta, so AVB rejects it. Options: re-flash the original signed images; sign the new image with the OEM key and regenerate vbmeta (production path); or on a development device, unlock the bootloader so failures are not enforced (ORANGE), or flash vbmeta with verification disabled (fastboot --disable-verity --disable-verification flash vbmeta vbmeta.img), which requires an unlocked device. Also make sure the rollback index of the new image is not lower than the stored one.

The device only shows up as Qualcomm 9008 after a failed flash. What now?

PBL could not find or authenticate a valid XBL, so it entered EDL. Use the vendor flashing tool with the correct, signed Firehose programmer for that exact SoC and the OEM key, plus the full factory image set (including xbl, xbl_config, and the partition table rawprogram/patch files). Common reasons for the brick: flashing images for a different SoC or board, an anti-rollback violation (older firmware than the fuse counter), or an interrupted write to the boot LUN. If EDL itself fails, check the USB connection and power, then escalate to hardware analysis.

Boot fails randomly on some units but not others. How do you investigate?

Random, unit-specific failures point to hardware margins or timing. Collect UART logs from failing units to see the stage. If it is XBL, suspect DDR training (marginal memory parts, temperature, stale cached training data - try forcing retraining). If it is the kernel, look for race conditions in driver probe order, deferred-probe dependencies, or voltage/clock settings near the limit. Correlate with hardware lot, memory vendor, temperature and battery level; try stress tests (cold/hot chamber, repeated reboot loops) to reproduce, and compare register dumps between good and bad units.

A driver is not probing at boot. How do you investigate?

Check the kernel log for the probe or its absence. Confirm the DT node exists and is enabled (status = "okay") in the live tree under /proc/device-tree, and that its compatible string matches the driver. Check whether the module is loaded (lsmod) and in the right list (vendor_boot vs vendor_dlkm). Look at /sys/kernel/debug/devices_deferred for a probe deferred on a missing regulator, clock, GPIO or interrupt parent. Verify power, clock and pinctrl prerequisites, and use initcall_debug or dynamic debug for more detail.

system_server crashes in a loop right after boot. How do you find the root cause?

Capture adb logcat -b crash -b system -b main from the very start and search for FATAL EXCEPTION IN SYSTEM PROCESS and the Java stack; look in /data/system/dropbox for system_server_crash entries and in /data/anr for Watchdog traces. Identify the service and code path: common causes are an OEM service throwing during start, a null result from a HAL that is not running, a corrupted settings or package XML, or a mismatch between framework and a vendor or APEX module. Fix the service or its dependency; wipe or restore only the corrupted data if that is the cause.

How would you reduce boot time by 30%?
  1. Define the metric: power key to sys.boot_completed or to the first Home frame, measured over many cold boots.
  2. Break it down per stage: bootloader logs, dmesg timestamps and initcall_debug, ro.boottime.*, bootchart or a Perfetto boot trace, boot_progress events.
  3. Attack the largest blocks: async driver probe and module moves, quiet console, removing blocking .rc commands, starting non-critical services after boot, lazy HALs, trimming Zygote preload, moving OEM service work off the boot path, speeding up PMS scanning.
  4. Guard the result with an automated boot-time regression test.
First boot after a factory reset takes several minutes. Why, and what can be done?

The first boot does work that normal boots skip: creating and encrypting /data (FBE and metadata keys), PackageManager scanning every package from scratch and writing its database, compiling apps (dexopt) that do not have precompiled code, activating APEX modules, and setup-wizard initialization. Improvements: ship apps precompiled with profiles (speed-profile), use cloud profiles, reduce preinstalled apps, keep the boot image and preloaded classes up to date, and make sure storage is fast (UFS, write booster). After an A/B OTA, otapreopt compiles in the background before the reboot so the post-update boot stays fast.

adb remount fails or changes disappear after reboot. Why?

System partitions are protected by dm-verity and are read-only, and on dynamic-partition devices they are sized exactly to their content. On a userdebug/eng build with an unlocked bootloader, adb root, then adb disable-verity (or adb remount, which does it for you), then reboot, then adb remount. Writes go to an overlayfs backed by /data or scratch space, not to the real partition; flashing a new image or re-enabling verity discards them. On a locked user build this is not possible by design.

Boot animation plays, then the device reboots into recovery asking to factory reset. What is going on?

That is Rescue Party. system_server or a persistent system app crashed repeatedly, and after resetting settings did not help, the package watchdog rebooted into recovery. Before wiping, pull the logs if possible (from recovery via adb on debug builds, or the previous boot's dropbox and pstore). Common causes are a bad OEM app update, a corrupted settings or package database, or a mainline module update, which the watchdog tries to roll back first. A factory reset fixes data corruption but not a bug in the system image.

The device boots only when a UART cable is attached (or only with debug logs enabled). What might cause that?

That is a timing or power-dependent bug. Verbose logging or UART slows early code, which can hide race conditions (for example a driver reading hardware before its power rail is stable, or a missing delay after reset). The cable can also supply a ground or back-power path that changes power sequencing, or pull a strap pin that alters boot configuration. Compare timestamps with and without logging, check rail and reset timing on a scope, review delays required by the datasheets, and look for dependencies that are satisfied only by accident.

A service defined in a vendor .rc file never starts. What do you check?

Confirm the file is in a directory init reads (/vendor/etc/init/) and parses without errors (dmesg | grep init: shows parse errors). Check the service's class is actually started in this boot mode and whether it is disabled and must be started by a trigger. Verify the trigger condition ever becomes true (for example a property that is never set). Check the binary path and permissions, the executable's SELinux label (without a domain transition init refuses to start it), and getprop init.svc.<name> for its state.

A watch reboots into charger mode but never proceeds to a full boot. How would you debug it?

Check the PMIC power-on reason and androidboot.mode passed by the bootloader, and whether the power-key event reaches the charger UI (input driver probed in charger mode, correct key mapping). Look at logs of the charger process and the health HAL: a crash, a battery reading error, or a battery level below the boot threshold keeps it in charger mode. Verify the charger class in the .rc files includes everything needed and that the reboot from charger to normal mode is issued. Also check thermal or low-voltage limits that block normal boot on a small battery.

You must bring up a new board and it hangs before the logo. What is your plan?
  1. Get a UART console and confirm power rails and clocks with a scope or bench supply current profile.
  2. Check whether PBL runs: does the device enumerate in EDL when storage is blank? Are the images signed for this fuse configuration?
  3. Look at XBL logs: DDR training results for the specific memory part, xbl_config settings for this board, PMIC configuration.
  4. Check that storage (UFS/eMMC) is detected and provisioned (LUN layout, boot LUN enabled).
  5. Once ABL runs, verify the splash partition and display panel configuration for the logo.

Work stage by stage and change one variable at a time.

Boot time regressed by 3 seconds between two builds. How do you find the cause?

Capture multiple cold boots of both builds with identical conditions and compare per stage: kernel timestamps (last kernel line before init), ro.boottime.* for each service, boot_progress events, and a Perfetto boot trace. Find which stage grew, then which service, initcall or code path in it. Common culprits: a new blocking exec/wait in an .rc file, a driver now probing synchronously or deferring repeatedly, a new system service doing disk or network I/O at start, a larger preload list, or a missing precompiled profile. Bisect the changes in that area.

A device with a working slot A fails to boot slot B after flashing only some images. What is the likely issue?

A mixed-build slot. Images in one slot must match each other: the kernel in boot_b with the modules in vendor_boot_b and vendor_dlkm_b (KMI and module signature), the vbmeta hashes with the images, and the system SELinux policy with the vendor mapping files. Flashing a new boot but an old vendor_boot leads to module load failures in first-stage init; a new vendor image with an old vbmeta fails AVB. Flash all images for that slot from the same build (fastboot flashall or an update package) and compare with the working slot.