The behavior change archive
Android's real compatibility story is not the API — it is the gated behaviour change. This page explains the two scopes, the migration ladder, and how to use the archive and targetSdk to predict what a platform upgrade will do to an app.
Here is the sentence that explains most Android upgrade surprises: the platform you run on and the platform you are treated as depend on two different numbers. The device decides the first. Your manifest decides the second. Every behaviour change in Android's recent history is a consequence of that split.
TL;DR#
- A behaviour change is a change to what existing code does, not to what compiles. It is the category that breaks apps, and it has its own documentation genre.
- There are two scopes: all apps (applies regardless of
targetSdk) and targeting (applies only when the app'stargetSdkreaches a level). - Google Play's annual minimum target is what turns the targeting scope from optional into inevitable. Without it, apps would never opt in.
- The archive has a shape: background limits, storage scoping, permission gating, and UI/layout defaults, in roughly that order of aggressiveness over time.
- The practical method is a migration ladder: read the changes between your current target and the next, fix one level at a time, and test with the platform behaviour-toggle available on a device.
Mental model#
Imagine a building that renovates one floor each year.
Everyone in the building keeps their own key and their own furniture. When a floor is renovated, tenants whose lease was signed after the renovation date get the new rules: the new fire exits, the new door widths, the new noise policy. Tenants on older leases keep the old rules, even though they live in the same renovated building.
The building is the OS version. The lease is targetSdk. The renovation date is the API level at
which a change became mandatory for new leases. And the "changes that apply to everyone" are the
building-wide things — the front door now needs a fob, the lifts have a new capacity limit — which
no lease can exempt you from.
Where the analogy breaks#
A real renovation changes the physical floor for everyone. Android's version has the opposite property: two apps on the same device can be subject to different rules for the same feature, and both are correct. That is not a bug or a compatibility hack; it is the design that lets the ecosystem move without breaking installed software. It also means "it works on my phone" is a weaker statement than it sounds — the phone is not the only variable.
The big picture#
Text description of this diagram
A four-lane timeline of Android releases. The update lane highlights the mechanism changes: Project Treble in 2017, Mainline in 2019, GKI in 2020, the Play target API requirement in 2023 and two SDK releases a year from 2025. The architecture lane shows the platform reorganisations that created the behaviour-change categories: Dalvik to ART in 2014, and adaptive-first in 2026. Read as a pair, the two lanes explain why behaviour changes accelerated after 2017: once updates could ship more often, more of them were compatibility-gated.
The timeline explains the trend. Before Treble and Mainline, a platform upgrade reached few devices, so a behaviour change had limited blast radius and could be broad. After them, updates reach more devices more often, so the platform needs the targeting scope to keep old apps working while new ones move forward.
Deep dive#
Two scopes, not one#
All-apps changes apply to every app on the device once the OS updates. They are rare and they are reserved for things the platform cannot allow to differ between apps: security boundaries, privacy protections, and system-wide behaviours. Android 9's restriction on non-SDK interfaces is the canonical example: an app that reflected into hidden internals gets the restriction regardless of its target.1
Targeting changes apply only when the app's targetSdk is at or above the level that
introduced them. This is the majority of changes, and it is where targetSdk earns its importance.
Android 13's notification permission is a targeting change: an app targeting API 33 must request
POST_NOTIFICATIONS; one targeting 32 does not.2
The distinction is not cosmetic. It determines whether an upgrade is a migration (you opt in by raising the target) or an incident (the platform changes under you). Most well-run apps experience only migrations because they raise the target deliberately. Most upgrade incidents come from all-apps changes and from platform updates that the app never tested against.
The migration ladder#
A targetSdk bump is not one change; it is the accumulated set of changes between the old and new
level. The safe procedure is a ladder, one rung at a time:
- Read the archive for every level between current and next. The behaviour-change pages list them per level, with the scope tag.
- Raise the target by one level at a time where practical, and test the app on a device or emulator at the new target.
- Use the platform's behaviour toggles during development. A device running the new OS can usually apply the new behaviour to an app even when its target is old, which lets you test before committing the manifest change.
- Treat every all-apps change separately. These do not wait for the ladder; they are already active on any updated device.
The ladder has a cost that is easy to underestimate: raising targetSdk also raises the minimum
you must support in code, because you can no longer rely on the old behaviour. That is the point,
but it is work.
The archive's shape#
Across Android 9 to 17, the behaviour changes fall into recognisable families. Knowing the families lets you predict the next release's changes before reading them.
| Family | Typical change | Why it recurs |
|---|---|---|
| Background execution | Services restricted, then foreground-service types required, then timeouts | Battery and thermal pressure never goes away |
| Storage | Scoped storage, then granular media permissions, then photo picker | Shared storage is the largest privacy surface |
| Permissions | Runtime grants, one-time grants, auto-reset, approximate location | Users cannot audit what they cannot see |
| Layout and UI | Edge-to-edge enforcement, adaptive layouts, orientation ignored on large screens | Screen shapes keep multiplying |
| Identity and tracking | Identifier restrictions, clipboard limits, local network permission | Tracking is an arms race |
| Notifications | Channels, then the runtime permission, then custom-view restrictions | The shade is a shared, scarce surface |
Android 17 in the archive#
Android 17 is a useful case study because it contains both kinds of change at once. For apps targeting API 37, orientation and resizability restrictions are ignored on large screens, and the version data records that activities no longer restart for keyboard, navigation, touchscreen and colour-mode changes by default, with an opt-in attribute to restore the old behaviour. That specific configuration-change rule is not listed on the behaviour-changes page used for the rest of this section.unverified(The Android 17 behaviour-changes page uses different wording for this change; it is recorded here from the version data on this site) For all apps, encrypted client hello is enabled. The first two are migrations you opt into; the third is an incident you cannot opt out of.4
That mix is the modern normal. A single release is never "a targeting release" or "an all-apps release"; it is a bundle, and your job is to sort the bundle by scope before you plan the work.
The change that is not documented#
Some behaviour changes do not appear in the release notes as changes at all. They appear as fixes, or as performance improvements, or as bugs that were closed. A method that used to accept a malformed argument now throws; a callback that used to fire twice now fires once.
Those are the hardest changes to migrate, because the documentation does not tell you to look. The only reliable defences are tests that assert behaviour rather than signatures, and a habit of running the app against a new platform before raising the target. A test suite that only checks that methods exist will pass through every one of these changes.
This is also why the platform's own compatibility tooling matters. The behaviour-change pages are the documented subset; the full set is enforced by the compatibility framework, which is why a change can be gated even when its documentation is thin.
What the archive is not#
The archive is not a list of every difference between two releases. It is the subset that the platform considers compatibility-relevant, documented for developers. Kernel changes, vendor changes and internal refactors are excluded, and some developer-facing changes are documented only in the API diff because they added rather than changed a capability.
Read it as a contract, not as a changelog. The contract is what the platform promises to gate; the changelog is everything that happened.
Predicting the next change#
You can forecast a release's behaviour changes with uncomfortable accuracy by asking three questions about the current platform:
- What is still expensive for the system? Battery, memory, thermal budget. The answer becomes a background or foreground-service restriction.
- What data can an app still reach that the user cannot see? The answer becomes a permission or a picker.
- What does an app still assume about the screen? The answer becomes an adaptive-layout or orientation change.
None of this requires inside knowledge. It is the same logic the platform team applies, and it is why the archive reads like a sequence rather than a list.
How it evolved#
| API | Version | What changed |
|---|---|---|
| 18 | 4.3 Jelly Bean |
|
| 23 | 6.0 Marshmallow |
|
| 28 | 9 Pie |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 33 | 13 Tiramisu |
|
| 37 | 17 Cinnamon Bun |
|
The permission rows show the pattern clearly: each release narrows the default and adds a way for the user to say no. Runtime permissions in 6.0, one-time grants in 11, auto-reset in 11, granular media permissions in 13, selected photos in 14. The direction never reverses.
Under the hood#
- Build.javaVERSION.SDK_INT: the platform level the device reports
- ApplicationInfo.javatargetSdkVersion on the installed package: the level the app is treated as
- AppOpsService.javathe per-operation switches that many privacy changes are implemented with
Curiosity corner#
- A device can run API 37 and treat your app as API 28. The compatibility framework applies the old behaviour on purpose, and it is why an app can survive several OS upgrades untouched.
- Play's annual target requirement is the enforcement arm of the targeting scope. Without it, behaviour changes would be optional forever.
- Android 16 and 17 both change large-screen orientation behaviour. The change repeats because the first release applied to some apps and the next broadened it.
Try it#
adb shell getprop ro.build.version.sdk
adb shell dumpsys package com.android.chrome | grep -E "targetSdk|minSdk"
adb shell dumpsys package com.android.settings | grep -E "targetSdk|minSdk"Example output
Illustrative output — replace the package and expect different values.Build it#
B04 — Permissions playground lets you flip a target level and watch a permission change take effect, which is the ladder in miniature.
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.
- docsPerubahan perilaku: aplikasi yang menargetkan API level 28+developer.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 13 or higherdeveloper.android.comaccessed 2026-10-27↩
- docsDisplay content edge-to-edgedeveloper.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 17developer.android.comaccessed 2026-10-27↩
- docsRecursos e APIsdeveloper.android.comaccessed 2026-10-27↩
- docsTarget API level requirements for Google Play appsdeveloper.android.comaccessed 2026-10-27↩
- docsAndroid releases and versionsdeveloper.android.comaccessed 2026-10-27↩