{% include "_versions.html" %}

In Android 8.0, the device kernel split into System-on-Chip (SoC), device, and board-specific deliverables. This sets up the kernel and Android such that Original Device Manufacturers (ODMs) and Original Equipment Manufacturers (OEMs) can work in isolated board–specific trees for board–specific features, drivers, etc., enabling them to override common kernel configuration, add new drivers in the form of kernel modules, etc.

This page provides details on requirements for:

Loadable kernel modules

All SoC kernels must support loadable kernel modules. As a starting point, the following kernel-config options (or their kernel-version equivalent) have been added to android-base.cfg in all common kernels and must be enabled in all device kernels:

CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y

Kernel modules should support unloading and reloading whenever possible.

Module signing

Optionally, ODMs can enable module signing in their own kernel configuration by enabling following kernel config options:

CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y

On devices required to support verified boot, Android requires the kernel modules to be in the partitions that have dm-verity enabled. Module signing is not mandatory and will not be tested against; however, if desired, an ODM can enable module signing as long as they have the key signing and other infrastructure required to ensure independent kernel and filesystem OTA updates in the future.

File locations

While Android 7.x and earlier versions do not mandate against kernel modules (and include support for insmod and rmmod), Android 8.x and higher recommends the use of kernel modules in the ecosystem. The following table shows potential board–specific peripheral support required across three Android boot modes:

Boot Mode Storage Display Keypad Battery PMIC Touchscreen NFC, Wi-Fi,
Bluetooth
Sensors Camera
Recovery
Charger
Android

In addition to availability in Android boot modes, kernel modules may also be categorized by who owns them (the SoC vendor or the ODM). If kernel modules are being used, requirements for their placement in filesystem are as follows:

In Android 7.x and earlier, /vendor and /odm partitions are not mounted early. In Android 8.x and higher, to make module loading from these partitions possible, provisions have been made to mount partitions early for both non-A/B and A/B devices. This also ensures the partitions are mounted in both Android and Charger modes.

Android build system support

In BoardConfig.mk, the Android build defines a BOARD_VENDOR_KERNEL_MODULES variable that provides a full list of the kernel modules intended for the vendor image. The modules listed in this variable are copied into the vendor image at /lib/modules/, and, after being mounted in Android, appear in /vendor/lib/modules (in accordance with the above requirements). Example configuration of the vendor kernel modules:

vendor_lkm_dir := device/$(vendor)/lkm-4.x
BOARD_VENDOR_KERNEL_MODULES := \
  $(vendor_lkm_dir)/vendor_module_a.ko \
  $(vendor_lkm_dir)/vendor_module_b.ko \
  $(vendor_lkm_dir)/vendor_module_c.ko

… where a vendor kernel module pre-built repository is mapped into the Android build at the location listed above.

The recovery image is likely to contain a subset of the vendor modules. The Android build defines the variable BOARD_RECOVERY_KERNEL_MODULES for these modules. Example:

vendor_lkm_dir := device/$(vendor)/lkm-4.x
BOARD_RECOVERY_KERNEL_MODULES := \
  $(vendor_lkm_dir)/vendor_module_a.ko \
  $(vendor_lkm_dir)/vendor_module_b.ko

The Android build takes care of running depmod to generate the required modules.dep files in /vendor/lib/modules and /lib/modules (recovery ramfs).

Module loading & versioning

We recommend loading all kernel modules in one pass from init.rc* by invoking modprobe -a. This avoids the overhead of repeatedly initializing the C runtime environment for the modprobe binary. The early-init event can be modified to invoke modprobe:

on early-init
    exec u:r:modprobe:s0 -- /vendor/bin/modprobe -a -d \
        /vendor/lib/modules module_a module_b module_c ...

Typically, a kernel module must be compiled with the kernel that the module is to be used with (otherwise the kernel will refuse to load the module). CONFIG_MODVERSIONS provides a workaround by detecting breakages in the ABI. This feature calculates a Cyclic Redundancy Check (CRC) value for the prototype of each exported symbol in the kernel and stores the values as part of the kernel; for symbols used by a kernel module, the values are also stored in the kernel module. When the module is loaded, the values for the symbols used by the module are compared with the ones in the kernel. If the values match, the module is loaded; otherwise the load fails.

To enable the updating of the kernel image separately from the vendor image, enable CONFIG_MODVERSIONS. Doing so allows small updates to the kernel (such as bug fixes from LTS) to be made while maintaining compatibility with existing kernel modules in the vendor image. However, CONFIG_MODVERSIONS does not itself fix an ABI breakage. If the prototype of an exported symbol in the kernel changes, either due to modification of the source or because the kernel configuration changed, this breaks compatibility with kernel modules that use that symbol. In such cases, the kernel module must be recompiled.

For example, the task_struct structure in the kernel (defined in include/linux/sched.h) contains many fields conditionally included depending on the kernel configuration. The sched_info field is present only if CONFIG_SCHED_INFO is enabled (which occurs when CONFIG_SCHEDSTATS or CONFIG_TASK_DELAY_ACCT are enabled). If these configuration options change state, the layout of the task_struct structure changes and any exported interfaces from the kernel that use task_struct are altered (e.g. set_cpus_allowed_ptr in kernel/sched/core.c). Compatibility with previously-compiled kernel modules that use these interfaces breaks, requiring those modules to be rebuilt with the new kernel configuration.

For more details on CONFIG_MODVERSIONS, refer to the documentation in the kernel tree at Documentation/kbuild/modules.txt.

Mounting partitions early (first stage mount)

 REQUIRED 

All Treble-enabled devices must enable first stage mount to make sure init can load SELinux policy fragments that are spread across system and vendor partitions (this also enables loading of kernel modules as soon as possible after kernel boot).

Android must have access to the filesystem(s) on which the modules reside. To enable, Android 8.x and higher supports mounting /system, /vendor, or /odm as early as init's first stage (i.e before selinux is initialized). Device makers can use device tree overlays to specify fstab entries for early mounted partitions.

Early mounting partitions, VBoot 1.0

Requirements to early mount partitions with vboot 1.0 include:

  1. Device node paths must use their by-name symlinks in fstab and device tree entries. For example, instead of specifying partitions using /dev/block/mmcblk0pX, ensure partitions are named and the device node is /dev/block/…./by-name/{system,vendor,odm}.
  2. Paths given for PRODUCT_{SYSTEM,VENDOR}_VERITY_PARTITION and CUSTOM_IMAGE_VERITY_BLOCK_DEVICE in the device configuration for the product (i.e. in device/oem/project/device.mk) must match the corresponding block device nodes specified by-name in the fstab/device tree entries. Example:
    PRODUCT_SYSTEM_VERITY_PARTITION := /dev/block/…./by-name/system
    PRODUCT_VENDOR_VERITY_PARTITION := /dev/block/…./by-name/vendor
    CUSTOM_IMAGE_VERITY_BLOCK_DEVICE := /dev/block/…./by-name/odm
    
  3. Entries provided via device tree overlays must not repeat in the fstab file fragments. For example, when specifying an entry to mount /vendor in the device tree, the fstab file must not repeat that entry.
  4. Partitions requiring verifyatboot must not be early mounted (doing so is unsupported).
  5. The verity mode/state for verified partitions must be specified in kernel cmdline using androidboot.veritymode option (existing requirement).

Early mounting device tree, VBoot 1.0

In Android 8.x and higher, init parses the device tree and creates fstab entries to mount the partition early during its first stage. An fstab entry takes the form:

src mnt_point type mnt_flags fs_mgr_flags

Device tree properties are defined to mimic that format:

Example: /system and /vendor on N6P

The following example shows device tree early mount for system and vendor partitions on Nexus 6P:

/ {
  firmware {
    android {
      compatible = "android,firmware";
  fstab {
    compatible = "android,fstab";
    system {
      compatible = "android,system";
      dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/system";
      type = "ext4";
      mnt_flags = "ro,barrier=1,inode_readahead_blks=8";
      fsmgr_flags = "wait,verify";
    };
    vendor {
      compatible = "android,vendor";
      dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor";
      type = "ext4";
      mnt_flags = "ro,barrier=1,inode_readahead_blks=8";
      fsmgr_flags = "wait";
    };
      };
    };
  };
};

Example: /vendor on Pixel

The following example shows device tree early mount for /vendor on Pixel (remember to add slotselect for partitions subject to A/B):

/ {
  firmware {
    android {
      compatible = "android,firmware";
      fstab {
        compatible = "android,fstab";
        vendor {
          compatible = "android,vendor";
          dev = "/dev/block/platform/soc/624000.ufshc/by-name/vendor";
          type = "ext4";
          mnt_flags = "ro,barrier=1,discard";
          fsmgr_flags = "wait,slotselect,verify";
        };
      };
    };
  };
};

Early mounting partitions, VBoot 2.0

VBoot 2.0 is Android Verified Boot (AVB). The requirements to early mount partitions with VBoot 2.0 are:

  1. The device node paths must use their by-name symlinks in fstab and device tree entries. For example, instead of specifying partitions using /dev/block/mmcblk0pX, ensure the partitions are named and the device node is /dev/block/…./by-name/{system,vendor,odm}.
  2. Build system variables (such as PRODUCT_{SYSTEM,VENDOR}_VERITY_PARTITION and CUSTOM_IMAGE_VERITY_BLOCK_DEVICE) used for VBoot 1.0 are NOT required for VBoot 2.0. Instead, new build variables introduced in VBoot 2.0 (including BOARD_AVB_ENABLE := true) should be defined; for a full configuration, refer to Build-System-Integration for AVB.
  3. Entries provided via device tree overlays must not repeat in the fstab file fragments. For example, if you specify an entry to mount /vendor in the device tree, the fstab file must not repeat that entry.
  4. VBoot 2.0 does not support verifyatboot, regardless of whether early mount is enabled or not.
  5. The verity mode/state for verified partitions must be specified in kernel cmdline using androidboot.veritymode option (existing requirement). Make sure to include the following fixes for AVB:

Early mounting device tree, VBoot 2.0

The configuration in device tree for VBoot 2.0 is the same as that in VBoot 1.0, with the following exceptions:

Example: /system and /vendor on N5X

The following example shows device tree early mount for system and vendor partitions on Nexus 5X. Note that:

Example: /vendor on Pixel

The following example shows mounting /vendor early on a Pixel. Note that:

Device tree overlay support (Bootloader)

Device Tree Overlay (DTO) was designed to extend the existing flattened device-tree (FDT) implementation so that the initial device-tree data in kernel can be modified by userspace at runtime by loading additional overlay FDTs that amend the original data. Android does not require runtime updates of DT blobs from user space, but instead recommends that vendors add the device tree patching in the bootloader with the help of libfdt/libufdt.

Support for DTOs in Android varies by Android release:

Partitioning requirements

Most Android devices today append the DT blob to the kernel at build time, which the bootloader knows how to read from. As Android has no specific requirements for how to build/store DT blobs (which is considered as part of the SoC kernel), the DT blob can be appended to the kernel or stored in a separate partition. The only assumption is that the bootloader already knows how and where to load the DT blob from.

Requirements for Device Tree Overlay support (if used):

Bootloader requirements

Requirements for bootloader include the following:

For more details about adding support for DTO in bootloader, see Device Tree Overlays.

Core kernel requirements

As of Android 8.0, Android mandates a minimum kernel version and kernel configuration and checks them both in VTS as well as during an OTA. Android device kernels must enable the kernel .config support along with the option to read the kernel configuration at runtime through procfs.

Kernel .config support

All device kernels must enable the entirety of android-base.cfg, which must include the following kernel–config options (or their kernel–version equivalent):

CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y

Kernel version

For Android {{ androidPVersionNumber }}, the minimum LTS kernel version requirements are 4.4.107, 4.9.84, and 4.14.42.

For details on LTS kernels, refer to Long-term stable kernels and Android Common Kernels

Device tree support

Device tree support in the kernel must be enabled and bootloaders must pass the hardware description in the form of device tree to the kernel (unless the platform supports ACPI). The device tree must also be available for Android to read and be able to pass vendor/odm specific parameters to Android. CONFIG_OF (along with all other device/subsystem specific CONFIG_OF_* kernel config options) are mandatory.

CONFIG_PROC_DEVICETREE is required on kernels prior to 3.15 so Android can access vendor/odm specific configuration very early during boot. On kernels 3.15 and later, the functionality of this option is merged into CONFIG_OF.

CONFIG_OF=y
CONFIG_PROC_DEVICETREE=y (kernels prior to 3.15)

For an example of using device tree to early mount vendor/odm partitions, refer to the AOSP changelist.

DebugFS

The implementation of the vendor interface should not rely on debugfs. It may be enabled, but VTS testing may be done with debugfs unmounted.

Future Android versions

The current Android release recommends that all board–specific code is built and shipped as kernel modules in devices. The rest of the kernel is treated monolithically with respect to Android (whether or not is it is actually a monolithic kernel, or parts of it are compiled as kernel modules).

This monolithic kernel is an SoC kernel that can boot on the SoC vendor's reference hardware but nothing beyond that. Today, SoC kernels are treated similar to the common kernel; they are also heavily replicated in board–specific repos. This distribution model causes them to be fixed differently for the same bug in each branch, delaying future updates to the kernel due to cherry–picking at different times or fixing the same bug differently. To counter this, the SoC kernels must be a separate deliverable, with everyone who uses the SoC contributing to the same SoC kernel.

Figure 1 (below) illustrates a common example of how SoC kernels get fragmented over time, across Android releases, and across ODMs.

Figure 1. Device kernel replication

Figure 1 shows the following:

  1. It takes a significant amount of effort and time for everyone to cross-merge across board–specific branches/tags.
  2. While waiting for the cross-merge, Android device manufacturers patch their own kernel for bugs/security fixes.
  3. Divergence from the ancestor make future upgrades/merges really difficult.

The proposed model for a common SoC kernel addresses problems created by upmerging changes (SoC-specific bug fixes, LTS upgrades, security fixes, etc.). Figure 2 (below) illustrates how the workflow will change in an ideal, unified–per–SoC–kernel scenario:

Figure 2. Android 8.x and higher device kernels

This is intended to solve the problem of fragmented kernel repos by recommending and working with device manufacturers to stay up to date with the common SoC kernel. Android 8.x and higher provides all possible options to ODMs to help them avoid maintaining their own SoC kernels and instead rely on the common SoC kernel for LTS upgrades/bug fixes/security patches/etc.

As a start, we want to facilitate all ODMs/vendors using a single kernel source for an SoC. In the future, we want to move towards a single binary distribution of kernel per-SoC.

Upstreaming

To make updating to newer kernel versions much easier and almost automatic, and to provide a more secure and reliable platform for ODMs to build a product with, it is strongly recommended that SoC vendors work to upstream their kernel changes and get them accepted into the main kernel.org repository. While doing so requires additional, up front efforts in time and engineering resources, it is well documented to save both time and money in the long run. It has also been documented that merged code is of a much higher quality with fewer bugs and security issues (and usually smaller) than code that has not been reviewed by the community.

If full support for the SoC is merged upstream, the community can make needed API changes as the internal kernel API evolves over time, automatically extending the longevity of the platform. The kernel can also be automatically tested for any regressions in development and stable releases by adding the hardware platform to one of the many community-managed kernel test platforms (such as kernelci.org).

For help working with the Linux kernel community to upstream your code, refer to the following resources:

The community uses a minimal review process to accept stand-alone drivers and filesystems into the staging portion of the kernel, where the community works to improve code quality.