The security model
Android security is not one feature but a set of boundaries, each of which assumes the one outside it has already failed. Read them as rings and the design starts to make sense.
Every month, Android devices run code written by people the device owner has never met. Some of that code is hostile. The security model is the set of mechanisms that lets a phone do that without handing over the user's messages, photos and bank details.
TL;DR#
- Android security is defence in depth: a hardware root of trust, verified boot, the kernel, the app sandbox, permissions, and app signing.
- Each layer assumes the layers outside it have failed. That is the design principle, not a slogan: it is why the kernel still enforces SELinux when the framework is compromised.
- The app sandbox is the central mechanism: a unique UID per app, a private data directory, and an SELinux domain.
- and dm-verity make a modified system image either refuse to boot or fail at read time, and key lets a remote service check what a device is running.
- keeps keys in hardware, so a full software compromise still does not yield the key material.
Mental model#
Think of a castle with a bank vault inside it.
The outer wall is the hardware root of trust: it cannot be moved and it decides whether the gates open at all. Inside, verified boot is the gate check — the castle refuses to open if the walls have been altered. The keep is the kernel: everything inside the castle is subject to its rules. The rooms are apps, each with its own lock. The doors between rooms are permissions, and the vault is the secure hardware, where the keys live and where even the king needs the right credentials.
Each of those assumes the previous one has been breached. The vault exists because the rooms might fall. The keep exists because a room's lock might be picked.
Where the analogy breaks#
A castle's layers are all in the same place, physically. Android's layers are in different privilege domains: the kernel and the TEE are separate execution environments, and the TEE's memory is not readable even by the kernel. The physical metaphor undersells one of the most important properties: the innermost layer is not merely guarded, it is unreachable.
The big picture#
Text description of this diagram
Concentric rings representing Android's security boundaries, outermost first. The hardware root of trust (boot ROM, DICE, RPMB, TEE/StrongBox) cannot be updated and cannot be read. Verified boot (vbmeta, dm-verity, rollback index) detects modified system or vendor images. The kernel (UIDs, GIDs, capabilities, SELinux, seccomp) enforces every access at the syscall boundary. The app sandbox (per-app UID, private data directory, untrusted_app domain) stops one app from reading another's data. Permissions and consent (runtime permissions, AppOps, one-time grants) let the user say no. Keys and secrets (FBE CE/DE keys, Keystore keyblobs, synthetic password) are the data that matters when everything else fails. Each ring assumes the ring outside it has already failed.
The ordering is the argument. Each ring's "cannot" is the next ring's reason to exist.
Deep dive#
Ring 1: the hardware root of trust#
Everything above the bootloader is verifiable only if something below it is not. That something is a small amount of code in ROM, plus a secret provisioned at manufacture.
DICE is the modern mechanism. It derives a compound device identifier from a unique device secret and measurements of each firmware stage, cumulatively: each stage combines its own image's hash with the previous stage's identifier. A change to any stage changes the identity of that stage and every stage after it. That gives a remote service a way to verify what firmware ran, without trusting anything above the ROM.
The property that matters: the key material derived from a changed boot chain is different. An attacker who modifies firmware cannot decrypt data that was sealed to the genuine chain.
Ring 2: verified boot and dm-verity#
Verified boot checks that each partition is signed by the device's root key.1 The chain runs from the
root of trust to the bootloader, to the boot image, to vbmeta, to the system and vendor partitions.
makes the check continuous rather than one-off: it builds a hash tree over a read-only partition, so the kernel can verify each block as it is read. That is why a tampered system partition fails at read time, not just at boot — and why the failure surfaces as an I/O error in a specific file rather than a boot loop.
Ring 3: the kernel#
The kernel enforces four things that matter here:
- UIDs and GIDs — the identity every file access and IPC call is checked against.
- SELinux — mandatory access control, so that even a process with the right UID can be confined to a domain that may not do what the UID would allow.
- seccomp — a syscall filter, so a compromised process has fewer kernel entry points to attack.
- Capabilities — fine-grained privilege, so a process can have one root-like power without all of them.
The kernel is the layer that must not fail. It is also mostly C, which is why memory-safety work matters so much here: a kernel memory bug is a bypass of every ring above it.
Ring 4: the app sandbox#
Every app gets a unique UID and runs in its own process. Its data lives in a directory owned by that UID with mode 0700 for apps targeting API 24Android 7.0 or higher. Since API 28Android 9, non-privileged apps also get individual SELinux sandboxes, so the mandatory policy distinguishes one app from another rather than treating all third-party apps as one domain.
The consequence is that an app cannot read another app's files, cannot see its memory, and cannot impersonate it — even if it has code execution in its own process.
Ring 5: permissions and consent#
Permissions are how an app asks for more than its sandbox allows. The model has three layers:
- Protection level — how a permission can be granted.
normalis automatic,dangerousneeds the user,signatureneeds the same signing key,privilegedneeds to be on the system image. - Grant state — whether this app has this permission right now. Since API 23Android 6.0, dangerous permissions are granted at runtime; since API 33Android 13, notifications have their own runtime permission.
- AppOps — a second, finer-grained allow/deny for individual operations, which is what the privacy toggles in Settings actually change.
were the biggest change in the model's history. They moved the decision from "at install, take it or leave it" to "at use, with context". They also made it normal for an app to be denied and still run.
Ring 6: keys and secrets#
The innermost ring is not a boundary around code; it is a boundary around data.
means a stolen phone's storage is ciphertext without the credential. means a key can be used without being extractable: the private key never leaves the TEE or StrongBox, and the app asks for an operation, not for the key.
That is the last line. If an attacker has code execution in the kernel, they can read memory, but they cannot read the key inside the TEE, and they cannot decrypt credential-encrypted storage without the user's credential — which is rate-limited in hardware.
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 trajectory is from coarse to fine. Android 4.x added SELinux in permissive mode, then enforcing at API 21Android 5.0. Android 6.0 added runtime permissions. Android 7.0 added FBE. Android 9 added per-app SELinux sandboxes. Android 10 restricted background activity starts. Android 11 added one-time permissions and scoped storage enforcement. Android 13 added the notification permission and granular media permissions. Android 15 added Private Space. Each release narrowed a specific capability that had turned out to be too broad.
Under the hood#
- the SELinux policy tree: domains, types and allow rules
- ContextImpl.javawhere an app's data directories are resolved, per user and per storage class
- the Keystore daemon, rewritten in Rust for Android 12
- the KeyMint HAL, where key operations happen in secure hardware
Curiosity corner#
- A device can be secure and still be rooted. Root is a deliberate choice by the owner; the security model is about remote attackers and hostile apps, not about the person holding the phone.
- The sandbox is older than the permission system. UID isolation shipped in Android 1.0; runtime permissions arrived in 6.0. The model worked for seven years without asking the user anything at runtime.
private-spaceis a security feature that looks like a launcher feature. A hidden profile with its own encryption key is a way to protect data from someone who has the unlocked phone.
Try it#
adb shell getenforce
adb shell getprop ro.boot.verifiedbootstate
adb shell getprop ro.boot.flash.locked
adb shell ls -ld /data/data/com.android.chrome
getenforce prints Enforcing on any production device. verifiedbootstate prints green on a
locked device with a verified boot chain and orange on an unlocked one. The ls shows the app's
private directory owner and mode — the sandbox, visible as a filesystem permission.
Check yourself#
Check yourself
Which layer enforces the app sandbox?
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.
- docsVerified bootsource.android.comaccessed 2026-10-27↩
- docsApplication sandboxsource.android.comaccessed 2026-10-27↩
- docsAndroid security overviewsource.android.comaccessed 2026-10-27↩
- docsSELinuxsource.android.comaccessed 2026-10-27↩
- docsKeystoresource.android.comaccessed 2026-10-27↩
- docsDICE (Device Identifier Composition Engine)source.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↩
- docsPermissions on Android | Privacydeveloper.android.comaccessed 2026-10-27↩