Skip to content

Android Architecture

Overview

Android is a Linux-based mobile operating system developed by Android Inc. (acquired by Google in 2005) and released as open source under Apache 2.0 (with some GPL components). It is the world's most widely deployed operating system by active device count — approximately 3.5 billion active Android devices as of 2024, spanning smartphones, tablets, wearables, TVs, automotive systems, and embedded devices.

Android is not simply Linux with a mobile UI. It is a fundamentally restructured software stack that replaces standard GNU userspace with a purpose-built Android runtime, a custom IPC mechanism (Binder), a Java/Kotlin application model, and a deep security architecture built around per-application Linux process isolation. Understanding Android means understanding both the Linux kernel it builds on and the Android-specific layers above it.

Prerequisites

  • Linux kernel fundamentals: processes, IPC, memory management, device drivers
  • Java/Kotlin programming (for framework-level understanding)
  • C/C++ systems programming (for HAL and native layer)
  • Basic operating systems concepts: scheduling, virtual memory, IPC

Historical Context

Android Timeline:

2003  Andy Rubin, Rich Miner, Nick Sears, Chris White found Android Inc.
      Original concept: OS for digital cameras

2005  Google acquires Android Inc. for ~$50M
      Project pivots to mobile phones

2007  OHA (Open Handset Alliance) announced: Google + carriers + OEMs
      Apple announces iPhone (December — first shipped January 2007)

2008  Android 1.0 on HTC Dream (T-Mobile G1)
      Dalvik VM, Linux 2.6 kernel, limited API

2010  Android 2.2 (Froyo): JIT compiler in Dalvik, significant performance jump
      Android market share begins growing rapidly

2011  Android 4.0 (Ice Cream Sandwich): unified phone/tablet UI, Holo design
      Project Butter (4.1 Jelly Bean 2012): 60fps rendering, vsync

2014  Android 5.0 (Lollipop): ART replaces Dalvik, Material Design
      SELinux enforcing mode becomes mandatory
      64-bit AArch64 support

2017  Android 8.0 (Oreo): Project Treble — decouples vendor from framework
      Background execution limits, new notification system

2019  Android 10: mandatory Project Mainline, scoped storage, foldables
      Background location restrictions

2021  Android 12: Material You, Privacy Dashboard, approximate location
      Hardware-backed attestation requirements tightened

2023  Android 14: partial photo/video access, predictive back gesture
      First-class 64-bit only support (dropped 32-bit system support)

Android Layer Stack

+-------------------------------------------------------------+
|                     APPLICATIONS                            |
|   (Java/Kotlin — run in ART, isolated per-app process)      |
|   Phone  Maps  Browser  Camera  3rd-party apps              |
+-------------------------------------------------------------+
|                  APPLICATION FRAMEWORK                      |
|   Activity Manager    Window Manager   Notification Manager |
|   Package Manager     Power Manager    Content Providers    |
|   Telephony Manager   Location Manager View System          |
+-------------------------------------------------------------+
|               ANDROID RUNTIME (ART)                         |
|   DEX bytecode    AOT compilation   GC (Concurrent mark-   |
|   JNI bridge      Profile-guided    sweep + generational)   |
|   Core libraries  optimization      Stack maps for GC       |
+-------------------------------------------------------------+
|    NATIVE C/C++ LIBRARIES    |    HARDWARE ABSTRACTION LAYER|
|   libc (bionic)  libz        |   Camera HAL   Audio HAL    |
|   libssl/crypto  libsqlite   |   Bluetooth    GPS HAL      |
|   Skia (2D)      WebKit      |   Sensor HAL   Wifi HAL     |
|   OpenGL ES      Vulkan      |   Power HAL    Keymaster    |
+-------------------------------------------------------------+
|                    LINUX KERNEL                              |
|   Binder IPC driver    Ion memory allocator                 |
|   Android wakelocks    Ashmem (anonymous shared memory)     |
|   Paranoid networking  USBGadget   Low memory killer        |
|   cpusets / cpufreq    Incremental FS (INCFS)               |
+-------------------------------------------------------------+
|                     HARDWARE                                 |
|   SoC: Snapdragon / Exynos / Dimensity / Tensor            |
|   Secure Enclave  Camera ISP  DSP  GPU  Modem              |
+-------------------------------------------------------------+

Linux Kernel: Android Extensions

Android uses a modified Linux kernel with several Android-specific additions. Since Project Mainline and AOSP's "Generic Kernel Image" (GKI) initiative (Android 11+), the goal is to minimize the delta between Android kernel and mainline Linux.

Binder IPC Driver

The most important Android-specific kernel component. /dev/binder implements Android's high-performance, secure IPC (covered in depth in 02-binder-ipc.md).

ION Memory Allocator

ION (replaced by DMA-BUF Heaps in Android 12+) provides shared memory between processes and hardware components (GPU, camera, DSP) without intermediate copies. A camera frame can be allocated in ION, written by the camera ISP, read by the GPU for rendering, and read by the encoder for H.264 compression — all without any CPU copy.

Android Wakelocks

Standard Linux power management was insufficient for mobile. Android added wakelocks: a process holds a wakelock to prevent the system from suspending. The framework's PowerManager.WakeLock in Java maps to kernel wakelocks.

Wakelock lifecycle:
  App acquires wakelock -> kernel prevents suspend
  App does work (music playback, GPS fix)
  App releases wakelock -> system can suspend

If app crashes while holding wakelock -> wakelock leaked
  -> Battery drain (device never sleeps)
  -> Detected by BatteryStats: "wakelocks held" metric

Android 6.0 introduced Doze mode — the framework overrides wakelocks when the screen is off and the device is stationary, periodically batching network and sync operations.

Low Memory Killer (LMK)

Android has no swap partition on most devices. When memory pressure mounts, the kernel's LMK kills background processes. Each process has an OOM score adjusted by the Android framework based on its visibility and importance:

OOM Score Adj -> Process State:
  -1000:  System-critical (init, system_server) — never killed
  -900:   Persistent services
     0:   Foreground app (screen visible, user interacting)
   100:   Visible (partially obscured)
   200:   Service (started service)
   500:   Cached (background, recently used)
   900:   Background (background, not recently used)
  1000:   Empty (no active components) — killed first

LMK kills in order from highest oom_score_adj first.

The userspace LMKD daemon (replacing the in-kernel LMK since Android 10) uses pressure stall information (PSI) from the kernel to make kill decisions based on memory pressure levels rather than just free page count.


Hardware Abstraction Layer (HAL)

HAL is a C interface layer between Android's Java/native framework and hardware-specific kernel drivers. Its purpose: allow Android framework code to work across different hardware without recompilation, while letting OEMs implement hardware features without modifying the framework.

HAL Architecture (Project Treble)

Before Android 8.0 (Oreo), HAL modules were loaded directly into the framework process as .so shared libraries. This meant the framework had direct access to vendor code running in the same process. Framework updates required OEM cooperation to update their HAL code simultaneously.

Project Treble (Android 8.0) separated HAL into its own process:

Before Treble:                    After Treble:

  system_server                   system_server
  +-------------------+           +------------------+
  | Framework code    |  Binder   | Framework code   |
  | HAL .so loaded    |---------> | HIDL / AIDL      |
  | in same process   |           | interface client |
  +-------------------+           +------------------+
                                          |
                                     Binder IPC
                                          |
                                  +------------------+
                                  | HAL service      |
                                  | (separate process|
                                  | in vendor         |
                                  | partition)        |
                                  | camera.so         |
                                  | audio.default.so  |
                                  +------------------+

HIDL (HAL Interface Definition Language, Android 8-11) and then AIDL (Android 12+) define stable interfaces between framework and HAL. This means Google can update the Android framework (system partition) independently of the OEM HAL (vendor partition) — enabling faster security updates without OEM participation.


Android Runtime (ART)

ART replaced the Dalvik VM in Android 5.0 (Lollipop). The transition was the most significant performance improvement in Android history.

Dalvik vs. ART

Dalvik (pre-5.0):
  .java source -> javac -> .class (JVM bytecode)
       -> dx -> .dex (Dalvik bytecode)

  On device: JIT compilation + interpreter
  - JIT compiles hot methods on first execution
  - Cold start = slow (interpreter until JIT kicks in)
  - JIT-compiled code is temporary, regenerated on reboot

ART (5.0+):
  .java source -> javac -> .class
       -> d8/r8 -> .dex

  On device at install time:
  - dex2oat: Ahead-Of-Time compilation: .dex -> .oat (native code)

  ART 7.0+: Hybrid AOT + JIT + Profile-Guided Optimization (PGO)
  - App first run: interpreted + JIT profiling
  - Background dex2oat: AOT compile hot paths from profile
  - Result: fast startup, optimal steady-state performance

ART Garbage Collection

ART's GC is generational, concurrent, and compacting:

  • Young generation: Small objects, collected frequently. Bump-pointer allocation.
  • Old generation: Long-lived objects, collected less often. Compaction reduces fragmentation.
  • Concurrent: GC runs concurrently with application threads — short stop-the-world pauses only for root scanning and final reference processing.
  • Low-pause target: GC pause < 10ms for foreground apps (via GcCause::kGcCauseForeground priority elevation).

ART uses read barriers (with CC — Concurrent Copying collector) to allow object relocation while the app continues running. Objects can be moved in memory while live references to them remain valid because reads are intercepted to look up the forwarding address.


Android App Model

Android applications are composed of four component types:

Activity: Single screen with UI
  - Has lifecycle: onCreate -> onStart -> onResume -> [running]
    -> onPause -> onStop -> onDestroy
  - Back stack management: TaskStack

Service: Background work, no UI
  - Started service: runs until stopSelf() or stopService()
  - Bound service: IPC endpoint, stays alive while clients bound
  - Foreground service: requires persistent notification,
    survives memory pressure better than background

BroadcastReceiver: Event handler for system/app broadcasts
  - Intent-based message bus
  - Manifest-declared: launched for events even if app not running
  - Dynamic: registered in code while component is running

ContentProvider: Structured data sharing between apps
  - URI-based access model
  - Enforces permissions per URI
  - Contacts, MediaStore, Settings are system ContentProviders

Components are loosely coupled — Activities can launch Activities in other apps, Services can be bound from other packages. The Intent system is the glue.

Intent System

Intents are the mechanism for component invocation:

  • Explicit intent: Named target component (new Intent(context, MyActivity.class))
  • Implicit intent: Describes an action + data (ACTION_VIEW + content://...). Android resolves to the best matching component (or shows a chooser)

The Android framework's Activity Manager validates intent routing, enforces permissions, and manages task stacks.


Zygote: Warm App Start

Cold starting every app from scratch would mean loading the Android framework classes (hundreds of MB) each time. Zygote solves this:

Boot sequence:
  init (PID 1)
    -> Zygote (/system/bin/app_process)
         - Loads and initializes ART runtime
         - Pre-loads ~800 framework Java classes
         - Pre-loads common resources (themes, drawables)
         - Opens /dev/binder
         - Listens for spawn requests on /dev/socket/zygote
    -> Forks for each app launch request:
         fork() -> new process inherits:
           - ART runtime (initialized)
           - Pre-loaded classes (shared, copy-on-write pages)
           - /dev/binder FD
         child process:
           - Drops privileges to app's UID
           - Loads app-specific code
           - Calls Application.onCreate() -> Activity.onCreate()

Performance benefit:
  Cold start without Zygote: ~500ms (load ART + framework classes)
  Warm start from Zygote fork: ~50-100ms (fork is fast, pages are CoW)

The pre-loaded framework classes share physical pages across all apps (copy-on-write semantics). On a device running 50 apps, the ~300MB of pre-loaded ART data appears once in physical RAM, not 50 times.


Android Permissions Model

Android's permission system enforces what data and capabilities each app can access.

Install-Time Permissions (Protection Level: Normal)

Low-risk permissions, automatically granted at install. Example: INTERNET, BLUETOOTH, VIBRATE. The user is not prompted; they appear in the Play Store listing.

Runtime Permissions (Protection Level: Dangerous)

Introduced in Android 6.0. High-risk permissions require runtime user confirmation. Granted per-permission, not per-app. Can be revoked at any time:

Runtime permission categories:
  CAMERA          - Physical camera hardware
  MICROPHONE      - Microphone input
  LOCATION        - GPS / network location (fine / coarse)
  CONTACTS        - Contact database
  STORAGE         - Read/write external storage (pre-Android 10)
  PHONE           - Make calls, read call log
  CALENDAR        - Calendar database
  BODY_SENSORS    - Heart rate, etc.

Android 12+ partial permissions:
  BLUETOOTH_SCAN (separated from legacy BLUETOOTH)
  READ_MEDIA_IMAGES / READ_MEDIA_VIDEO (instead of READ_EXTERNAL_STORAGE)
  APPROXIMATE_LOCATION (new — coarse only, without fine)

Android Sandbox

Each app has a unique Linux UID assigned at install time. This is the foundation of Android's security model:

App isolation via Linux UIDs:

  com.google.android.maps    -> UID 10052
  com.instagram.android      -> UID 10083  
  com.example.myapp          -> UID 10104

  Each app's data directory:
  /data/data/com.example.myapp/   owned by UID 10104

  Other apps cannot read this directory — standard Linux DAC.
  Even root is not normally accessible to apps (SELinux).

SELinux on Android

Android enforces SELinux in enforcing mode since Android 5.0. Every process, file, socket, and device has a type label. Policy defines which types can interact. The policy ships as a compiled binary in the system image:

  • u:r:untrusted_app:s0 — third-party app domain
  • u:r:system_server:s0 — system_server domain
  • u:r:servicemanager:s0 — Binder ServiceManager

An app exploiting a memory corruption vulnerability cannot escape its SELinux domain to access other apps' data or kernel interfaces without also exploiting an SELinux policy bypass.


Production Examples

Google Pixel 8 (2023): Tensor G3 SoC (2 Cortex-X3 + 2 Cortex-A715 + 4 Cortex-A510), 8GB LPDDR5 RAM, 128/256GB UFS 3.1 storage. Android 14. Tensor Security Core (dedicated security chip for Titan M2). Protected Computing for on-device ML. Android 14 requires ARMv8.0 minimum — drops old 32-bit-only SoCs.

Samsung Galaxy S24 Ultra: Snapdragon 8 Gen 3 (in US/Korea) or Exynos 2400. One UI 6.1 over Android 14. Samsung's hardware HAL layers implement camera tuning, S Pen digitizer, and Samsung-specific features as HAL extensions above standard Android HAL interfaces.

Android in Automotive (Android Auto / AAOS): Android Automotive OS runs natively on the vehicle's head unit. Distinct from Android Auto (phone projection). AAOS provides car-specific system services (CarHvacManager, CarSensorManager, VehicleHAL for CAN bus data). Used in Volvo, Polestar, BMW, Renault, and GM vehicles.


Debugging Notes

  • adb shell dumpsys: Most powerful Android debugging command. dumpsys activity shows task stacks and Activity states. dumpsys meminfo shows per-app memory usage. dumpsys batterystats reveals wakelock abuse.
  • Android Profiler in Android Studio: CPU profiler (sampling + tracing), memory profiler (heap dumps, allocation tracking), network profiler. Attach to running process or profile from launch.
  • strace on Android: adb shell strace -p <pid> requires root or profiling permissions. Reveals unexpected file access, IPC activity, or system call failures.
  • systrace / Perfetto: adb shell perfetto records kernel scheduler events, Binder transactions, frame rendering timeline. Essential for diagnosing jank (missed 16ms vsync deadlines). Replaced the older systrace in Android 10+.
  • ANR (Application Not Responding): Triggered when the main thread does not handle an input event within 5 seconds (foreground), or a broadcast handler exceeds 10 seconds. Check /data/anr/traces.txt for the main thread stack trace at time of ANR. Common cause: disk I/O or Binder call blocking the main thread.

Security Implications

  • Permissions granularity creep: The permission system has hundreds of permissions; many are confusingly named or overlap. Users cannot make informed decisions. Android 12+ Privacy Dashboard shows which apps accessed camera/mic/location in the last 24 hours.
  • One-time permissions (Android 11+): Camera, microphone, and location can be granted for "only this time" — revoked when app moves to background.
  • Sideloading risk: Apps installed outside Play Store bypass Google Play Protect scanning. Android requires explicit user opt-in, but social engineering attacks exploit this. Enterprise MDM (Mobile Device Management) can disable sideloading.
  • Kernel attack surface: Despite SELinux, kernel vulnerabilities are the most impactful Android attack vector — they can escape all userspace sandboxes. The annual Android Security Bulletin patches kernel vulnerabilities under CVEs. Project Zero's research has repeatedly shown Binder driver bugs as high-severity.
  • Spectre/Meltdown on Android: ARM CPUs in Android devices were affected. Android's mitigations: KPTI (Kernel Page Table Isolation) enabled by default on AArch64, swpf instruction flushing, and compiler-based mitigations in ART.

Performance Implications

  • Cold vs. warm vs. hot start: Cold start (process not running): ~500ms-2s. Warm start (process running, Activity recreated): ~200-500ms. Hot start (Activity in back stack, just brought forward): ~100-200ms. Zygote enables warm over cold. Retained process state enables hot.
  • Binder call overhead on main thread: Every bound service call goes through Binder IPC. Synchronous Binder calls block the calling thread. Main thread Binder calls to slow services cause jank. Use async Binder (AIDL oneway keyword) or coroutines to avoid blocking.
  • ART Ahead-of-Time vs. Just-in-Time: Profile-guided compilation (introduced Android 7) produces the best performance. The first run is slower (JIT profiling); subsequent runs benefit from AOT compilation of hot paths. Cloud-based profile delivery allows new installs to benefit from other users' profiles.
  • GC pause: Despite concurrent GC, stop-the-world pauses can cause dropped frames. Applications should minimize allocation rate in rendering loops. Allocation Tracker in Android Studio identifies hot allocation sites.
  • Memory pressure and app process death: When the system kills background processes, restoring state requires a cold start. Activity onSaveInstanceState and ViewModel survive process death. Design apps to restore state gracefully.

Failure Modes

  • Wakelock leak: App acquires PARTIAL_WAKE_LOCK and crashes before releasing. Device never sleeps; battery drains in hours instead of days. Detected by adb shell dumpsys power | grep "Wake Locks" and battery stats.
  • Content Provider crash loop: A ContentProvider that crashes causes all apps depending on it to die. Can cascade into system instability. ContentProvider crashes are surfaced in logcat and adb bugreport.
  • Implicit broadcast abuse: Pre-Android 8, apps received many system broadcasts (battery changed, network state changed) even when not running. This caused millions of apps to wake up for every battery status change. Android 8+ restricts background implicit broadcasts.
  • Doze mode interfering with RT tasks: Background services in Doze mode (screen off, stationary) are deferred for up to hours. Apps requiring periodic background work must use WorkManager with constraints, JobScheduler, or foreground services.

Modern Usage

  • Android 14 Health Connect: Centralized health data platform with unified permissions for fitness, nutrition, sleep. Apps share data through the Health Connect ContentProvider rather than direct API access.
  • Android 15 predictive back gesture: Framework-level API for previewing the back destination before committing. Requires application opt-in via manifest.
  • Google Play Integrity API (replacing SafetyNet): Stronger device integrity checking for banking and payment apps. Backed by hardware attestation via the Secure Enclave.
  • Android for Cars: Android Automotive OS in production vehicles from Volvo, BMW, Renault. Full Android stack running on the vehicle's IVI unit with Vehicle HAL integration.

Future Directions

  • Mainline (Project Mainline): Google-updateable system modules delivered outside of full OTA. 30+ modules including Media codecs, DNS resolver, TLS, Wi-Fi. Allows security patches without waiting for OEM OTA cycle.
  • Generic Kernel Image (GKI): Standardized Android kernel that all Android 11+ devices run. Vendor-specific code moves to loadable kernel modules (GKI modules). Enables Google to ship kernel security updates independently of OEM.
  • Android Virtualization Framework (AVF): Protected VMs using ARM virtualization. pKVM (protected KVM) hypervisor. Used for Protected Compute — isolated environments where even the host OS cannot read the VM's memory. Enables confidential ML model inference.
  • RISC-V Android: Google has announced first-class RISC-V support in Android. AOSP RISC-V builds are functional. First commercial Android RISC-V hardware expected in 2025-2026.

Exercises

  1. Use adb shell dumpsys activity to observe the Activity back stack of a running app. Navigate through multiple screens and observe how the stack grows. Then use the back button and watch it shrink. Identify any Activities with unusual flags in the record.
  2. Write a simple Android app that deliberately leaks a PARTIAL_WAKE_LOCK. Confirm the leak with adb shell dumpsys power. Then fix the leak. Use BatteryHistorian to visualize battery impact.
  3. Use Android Studio's Memory Profiler to capture a heap dump of your app after navigating through several screens. Identify whether any Activities are being retained after their onDestroy is called (memory leak). Common cause: anonymous inner class holding Activity reference.
  4. Examine the SELinux policy on an Android device with adb shell cat /sys/fs/selinux/policy | audit2allow. Find the domain for a third-party app process and list what file types and Binder services it is allowed to access.
  5. Build AOSP from source for a supported target (or use an Android Emulator build). Modify the ActivityManager to log the OOM score adjustment of each process on every adjustment event. Observe the priority adjustments during app lifecycle transitions.

References

  • Android Open Source Project Documentation: https://source.android.com/docs/
  • Reto Meier and Ian Lake, Professional Android (4th ed., Wrox, 2018)
  • Android Architecture Components Documentation: https://developer.android.com/topic/architecture
  • Google Android Security Team, "Android Security Bulletin": https://source.android.com/docs/security/bulletin
  • Eran Messeri, "Android ART Explained" (Google I/O 2014)
  • Android's SELinux Policy: https://source.android.com/docs/security/features/selinux
  • Project Treble Overview: https://android-developers.googleblog.com/2017/05/here-comes-treble-modular-base-for.html
  • Jeff Vander Stoep, "SEAndroid: Bringing flexible mandatory access control to Android" (USENIX LISA 2013)
  • Brendan Gregg, "Android Performance Profiling" — perf and Perfetto on Android
  • Android Compatibility Definition Document (CDD): https://source.android.com/docs/compatibility/cdd