Partition Layout

In Android 10, the root file system is no longer included in ramdisk.img and is instead merged into system.img (that is, system.img is always created as if BOARD_BUILD_SYSTEM_ROOT_IMAGE was set). Devices launching with Android 10:

  • Use a system-as-root partition layout (automatically enforced by the build with no options to change the behavior).
  • Must use a ramdisk, which is required for dm-linear.
  • Must set BOARD_BUILD_SYSTEM_ROOT_IMAGE to false. This setting is used only to differentiate between devices that use a ramdisk and devices that don't use a ramdisk (and instead mount system.img directly).

The meaning of a system-as-root configuration differs between Android 9 and Android 10. In an Android 9 system-as-root configuration, BOARD_BUILD_SYSTEM_ROOT_IMAGE is set to true, which forces the build to merge the root file system into system.img then mount system.img as the root file system (rootfs). This configuration is mandatory for devices launching with Android 9 but is optional for devices upgrading to Android 9 and for devices running lower versions of Android. In an Android 10 system-as-root configuration, the build always merges $TARGET_SYSTEM_OUT and $TARGET_ROOT_OUT into system.img; this config is the default behavior for all devices running Android 10.

Android 10 makes further changes to support dynamic partitions, a userspace partitioning system that enables over-the-air (OTA) updates to create, resize, or destroy partitions. As part of this change, the Linux kernel can no longer mount the logical system partition on devices running Android 10, so this operation is handled by the first stage init.

The following sections describe the system-as-root requirements for system-only OTAs, provide guidance on updating devices to use system-as-root (including partition layout changes and dm-verity kernel requirements), and detail changes to ramdisk in Android 10.

About system-only OTAs

System-only OTAs, which enable Android releases to update system.img and product.img without changing other partitions, require a system-as-root partition layout. All devices running Android 10 must use a system-as-root partition layout to enable system-only OTAs.

  • A/B devices, which mount the system partition as rootfs, already use system-as-root and don't require changes to support system OTAs.
  • Non-A/B devices, which mount the system partition at /system, must be updated to use a system-as-root partition layout to support system OTAs.

For details on A/B and non-A/B devices, refer to A/B (Seamless) System Updates.

Using vendor overlay

Vendor overlay allows you to overlay changes to the vendor partition at device boot time. A vendor overlay is a set of vendor modules in the product partition that get overlaid on the vendor partition when the device boots, replacing and adding to the existing modules.

When the device boots, the init process completes the first stage mount and reads the default properties. Then it searches /product/vendor_overlay/<target_vendor_version> and mounts each subdirectory on its corresponding vendor partition directory, if the following conditions are met:

  • /vendor/<overlay_dir> exists.
  • /product/vendor_overlay/<target_vendor_version>/<overlay_dir> has the same file context as /vendor/<overlay_dir>.
  • init is allowed to mount on the file context of /vendor/<overlay_dir>.

Implementing vendor overlay

Install vendor overlay files in /product/vendor_overlay/<target_vendor_version>. Those files overlay the vendor partition when the device boots, replacing files of the same name and adding any new files. Vendor overlay can't remove files from the vendor partition.

Vendor overlay files must have the same file context as the target files they replace in the vendor partition. By default, the files in the /product/vendor_overlay/<target_vendor_version> directory have the vendor_file context. If there are file context mismatches between vendor overlay files and the files they replace, specify that in the device-specific sepolicy. File context is set at the directory level. If the file context of a vendor overlay directory doesn't match the target directory, and the correct file context isn't specified in the device-specific sepolicy, that vendor overlay directory isn't overlaid onto the target directory.

To use vendor overlay, the kernel must enable OverlayFS by setting CONFIG_OVERLAY_FS=y. Also, the kernel must be merged from the common kernel 4.4 or later, or patched with "overlayfs: override_creds=off option bypass creator_cred".

Vendor overlay implementation example

This procedure demonstrates implementing a vendor overlay that overlays the directories /vendor/lib/*, /vendor/etc/*, and /vendor/app/*.

  1. Add prebuilt vendor files in device/<vendor>/<target>/vendor_overlay/<target_vendor_version>/:

    device/google/device/vendor_overlay/28/lib/libfoo.so
    device/google/device/vendor_overlay/28/lib/libbar.so
    device/google/device/vendor_overlay/28/etc/baz.xml
    device/google/device/vendor_overlay/28/app/qux.apk
    
  2. Install the prebuilt vendor files to product/vendor_overlay in device/google/device/device.mk:

    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,device/google/device/vendor_overlay,$(TARGET_COPY_OUT_PRODUCT)/vendor_overlay)
    
  3. Define file contexts if the target vendor partition files have contexts other than vendor_file. Because /vendor/lib/* uses the vendor_file context, this example doesn't include that directory.

    Add the following to device/google/device-sepolicy/private/file_contexts:

    /(product|system/product)/vendor_overlay/[0-9]+/etc(/.*)?   u:object_r:vendor_configs_file:s0
    /(product|system/product)/vendor_overlay/[0-9]+/app(/.*)?   u:object_r:vendor_app_file:s0
    
  4. Allow the init process to mount the vendor overlay on file contexts other than vendor_file. Because the init process already has permission to mount on the vendor_file context, this example doesn't define the policy for vendor_file.

    Add the following to device/google/device-sepolicy/public/init.te:

    allow init vendor_configs_file:dir mounton;
    allow init vendor_app_file:dir mounton;
    

Validating vendor overlay

To validate the vendor overlay configuration, add files in /product/vendor_overlay/<target_vendor_version>/<overlay_dir> and check if the files are overlaid on the files in /vendor/<overlay_dir>.

For userdebug builds, there is a test module for Atest:

$ atest -v fs_mgr_vendor_overlay_test

Updating to system-as-root

To update non-A/B devices to use system-as-root, you must update the partioning scheme for boot.img and system.img, set up dm-verity, and remove any boot dependencies on the device-specific root folders.

Updating partitions

Unlike A/B devices that repurpose /boot as the recovery partition, non-A/B devices must keep the /recovery partition separate as they don't have the fallback slot partition (for example, from boot_a to boot_b). If /recovery is removed on non-A/B device and made similar to the A/B scheme, recovery mode could break during a failed update to the /boot partition. For this reason, the /recovery partition must be a separate partition from /boot for non-A/B devices, which implies that the recovery image will continue to be updated in a deferred manner (that is, the same as in devices running Android 8.1.0 or lower).

The following table lists image partition differences for non-A/B devices before and after Android 9.

Image Ramdisk (before 9) System-as-root (after 9)
boot.img Contains a kernel and a ramdisk.img:
ramdisk.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
Contains a normal boot kernel only.
recovery.img Contains a recovery kernel and a recovery ramdisk.img.
system.img Contains the following:
system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
Contains the merged content of original system.img and ramdisk.img:
system.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...

The partitions themselves don't change; both ramdisk and system-as-root use the following partition scheme:

  • /boot
  • /system
  • /system
  • /recovery
  • /vendor, etc.

Setting up dm-verity

In system-as-root, the kernel must mount system.img under / (mount point) with dm-verity. AOSP supports the following dm-verity implementations for system.img.

vboot 1.0

For vboot 1.0, the kernel must parse Android-specific metadata on /system, then convert to dm-verity params to set up dm-verity (requires these kernel patches). The following example shows dm-verity related settings for system-as-root in kernel command line:

ro root=/dev/dm-0 rootwait skip_initramfs init=/init
dm="system none ro,0 1 android-verity /dev/sda34"
veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f

vboot 2.0

For vboot 2.0 (AVB), the bootloader must integrate external/avb/libavb, which then parses the hashtree descriptor for /system, converts it to dm-verity params, and finally passes the params to the kernel through the kernel command line. (Hashtree descriptors of /system might be on /vbmeta or on /system itself.)

vboot 2.0 requires the following kernel patches:

The following example shows dm-verity related settings for system-as-root in kernel command line:

ro root=/dev/dm-0 rootwait  skip_initramfs init=/init

dm="1 vroot none ro 1,0 5159992 verity 1
PARTUUID=00000016-0000-0000-0000-000000000000
PARTUUID=00000016-0000-0000-0000-000000000000 4096 4096 644999 644999
sha1 d80b4a8be3b58a8ab86fad1b498640892d4843a2
8d08feed2f55c418fb63447fec0d32b1b107e42c 10 restart_on_corruption
ignore_zero_blocks use_fec_from_device
PARTUUID=00000016-0000-0000-0000-000000000000 fec_roots 2 fec_blocks
650080 fec_start 650080"

Using device-specific root folders

With system-as-root, after the generic system image (GSI) is flashed on the device (and before running Vendor Test Suite tests), any device-specific root folders added with BOARD_ROOT_EXTRA_FOLDERS are gone because the entire root directory content has been replaced by the system-as-root GSI. The removal of these folders might cause the device to become unbootable if a dependency on the device-specific root folders exists (for example, they're used as mount points).

To avoid this issue, don't use BOARD_ROOT_EXTRA_FOLDERS to add device-specific root folders. If you need to specify device-specific mount points, use /mnt/vendor/<mount point> (added in these changelists). These vendor-specific mount points can be directly specified in both the fstab device tree (for first-stage mount) and the /vendor/etc/fstab.{ro.hardware} file without additional setup (as fs_mgr creates them under /mnt/vendor/* automatically).

Ramdisk

In Android 10, the first stage ramdisk contains the first stage init binary (which performs early mounting as specified by fstab entries) and vendor fstab files. (As in Android 9, system.img contains the contents of $TARGET_ROOT_OUT.)

  • For devices with a boot-ramdisk (non-A/B), first stage init is a static executable located at /init. These devices mount system.img as /system, then perform a switch root operation to move the mount at /system to /. The contents of the ramdisk are freed after mounting has completed.
  • For devices that use recovery as a ramdisk, first stage init is located at /init within the recovery ramdisk. These devices first switch root to /first_stage_ramdisk to remove the recovery components from the environment, then proceed the same as devices with a boot-ramdisk (that is, mount system.img as /system, switch root to move that mount to /, and free ramdisk contents after mounting). If androidboot.force_normal_boot=1 is present in the kernel command line, devices boot normally (into Android) instead of booting into recovery mode.

After first stage init finishes, it executes /system/bin/init with the selinux_setup argument to compile and load SELinux onto the system. Finally, init executes /system/bin/init again with the second_stage argument. At this point, the main phase of init runs and continues the boot process using the init.rc scripts.

Partition layouts (non-A/B devices)

The following sections detail differences in partition layouts for non-A/B devices before and after Android 10.

boot.img

Ramdisk
(Android 8.x and lower)
System as root
(Android 9)
Ramdisk
(Android 10)

Contains a kernel and a ramdisk.img.

ramdisk.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
    
Contains a normal boot kernel only.

Contains a kernel and ramdisk.img.

ramdisk.img
  -/
    - init
    - vendor fstab files
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
    

recovery.img

Contains a recovery kernel and a recovery ramdisk.img

system.img

Ramdisk
(Android 8.x and lower)
System as root
(Android 9)
Ramdisk
(Android 10)

Contains a system.img.

system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
   

Contains the merged contents of $TARGET_SYSTEM_OUT and $TARGET_ROOT_OUT.

system.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
    

Contains the merged contents of $TARGET_SYSTEM_OUT and $TARGET_ROOT_OUT.

system.img
  -/
    - init.rc
    - init -> /system/bin/init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
    

Partition layouts (A/B devices)

The following sections detail differences in partition layouts for A/B devices before and after Android 10.

boot.img

System as root
(Android 9)
Ramdisk
(Android 10)
Contains normal boot kernel and recovery-ramdisk (BOARD_USES_RECOVERY_AS_BOOT := true).

Recovery-ramdisk is used only to boot into recovery.
Contains normal boot kernel and recovery-ramdisk (BOARD_USES_RECOVERY_AS_BOOT := true).

Recovery-ramdisk is used to boot into both recovery and Android.
ramdisk.img
  -/
    - init -> /system/bin/init
    - first_stage_ramdisk
       - vendor fstab files
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
    

system.img

Contains the merged contents of $TARGET_SYSTEM_OUT and $TARGET_ROOT_OUT.

system.img
  -/
    - init.rc
    - init -> /system/bin/init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...