The three-axis modularity story
Treble split vendor from system, Mainline split the system from itself, and GKI split the kernel from the device. Three axes, one idea: find the boundary, formalise it, and make it cheap to cross.
Three projects, three boundaries, one pattern. Treble drew a line between vendor and system. Mainline drew lines inside the system. GKI drew a line through the kernel. Each one converted a monolith into a contract, and each one was motivated by the same arithmetic: a fix that requires a full rebuild reaches fewer devices than a fix that does not.
TL;DR#
- (Android 8.0, API 26Android 8.0) split the vendor image from the system image behind a versioned HAL interface.
- (Android 10, API 29Android 10) split the system image into independently updatable modules, packaged as APEX or APK.
- (Android 11, API 30Android 11) split the kernel into a Google-built core and vendor loadable modules joined by a stable .
- The three axes are independent: a device can have any combination, and most modern devices have all three.
- Each axis trades the same things: process and interface complexity now, in exchange for not rebuilding everything later.
Mental model#
Think of a building renovated in three stages.
First the external wall is turned into a curtain wall: the interior can be replaced without touching the structure. That is Treble.
Then the interior is fitted with modular partitions: rooms can be reconfigured without rebuilding the floor. That is Mainline.
Then the foundation is separated from the building: the slab is standardised so the structure above can be replaced without re-pouring concrete. That is GKI.
Each stage is a different boundary, and none of them depends on the others being done. You can have a curtain wall and a monolithic foundation.
Where the analogy breaks#
A building's stages happen in order, over years, with the occupants displaced. Android's three axes were developed largely in parallel and ship simultaneously. A single device launched with Android 12 has all three from day one, which is why the "three stages" framing is a teaching device rather than a history.
The big picture#
Text description of this diagram
A two-layer diagram. The upper layer shows the phone's stack from apps to kernel, annotated with who can change each part. The lower layer shows the update reality for each part: silent app updates, silent Play services updates, monthly Play System Updates with one reboot, quarterly-to-yearly full OTAs, vendor OTAs that often never happen, and kernel updates that ride on an OTA. Read together, the diagram shows three independent update axes: Play for apps and modules, the OEM for the platform and vendor image, and the OEM again for the kernel. GKI is the attempt to make the last of those cheaper.
Deep dive#
Axis 1: Treble, the vendor seam#
Treble's boundary is a process boundary with a declared interface. The vendor implements HALs; the framework consumes them; VINTF checks that the two agree.
What it made possible: replace system.img without rebuilding vendor.img.
What it did not make possible: replace anything inside system.img without a full release.
That second limit is what motivated Mainline. Once the vendor seam existed, the system image was still a monolith — and it was the monolith that contained the media codecs, the TLS library and the runtime, which are the parts most likely to need a security fix.
Axis 2: Mainline, the internal seams#
Mainline's boundary is a container boundary. A module is a package with its own version and its own contents, mounted or loaded at boot, updated through Play.
What it made possible: fix a codec on a device whose OEM stopped shipping releases. What it did not make possible: change the kernel, or change the parts of the framework that are too entangled to containerise.
The APEX mechanism is what makes it work for native code: a mounted ext4 image with dm-verity means
the contents are real files at real paths, visible to the dynamic linker and to init, not just to
an app runtime.
Axis 3: GKI, the kernel seam#
GKI's boundary is an ABI boundary. The is the set of symbols and structure layouts that vendor modules may rely on, and it is stable within a kernel LTS branch.
The mechanism:
- The GKI kernel is built from the Android Common Kernel (ACK).
- It contains no SoC-specific or board-specific code.
- Device support lives in loadable vendor modules, built against the KMI.
- Because the KMI is stable, a new kernel image can be installed without changing the vendor image.
The version history matters: AOSP states that beginning with Android 12, devices shipping with kernel 5.10 or higher must ship the GKI kernel. GKI itself arrives with Android 11; the mandate expands at Android 12.
How the axes interact#
The three are not orthogonal in practice, and the interactions are where real devices get interesting.
GKI depends on the vendor image being separate. If the kernel and vendor code were in one image, there would be no point in a stable KMI. GKI inherits Treble's premise.
Mainline modules can carry HALs. The Wi-Fi module contains its own HAL interface and its own service. That means a Mainline update can, in principle, change a HAL — but only a HAL whose consumer is also in a module, not one the vendor implements.
The vendor image is the residue. After all three axes, the vendor image is what remains: drivers, firmware, and the HAL implementations whose interfaces the platform consumes. That is the part Treble could not make updatable by Google, and it is still the part that ages worst.
What the whole picture buys#
Put the three together and you get a device where:
- An app update is a download and no reboot.
- A Play System Update is a monthly download, one reboot, atomic, rollback-capable.
- A vendor OTA is the OEM's business, but it no longer has to include the framework or the kernel.
- A kernel fix can, in principle, ship as a boot image update without a vendor rebuild.
The last one is the least realised in practice, because shipping a kernel still rides on an OEM release. GKI made it technically cheap; it did not make it commercially automatic. That gap is the honest summary of the entire module: modularity removes technical blockers, and the commercial ones remain.
The four questions to ask of any device#
When you want to know how updatable a device really is, these are the questions the three axes suggest:
- Is there a VINTF manifest? If yes, the vendor seam exists.
- Which modules does it have?
cmd apex listand the module metadata answer this. - Which kernel, and is it GKI? The build properties and the presence of
/vendor/lib/modulesare the clues. - Who last shipped an update, and when? No amount of architecture fixes a support policy.
The fourth question is the one that matters most to a user, and it is the one that architecture cannot answer.
How it evolved#
| API | Version | What changed |
|---|---|---|
| 1 | 1.0 |
|
| 17 | 4.2 Jelly Bean |
|
| 19 | 4.4 KitKat |
|
| 23 | 6.0 Marshmallow |
|
| 24 | 7.0 Nougat |
|
| 26 | 8.0 Oreo |
|
| 28 | 9 Pie |
|
| 29 | 10 |
|
| 30 | 11 |
|
| API | Version | Kernel |
|---|---|---|
| 1 | 1.0 |
|
| 2 | 1.1 |
|
| 3 | 1.5 Cupcake |
|
| 4 | 1.6 Donut |
|
| 5 | 2.0 Eclair |
|
| 6 | 2.0.1 Eclair |
|
| 7 | 2.1 Eclair |
|
| 8 | 2.2 Froyo |
|
| 9 | 2.3 Gingerbread |
|
| 10 | 2.3.3 Gingerbread |
|
| 11 | 3.0 Honeycomb |
|
| 12 | 3.1 Honeycomb |
|
| 13 | 3.2 Honeycomb |
|
| 14 | 4.0 Ice Cream Sandwich |
|
| 15 | 4.0.3 Ice Cream Sandwich |
|
| 16 | 4.1 Jelly Bean |
|
| 17 | 4.2 Jelly Bean |
|
| 18 | 4.3 Jelly Bean |
|
| 19 | 4.4 KitKat |
|
| 20 | 4.4W KitKat (Wear) |
|
| 21 | 5.0 Lollipop |
|
| 22 | 5.1 Lollipop |
|
| 23 | 6.0 Marshmallow |
|
| 24 | 7.0 Nougat |
|
| 25 | 7.1 Nougat |
|
| 26 | 8.0 Oreo |
|
| 27 | 8.1 Oreo |
|
| 28 | 9 Pie |
|
| 29 | 10 |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 32 | 12L |
|
| 33 | 13 Tiramisu |
|
| 34 | 14 Upside Down Cake |
|
| 35 | 15 Vanilla Ice Cream |
|
| 36 | 16 Baklava |
|
| 37 | 17 Cinnamon Bun |
|
The two tables side by side tell the story better than either alone. The architecture column shows the seams appearing (vendor, then modules, then kernel). The kernel column shows the versions moving, which is the substrate the seams have to work on.
Under the hood#
- the Android Common Kernel tree that GKI is built from
- the kernel build rules, including the GKI and vendor-module split
- the vendor interface checking, inherited from Treble
- the Mainline module sources, one directory per module
Curiosity corner#
- GKI ships a single kernel binary plus modules per architecture, per LTS release. That is the unit of sharing: one kernel for every device on that LTS.
- A device can be Treble-compliant and still not have GKI. Treble is Android 8.0; GKI is Android 11, and the kernel mandate only starts with devices shipping kernel 5.10 on Android 12.
- The vendor image is shrinking in responsibility but not in importance. It is where the hardware lives, and no amount of modularity moves the hardware.
Try it#
adb shell getprop ro.treble.enabled
adb shell getprop ro.vndk.version
adb shell ls /apex | head -20
adb shell cat /proc/version
adb shell ls /vendor/lib/modules | head -10
The first two lines answer the Treble question. The third answers the Mainline question. The last two answer the kernel question: the version string identifies the LTS, and the presence of vendor modules shows the GKI split.
Check yourself#
Check yourself
What was the core technical barrier that kept Android phones on old software before 2017?
Sources#
Sources
Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.
- docsGeneric Kernel Image (GKI)source.android.comaccessed 2026-10-27↩
- docsStable KMIsource.android.comaccessed 2026-10-27↩
- docsAndroid Common Kernelsource.android.comaccessed 2026-10-27↩
- docsKernel modules overviewsource.android.comaccessed 2026-10-27↩
- docsModular system componentssource.android.comaccessed 2026-10-27↩
- docsVendor interface objects (VINTF)source.android.comaccessed 2026-10-27↩
- docsAndroid kernel overviewsource.android.comaccessed 2026-10-27↩
- docsGKI versioningsource.android.comaccessed 2026-10-27↩