Zygote
The big picturebeginner

What happens when you tap an icon

The whole platform, in thirty seconds. A tap on the launcher becomes a process, a window, a frame and a photon — and every module on this site is one line of this story.

10 minAPI 1–37 · 17interactivequizverified 2026-10-27

This is the page to read first if you want the whole shape of Android in one sitting. It follows a single tap from the digitizer to the first frame on the display, naming each mechanism as it passes. Nothing here is simplified to the point of being wrong; it is just compressed. Each step links to the module that takes it apart.

TL;DR#

  • A touch is read by the kernel, routed by system_server, and delivered to the launcher's window.
  • The launcher sends an intent to start an activity, which crosses Binder into the Activity Task Manager.
  • If the app is not running, the system asks Zygote to fork a process; the runtime and framework classes are already there.
  • The app creates its activity, its window and its Surface, and begins to draw.
  • The frame is recorded on the UI thread, rendered on the RenderThread, handed to SurfaceFlinger, and composed onto the display at the next vsync.
  • Most of this happens in well under a second, and the parts you can measure are the parts performance work targets.

Mental model#

Think of ordering a dish in a restaurant with a very large kitchen.

You tap the menu (the launcher). The waiter writes an order slip (an intent) and takes it to the kitchen dispatch desk (system_server). The dispatcher checks whether a cook is available. If not, it clones one from the template (Zygote). The cook prepares the plate, hands it to the pass, and the expediter (SurfaceFlinger) puts it on the tray and sends it out.

Where the analogy breaks#

In a restaurant, one dish appears at a time. On Android, the "kitchen" is constantly preparing many dishes in parallel, and the display only shows a dish when it is exactly ready — at the moment the screen refreshes. If the plate is late, the previous dish stays on the table. That timing constraint is the part of the story most analogies miss.

The big picture#

Loading diagram…
Text description of this diagram

A sequence diagram of one tap on a launcher icon. The digitizer reports a touch through the kernel input driver. InputReader reads it and InputDispatcher routes it to the launcher window in system_server. The launcher receives the touch and builds an intent for the target activity. That intent crosses Binder to ActivityTaskManagerService, which checks whether the target process exists. Because it does not, ActivityTaskManager asks Zygote to fork a new process. The child starts the ActivityThread main loop, attaches to the system, and creates the activity. The activity creates its window and a Surface backed by a BufferQueue. The UI thread measures, lays out and draws; the RenderThread replays the drawing commands on the GPU into a buffer. That buffer is queued to SurfaceFlinger, which composes it with the launcher's still-visible window and hands the frame to the display at the next vsync. Each step has a module on this site that explains it in depth.

Deep dive#

1. The touch#

The digitizer controller reports coordinates and pressure through the kernel's input subsystem, which exposes them as an event device. system_server reads those events through InputReader, which turns raw events into higher-level ones (down, move, up), and InputDispatcher, which decides which window should receive them based on position, focus and touchable regions.

The launcher's window is a normal window. It gets the touch through an input channel — a socket pair between system_server and the launcher process.

2. The intent#

The launcher has a list of installed activities, obtained from the package manager. A tap maps to a component name, and startActivity() creates an explicit intent.

The call does not execute in the launcher. It crosses Binder to the ActivityTaskManager service, in system_server. That service checks the caller's identity, resolves the target, checks that the caller is allowed to start it, and decides how it fits into the task and back stack.

3. The process#

If the target app already has a process, the system reuses it. In the interesting case it does not, so the system asks Zygote to fork.

Zygote is a process that has already loaded the framework classes, the resources and the common native libraries. fork() gives the child a copy-on-write view of all of it. The child then specialises: it becomes a process for a particular app, with the right UID, the right SELinux domain, and a running ART instance.

4. The attach#

The child's ActivityThread.main() starts the main Looper and waits. system_server then sends it a message (over Binder) telling it which components to instantiate, with the activity's launch details. The app creates its Application, then the Activity, and calls onCreate().

This is why "the app starts" is multiple moments: process creation, application creation, activity creation, first layout, first draw. adb shell am start -W reports them separately, and they have different optimisation strategies.

5. The window and the surface#

The activity asks the WindowManager for a window. A window gets a Surface, which is the producer end of a BufferQueue: a place to draw that another process can consume.

The WindowManagerService, in system_server, decides the window's size, layer and position. The app is told the final geometry in a traversal, and only then draws.

6. The frame#

The UI thread records drawing commands. Since Android 5.0 they are handed to the RenderThread, which replays them on the GPU through Skia. When the GPU finishes, the buffer is queued to SurfaceFlinger.

Timing is everything here. The app aims to finish just before the display's next vsync, so the buffer is ready when the compositor needs it. Miss that deadline and the display shows the previous frame — the user sees a stutter, even though nothing crashed.

7. The composition#

SurfaceFlinger has layers from the launcher (still visible underneath during the transition) and the new app. It asks the display hardware's composer which layers it can handle natively, and does the rest on the GPU. The final image is scanned out to the panel.

The app's first frame is now on screen. From tap to visible frame, a fast device does this in a few hundred milliseconds; a cold start on a busy device can take several times longer.

How it evolved#

Each era attacked a different part of this path.

2008–2012Pre-ButterDrawing was loosely timed; stutter was normal and notorious.API 1
2012 →Project Buttervsync-driven scheduling and triple buffering make frames predictable.API 16
2014 →RenderThreadRendering moves off the UI thread, so animation survives slow app code.API 21
2019 →Zygote optimisationUSAP pools and profile-guided compilation shave the cold start.API 29
2026 →Memory and queue workStrict memory limits and a lock-free MessageQueue change the budget again.API 37

Under the hood#

The files that carry this story:

Curiosity corner#

  • The launcher is not special. It is an app with a CATEGORY_HOME activity, which is why you can replace it.
  • A frame can be "late" without being slow. If the compositor misses its slot by a millisecond, the display repeats the previous frame anyway.

Try it#

Watch a cold start

adb shell am force-stop com.android.settings adb shell am start -W com.android.settings

The TotalTime line is the wall-clock cost of the launch. Force-stopping first makes it a cold start, which is the case that matters.

Check yourself#

Check yourself

1 / 12

You run `adb shell ps -A` and see that `system_server` and your app share the same parent process. What is the parent?

0 answered · 0 correct

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.

  1. docsAndroid platform architecture (AOSP)source.android.comaccessed 2026-10-27↩
  2. docsZygotesource.android.comaccessed 2026-10-27↩
  3. docsBinder overviewsource.android.comaccessed 2026-10-27↩
  4. docsGraphics architecturesource.android.comaccessed 2026-10-27↩
  5. docsInput overviewsource.android.comaccessed 2026-10-27↩
  6. docsApp startup timedeveloper.android.comaccessed 2026-10-27↩