How Android OS Works Internally

📖 Concept

Understanding Android OS internals separates senior engineers from mid-level ones. At Google, you're expected to reason about framework-level behavior when debugging complex issues.

Boot sequence:

1. Bootloader → Linux Kernel
2. Kernel starts init process (PID 1)
3. init starts system daemons:
   - servicemanager (Binder registry)
   - surfaceflinger (compositing)
   - zygote (app process factory)
4. Zygote preloads Android classes & resources
5. Zygote forks system_server
6. system_server starts all Android services:
   - ActivityManagerService (AMS)
   - WindowManagerService (WMS)
   - PackageManagerService (PMS)
   - InputManagerService
7. AMS starts the Launcher app

Key system services:

  • AMS (ActivityManagerService): Manages Activity lifecycle, processes, tasks, and back stacks
  • WMS (WindowManagerService): Manages windows, input dispatch, screen layout
  • PMS (PackageManagerService): Manages installed packages, permissions, IntentFilters
  • SurfaceFlinger: Composites all window surfaces into the final display frame

Rendering pipeline:

App Process:
  UI Thread: measure → layout → draw (record display list)
  RenderThread: execute display list → OpenGL/Vulkan commands

System Process:
  SurfaceFlinger: composite all surfaces → display

16.6ms per frame (60 FPS). If UI Thread + RenderThread exceed this budget → dropped frame (jank).

Threading model:

  • Main/UI Thread: All UI operations, lifecycle callbacks. Blocking = ANR after 5 seconds.
  • RenderThread: Executes GPU commands. Introduced in Android 5.0 to offload GPU work from UI thread.
  • Binder threads: Handle IPC calls (pool of 15-16 threads per process).
  • Worker threads: Your coroutines, AsyncTask (deprecated), executors.

💻 Code Example

codeTap to expand ⛶
1// Understanding the rendering pipeline
2// The Choreographer coordinates frame rendering at VSYNC boundaries
3
4// Check for jank using Choreographer
5class JankDetector {
6 private var lastFrameTime = 0L
7
8 fun start() {
9 Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback {
10 override fun doFrame(frameTimeNanos: Long) {
11 if (lastFrameTime > 0) {
12 val frameMs = (frameTimeNanos - lastFrameTime) / 1_000_000
13 if (frameMs > 16) {
14 Log.w("Jank", "Frame took ${frameMs}ms (budget: 16ms)")
15 }
16 }
17 lastFrameTime = frameTimeNanos
18 Choreographer.getInstance().postFrameCallback(this)
19 }
20 })
21 }
22}
23
24// StrictMode — detect main thread violations during development
25class MyApplication : Application() {
26 override fun onCreate() {
27 super.onCreate()
28 if (BuildConfig.DEBUG) {
29 StrictMode.setThreadPolicy(
30 StrictMode.ThreadPolicy.Builder()
31 .detectDiskReads()
32 .detectDiskWrites()
33 .detectNetwork()
34 .penaltyLog() // Log violations
35 .penaltyFlashScreen() // Flash screen on violation
36 .build()
37 )
38 StrictMode.setVmPolicy(
39 StrictMode.VmPolicy.Builder()
40 .detectLeakedSqlLiteObjects()
41 .detectLeakedClosableObjects()
42 .detectActivityLeaks()
43 .penaltyLog()
44 .build()
45 )
46 }
47 }
48}
49
50// Understanding Looper/Handler/MessageQueue
51// Main thread runs a Looper that processes Messages from a MessageQueue
52// Every lifecycle callback, touch event, and invalidate() is a Message
53
54// How ANR happens:
55// 1. System sends an input event message to your app's MessageQueue
56// 2. If the current message is blocking (heavy computation, disk I/O)
57// 3. The input event waits in the queue
58// 4. After 5 seconds, AMS triggers ANR dialog

🏋️ Practice Exercise

Practice:

  1. Trace the Android boot sequence from bootloader to Launcher
  2. Explain what happens at the OS level when you rotate your device
  3. Use adb shell dumpsys activity activities to inspect the Activity stack
  4. Enable StrictMode and identify main thread violations in your app
  5. Explain the role of SurfaceFlinger in the rendering pipeline
  6. What's the maximum number of Binder threads per process? Why does it matter?

⚠️ Common Mistakes

  • Assuming the UI thread is only for drawing — it also handles lifecycle callbacks, input events, and Binder calls

  • Not understanding that each VSYNC signal triggers a frame render — if your frame isn't ready, it's a dropped frame

  • Ignoring Binder thread limits — if all 15-16 threads are busy with IPC calls, new IPC calls will block

  • Thinking Android services run in separate threads — Services run on the main thread by default

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for How Android OS Works Internally. Login to unlock this feature.