Zygote
AOSP source tournerd

Ten reading quests

Ten source-reading quests, each with a question and a place to look: the zygote fork, the init language, a system service's birth, the framework facade, an IPC call, package install, the frame loop, permissions, intent resolution, and a Mainline boundary.

11 minAPI 1–37 · 17interactiveverified 2026-10-27

Ten quests. Each one is a question with an answer that exists in the source, a path to start from, and a hint about where to look. Do them in order if you want a tour of the platform; pick the ones that match your current question if you do not.

The checklist below tracks your progress in this browser. It is a reading aid, not a grade, and it does not claim you have read a file if you have only opened it.

Loading diagram…
Text description of this diagram

An interactive checklist of ten source-reading quests. Each item shows a numbered title, a question, a file path to start from, and a collapsible hint. A progress bar at the top counts completed quests, and each item has a checkbox that stores its state in the browser. The quests in order are: find where an app process is born in ZygoteInit; read the init language in system/core/init/README.md; follow one system service's birth in SystemServer; see the client side of the framework boundary in SystemServiceRegistry; trace one IPC call in Binder; read the package install path in PackageManagerService; find where a frame begins in Choreographer; read a permission check in PermissionManagerService; follow an intent through resolution in ComputerEngine; and see a Mainline module's boundary in packages/modules.

TL;DR#

  • The first three quests explain the rest: zygote, init, and system_server's phases.
  • The middle four are the framework's shape: the facade, Binder, the package manager, and the frame loop.
  • The last three are policy: permissions, intent resolution, and Mainline boundaries.
  • Each quest has a question, not just a file. Reading without a question produces notes you cannot use.

Mental model#

A quest is a question with a destination.

The destination is a file, but the file is not the answer. The answer is a sentence you can say out loud: "the child process stops accepting connections and calls handleSystemServerProcess because it must become a server." If you cannot say the sentence, you have not finished the quest.

Where the analogy breaks#

In a game, the destination is the reward. Here, the destination is often the least interesting part: a file that is mostly boilerplate, with the answer in one method. The value is in the route you took and the surrounding code you read to make sense of it.

The big picture#

The ten quests form a route through the platform, from the boot-time creation of processes to the policy that governs them:

Deep dive#

Quest 1 — Find where an app process is born#

Start at: frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

Question: which method runs after the fork, and what does it do with the classes Zygote preloaded?

Where to look. Read main() and the loop that accepts connections. The fork itself happens in the connection handler; the child then calls a method whose name says it must no longer accept connections. What happens next is the child becoming a running app process: it closes the socket, attaches to the system, and enters the ActivityThread loop.

What you should be able to say. Why forking is cheap (copy-on-write pages, preloaded classes) and what the child still has to do that the parent cannot do for it.

Quest 2 — Read the init language#

Start at: system/core/init/README.md

Question: what is the difference between an action and a service in init.rc?

Where to look. The README is the specification of the init language. Look for the definitions of both: an action is a set of commands triggered by an event (on boot, on property:...); a service is a program started by name, with options such as class, user, oneshot and disabled.

What you should be able to say. Why init can start services in parallel with trigger ordering, and what a oneshot service means for restarts.

Quest 3 — Follow one system service's birth#

Start at: frameworks/base/services/java/com/android/server/SystemServer.java

Question: in which phase is ActivityManagerService started, and what does it need from earlier phases?

Where to look. SystemServer.main() runs a sequence of start methods: bootstrap services, core services, then other services. Read the comments around the calls; they usually say what must come first.

What you should be able to say. Why the order is not arbitrary, and what "started" means for a service that is registered in ServiceManager and then has its own threads.

Quest 4 — See the client side of the framework boundary#

Start at: frameworks/base/core/java/android/app/SystemServiceRegistry.java

Question: how does getSystemService(String) turn a constant into a manager object?

Where to look. The class has a static registry that maps names to fetchers. Each fetcher knows how to create its manager, usually by obtaining a Binder interface. The registry is also where the caching happens: a manager per context, not per call.

What you should be able to say. The difference between the manager object you hold and the service that does the work, and why a new Context can produce a different manager instance.

Quest 5 — Trace one IPC call#

Start at: frameworks/base/core/java/android/os/Binder.java

Question: where does the Java object cross into native code, and what is transferred?

Where to look. Find execTransact and the native method declarations. Then find Parcel, which is the container the arguments are written into. The generated Stub/Proxy pair is the layer above.

What you should be able to say. What a transaction actually moves (a parcel with a method code, an interface descriptor and argument data), and why an exception in the service does not propagate as an exception across the boundary.

Quest 6 — Read the package install path#

Start at: frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

Question: what happens between receiving an install request and the package being visible to other apps?

Where to look. Start at installPackage and follow the calls into the installer and the settings object that persists the package. Note where the signature is verified and where the package's permissions are granted.

What you should be able to say. Which steps are synchronous and which are deferred, and why an install can succeed but an app still not be launchable immediately.

Quest 7 — Find where a frame begins#

Start at: frameworks/base/core/java/android/view/Choreographer.java

Question: what schedules the next frame callback, and what happens if the work takes too long?

Where to look. doFrame and the vsync request. The timestamp passed to the callback is the intended frame time, not the current time, which is why a late frame is detectable: the work started after its deadline.

What you should be able to say. Why the Choreographer is the right place to measure UI work, and why the RenderThread is not.

Quest 8 — Read a permission check#

Start at: frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java

Question: what is the difference between a permission check and an AppOp check?

Where to look. checkPermission versus the AppOps calls. A permission is a grant at install or runtime; an AppOp is a per-operation switch that can be toggled later and is often what the privacy UI actually controls.

What you should be able to say. Why the platform has two systems, and which one a "deny" in Settings actually changes.

Quest 9 — Follow an intent through resolution#

Start at: frameworks/base/services/core/java/com/android/server/pm/ComputerEngine.java

Question: how does the system turn an implicit intent into a concrete component?

Where to look. queryIntentActivities and the intent-filter matching code. Resolution is a match over installed packages, not a registry lookup, which is why installing an app can change the result of an intent.

What you should be able to say. What makes a filter match (action, category, data), and why CATEGORY_DEFAULT matters for implicit intents.

Quest 10 — See a Mainline module's boundary#

Start at: packages/modules/

Question: pick one module and find its manifest and its APEX definition. What does it own, and what may it not touch?

Where to look. Each module directory has an Android.bp with an apex module and a manifest that lists what it provides. Compare the interface it exposes with the code it contains.

What you should be able to say. Why the interface is narrower than the implementation, and what would break if the module were updated independently of the platform.3

How it evolved#

Mainline modules3 releases
APIVersionWhat changed
289 Pie
  • Mainline groundwork
2910
  • Project Mainline: APEX and updatable system modules
  • Project Mainline starts shipping through Play
3011
  • GKI: the Generic Kernel Image splits the kernel into core + vendor modules

The mainline rows show why quest 10 exists at all: the modules are the platform's newest structural feature, and their boundaries are the ones most likely to change.

Under the hood#

Curiosity corner#

  • SystemServer starts services in phases for a reason. A service that needs another service cannot start until that service is registered.
  • Choreographer is named after the person who arranges dance. It arranges the callbacks for a frame, in the order they must run.
  • Some quests have no single answer. Intent resolution, in particular, depends on what is installed, so the "answer" is a procedure rather than a value.

Try it#

Search a checkout
grep -rn "class ZygoteInit" frameworks/base/core/java/com/android/internal/os/
grep -rn "doFrame" frameworks/base/core/java/android/view/Choreographer.java
ls packages/modules
Example output
Illustrative — requires a local checkout.

Build it#

N02 — Add a system service is quest 3 and quest 4 done from the other direction: you add the service instead of reading one.

Check yourself#

Three questions to answer without looking back. Open each one only after you have tried.

1. What does a Manager object in your app actually hold? A Binder proxy to a service, not the service itself. The policy lives on the service side, usually in system_server, and every call crosses a process boundary.

2. Why does the build use a declarative Android.bp instead of a script? Because a declarative module definition can be analysed. Soong can build a complete dependency graph before running anything, which is what makes Ninja parallel and incremental. Conditionals in a script would make the graph depend on execution.

3. What is the difference between reading a facade and reading a service? The facade defines the public contract — validation, defaults, deprecation. The service implements the behaviour and holds the state. A bug in behaviour is almost always on the service side; a compatibility question is almost always on the facade side.

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. docsZygotesource.android.comaccessed 2026-10-27↩
  2. sourcesystem/core/rootdir/init.rcandroid.googlesource.comaccessed 2026-10-27↩
  3. docsModular system componentssource.android.comaccessed 2026-10-27↩
  4. sourceAndroid Code Search (cs.android.com)cs.android.comaccessed 2026-10-27↩
  5. sourcesystem/core/init/README.mdandroid.googlesource.comaccessed 2026-10-27↩
  6. docsAndroid platform architecture (AOSP)source.android.comaccessed 2026-10-27↩
  7. docsBinder overviewsource.android.comaccessed 2026-10-27↩
  8. docsAndroid Interface Definition Language (AIDL) | Background workdeveloper.android.comaccessed 2026-10-27↩
  9. docsConfiguration (aconfig) overviewsource.android.comaccessed 2026-10-27↩