This chapter turns the role map in Boot and partitions into a source/spec reading exercise. It does not teach flashing, image patching, or recovery procedures. A boot image is a structured format whose fields depend on a header version; reading one safely means matching the parser/spec version and treating every conclusion as evidence-limited.
Before you start#
Read Bytes, Hex, and Trust, Boot and partitions, and Programs, Memory & System Calls. You should know hex is a notation for bytes and understand that a signature/verified chain establishes integrity relative to a trust root, not software correctness. No image modification or device access is required.
Learning goals#
You will distinguish a partition name from the image format stored there; explain why header version must be identified before parsing fields; interpret a versioned component map; distinguish Android release from device launch/layout; and create an offline inventory without writing to a device or extracting private data.
Bytes, headers, and conditional layouts#
A byte is an 8-bit unit, commonly displayed in hexadecimal (two hex digits per byte). A field is a byte range interpreted according to a format definition. A parser does not know a field's meaning from its value alone: it needs the correct format and version. A magic value is a fixed byte sequence used by some formats to help identify them. Finding a magic value is a clue, not proof the whole file is valid or authentic. A hash summarizes bytes; a signature is checked using a trust key and verification rules. Neither tells you the code is safe. Android Verified Boot validates images/metadata according to the configured chain, rollback indices, and device state.
Versioned image map
The following is a learning comparison, not a complete compatibility matrix. Use the linked AOSP table for all fields and supported version behavior.
| Layout family (examples) | boot | init_boot | vendor_boot | Other evidence to inspect |
|---|---|---|---|---|
| Older boot-ramdisk designs | Kernel plus ramdisk may be packaged together. | Typically absent in this older design. | Layout-specific vendor data may be elsewhere or absent. | Header version, recovery design, fstab, AVB descriptors. |
| Android 10/11 first-stage-init transition | Boot image commonly contains kernel and first-stage ramdisk in documented layouts. | Not the generic modern split role in these historical docs. | Vendor ramdisk details depend on design. Ramdisk partitions page explicitly applies to Android 11 and lower; system-as-root/recovery arrangement matters. | |
| Android 12+ GKI-family designs Commonly carries GKI kernel; boot header version and board design affect content (header versions). | Generic ramdisk partition on designs using the generic boot partition scheme; Android 13+ devices commonly use this split. | Vendor-specific ramdisk fragments and related vendor boot content in supported formats. | Boot header version, generic/vendor ramdisk table, DTB/bootconfig placement, launch level, build config. | |
| Product-specific variations | Kernel and associated payload according to actual design. | Optional. | May combine fragments/configuration differently. | dtbo, recovery, vbmeta, chained metadata, slots, dynamic partitions, fstab and vendor data. |
Do not turn the table into rules like “Android 13 means init_boot” or “Android 14 has vendor_boot.” Android version and device launch version are related but not interchangeable. A later OS update can retain a device's original partition architecture. boot, init_boot, and vendor_boot are names/roles; actual payload is established from the matching header and build configuration.
Fields and neighboring images
- Offset 0, 8 bytes
- Boot magic ANDROID! is a format clue, not authentication.
- Offset 40, u32
- header_version is at this offset for boot header versions 0–4.
- Offset 12, version 0
- kernel_addr: a field with a different meaning from the v3 field at the same position.
- Offset 12, version 3
- ramdisk_size. In v3, kernel_size is at offset 8; v0 offsets must not be reused.
The Android 14 AOSP header definitions are in include/bootimg/bootimg.h. Its boot_img_hdr_v3 lays out magic[8], kernel_size, ramdisk_size, os_version, header_size, reserved words, header_version, and command-line bytes; boot_img_hdr_v4 extends v3 with signature_size. The AOSP header guide documents the associated format and alignment rules. In the boot header, header_version stays at byte offset 40 across versions 0–4, so a parser can read it first; the neighboring fields change meaning, e.g. offset 12 is kernel_addr in v0 but ramdisk_size in v3 (boot image header guide). v3/v4 boot header pages are 4096 bytes; v3 header_size describes the header structure, not the full page. Vendor-boot v4 has separate fields including vendor ramdisk table sizes/count and bootconfig size. Do not reuse a v0/v1 offset to parse v3/v4. A real parser must validate the magic, version, header structure size, and all declared section lengths against the actual buffer before trusting any field.
Related components are not all fields in one file:
- DTB/DTBO: base device-tree blob and optional overlays may be in separate images/partitions or packaged according to platform design (DTB images, overlays). Their job is hardware description, not boot policy.
- Bootconfig/kernel command line: parameters passed to early kernel/userspace (bootconfig extends the command line); command-line inspection does not show every bootconfig value or prove image integrity.
- Recovery: may be a separate image/partition or share a boot/ramdisk strategy. The device's recovery design must be established from evidence.
vbmeta: AVB metadata contains descriptors and relationships for verified images, potentially using chained partitions (Verified Boot). It is not the kernel/ramdisk payload itself. Verification details depend on chain and device lock state.superand slots: dynamic logical partitions may live insuper; A/B metadata selects slot-aware images. Neither mechanism changes the meaning of a boot-header field. Slot naming is not a cryptographic validation result.
An image's location also does not establish its contents. A file called boot.img could be a factory archive's image, a build artifact, a repacked image, or a file from another device. Record provenance, hash, source URL/build fingerprint, target product, and parser version. Never upload private device images or keys to an untrusted site.
Practice#
Prerequisites: workstation shell with Python 3 (standard library only) and browser access to AOSP documentation. No device, root, JDK, downloaded image, or third-party parser is needed. This lab constructs a synthetic teaching record in memory. It is not a bootable image, has no real kernel or ramdisk, and must never be flashed or passed to a boot tool.
Browser-only field card
Synthetic teaching data, not a device capture.
- Offsets 0–4095: header page
- Selected v3 header fields; header_size is 1580, inside a 4096-byte page.
- Offsets 4096–8191: kernel page
- 4 bytes of K at 4096–4099, followed by 4092 padding bytes.
- Offsets 8192–8194: ramdisk filler
- 3 bytes of R; the provided buffer ends here.
If you cannot run Python, use this provided synthetic metadata card. It represents only selected boot_img_hdr_v3 fields, not a complete header or valid image:
format: synthetic Android-style boot header training fixture
magic bytes [0..7]: 41 4e 44 52 4f 49 44 21 ASCII "ANDROID!"
kernel_size u32 little-endian at offset 8: 4
ramdisk_size u32 little-endian at offset 12: 3
header_size u32 little-endian at offset 20: 1580
header_version u32 little-endian at offset 40: 3
buffer length: 8195 bytes (header page + 4096-byte kernel page + 3 filler bytes)
kernel-page filler at offset 4096: 4 bytes 0x4b; ramdisk-page filler at offset 8192: 3 bytes 0x52
The offsets and field names are based on Android 14's tagged boot_img_hdr_v3 definition. The chosen values and filler are synthetic. They do not form a valid signed, bootable, or device-compatible boot image.
Run the in-memory parser
This complete program uses BytesIO and struct; it writes no files. It parses only the selected v3 header fields and checks header/page/payload bounds. It is a teaching parser, not AOSP mkbootimg or a production-robust Android image parser.
# HOST workstation shell
python3 - <<'PY'
from io import BytesIO
import struct
PAGE = 4096
HEADER_SIZE_V3 = 1580 # sizeof(boot_img_hdr_v3) in the tagged AOSP header
def make_fixture():
image = bytearray(PAGE * 2 + 3)
image[0:8] = b"ANDROID!"
struct.pack_into("<I", image, 8, 4) # kernel_size
struct.pack_into("<I", image, 12, 3) # ramdisk_size
struct.pack_into("<I", image, 20, HEADER_SIZE_V3)
struct.pack_into("<I", image, 40, 3) # header_version
image[PAGE:PAGE + 4] = b"K" * 4 # filler, NOT a kernel
image[PAGE * 2:PAGE * 2 + 3] = b"R" * 3 # filler, NOT a ramdisk
return bytes(image)
def parse_v3(data):
stream = BytesIO(data)
if len(data) < PAGE:
raise ValueError("truncated: missing 4096-byte v3 header page")
if stream.read(8) != b"ANDROID!":
raise ValueError("bad boot magic")
kernel_size, ramdisk_size = struct.unpack_from("<II", data, 8)
header_size = struct.unpack_from("<I", data, 20)[0]
header_version = struct.unpack_from("<I", data, 40)[0]
if header_version != 3:
raise ValueError(f"unsupported fixture parser version: {header_version}")
if header_size != HEADER_SIZE_V3 or header_size > PAGE:
raise ValueError(f"invalid v3 header_size: {header_size}")
if kernel_size == 0 or ramdisk_size == 0:
raise ValueError("v3 fixture requires nonempty kernel and ramdisk sections")
ramdisk_offset = PAGE + ((kernel_size + PAGE - 1) // PAGE) * PAGE
if ramdisk_offset + ramdisk_size > len(data):
raise ValueError("declared payload sizes exceed available bytes")
return "\n".join((
"magic: ANDROID!",
f"header_version: {header_version}",
f"header_size: {header_size}",
f"kernel_size: {kernel_size}",
f"ramdisk_size: {ramdisk_size}",
f"buffer_length: {len(data)}",
"classification: synthetic/non-bootable fixture",
))
fixture = make_fixture()
print(parse_v3(fixture))
print("truncated case:")
try:
parse_v3(fixture[:100])
except ValueError as exc:
print(type(exc).__name__ + ":", exc)
print("oversized declaration case:")
bad = bytearray(fixture)
struct.pack_into("<I", bad, 8, 9999)
try:
parse_v3(bytes(bad))
except ValueError as exc:
print(type(exc).__name__ + ":", exc)
PY
Expected output:
magic: ANDROID!
header_version: 3
header_size: 1580
kernel_size: 4
ramdisk_size: 3
buffer_length: 8195
classification: synthetic/non-bootable fixture
truncated case:
ValueError: truncated: missing 4096-byte v3 header page
oversized declaration case:
ValueError: declared payload sizes exceed available bytes
This is a source-offset exercise: it demonstrates that values at selected offsets can be decoded under a declared format. It does not validate every boot_img_hdr_v3 field, signatures, AVB descriptors, vendor_boot, or device compatibility. The 4 K bytes and 3 R bytes are filler only, not actual payloads. A real image has format-specific alignment and integrity requirements. Do not save or rename this fixture as boot.img.
Expected failure interpretation: short input is truncated; wrong magic should fail; header_version other than 3 is unsupported by this deliberately narrow parser; wrong header_size is rejected; declared section sizes beyond available bytes are rejected. A parser error is not a reason to patch bytes or try a different header offset blindly. After the code, compare field names/offsets against the tagged header and AOSP format document. For v4, notice the inherited v3 header plus signature_size; this exercise intentionally refuses v4 rather than pretending to parse it.
Knowledge check#
- Why must a parser identify the boot header version before interpreting offsets?
- Does a valid
bootimage imply that the device has no separateinit_boot? - What do DTB and DTBO contribute, and are they always in
boot? - What does
vbmetado, and why is it not “the boot image checksum”? - If an Android 14 device lacks a
vendor_bootpartition name in a shell listing, what can you conclude?
Answers#
- Fields, offsets, and payload organization vary by version; the wrong parser can misread bytes or accept malformed data.
- No. The images have different roles and may coexist in a supported split layout; exact design is device-specific.
- DTB supplies base hardware description; DTBO can overlay it. Packaging varies, so neither is guaranteed to be in
boot. - AVB metadata describes integrity relationships/policy for images and may chain to other metadata; it is not simply a checksum filename or all payload data.
- Only that this particular listing/build did not expose that name. It does not establish the full image layout or content.
Checkpoint#
Submit the parser's expected output (or hand-annotated field card), its two failure-case outputs, and a versioned image map with source links. Include an inventory template with artifact provenance, hash, header version, interpreted fields, layout-dependent items, and unknowns. Pass if you correctly identify the v3 selected offsets, reject truncated/oversized data, and label the fixture non-bootable. Remediation: compare offsets against the pinned bootimg.h, recount bytes from offset zero, and rerun the in-memory parser; do not proceed to a real image until each field is explained.
Sources#
- AOSP boot image header — canonical version-specific fields and format changes.
- Pinned Android 14
bootimg.h— C definitions forboot_img_hdr_v3,boot_img_hdr_v4, and vendor boot header structures; offsets in the fixture are checked against this file. - AOSP generic boot and vendor boot partitions.
- AOSP ramdisk partitions — historical Android 11-and-lower page; directs Android 12+ readers to generic boot docs.
- Kernel bootconfig — structured boot parameters that extend the command line.
- AOSP DTB images, device tree overlays, Verified Boot, and dynamic partitions.
- AOSP Android 14 init source.