ADB
Also called: android debug bridge, adb shell
ADB (Android Debug Bridge) is the command-line tool for communicating with an Android device — installing packages, reading logs, running shell commands and automating input. It works over USB or over TCP, and it is the standard interface for driving a device programmatically rather than by hand.
ADB has three parts: a client you invoke on the command line, a server process on your machine that owns the connections, and a daemon (adbd) running on the device. The client never talks to the device directly — it talks to the local server, which listens on TCP port 5037 and multiplexes every attached device. This is why the first adb command after a reboot is slow (it starts the server) and why adb kill-server fixes a surprising share of problems.
How the connection is established
Over USB, the device must have developer options and USB debugging enabled, and it prompts once with an RSA fingerprint dialog. The key pair lives at ~/.android/adbkey and adbkey.pub on the host; accepting the dialog stores the public key on the device, which is why a fresh machine gets prompted again and a wiped device forgets you. Over the network, adb tcpip 5555 restarts adbd listening on TCP, and adb connect host:5555 attaches to it. On Android 11 and later, wireless debugging pairs on a random port with a six-digit code and then keeps a TLS channel, which is a meaningful improvement: classic adb over TCP authenticates the client but does not encrypt the session.
The commands that do most of the work
- adb devices -l — the first thing to run. It lists serials and states: device (ready), unauthorized (the fingerprint dialog was not accepted), offline (daemon unreachable or asleep).
- adb install -r -t app.apk — install, replacing an existing copy, allowing test-only builds.
- adb shell — a shell on the device; without arguments it is interactive, with arguments it runs one command and exits.
- adb shell input tap 540 1200 / input swipe 540 1600 540 600 300 / input text hello — synthetic touch, scroll and keyboard input.
- adb shell am start -n com.example/.MainActivity — launch a specific activity; adb shell pm list packages -3 lists third-party packages only.
- adb logcat *:E — errors only. Crashes, ANRs and permission denials all surface here first.
- adb exec-out screencap -p > screen.png — a screenshot straight to stdout, without the CRLF corruption that adb shell screencap causes on some hosts.
- adb pull /sdcard/file . and adb push file /sdcard/ — move files in either direction.
Reading the device state that actually matters
For anyone auditing a fleet, ADB is mostly a read tool. adb shell getprop ro.product.model, ro.product.manufacturer and ro.build.fingerprint return the identity values apps read from build.prop. adb shell settings get secure android_id returns the Android ID for the current user and app-signing key. adb shell dumpsys window | grep mCurrentFocus names the activity on screen, which is the reliable way for a script to know where it is. adb shell dumpsys battery and adb shell getprop persist.sys.timezone cover two of the values that most often contradict a proxy region.
Failure modes and what they mean
- unauthorized — the RSA dialog was never accepted, or the device was factory reset and dropped your public key. Revoke authorisations on the device and reconnect.
- offline — usually the daemon after a sleep or a network drop. adb disconnect then adb connect, or adb kill-server on the host.
- "adb server version doesn’t match this client" — two different platform-tools versions on one machine, often one shipped inside an IDE or an emulator bundle. Kill the server and put a single version on PATH.
- "more than one device/emulator" — pass adb -s <serial>, or export ANDROID_SERIAL. Any script that runs against a fleet needs one of these on every call.
- input text silently dropping words — the command does not accept literal spaces. Use %s for a space, and escape shell metacharacters; non-ASCII text is not supported at all and needs a different input path.
- Commands appearing to succeed on a locked screen — input events land nowhere. Scripts should unlock first and verify with dumpsys window rather than assume.
- Black screenshots — a window marked FLAG_SECURE (banking apps, some login screens) cannot be captured; the frame comes back empty rather than erroring.
ADB in a cloud environment
When devices live in a datacenter rather than on your desk, ADB access is offered as a host and port per device. The value of that is that existing tooling transfers unchanged — Appium’s UiAutomator2 driver, Espresso runs, and custom scripts all speak the same protocol whether the device is on a USB cable or across a WAN. It is worth confirming a provider exposes real ADB rather than only a proprietary API, because that single fact decides whether the automation you already wrote will run.
The difference you will feel is latency. Each adb shell invocation is a round trip, so a script that issues hundreds of individual commands turns tens of milliseconds of network delay into minutes of wall clock. The fix is to send fewer, larger commands: push a shell script and run it once, chain commands with && inside a single adb shell call, and read state in batches rather than one getprop at a time.
Note also that enabling ADB is itself a device state an app can observe. adb shell settings get global adb_enabled returns 1, and any app can read the same value through Settings.Global; ro.debuggable and the developer-options flag are equally visible. A device with USB debugging permanently on is not in a default configuration, which matters for some workloads and is irrelevant for others — but it should be a decision rather than an accident.
