Zygote
Bootnerd

Verified boot and A/B updates

Two mechanisms that make an Android phone trustworthy and hard to brick: a chain of signatures rooted in hardware, and two copies of the system so an update can never destroy the one you are using.

15 minAPI 19–37 · 17interactivequizverified 2026-10-27

Two questions dominate a phone's boot design. The first is "how do I know this code is what it claims to be?" The second is "how do I update it without risking a device that will not start?"

They have different answers, which is why this page covers both. Verified boot is a chain of signatures that begins in silicon and ends with dm-verity checking blocks as they are read. A/B updates are a duplication scheme that lets a phone be updated while it is being used, and roll back if the new version fails.

They meet in one place: the bootloader reads a flag from verified metadata to decide which slot to boot.

TL;DR#

  • Verified boot was introduced in Android 4.4 with dm-verity, and became AVB (Android Verified Boot 2.0) with Android 8.0, alongside Treble.
  • The chain is: boot ROM → bootloader → verified boot/init_boot/dtbo/recovery partitions → the vbmeta metadata → dm-verity for the read-only system partitions.
  • holds a hash descriptor for boot and hashtree descriptors for system and vendor: the root hash, salt and offset of a hash tree that dm-verity walks at read time.
  • Rollback protection rejects a device image older than the highest version it has seen, which is what stops an attacker from reinstalling a known-vulnerable build.
  • A/B keeps two copies of the system in slots _a and _b. An update is written to the inactive slot while the phone runs, and a failed boot falls back to the old one.
  • Virtual A/B, mandatory for devices launching with Android 11 and higher, avoids duplicating the whole system by writing the update into /data and merging it after a successful boot.

Mental model#

Verified boot is a chain of signature checks, like a notarised document.

The first page is notarised by an authority nobody can impersonate (the boot ROM, which is in hardware). Each subsequent page has a signature that the previous page vouches for. If any signature is wrong, the chain stops and the document is not accepted.

The clever part is that the last pages are too long to check all at once. So the notary signs a root hash of a tree of hashes, and each page is checked when it is read. That is dm-verity: verification on demand, with a single trusted hash at the root.

A/B updates are like a hotel with two identical wings.

Guests stay in wing A while the staff renovate wing B. When wing B is ready, guests move. If wing B turns out to be uninhabitable, everyone goes back to wing A, which was never touched.

The catch is that identical wings cost twice the space. Virtual A/B is the trick for a hotel that cannot afford the second wing: the staff renovate in a shared basement (space on /data), and only after the new wing proves habitable do they merge the changes into the real one.

Where the analogy breaks#

The notary chain has a genuine weak point: the last signature is checked by the thing it is protecting. dm-verity is enforced by the kernel, so an attacker who controls the kernel can ignore the check. That is why the bootloader verifies the kernel itself, and why the root of trust is hardware.

The hotel analogy misses rollback protection. Renovated wing B is not just "newer"; it is refused if it is older than what the hotel has already certified, because an old build has old vulnerabilities.

The big picture#

Loading diagram…
Text description of this diagram

A state machine for an A/B update. The device begins running slot A. update_engine writes the new build into slot B. The device enters a reboot-pending state, then reboots into B. update_verifier checks B with dm-verity before zygote starts. If verification passes, B is marked successful and becomes the new known-good slot. If the boot fails or never reports success after its retries, the bootloader falls back to slot A, from which the device can retry the update.

The important thing to notice is where verification sits: after the reboot, before zygote. If dm-verity found corruption in the new slot, the device never gets far enough to mark it successful, and the fallback happens. The update path and the verification path are designed to fail in the same direction.

Deep dive#

The chain of trust#

Verified boot has four links, and each one checks the next.

1. Boot ROM to bootloader. The ROM contains a public key or a hash of the bootloader, and checks it before executing. This is the only link that cannot be updated, which is exactly why it is trusted.

2. Bootloader to boot partitions. The bootloader verifies boot, init_boot, dtbo and recovery against the VBMeta struct in vbmeta, including the boot image header version. If the signatures do not match the device's trusted key, the bootloader decides what to do based on its lock state.1

3. vbmeta to the system partitions. The VBMeta struct holds a hash descriptor for boot and hashtree descriptors for system and vendor. A hashtree descriptor is not the partition's hash; it is the root hash, salt and offset of a tree of block hashes. That is what dm-verity consumes.

4. dm-verity to each block. As the kernel reads a block, it hashes it and checks the hash against the tree. A mismatch produces an I/O error — the read appears to fail as if the block were corrupt.2

What the VBMeta struct contains#

VBMeta is the data structure that ties the whole thing together. It contains, in the words of the AVB documentation, "a number of descriptors (and other metadata)" and all of it is cryptographically signed.

The descriptor types that matter:

DescriptorWhat it describes
Hash descriptorA single hash of an entire partition — used for boot
Hashtree descriptorThe root hash, salt and offset of a hash tree — used for system and vendor
Chain partition descriptorDelegation: the name of a partition and the public key trusted for it

The chain partition descriptor is the interesting one. It lets the top-level vbmeta say "the vendor partition is verified by a different key, and here is that key". This is how Treble's ownership split reaches verified boot: Google can own vbmeta for the system while the OEM owns a chained vbmeta_vendor. It also means a chained partition can be updated without changing the top-level struct, because the footer at the end of the partition carries the offset of its own VBMeta struct.3

Rollback protection#

Every VBMeta struct has a rollback index baked into it, and the device stores the highest index it has seen in tamper-evident storage. On boot, AVB requires:

rollback_index[n] >= stored_rollback_index[n]

If the image's index is lower, the boot is refused. The index is increased whenever a security fix ships, so an attacker who has an old, vulnerable signed image cannot install it on a device that has already seen the fix.3

This is why downgrading a phone is difficult even with an unlocked bootloader. The lock state controls whether unsigned images are accepted, but rollback protection controls whether older signed images are accepted, and it applies in both states.

Device states#

The bootloader reports what it found through androidboot.verifiedbootstate, and that value drives the user-visible warning:45

StateMeaningWhat the user sees
greenLocked, standard root of trust, everything verifiedNothing
yellowLocked, but a user-supplied root of trust was usedA warning that a custom key is in use
orangeUnlockedA warning on every boot
redVerification failed, or no valid OSA warning; the device may refuse to boot

The eio / restart distinction is separate. androidboot.veritymode=eio means a dm-verity failure surfaces as an I/O error, letting the system continue in a degraded state. restart means the device reboots instead. Most production devices use eio, because a device that reboots on every read error is worse than one that reports a corrupt file.

A/B: the update that cannot brick you#

Before A/B, an Android update was applied in recovery: the phone rebooted into a minimal environment, wrote the new system image in place, and rebooted again. If anything went wrong — power loss, a bad package, a corrupt write — the device had no working system to fall back to.

A/B changes the geometry. The device has two sets of partitions, _a and _b. One is the running system; the other is a target. An update is written to the inactive slot while the phone is running, verified, and marked bootable. The next reboot starts the new slot. If it fails, the bootloader switches back.6

Several pieces make that work:

The boot control HAL. A vendor-implemented interface that lets update_engine and the framework tell the bootloader which slot to boot and which slots are bootable or successful.

Slot flags. Each slot carries bootable and successful flags. A slot that is bootable but not successful is on probation: if it does not report success after its retry budget, the bootloader marks it unbootable and falls back.

update_engine. A background daemon that writes the OTA payload's blocks into the inactive slot, applies the operations in order, discards temporary data, re-reads and hash-verifies the partitions, runs the post-install program, and marks the target active. Streaming A/B writes blocks as they download, so the package never has to fit in /cache or /data all at once.7

update_verifier. Runs early in the boot of the new slot — init's zygote-start trigger calls exec_start update_verifier — and checks the slot with dm-verity before the framework starts. It is the program that calls markBootSuccessful.

The storage cost, and Virtual A/B#

Duplicating the system is expensive. The A/B FAQ gives an example of roughly 320 MiB of extra image, which is 2% of a 16 GiB device but nearly 10% of a 4 GiB device.8 On low-end hardware that is unacceptable, and on high-end hardware it is wasteful.

Virtual A/B solves it by not keeping a second copy of the dynamic partitions. Instead, the update delta is written into a snapshot — copy-on-write data stored in /data — and after a successful boot the snapshot is merged into the base partition. Only the partitions the bootloader itself reads are duplicated; everything updateable is snapshotted.

Virtual A/B was the mechanism for devices launching with Android 11 and higher, and it is now the main update path. Its costs are real and worth stating: it needs temporary space in /data during the update, and that space is returned afterwards. Compression, added in Android 12, reduces the snapshot size considerably — AOSP gives figures around 45% smaller for full OTAs and 55% for incremental ones, and a comparison table showing a 4.5 GB super partition for Virtual A/B versus 9 GB for conventional A/B.9

How it evolved#

The A/B and verified boot stories run in parallel and converge.

The updatability story7 releases
APIVersionWhat changed
194.4 KitKat
  • Kernel moved under a tighter vendor control
236.0 Marshmallow
  • Fingerprint HAL
247.0 Nougat
  • Project Treble groundwork
268.0 Oreo
  • Project Treble: the vendor interface separates vendor and system code
  • HIDL for HALs
289 Pie
  • Mainline groundwork
2910
  • Project Mainline: APEX and updatable system modules
  • Project Mainline starts shipping through Play
3011
  • GKI: the Generic Kernel Image splits the kernel into core + vendor modules

Verified boot: Android 4.4 added dm-verity and the first verified boot. Android 7.0 began strict enforcement and added forward error correction, so a small amount of corruption can be recovered rather than surfacing as an I/O error. Android 8.0 introduced AVB with Treble, standardising the footer format and adding rollback protection.112

Updates: recovery-based updates gave way to A/B with Android 7.1. Streaming A/B followed. Virtual A/B became the default from Android 11. Dynamic partitions (Android 10) changed the target of an update from a fixed partition to a logical one inside super.

Under the hood#

Curiosity corner#

  • dm-verity failure looks like disk corruption, not like a security warning. An app reading a tampered block gets an I/O error, because that is the behaviour that breaks the fewest assumptions in existing code.
  • A rooted device can pass verified boot. orange is not a failure; it is a state. The device boots, warns the user, and continues. What it cannot do is pretend to be green.
  • The rollback index is why "downgrade protection" exists on phones. It is the same mechanism, seen from the user's side.
  • A/B is why the cache partition became optional. Updates no longer stage in /cache, so on many modern devices it is gone entirely.

Try it#

Read the verification state

adb shell getprop | grep -E "verifiedboot|veritymode|slot_suffix" adb shell getprop | grep vbmeta adb shell getprop ro.boot.dynamic_partitions adb shell getprop ro.boot.slot_suffix

Example output
[ro.boot.verifiedbootstate]: [green]
[ro.boot.veritymode]: [enforcing]
[ro.boot.slot_suffix]: [_a]
[ro.boot.dynamic_partitions]: [true]
[ro.boot.dynamic_partitions_retrofit]: [false]
[ro.boot.vbmeta.device_state]: [locked]
[ro.boot.vbmeta.digest]: [f3a1...]
[ro.boot.vbmeta.avb_version]: [1.3]

ro.boot.* properties are set by init from the kernel command line and bootconfig, which the bootloader populated. They are a read-only record of what the bootloader decided, and on a locked device they cannot be forged without breaking the chain.

Check yourself#

Check yourself

1 / 12

Which stage runs first after the power button is pressed?

0 answered · 0 correct

Sources#

Sources

Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.

  1. docsBootloader overviewsource.android.comaccessed 2026-10-27↩
  2. docsdm-veritysource.android.comaccessed 2026-10-27↩
  3. docsAndroid Verified Boot (AVB)source.android.comaccessed 2026-10-27↩
  4. docsVerified boot flowsource.android.comaccessed 2026-10-27↩
  5. docsVerified boot device statessource.android.comaccessed 2026-10-27↩
  6. docsA/B (seamless) system updatessource.android.comaccessed 2026-10-27↩
  7. docsImplement A/B updatessource.android.comaccessed 2026-10-27↩
  8. docsA/B updates FAQsource.android.comaccessed 2026-10-27↩
  9. docsVirtual A/Bsource.android.comaccessed 2026-10-27↩
  10. docsDynamic partitionssource.android.comaccessed 2026-10-27↩
  11. docsVerified bootsource.android.comaccessed 2026-10-27↩