Generated from contracts/proto/*.proto by protoc-gen-doc. The narrative
contract — run liveness, the pool, sessions, status mapping — is in the repository's
.docs/server-api.md.
false: only the package may handle it (-p), so no chooser can appear. true: Android resolves it as a tapped link would — another app, the browser, or a chooser.
The app's own languages (cmd locale set-app-locales, API 33+; FAILED_PRECONDITION, UNSUPPORTED_API below), BCP-47 tags in preference order; empty = follow the system. Read back after the change; restored on detach like the device conditions.
am start -W of the launcher intent, as the home screen does: the app's existing task comes back as it was left; with no task, the launcher activity starts.
Pick variants: exactly one match (default; more is AMBIGUOUS), the first in accessibility
order, or the zero-based index-th in accessibility order (NOT_FOUND when absent).
A View resource id. With package_name: exactly package_name:id/name. Without: name in any
package (<any>:id/name) or the bare name, which is how a Compose testTag appears under
testTagsAsResourceId. name never contains :id/; put the package in package_name.
A complete selector: the node tree and how an action picks among matches. Package ownership
is an ordinary PROPERTY_PACKAGE_NAME predicate; there is no separate execution scope.
Built by the client DSLs and validated identically by the server and the driver.
Waits for a toast. text (≤ 1024 chars) is compared under mode (default exact); absent =
any text. package_name absent = a toast from any package. A toast posted up to 3.5 s before
the command (the longest one stays up) counts.
Taps the dialog's button for choice; it must be offered, exactly once.
With accuracy, the dialog's radio for it is selected first; it must be offered too (both are
found before any input). UNSPECIFIED leaves the accuracy as the dialog shows it.
One protocol request minus session identity (the server owns session id, generation and
request ids). Exactly one op must be set; its case name is the protocol op.
An active notification: the package that posted it, its title and text (Notification extras
android.title / android.text, absent when it has none), the titles of its action buttons,
whether a swipe can dismiss it, and when it was posted (wall clock, epoch milliseconds).
Dismisses the one matching notification as a swipe does. NOT_FOUND / AMBIGUOUS, or
ACTION_REJECTED (NOT_CLEARABLE) for an ongoing one, before anything changes.
Press and hold on selector's centre until it becomes a long press, move to target's centre,
hold there, release: one gesture. Both resolve to exactly one element before input starts.
The node is showing its hint: on API 26+ an empty field then reports the hint as text. text is always the raw accessibility text; selectors match that same raw text.
A failed command. Driver-side failures and driver-transport loss are data (including
TRANSPORT_LOST / INDETERMINATE with detail = transmission state), never a gRPC error:
gRPC status codes are reserved for the client↔server call itself.
Which notifications a notification op means; every field given must match (none: any).
package_name exactly; title and text (≤ 1024 chars each) under mode (default exact).
The notifications are what a NotificationListenerService in the driver app sees: the server
gives the driver notification access (cmd notification allow_listener) before the first
notification op and takes it back on detach. Group summaries are left out.
Opens the one matching notification as a tap on it in the shade does: sends its content
intent and, when it auto-cancels, removes it. With action (≤ 1024 chars), sends the intent
of its action button with exactly that title instead, and the notification stays. NOT_FOUND /
AMBIGUOUS, or ACTION_REJECTED (ACTION_NOT_OFFERED) when it has no content intent or no such
action, before anything is sent.
An accessibility action on the one matching node, as a screen reader performs it (no touch,
so no occlusion check): a standard action, or a custom one by its exact label (≤ 1024 chars).
The node must offer it: ACTION_REJECTED (ACTION_NOT_OFFERED) before input otherwise.
The runtime-permission dialog on screen: the package of its window (what a selector's package
scope names; Google builds rename the controller, so it differs from the resource ids' package)
and the choices it offers, in PermissionChoice order.
Mock location: the gps and network providers (and fused, API 31+) report this fix, as
LocationManager test providers the driver owns, sent again every second until the driver
stops or the next set_location. latitude -90..90, longitude -180..180, accuracy_m > 0
(default 5 m), altitude_m absent = no altitude. The driver app needs the mock-location app-op
(the host's DeviceService.SetLocation grants it first); without it Android refuses
(ERR_ACTION_REJECTED).
ACTION_SET_PROGRESS on the one matching range node (SeekBar, Slider, RatingBar): value in
the node's own RangeInfo units, finite and within its min..max. A node without the action or
a value outside the range is ACTION_REJECTED (ACTION_NOT_OFFERED / OUT_OF_RANGE) before input.
Closed error taxonomy shared with the device protocol; Error.detail refines it with a
stable sub-reason. See the errors guide for meaning, mutation risk and retryability.
Name
Number
Description
ERR_UNSPECIFIED
0
ERR_INVALID_REQUEST
1
ERR_INVALID_SELECTOR
2
ERR_UNSUPPORTED
3
ERR_UNAUTHENTICATED
4
ERR_SESSION_MISMATCH
5
ERR_DUPLICATE_OR_STALE
6
ERR_OVERLOADED
7
ERR_AUT_MISMATCH
8
ERR_NOT_FOUND
9
ERR_AMBIGUOUS
10
ERR_NOT_INTERACTABLE
11
ERR_STALE_DURING_COMMAND
12
ERR_ACTION_REJECTED
13
ERR_WAIT_TIMEOUT
14
ERR_CANCELLED
15
ERR_DEADLINE_EXCEEDED
16
ERR_AUT_NOT_INSTALLED
17
ERR_AUT_CRASHED
18
ERR_AUT_ANR
19
ERR_SYNC_PROVIDER_UNAVAILABLE
20
ERR_DRIVER_UNHEALTHY
21
ERR_TRANSPORT_LOST
22
ERR_INDETERMINATE
23
ERR_ARTIFACT_TRANSFER_FAILED
24
ERR_PAYLOAD_TOO_LARGE
25
ERR_INTERNAL
26
ERR_UNKNOWN
27
ERR_STALE_BEFORE_INPUT
28
The resolved node went stale (its view was detached or replaced) before any input was sent.
A button of the runtime-permission dialog, by what it grants. Which ones a dialog offers depends
on the permission, the Android version and the controller build (wait_permission_prompt).
Name
Number
Description
PERMISSION_CHOICE_UNSPECIFIED
0
PERMISSION_ALLOW
1
"Allow"
PERMISSION_ALLOW_FOREGROUND_ONLY
2
"While using the app"
PERMISSION_ALLOW_ONE_TIME
3
"Only this time"
PERMISSION_ALLOW_ALWAYS
4
"Allow all the time" (API 29 background location)
PERMISSION_ALLOW_SELECTED
5
"Select photos and videos" (API 34 partial media access)
PERMISSION_ALLOW_ALL
6
"Allow all" (API 34 media)
PERMISSION_DENY
7
"Don't allow" / "Deny"
PERMISSION_DENY_AND_DONT_ASK_AGAIN
8
"Deny & don't ask again"
PERMISSION_KEEP_FOREGROUND_ONLY
9
"Keep while app is in use" (an upgrade request refused)
PERMISSION_KEEP_ONE_TIME
10
"Keep only this time" (an upgrade request refused)
A standard accessibility action that takes no arguments (AccessibilityNodeInfo.AccessibilityAction),
as a screen reader performs it. Click and long click are not here: tap / long_tap touch.
A bug in the daemon or host core (INTERNAL). Report it with the daemon log.
FAILURE_REASON_INVALID_ARGUMENT
2
Caller input the daemon rejects before doing anything (INVALID_ARGUMENT).
FAILURE_REASON_UNAUTHENTICATED
3
Missing or wrong daemon token (UNAUTHENTICATED).
FAILURE_REASON_UNKNOWN_CLIENT_CONNECTION
4
The client_connection_id is not (or no longer) known (NOT_FOUND).
FAILURE_REASON_UNKNOWN_ATTACHED_DEVICE
5
The attached_device_id is not (or no longer) attached (NOT_FOUND).
FAILURE_REASON_NOT_OWNER
6
The device is attached by another client connection (PERMISSION_DENIED).
FAILURE_REASON_DEVICE_BUSY
7
Another session holds the device's lock: FAILED_PRECONDITION without a wait, DEADLINE_EXCEEDED after waited_ms.
FAILURE_REASON_DEVICE_QUARANTINED
8
The device's journal keeps it out of service until an explicit reset (FAILED_PRECONDITION).
FAILURE_REASON_HOST_WAIT_TIMEOUT
9
A host-side wait (app process, window, idle) ran out of time (DEADLINE_EXCEEDED).
FAILURE_REASON_ADB_TIMEOUT
10
An ADB command did not finish within its timeout (DEADLINE_EXCEEDED).
FAILURE_REASON_ADB_FAILED
11
An ADB command failed, or is gated by an earlier unreaped one (UNAVAILABLE).
FAILURE_REASON_ADB_REAP_UNCERTAIN
12
An ADB command left an uncertain residual; the device may have changed (FAILED_PRECONDITION).
FAILURE_REASON_APP_LIFECYCLE
13
An app lifecycle postcondition did not hold (FAILED_PRECONDITION).
FAILURE_REASON_DRIVER_BUILD_MISMATCH
14
The installed driver is not the build this daemon expects (FAILED_PRECONDITION).
FAILURE_REASON_DRIVER_START_FAILED
15
The driver could not be started or authenticated (UNAVAILABLE).
FAILURE_REASON_DRIVER_TRANSPORT
16
The driver connection was lost around a host-issued command (UNAVAILABLE).
FAILURE_REASON_DRIVER_COMMAND
17
A host-issued driver command (for example attach's device info) failed with error_code (FAILED_PRECONDITION).
FAILURE_REASON_SESSION_UNUSABLE
18
The session can no longer run operations: detach and attach again (ABORTED).
FAILURE_REASON_DAEMON_PRECONDITION
19
The daemon cannot serve the request in its current state (FAILED_PRECONDITION).
FAILURE_REASON_UNKNOWN_REF
20
The ref is not in the attached device's latest screen snapshot (NOT_FOUND).
FAILURE_REASON_REF_NOT_ADDRESSABLE
21
The ref's node had no selector that matched it alone (FAILED_PRECONDITION).
FAILURE_REASON_UNSUPPORTED_API
22
The device's API level is below what the call needs; detail names it (FAILED_PRECONDITION).
FAILURE_REASON_DEVICE_SETTING
23
The device did not take a setting: it read back another value (FAILED_PRECONDITION).
FAILURE_REASON_DEVICE_FILE
24
A device file Tap cannot write or read as asked: it exists and is not this session's, its directory is missing, it is not a regular file, or it did not read back (FAILED_PRECONDITION).
An AppService call. operation is the RPC in snake_case: install, uninstall, force_stop,
clear_data, grant_permission, revoke_permission, launch, cold_launch, foreground, open_link,
set_locales.
Host boundaries around the validated RPC block, including queued/transport work. Not device input/capture times. Compare with video receipt only when clock_id matches. Missing on events from older daemons; never derive these from epoch timestamps.
Present: a held connection. It needs no Observe stream (opening one is FAILED_PRECONDITION) and ends on Disconnect, daemon shutdown, or idle_timeout_ms after the last call that named it. Its name must be non-blank and unique among held connections (FAILED_PRECONDITION).
Long-lived stream the client keeps open for the life of the connection; it must be opened shortly after Connect. Its end is the liveness signal: the stream ending (either side) disconnects the client. The first event is observing; a daemon-initiated disconnect sends closing and then completes the stream normally.
The connection's event log (event_log.proto) after after_seq. Kept for every connection, the last 2000 events; renews a held connection like any call naming it.
Only with ScreenSnapshotRequest.selector_candidates: every selector that matched only this node, best first (the first is selector). A candidate that merely adds predicates to an earlier one is left out, and a BY_INDEX pick is offered only when nothing else is unique.
A bounded artifact: video is H.264 MP4, audio is Opus, combined is Matroska (H.264+Opus).
Clients select tracks at Start; Stop returns their one muxed file (never two scrcpy children).
Empty means no audio. "output" (Android 11+; mutes the device speakers), "playback" (Android 13+; keeps local playback, apps can opt out) or "mic" (the device microphone).
A compact, ref-addressed outline of the screen, parsed from the diagnostic hierarchy dump (.docs/agent-surface.md). Refs name selectors the daemon synthesised, never node handles.
The selector a ref of the latest snapshot names. Unknown ref: NOT_FOUND (UNKNOWN_REF); a node with no selector: FAILED_PRECONDITION (REF_NOT_ADDRESSABLE).
Device-wide conditions. Each changed value is captured before the session's first change of it, journaled, and restored when the device is detached (or by the next attach when the daemon died first); a restore that cannot be proven quarantines the device. Every change is read back: a value the device did not take is FAILED_PRECONDITION (DEVICE_SETTING). The three animation scales (window, transition, animator duration): all 0 or all 1.
Airplane mode (cmd connectivity airplane-mode), Wi-Fi (svc wifi) and mobile data (svc data): the real switches, nothing mocked. API 29+. Airplane mode is written first; all three are captured on the first change and restored airplane mode first. A device reached over ADB on the network refuses Wi-Fi off / airplane mode on (FAILED_PRECONDITION).
The device-wide locale list (Settings › Languages), 1 to 16 BCP-47 tags in preference order (INVALID_ARGUMENT otherwise). Android has no shell command for it: the driver app applies it as Settings' language picker does, and it is read back (system_locales).
Mock location: the device reports this fix from its location providers until detach. latitude -90..90, longitude -180..180, accuracy_m > 0 (default 5), altitude_m finite (INVALID_ARGUMENT otherwise). The driver app becomes the mock-location app (its android:mock_location app-op) and location is turned on when it is off; both are captured and restored on detach, which ends the mock. The driver serves the fix (set_location).
Keeps the screen on while the device is plugged in (USB, AC or wireless): Settings.Global stay_on_while_plugged_in 7, or 0. Captured and restored on detach.
The accessibility display settings: high-contrast text, color inversion and bold text (API 31+, else FAILED_PRECONDITION / UNSUPPORTED_API before anything changes), as Settings › Accessibility writes them. At least one must be set. Captured and restored on detach.
Files. The bytes travel in the call (never a path on the server's machine), at most 512 MiB. A file Tap cannot write or read as asked is FAILED_PRECONDITION / DEVICE_FILE.
Copies a file to device_path (absolute, normalised; its directory must exist): a PushFileHeader first, then the bytes. A file already there is refused unless this attached device pushed it; the size is read back. Pushed files are deleted on detach. |
| PullFile | PullFileRequest | PullFileResponse stream | Streams the regular file at device_path back in chunks. |
| AddMedia | AddMediaRequest stream | AddMediaResponse | Adds a photo or video to the gallery: an AddMediaHeader (file_name with a photo or video extension), then the bytes. Written to /sdcard/Pictures/Tap/ or /sdcard/Movies/Tap/ and indexed by the media scanner (read back); a name already there is refused unless this attached device added it. Deleted, and dropped from the index, on detach. |
Host receipt of the full packet on the clock clock_id names — the clock of LoggedEvent.started_monotonic_ns. Not device capture or input execution time.
The daemon-wide activity log after after_seq: the retained backlog, then live activity as it happens, until the client cancels or the daemon stops. The first response also carries the live connections, so names survive eviction of their connection_opened.
One device's screen as H.264, from a scrcpy server the daemon runs while anyone watches that serial; readers of one serial share it. Needs tap start --scrcpy-server. No input, no screen wake, no attachment.