How Android evolves
Android changes on a schedule, not a whim: an annual release train, three independent modularity seams, and feature flags that let one codebase produce many releases. Learn the machinery and the version history stops looking like a list of surprises.
Most people meet Android's version history as a list of names and numbers, and the list looks arbitrary: why is there a 12L, why did the numbers skip from 9 to 10, why did the release date move from autumn to spring? None of it is arbitrary. Android evolves through a fairly strict machine, and once you can see the machine, each release is a predictable output rather than a surprise.
TL;DR#
- Android ships on an annual train with a fixed branch point, and since Android 16 there are two SDK releases a year with feature drops between them.
- The API level is the compatibility identity, not the marketing version. They usually move together, but not always: Android 12L is API 32 while Android 12 is API 31.
- Three independent seams make the platform updateable: Treble for the vendor boundary, Mainline for modules inside the system, GKI for the kernel.
- Platform development is trunk-stable: all work lands on one branch, and a release configuration plus feature flags (aconfig) decides what a given release actually contains.
- Compatibility is enforced by documents and tests, not good intentions: the CDD says what a device must do, the CTS checks it, and a device that fails does not ship with Google's apps.
Mental model#
Think of a national railway that runs one timetable for the whole country.
The timetable is the release train. Trains leave on fixed dates whether or not every carriage is finished; a carriage that misses the departure waits for the next one. That is why features sometimes appear a release later than you expected, and why a release can look quiet even though the team was busy.
The track gauge is the API level. Every train on the network has to fit the same rails. Build a carriage to a different gauge and it will not run, no matter how good it is. This is the part that does not bend for marketing: an app compiled against API 35 expects API 35's shape.
The stations are the modularity seams. Treble is the station where the national network hands over to a regional operator. Mainline is a set of stations where individual carriages can be swapped without stopping the train. GKI is the standard locomotive that every operator can use.
The signals and rulebook are the CDD and CTS: the documents and tests that decide whether a train is allowed to carry passengers at all.
Where the analogy breaks#
A railway's timetable is published years ahead and rarely changes. Android's schedule has changed at least twice in the last five years: the major release moved from autumn to Q2 with Android 16, and a second SDK release was added in Q4. The machine is stable in its shape — branch, stabilise, ship, patch — but the dates are a product decision, not a law of nature. Treat the train as a pattern, not a calendar you can extrapolate indefinitely.
The big picture#
Text description of this diagram
A timeline from 2008 to 2026 in four lanes. The architecture lane shows Android 1.0 in 2008 with Dalvik, Project Butter in 2012, ART replacing Dalvik in 2014, and adaptive-first in 2026. The update lane shows Project Treble in 2017, Mainline modules through Play in 2019, GKI in 2020, the Play target API requirement in 2023, and two SDK releases a year from 2025. The developer surface lane shows the original SDK in 2009, runtime permissions in 2015, and Kotlin-first in 2019. The devices lane shows tablets with Honeycomb in 2011, Wear and TV in 2014, cars in 2017, large screens again with 12L in 2021, and XR in 2024. Three era bands span the chart: Dalvik era 2008 to 2014, ART era 2014 to 2017, and modularisation 2017 to 2026.
The lanes are deliberately not the same kind of thing. Architecture events are one-off reorganisations that take years to pay off. Update events are mechanisms that change how every later release reaches a device. Developer-surface events change what you write. Form factors change who the platform is for. A release like Android 8.0 appears in two lanes at once, because Treble was both an architectural split and an update mechanism.
Deep dive#
The release train#
A modern Android release is a long-running branch cut from a single main development branch. The cut happens months before the release, because after it the branch has to be stabilised: bugs fixed, compatibility verified, and the release tested against the CDD and CTS. During that window, work that is not already in the branch does not ship in that release.
Two consequences follow, and both explain things that look odd from the outside.
First, a feature can be finished and still not ship. If it missed the cut, it waits. Second, a release's feature list is decided at the cut, not at launch. Marketing copy written after the cut describes work that was already frozen.
Since Android 16, the schedule has two SDK releases a year: the major release in Q2 and a second SDK release in Q4, with feature drops in between. The intent is smaller, more predictable changes for developers instead of one large annual wave.1 The version numbers still move one at a time, because the API level is what compatibility is measured against.
The three modularities#
For most of Android's life an update meant replacing the whole system image, and that meant every party in the chain had to agree: Google, the SoC vendor that supplied drivers and HALs, the phone maker, and often the carrier. Any one of them could delay or block the update. Android's answer was not one big fix but three separate seams, each removing a different dependency.
Treble (Android 8.0, API 26) split the vendor implementation from the system image behind a versioned vendor interface. After Treble, a platform update no longer required the SoC vendor to recompile its HALs: the interface between them was stable, and the vendor image could stay put. The formal artefacts are the vendor manifest and the compatibility matrix, which declare what each side provides and what it requires.2
Mainline (Android 10, API 29) went further and made individual core components updateable as modules, delivered through Google Play rather than a full OS update. A module is packaged as an APEX (or, for some components, an APK), carries its own version, and declares a narrow interface to the rest of the system.2 The point is not that every component is updateable; it is that the update unit became smaller than the OS.
GKI (Android 11, API 30) did the same for the kernel. The Generic Kernel Image is one kernel binary shared across devices, with vendor code moved into loadable modules behind a stable Kernel Module Interface. A vendor can update its modules without forking the core kernel, and Google can ship kernel security fixes to many devices at once.
Trunk stable and aconfig#
The build side of evolution is less visible but just as important. Android develops trunk-stable: all platform work lands on one main branch, rather than one long-lived branch per release. A release is then a configuration of that branch, not a separate copy of the code.3
The mechanism that makes this work is a feature-flag system called aconfig. A feature declares a flag; a release configuration decides the flag's value for a given release or product. The same source can therefore produce different behaviour for different releases without a divergent branch. That reduces merge pain, and it makes a release's content explicit: you can read the configuration instead of diffing two branches.
Trunk-stable has a cost that developers feel. Because the code is shared, a change can affect several releases at once, and the flag becomes part of the contract: a flag that is enabled in one release and disabled in another is a behaviour difference that has to be tested in both. It also means "which release added this?" is often answered by a configuration file rather than a commit date.
What a release actually contains#
A release is not just code. It is a bundle of commitments:
| Artefact | What it is | Who it binds |
|---|---|---|
| CDD | The Compatibility Definition Document: the requirements a device must meet to call itself Android | Device makers |
| CTS | The Compatibility Test Suite: automated tests that check the CDD | Device makers, in CI |
| VTS | Vendor Test Suite: the equivalent for the vendor interface after Treble | Device makers |
| API diff | A generated list of public API changes between two levels | App developers |
| Behaviour-change docs | A list of changes gated by targetSdk, with migration notes | App developers |
The CDD and CTS are the reason "Android" means something across thousands of device models. A device that fails CTS does not ship with Google's apps. The API diff and behaviour-change docs are the contract with app developers, and they are the subject of the next two pages.45
How it evolved#
The shape of the platform changed three times, and each change was a response to a specific failure.
| 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 |
|
The pattern is the same each time: find the boundary where change is most expensive, formalise it, and make the two sides independently replaceable. Treble found the HAL boundary. Mainline found the boundary between system components. GKI found the boundary between the core kernel and vendor modules. The 2020s added a fourth, less discussed seam: the boundary between a phone and every other shape a screen can take, which is the subject of Android beyond phones.
Under the hood#
Three files that show the machinery rather than describe it:
- release_config_map.textprotothe release configurations that trunk-stable builds select between
- version_defaults.mkwhere the platform version, API level and codename are assembled at build time
- Build.javawhat the running system reports about itself: VERSION.SDK_INT, RELEASE, CODENAME
Curiosity corner#
- The dessert names stopped but the alphabet did not. Public releases stopped using dessert names with Android 10 in 2019, but internal codenames continue in alphabetical order — which is why the codenames in this site's version tables still read like a menu.
- The version number skipped nothing; the API level did the skipping. There was never an Android 10 API 30. The two counters are independent.
- "Project Treble" is a musical metaphor. The name refers to the treble register, because the project raised the abstraction level between hardware and software.
Try it#
adb shell getprop ro.build.version.sdk
adb shell getprop ro.build.version.release
adb shell getprop ro.build.version.codename
adb shell getprop ro.build.version.security_patchExample output
Illustrative output — values differ per device.Build it#
The builder track's B01 — Hello lifecycle is the smallest project
that makes targetSdk behaviour visible: run it once with an old target and once with a current
one, and watch which callbacks and restrictions change.
Check yourself#
Check yourself
What does an API level identify?
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.
- docsAndroid releases and versionsdeveloper.android.comaccessed 2026-10-27↩
- docsModular system componentssource.android.comaccessed 2026-10-27↩
- docsConfiguration (aconfig) overviewsource.android.comaccessed 2026-10-27↩
- docsAndroid Compatibility Definition Document (CDD)source.android.comaccessed 2026-10-27↩
- docsCompatibility Test Suite (CTS)source.android.comaccessed 2026-10-27↩
- wikiAndroid version historyWikipediaaccessed 2026-10-27↩
- docsTarget API level requirements for Google Play appsdeveloper.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 17developer.android.comaccessed 2026-10-27↩
- sourceAndroid Gerrit code reviewandroid-review.googlesource.comaccessed 2026-10-27↩