Partitions

Android devices include several partitions that serve different functions in the boot process. To support A/B updates, the device will need one slot per partition for boot, system, vendor, and radio.

Flow

Here is how the bootloader operates:

  1. The bootloader gets loaded first.
  2. The bootloader initializes memory.
  3. If A/B updates are used, determine the current slot to boot.
  4. Determine whether recovery mode should be booted instead as described in Supporting updates.
  5. The bootloader loads the image, which contains the kernel and RAM disk (and in Treble even more).
  6. The bootloader starts loading the kernel into memory as a self-executable compressed binary.
  7. The kernel decompresses itself and starts executing into memory.
  8. From there on, older devices load init from the RAM disk and newer devices load it from the /system partition.
  9. From /system, init launches and starts mounting all the other partitions, such as /vendor, /oem, and /odm, and then starts executing code to start the device

Images

The bootloader relies upon these images.

Kernel images

Kernel images are created in a standard Linux format, such as zImage, Image, or Image.gz. Kernel images can be flashed independently, combined with RAM disk images, and flashed to the boot partition or booted from memory. When creating kernel images, concatenated device-tree binaries are recommended over using a separate partition for the device tree. When using multiple Device Tree Blobs (DTBs) for different board revisions, concatenate multiple DTBs in descending order of board revision.

RAM disk images

RAM disks should contain a root file system suitable for mounting as a rootfs. RAM disk images are combined with kernel images using mkbootfs and then flashed into the boot partition.

Boot images

Boot images should contain a kernel and RAM disk combined using an unmodified mkbootimg.

The mkbootimg implementation can be found at: system/core/mkbootimg

The bootloader reads the bootimg.h header file generated by mkbootimg and updates the kernel header to contain the correct location and size of the RAM disk in flash, base address of the kernel, command line parameters, and more. The bootloader then appends the command line specified in the boot image to the end of the bootloader-generated command line.

File system images (system, userdata, recovery)

YAFFS2 image format

If using raw NAND storage, these images must be YAFFS2, generated by an unmodified mkyaffs2image, as found in the Android Open Source Project (AOSP) at external/yaffs2/yaffs2/utils. They have the format:


| 2k bytes of data| yaffs extra data | padding | | 0  2048 | 0 64 | variable|

The bootloader is responsible for consuming these images and relocating the yaffs extra data into the appropriate location in the out-of-band area for the given nand hardware. If software ECC is required, the bootloader should also do that computation at this time.

Sparse image format

The sparse image format should be supported. It is described in the document "ext4 compressed images" and in system/core/libsparse/sparse_format.h; it is implemented in: system/core/libsparse/sparse_read.cpp

If using a block-based storage device, ext4 or f2fs should be supported. To quickly transfer and flash large, empty ext4 file systems (userdata), store the image in a sparse format that contains information about which areas of the file system can be left unwritten. The file format is written by the mke2fs utility that is also used to create the images the file format is read and flashed by the bootloader. See the sections below for attributes:

File format

32-bit CRC32 checksum of original data, counting "don't care" as 0 Standard 802.3 polynomial, use a public domain table implementation

Chunk
Data
Implementing the writer

The mke2fs utility already knows what areas of the image need to be written, and will encode "don't care" chunks between them. Another tool, img2simg, will convert regular (non-sparse) images to sparse images. Regular images have no information about "don't care" areas; the best a conversion can do is look for blocks of repeated data to reduce the resulting image size.

Implementing the reader

Readers should reject images with unknown major versions and should accept images with unknown minor versions. Readers may reject images with chunk sizes they do not support.

Once the major version is validated, the reader should ignore chunks with unknown type fields. It should skip over the chunk in the file using the "chunk size in file" and skip "chunk size in blocks" blocks on the output.

A Cyclic Redundancy Check - 802.3 CRC32 - should be calculated for the data that will be written to disk. Any area that is not written (don't care, or a skipped chunk), should be counted as 0s in the CRC. The total number of blocks written or skipped should be compared against the "total blocks" field in the header. The tool simg2img will convert the sparse image format to a standard image, which will lose the sparse information.