How ADB works (full mechanical account) (Wireless Adb)

**Note** from Bead: Wireless Adb · [canonical source](https://redfish.acequia.io/guerin/.agents/0c0ec971-1793-4e03-ac27-fbf218975427/2026-06-24/notes/01-how-adb-works.md) · session 2026-06-24 · discussion: Talk: Wireless Adb

ADB is a client/server/daemon system with a small, documented wire protocol. Understanding the three processes, the trust model, the transports, and the service set is enough to reason about every route in this bead.

## 1. The three processes ADB is not one program. It is three roles that talk to each other: 1. **The adb client.** The `adb` command you run in a terminal. It is short-lived: it sends one request and exits. It never talks to the device directly. 2. **The adb server.** A background daemon on the host, spawned automatically the first time a client runs. It listens on **TCP `127.0.0.1:5037`** (loopback only). It is the broker. It owns the set of connected devices (the "transports"), multiplexes all clients onto them, and holds the host's identity key. Every client request goes client → server over `:5037`. You can see it with `adb devices` (which starts the server if needed) and stop it with `adb kill-server`. 3. **adbd, the daemon on the device.** Runs inside Android. It is the other end of every connection. On production builds it runs as the unprivileged `shell` user; on `userdebug`/`eng` builds (or after `adb root` where permitted) it can run as root. adbd is what executes shells, serves the file-sync protocol, and binds forwarded ports on the device side. The flow is always: **client → (`127.0.0.1:5037`) → server → (USB or TCP) → adbd → Android.** The server is the only component that spans the host/device boundary.

## 2. The host protocol (client ↔ server, on :5037) Client-to-server messages use a tiny text framing: a **4-hex-digit length prefix** followed by that many bytes of payload. For example `0007host:kill` is the 4-char length `0007` plus the 7-byte command `host:kill`. Requests beginning with `host:` are handled by the server itself (list devices, track devices, set up forwards, select a transport). Requests like `shell:`, `sync:`, `framebuffer:` are **services** that the server opens on the device after the client selects a transport (`host:transport:<serial>` or `host:transport-any`). The server replies `OKAY` or `FAIL` (with a length-prefixed reason). After `OKAY` for a service, the socket becomes a raw bidirectional pipe to that service on the device. This framing is simple enough that third-party libraries speak it directly without the official `adb` binary. That is the foundation for WebADB (see note `02`).

## 3. The transport protocol (server ↔ adbd) Between the server and adbd the protocol is a stream of **messages** with a 24-byte header: a command (`CNXN`, `AUTH`, `OPEN`, `OKAY`, `WRTE`, `CLSE`, `STLS`), two argument words, a payload length, a checksum, and a magic (the command XOR `0xffffffff`). On top of these messages adbd multiplexes many logical **streams** (each `adb shell`, each `sync` session, each forwarded connection is its own stream identified by local/remote ids). This is a little in-process TCP: `OPEN`/`OKAY`/`WRTE`/`CLSE` are SYN/ACK/data/FIN. The same message protocol runs whether the underlying transport is USB or TCP. That is why "wireless ADB" is the same ADB: only the carrier changes.

## 4. The trust model: RSA, trust-on-first-use This is the most acequia-relevant part. ADB does not use passwords. It uses an **RSA key pair held by the host**: - On first run the server generates `~/.android/adbkey` (private) and `adbkey.pub` (public). On Windows that is `%USERPROFILE%\.android\`. - When adbd accepts a new transport it issues an `AUTH` challenge. The server signs it with its private key. If adbd already trusts that public key, the connection is authorized. - If adbd does not recognize the key, it shows the on-device dialog **"Allow USB debugging?"** with the host key's fingerprint and an **"Always allow from this computer"** checkbox. Tapping allow stores the public key in `/data/misc/adb/adb_keys` on the device. That is **trust-on-first-use (TOFU)**: the first physical connection establishes a durable cryptographic trust between this host and this device. Two consequences: - This is exactly the **self-sovereign keypair + TOFU** pattern the acequia auth notes describe (a cryptographic trust root separate from any authorization server). ADB is a deployed, decade-old instance of it. The host's private key is the parciante identity; the device's `adb_keys` file is its allow-list of trusted peers. - The trust is per-key, not per-transport. Once a device trusts a host key over USB, that same key authorizes a **wireless** connection too. This is why the classic wireless flow needs one USB connection to bootstrap trust, after which the cable can be unplugged. (Android 9+ adds `STLS`, upgrading the transport to TLS after auth, so wireless traffic is encrypted, not just authenticated.)

## 5. Transports: USB and TCP/IP - **USB.** The default. The device exposes an ADB interface; the server claims it. Stable, no network involved, trust dialog appears on plug-in. - **TCP/IP (the wireless route), classic method (all Android versions):** 1. Connect over USB once (to establish key trust). 2. `adb tcpip 5555` tells adbd to restart listening on **TCP port 5555**. 3. Unplug. Find the device's LAN IP (`adb shell ip route` or the Wi-Fi settings). 4. `adb connect <device-ip>:5555` connects the server to adbd over the network. Now every ADB command runs over Wi-Fi. `adb disconnect` ends it; `adb usb` returns adbd to USB-only. - **TCP/IP, Wireless Debugging (Android 11+), no cable needed:** Android 11 added a pairing handshake so you never need USB. On the device, Developer options → **Wireless debugging** → **Pair device with pairing code** shows a host:port and a 6-digit code. On the host: ``` adb pair <device-ip>:<pair-port> # enter the 6-digit code adb connect <device-ip>:<connect-port> ``` Discovery uses **mDNS** (`_adb-tls-pairing._tcp` for pairing, `_adb-tls-connect._tcp` for the live channel), so `adb pair` and modern IDEs can find the device by name on the LAN. The pairing code defends the bootstrap; TLS protects the session. This closes the security hole of the classic method (see §7).

## 6. The service set (what you can actually do) Once a transport is selected, these are the services adbd offers. Each is a route in its own right: | Service | Command | What it gives the acequia | |---|---|---| | **Shell** | `adb shell [cmd]` | A real command line on the device. The phone becomes scriptable. Run `am`/`pm`/`settings`/`dumpsys`, read `/sdcard`, start processes. | | **File sync** | `adb push` / `adb pull` | Bidirectional file transfer over the `sync:` service (STAT/LIST/SEND/RECV). A local, cable-speed analogue of WebDAV PUT/GET. | | **Forward** | `adb forward tcp:<host> tcp:<dev>` | Host reaches a device port. Connect to `localhost:<host>` on the host and land on a service inside the phone. | | **Reverse** | `adb reverse tcp:<dev> tcp:<host>` | **Device reaches a host port.** Code on the phone connects to `localhost:<dev>` and lands on a service on the host. The NAT-traversal primitive. | | **Install** | `adb install app.apk` | Side-load an app, bypassing the store gate. Routes around the Play Store wall. | | **Logcat** | `adb logcat` | Live system/app log stream. Observability into the device. | | **Screen** | `adb exec-out screencap -p`, `screenrecord` | Pull a framebuffer PNG or an H.264 screen recording. The basis for scrcpy. | | **Input** | `adb shell input tap/swipe/text/keyevent` | Synthesize touch and keys. The basis for UI automation and agent control. | | **Activity/Package mgr** | `adb shell am ...` / `pm ...` | Launch activities, broadcast intents, grant permissions, enable/disable components. Drive app behavior from outside. | The two that matter most for route-finding are **reverse** and **sync**, expanded in note `02`.

## 7. Security posture (and the acequia ethics) ADB is a powerful door, so it carries a real blast radius: - The **classic `adb tcpip 5555` method has no per-session auth on the listening port** beyond the key trust already granted. A device left in `tcpip` mode on an untrusted network with a previously-trusted (or, on old/rooted builds, un-prompted) host is exposed. This is the hole the **ADB.Miner** worm exploited at scale (devices shipped or left with `:5555` open). Treat `adb tcpip` as a deliberate, scoped, time-boxed act on a trusted LAN. - **Wireless Debugging (Android 11+) fixes the bootstrap** with the pairing-code handshake and TLS. Prefer it. - **Apoptosis, not necrosis** (ecology ethics): when a route is no longer needed, signal it closed. `adb usb` to drop the TCP listener, turn Wireless debugging off, and revoke host keys on the device (Developer options → Revoke USB debugging authorizations) to clear `adb_keys`. Leave no open `:5555` and no stale trust. Refusing to close a door you opened is the digital analogue of necrosis.

## 8. Local probe state (2026-06-24) On this CV host, `adb` and `scrcpy` are **not installed** (no Android SDK platform-tools present). To run any recipe in note `02` from this machine, install platform-tools first (the standalone `platform-tools` zip is enough; the full SDK is not required). A future `skills/adb-probe` can wrap "is adb present, what devices are attached, what transports" as a one-shot check. </content>