Android from the foundation · Puzzle 5 of 6

Binder is the post office between processes

Processes can't touch each other's memory, so every call between them is packed into bytes and carried by the kernel's Binder driver, stamped with the caller's identity.

The problem

In puzzle 4, your "start B" letter went to the town hall. But in puzzle 1 we saw that one process can't touch another's memory. So how does a method call get from your house into the town hall at all?

See it

Your app hands a packed letter (Parcel) to its proxy; the kernel's Binder driver carries it, stamping your UID; a Binder thread in system_server takes it to the real method; a reply comes back; a 3 MB parcel doesn't fit the receiver's 1 MB mailbox your appproxy system_servermailbox post officeBinder driver, in the kernel ParcelUID 10101 Binder thread real method reply ← 3 MB ~1 MB mailbox: too big
  1. Your app wants the town hall to start a screen, but the town hall lives in another process. In your house sits a proxy: a counter that looks exactly like the town hall's service.

    Step 1 of 6
  2. Objects can't leave a process; bytes can. The proxy packs the call's arguments into a flat envelope: a Parcel.

    Step 2 of 6
  3. The kernel's Binder driver carries it, and stamps it with your app's UID. The receiver can't be fooled about who sent it. Predict: who picks it up at the town hall?

    Step 3 of 6
  4. The town hall keeps a few couriers waiting for mail: its Binder threads. One takes the Parcel, unpacks it, and calls the real method.

    Step 4 of 6
  5. The reply travels back the same way, and the proxy call in your app returns.

    Step 5 of 6
  6. Each process's mailbox for incoming calls holds about 1 MB, shared by all calls in flight. A 3 MB bitmap in an Intent doesn't fit: TransactionTooLargeException.

    Step 6 of 6

The building block

Binder is a driver in the Linux kernel (drivers/android/binderThe Binder driver in mainline Linux (now written in Rust) stamps the sender's user ID on every transaction. Android phones run Android's own kernel branches, which may still use the older C driver. 392 from_parent, 393 sender_euid: Kuid::current_euid(),transaction.rs, line 392 · Linux kernel ↗), and the kernel is the only code allowed into every process. On your side, a proxy looks like the service you're calling. It packs the arguments into a ParcelThe flat byte buffer that carries arguments across processes. 237 public final class Parcel {Parcel.java, line 237 · AOSP frameworks/base ↗. On the other side, a Binder thread unpacks it and calls the real method.

Two facts that come up all the time:

  • Who's calling. Binder stamps every call with the caller's UID, and its PID (process number). The receiver reads it with Binder.getCallingUid()Native: the UID the kernel stamped on the call. The caller can't fake it. 338 public static final native int getCallingUid();Binder.java, line 338 · AOSP frameworks/base ↗. That's how system_server checks permissions: the kernel guards files and memory (puzzle 1), and system_server guards everything else using this stamp.
  • Size. Each process's buffer for incoming calls is about 1 MB, shared by every call in flight.

The analogy

The post office. You hand your letter to the counter in your house (the proxy). The post office carries it, stamps your address on it, and a courier at the town hall's door (a Binder thread) brings it to the right desk.

Check yourself

You put a 3 MB bitmap into an Intent extra and start an Activity. What happens?

Not quite. Size isn't about speed here: the mailbox has a fixed size, and a parcel that doesn't fit fails.

Not quite. An Intent can't travel as an object: it's packed into a Parcel and carried by Binder, through a mailbox of about 1 MB.

Right. The Intent travels over Binder, whose buffer is about 1 MB per process, shared by all calls in flight. Pass a file URI or an ID instead.

Can an app lie to a system service about who it is?

Right. The UID comes from the kernel, not from the data, so the receiver can trust it for permission checks.

Not quite. The stamp isn't part of your letter's contents: the post office adds it, and you can't change it.

In the town hall, which worker picks up an incoming Binder call?

Right. Each process keeps a few Binder threads waiting for incoming calls.

Not quite. Binder calls arrive on the couriers (Binder threads). In puzzle 0's simplified picture the letter seemed to go straight to the clerk; this is the real hand-off.

Sources

What you now know

proxy → Parcel → Binder (kernel) stamps your UID → a Binder thread → the real method, and back. Every Intent and every system call travels this way, through a mailbox of about 1 MB.