Loadable Kernel Modules

As part of the module kernel requirements introduced in Android 8.0, all system-on-chip (SoC) kernels must support loadable kernel modules.

Kernel configuration options

To support loadable kernel modules, android-base.cfg in all common kernels includes the following kernel-config options (or their kernel-version equivalent):

CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y

All device kernels must enable these options. Kernel modules should also support unloading and reloading whenever possible.

Module signing

Original device manufacturers (ODMs) can optionally enable module signing in their 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 kernel modules to be in the partitions that have dm-verity enabled. Module signing isn't mandatory and isn't 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 file system OTA updates in the future.

File locations

While Android 7.x and lower don't mandate against kernel modules (and include support for insmod and rmmod), Android 8.x and higher recommend 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 file system are as follows:

  • All kernels should have built-in support for booting and mounting partitions.
  • Kernel modules must be loaded from a read-only partition.
  • For devices required to have verified boot, kernel modules should be loaded from verified partitions.
  • Kernel modules shouldn't be located in /system.
  • Kernel modules from the SoC vendor that are required for full Android or Charger modes should be located in /vendor/lib/modules.
  • If an ODM partition exists, kernel modules from the ODM that are required for full Android or Charger modes should be located in /odm/lib/modules. Otherwise, these modules should be located in /vendor/lib/modules.
  • Kernel modules from the SoC vendor and ODM that are required for Recovery mode should be located in the recovery ramfs at /lib/modules.
  • Kernel modules required for both Recovery mode and full Android or Charger modes should exist both in the recovery rootfs and either the /vendor or /odm partitions (as described above).
  • Kernel modules used in Recovery mode shouldn't depend on modules located only in /vendor or /odm, as those partitions aren't mounted in Recovery mode.
  • SoC vendor kernel modules shouldn't depend on ODM kernel modules.

In Android 7.x and lower, /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 that 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

In this example, a vendor kernel module pre-built repository is mapped into the Android build at the location listed above.

The recovery image may 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 and versioning

Load 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 refuses to load the module). CONFIG_MODVERSIONS provides a workaround by detecting breakages in the application binary interface (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 doesn't fix an ABI breakage by itself. 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 (for example, 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.