The Android Common Kernels (ACKs) are the basis for all Android product kernels. Vendor and device kernels are downstream of ACKs. Vendors add support for SoCs and peripheral devices by modifying the kernel source code and adding device drivers. These modifications can be extensive, to the point that as much as 50% of the code running on a device is out-of-tree code (not from upstream Linux or from AOSP common kernels).
Thus, a device kernel is comprised of:
- Upstream: The Linux kernel from kernel.org
- AOSP: Additional Android-specific patches from AOSP common kernels
- Vendor: SoC and peripheral enablement and optimization patches from vendors
- OEM/device: Additional device drivers and customizations
Nearly every device has a custom kernel. This is kernel fragmentation.
Figure 1. Android kernel hierarchy leads to fragmentation
The costs of fragmentation
Kernel fragmentation has several negative effects on the Android community.
Security updates are labor intensive
Security patches cited in the Android Security Bulletin (ASB) must be backported into each of the device kernels. However, due to kernel fragmentation, it's prohibitively expensive to propagate security fixes to Android devices in the field.
Difficult to merge Long-Term Supported updates
The Long-Term Supported (LTS) releases include security fixes and other critical bug fixes. Staying up to date with LTS releases has proven to be the most effective way to provide security fixes. On Pixel devices, it was discovered that 90% of the kernel security issues reported in the ASB had already been fixed for devices that stay up to date.
However, with all of the custom modifications in the device kernels, it's difficult to just merge the LTS fixes into device kernels.
Inhibits Android platform release upgrades
Fragmentation makes it difficult for new Android features requiring kernel changes to be added to devices in the field. Android Framework code must assume that as many as five kernel versions are supported and that no kernel changes were made for the new platform release (Android 10 supports 3.18, 4.4, 4.9, 4.14, and 4.19 kernels, which in some cases haven't been enhanced with new features since Android 8 in 2017).
Difficult to contribute kernel changes back to upstream Linux
With all of the changes being made to the kernel, most flagship devices ship
with a kernel version that's already at least 18 months old. For example, the
4.14 kernel was released by kernel.org
in November of 2017 and the first
Android phones using 4.14 kernels shipped in the Spring of 2019.
This long delay between upstream kernel release and products makes it difficult for the Android community to feed needed features and drivers into the upstream kernels, so it's challenging to fix the fragmentation issue.
Fixing the fragmentation: Generic Kernel Image
The Generic Kernel Image (GKI) project addresses kernel fragmentation by unifying the core kernel and moving SoC and board support out of the core kernel into loadable modules. The GKI kernel presents a stable Kernel Module Interface (KMI) for kernel modules, so modules and kernel can be updated independently.
The GKI:
- Is built from the ACK sources.
- Is a single-kernel binary plus associated loadable modules
per architecture, per LTS release (currently only arm64 for
android11-5.4
andandroid12-5.4
). - Is tested with all Android Platform releases that are supported for the associated ACK. There’s no feature deprecation for the lifetime of a GKI kernel version
- Exposes a stable KMI to drivers within a given LTS.
- Does not contain SoC- or board-specific code.
Here’s how an Android device looks with GKI implemented.
Figure 2. GKI architecture
GKI is a complex change that will be rolled out in several stages starting with the v5.4 kernels in the Android 11 platform release.
GKI 1.0 — GKI compatibility requirements
For some devices launching with the Android 11 platform release, Treble compatibility requires GKI testing for devices running v5.4 kernels.
Figure 3. Partitions for GKI compatibility testing
GKI compatibility means that the device passes the VTS and CTS-on-GSI+GKI
tests with the Generic System Image (GSI) and the GKI kernel installed by
flashing the GKI boot image into the boot
partition and GSI system image in
the system
partition. Devices can ship with a different product kernel and
can use loadable modules that GKI doesn't provide. However, both the product
and GKI kernels must load modules from the same vendor_boot
and vendor
partitions. Therefore, all product kernels are required to have the same binary
kernel module interface (KMI). Vendors can extend the KMI for product kernels as
long as it remains compatible with the GKI KMI. There's no requirement that
vendor modules be unloadable in GKI 1.0.
GKI 1.0 goals
- Don't introduce regressions in VTS or CTS when the product kernel is replaced by the GKI kernel.
- Reduce the kernel maintenance burden for OEMs and vendors to stay up to date with AOSP common kernels.
- Include core Android changes in kernels whether a device is upgraded to a new Android platform release or newly launched.
- Never break Android userspace.
- Separate hardware-specific components from the core kernel as loadable modules.
GKI 2.0 - GKI products
Some devices that launch with the Android S (AOSP experimental) (2021) platform release using kernel versions v5.10 or higher are required to ship with the GKI kernel. Signed boot images will be made available and updated regularly with LTS and critical bug fixes. Because binary stability will be maintained for the KMI, these boot images can be installed with no changes to vendor images.
GKI 2.0 goals
- Don't introduce significant performance or power regressions with GKI.
- Enable OEMs to deliver kernel security fixes and bug fixes (LTS) without vendor involvement.
- Reduce cost of updating major kernel version for devices (for example, from v5.10 to the 2021 LTS kernel).
- Maintain only one GKI kernel binary per architecture by updating kernel versions with a clear process for upgrading.
GKI design
KMI kernel branches
GKI kernels are built from the ACK KMI kernel branches, which are described in
detail in
Android Common Kernels.
The KMI is uniquely identified by the kernel version and the Android platform
release, so the branches are named <androidRelease>-<kernel version>
. For
example, the 5.4 KMI kernel branch for Android 11 is
named android11-5.4.
It's expected that for Android S (AOSP experimental) (not committed and shown only to demonstrate how the new branching model
will progress in the future) there will be two additional KMI kernels,
android12-5.4
and a second kernel based on the new LTS kernel, which should be
declared at the end of 2020.
KMI kernel hierarchy
Figure 4 shows the branch hierarchy for the 5.10 KMI kernels. android12-5.10
is the KMI kernel corresponding to Android S (AOSP experimental) and
android13-5.10
corresponds to Android T (AOSP experimental) (not
committed and shown only to demonstrate how the new branching model will
progress in the future).
Figure 4. KMI kernel hierarchy for 5.10
As shown in Figure 4, the KMI branches cycle through three phases: development (dev), stabilization (stab), and frozen. These phases are described in detail in Android Common Kernels.
After the KMI kernel is frozen, no KMI-breaking changes are accepted unless a serious security issue is identified that can't be mitigated without affecting the stable KMI. The branch remains frozen throughout its entire lifetime.
Bug fixes and partner features can be accepted into a frozen branch as long as the existing KMI isn't broken. The KMI can be extended with new exported symbols as long as the interfaces comprising the current KMI aren’t affected. When new interfaces are added to the KMI, they immediately become stable and can’t be broken by future changes.
For example, a change that adds a field to a structure used by a KMI interface is not allowed because it changes the interface definition:
struct foo {
int original_field1;
int original_field2;
int new_field; // Not allowed
};
int do_foo(struct foo &myarg)
{
do_something(myarg);
}
EXPORT_SYMBOL_GPL(do_foo);
However, adding a new function is fine:
struct foo_ext {
struct foo orig_foo;
int new_field;
};
int do_foo2(struct foo_ext &myarg)
{
do_something_else(myarg);
}
EXPORT_SYMBOL_GPL(do_foo2);
KMI stability
To realize the GKI goals, it’s critical to maintain a stable KMI for drivers. The GKI kernel is built and shipped in binary form, but vendor-loadable modules are built in a separate tree. The resulting GKI kernel and modules must work as if they were built together. For GKI compatibility testing, the boot image containing the kernel is replaced with a boot image containing the GKI kernel, and the loadable modules in the vendor image must function correctly with either kernel.
The KMI doesn't include all symbols in the kernel or even all of the 30,000+ exported symbols. Instead, the symbols that can be used by modules are explicitly listed in a set of symbol list files maintained publicly in the root of the kernel tree. The union of all the symbols in all of the symbol list files defines the set of KMI symbols maintained as stable. An example symbol list file is abi_gki_aarch64_db845c, which declares the symbols required for the DragonBoard 845c.
Only the symbols listed in a symbol list and their related structures and definitions are considered part of the KMI. You can post changes to your symbol lists if the symbols you need aren't present. After new interfaces are in a symbol list, and therefore are part of the KMI description, they're maintained as stable and must not be removed from the symbol list or modified after the branch is frozen.
Each KMI kernel tree has its own set of symbol lists. No attempt is made to
provide ABI stability between different KMI kernel branches. For example, the
KMI for android11-5.4
is completely independent of the KMI for
android12-5.4
.
Generally, the Linux community has frowned on the notion of in-kernel ABI stability for the mainline kernel. In the face of different toolchains, configurations, and an ever-evolving Linux mainline kernel, it isn't feasible to maintain a stable KMI in mainline. However, it's possible in the highly constrained GKI environment. The constraints are:
- The KMI is only stable within the same LTS kernel (for example,
android11-5.4
).- No KMI stability is maintained for
android-mainline
.
- No KMI stability is maintained for
- Only the specific Clang toolchain supplied in AOSP and defined for the corresponding branch is used for building kernel and modules.
- Only symbols known to be used by modules as specified in a symbol list are
monitored for stability and considered KMI symbols.
- The corollary is that modules must use only KMI symbols. This is enforced by failing module loads if non-KMI-symbols are required.
- After the KMI branch is frozen, no changes can break the KMI, including:
- Config changes
- Kernel code changes
- Toolchain changes (including updates)
KMI monitoring
ABI monitoring tools monitor KMI stability during presubmit testing. Changes that break the KMI fail presubmit testing and must be reworked to be compatible. These tools are available to partners and the public for integration into their build processes. The Android kernel team uses these tools to find KMI breakages during development and when merging LTS releases. If a KMI breakage is detected during an LTS merge, the KMI is preserved by either removing the offending patches or by refactoring the patches to be compatible.
The KMI is considered broken if an existing KMI symbol is modified in an incompatible way. Examples:
- New argument added to a KMI function
- New field added to a structure used by a KMI function
- New enum value added that changes the values of enums used by a KMI function
- Configuration change that changes the presence of data members affecting the KMI
Adding new symbols doesn't necessarily break KMI, but new symbols that are used must be added to a symbol list and to the ABI representation. Otherwise future changes to this part of the KMI won’t be recognized.
Partners are expected to use the ABI monitoring tools to compare the KMI between their product kernel and the GKI kernel and ensure that they're compatible.
The latest android11-5.4
binary GKI kernel can be downloaded from
ci.android.com
(kernel_aarch64
builds).
Single compiler
A compiler change can alter the internal kernel data structure layout that affects the ABI. Because it's critical to keep the KMI stable, the toolchain used to build the GKI kernel must be completely compatible with the toolchain used to build vendor modules. The GKI kernel is built with the LLVM toolchain included in AOSP.
As of Android 10, all Android kernels must be built with an LLVM toolchain. With GKI, the LLVM toolchain used to build product kernels and vendor modules must generate the same ABI as the LLVM toolchain from AOSP and partners must ensure that the KMI is compatible with the GKI kernel.
The Android kernel build documentation describes how the reference GKI kernel is built. In particular, the documented procedure ensures that the correct toolchain and configuration are used to build the kernel. Downstream partners are encouraged to use the same tooling for producing the final kernel to avoid incompatibilities caused by toolchain or other build-time dependencies.
Kernel configs
The GKI kernel is built using arch/arm64/configs/gki_defconfig
. Because these
configs affect the KMI, the GKI configs are managed very carefully. For the
frozen KMI kernels, configs can only be added or removed if there's no impact to
the KMI.
The GKI kernel must be configured to run on a diverse set of devices. Therefore it must have built-in support for all the subsystems and options required for all these devices, not including the loadable modules that are used to enable the hardware. Partners should request the needed config changes to dev kernels.
Boot changes
To facilitate a clean separation between the GKI and vendor components, the
boot
partition contains only generic components, including the kernel and a
ramdisk with GKI modules. A new version of the boot header (v3) is defined to
indicate compliance with the GKI architecture. The GKI version of the boot
images is delivered by Google and replaces the vendor's version of the boot
image when testing for GKI compatibility.
The ramdisk for first-stage init
, recovery
, and fastbootd
is an initramfs
image comprised of two CPIO archives that are concatenated by the bootloader.
The first CPIO archive comes from the new vendor_boot
partition. The second
comes from the boot
partition.
A summary of the changes is provided here. See Vendor boot partition for details.
Boot partition
The boot
partition includes a header, kernel, and a CPIO archive of the
generic portion of the boot ramdisk.
With a boot header v3 boot
partition, these sections of the prior boot
partition are no longer present:
- Second stage bootloader: If a device has a second stage bootloader it must be stored in its own partition.
- DTB: The DTB is stored in the Vendor boot partition.
The boot
partition contains a CPIO archive with the GKI components:
- GKI kernel modules located in
/lib/modules/
first_stage_init
and libraries it depends onfastbootd
andrecovery
(used in A/B and Virtual A/B devices)
The GKI boot image is provided by Google and must be used for GKI compatibility testing.
The latest arm64 android11-5.4
boot.img
is downloadable from
ci.android.com
in the aosp_arm64
build artifacts of the aosp-master
branch.
The latest arm64 android11-5.4
kernel image (Image.gz
) can be downloaded
from
ci.android.com
in the kernel_aarch64
build artifacts of the
aosp_kernel-common-android11-5.4
branch.
Vendor boot partition
The vendor_boot
partition is introduced with GKI. It's A/B'd with Virtual A/B
and consists of a header, the vendor ramdisk, and the device tree blob. The
vendor ramdisk is a CPIO archive that contains the vendor modules required for
device boot. This includes modules to enable critical SoC functionality as well
as storage and display drivers needed to boot the device and display splash
screens.
The CPIO archive contains:
- First-stage
init
vendor kernel modules located in/lib/modules/
modprobe
config files located in/lib/modules
modules.load
file indicating the modules to load during first-stageinit
Bootloader requirement
The bootloader must load the generic ramdisk CPIO image (from the
boot
partition) into memory immediately following the
vendor ramdisk CPIO image (from the
vendor_boot
partition). After decompression, the
result is the generic ramdisk overlaid on top of the file structure of the
vendor ramdisk.
GKI compatibility testing
For the Android 11 platform release, devices launched with a v5.4 kernel must run the VTS and CTS-on-GSI tests using the GKI boot image supplied by Google.
Contributing to the GKI kernel
The GKI kernel is built from the AOSP Common Kernels starting with
android11-5.4
. All submitted patches must conform to
these contribution guidelines,
which document two strategies:
- Best: Make all of your changes to upstream Linux. If appropriate, backport to the stable releases. These patches are merged automatically in the corresponding AOSP common kernels. If the patch is already in upstream Linux, post a backport of the patch that conforms to the patch requirements below.
- Less good: Develop your patches out of tree (from an upstream Linux point of view). Unless the patches are fixing an Android-specific bug, they're very unlikely to be accepted unless they've been coordinated with kernel-team@android.com.
For partners implementing GKI, there might be valid reasons why out-of-tree patches are required (especially if there are silicon schedules that must be met). For these cases, file a Buganizer issue.
Submit GKI changes through Gerrit to the android-mainline
branch
first and then backported to other release branches as needed.
The source code associated with loadable modules doesn't need to be contributed to the GKI kernel source tree, however it's strongly recommended to submit all drivers to upstream Linux.
Requesting backports from mainline
Generally, mainline patches needed by GKI partners can be backported to the GKI kernels. Upload the patch to Gerrit following the contribution guidelines.
If the patch has been posted upstream, but hasn't yet been accepted, it's recommended to wait until it is accepted. If the schedule doesn't permit waiting for the patch to be accepted upstream, file a Buganizer issue.
Adding and removing GKI configs
To request the addition or removal of configs in
arch/arm64/configs/gki_defconfig
, file a Buganizer issue clearly stating the
request and the justification. If there's no accessible Buganizer project, then
post the patch with the config change to Gerrit and make sure the commit message
clearly states the reason the config is needed.
Config changes in frozen KMI kernels must not affect KMI.
Modifying core kernel code
Modifications to core kernel code in AOSP common kernels are discouraged. First send patches to upstream Linux and then backport them. If there's a good reason for a core kernel change, file a Buganizer issue clearly stating the request and the justification. No Android-specific features are accepted without a Buganizer issue. Send an email to kernel-team@android.com if you can't create a Buganizer issue.
Exporting symbols using via EXPORT_SYMBOL_GPL()
Don't send patches upstream that contain only symbol exports. To be considered
for upstream Linux, additions of EXPORT_SYMBOL_GPL()
require an in-tree
modular driver that uses the symbol, so include the new driver or changes to an
existing driver in the same patchset as the export.
When sending patches upstream, the commit message must contain a clear justification for why the patch is needed and beneficial to the community. Enabling exports to benefit out-of-tree drivers or functionality isn't a persuasive argument to upstream maintainers.
If for some reason, the patch can't be sent upstream, file a Buganizer issue and explain why the patch can't be sent upstream. Generally, symbols that are the supported interface to a kernel subsystem are likely to be accepted as exports. However, random internal helper functions are unlikely to be accepted and you'll be asked to refactor your code to avoid using them.
Adding a symbol to a KMI symbol list
The KMI symbol lists must be updated with GKI kernel symbols used by vendor modules. Because only KMI symbols are maintained as stable, GKI doesn't allow modules to load if they rely on a non-KMI symbol.
The extract_symbols
script extracts the relevant symbols from a kernel build
tree and can be used to update a KMI symbol list. Refer to the
symbol listing documentation
for further details.