ADB has always had the capability to communicate with a device over TCP. However the process involved is convoluted and results in an insecure channel. The steps are as follows.
- Connect device via USB cable.
- Accept host's public key in the device UI dialog (pairing).
- Request adbd to open a TCP server socket
$ adb tcpip 5555
- Retrieve device's Wi-Fi IP address
IP=`adb shell ip route | awk '{print $9}'`
- Finally, connect over TCP
$ adb connect $IP:5555
After all these steps, adb server is communicating with adbd over TCP unencrypted. This means all traffic can be eavesdropped and open to MITM attacks.
ADB Wifi allows a user to pair a device and a host in a single step, without requiring prior USB connection.
Moreover, ADB Wifi uses TLS which allows for secure authentication and a secure connection after authentication.
ADB Wifi revolves around four capabilities.
- Pair without the user having to click "Allow debugging".
- Encrypt ADB traffic.
- Advertise services over the network.
- Auto-connect to paired devices.
A host and a device are considered paired if the host's public key
is in the device's /data/misc/adb/adb_keys
or /adb_keys
files (keystore). After pairing, the
host can be trusted by the device because the host
can use its private key to answer the challenges from the device (and the device can verify
answer using keys from the keystore until a matching public key is found).
To pair, ADB Wifi uses a Pairing Server running on the device. The Pairing Server communicates using RSA 2048-bit encryption (in a x509 certificate). Trust is bootstrapped using a shared secret, seeded either by a six-digit number (pairing code) or a 10-digit number (QR code pairing).
After pairing, and if the user has enabled "Wireless debugging", adbd listens on
a TCP server socket (port picked at random). This is not the same as the legacy tcpip
socket. The
legacy socket greets all communication attempts with an A_AUTH packet whereas
this socket opens communication with A_STLS which means all traffic will be
TLS encrypted (and authentication is different as well).
All this traffic is handled by the TLSServer which is forwarded to adbd's fdevent. When users toggle "Wireless Debugging", they start and stop the TLSServer.
All of the elements previously mentioned advertise their presence on the network via mDNS. Three service types are used.
_adb._tcp
: This is the legacy TCP service started viaadb tcpip <PORT>
._adb-tls-pairing._tcp
: The service advertised when the device pairing server is active._adb-tls-connect._tcp
: The service advertised when the device TLSServer is active.
Note that all services' instances are published by the device (adb server is merely a consumer
of mDNS packets). Both _adb._tcp
and _adb-tls-connect._tcp
are published directly
by adbd while _adb-tls-pairing._tcp
is published via NsdServiceInfo.
An instance name prefix is usually adb-
followed by the value of the property ro.serialno
plus a random suffix added
by the mdns backend.
The Pairing Server is special. Its service instance name changes whether it is intended to be used with a pairing code or a QR code.
- Pairing code:
adb-
<prop(persist.adb.wifi.guid)
> - QR code:
studio-
< RANDOM-10> (e.g:studio-58m*7E2fq4
)
When the host starts, it also starts mDNS service discovery for all three service types.
Any service instance of type _adb-tls-connect
being published by the device results in a connection attempt
by the host (if the device's GUID is known to the host from pairing). If the device was previously paired,
TLS authentication will automatically succeed and the device is made available to the host.
There is one exception. When the pairing client finishes on the host, it also attempts to connect to the device
it just paired with. This is because _adb-tls-connect
was already published before pairing even began, which
means the host cannot rely on the mDNS _adb-tls-connect
"Create" event being published.
On the device, three components must communicate. There is adbd, Framework (AdbDebuggingManager) and the mDNS daemon.
The Pairing Server and the TLS server are part of the adbd apex API. These two libraries are linked into system_server (AdbDebuggingManager). The rest of the communication works via system properties.
persist.adb.tls_server.enable
: Set when the Developer Settings UI checkbox "Use wireless debugging" is changed. adbd listens for these changes and manages the TLSServer lifecycle accordingly.service.adb.tls.port
: Set by adbd. Retrieved by Framework so it can publish_adb-tls-connect
.ctl.start
: Set tomdnsd
by adbd to make sure the mDNS daemon is up and running.persist.adb.wifi.guid
: Where the device GUID (used to build service instance name) comes from. Both adbd and Framework retrieve this property to build_adb-tls-connect
and_adb-tls-pairing
service instance names.
ADB Wifi can be set up and monitored with the command line.
$ adb mdns check
tells the user the name of adb's mDNS stack and its version.
$ adb mdns check
mdns daemon version [Openscreen discovery 0.0.0]
$ adb mdns services
lists all supported mdns services' instances discovered and still active,
followed by their service type and their resolved IPv4 address/port.
$ adb mdns services
List of discovered mdns services
adb-14141FDF600081 _adb._tcp 192.168.86.38:5555
adb-14141FDF600081-QXjCrW _adb-tls-pairing._tcp 192.168.86.38:33861
adb-14141FDF600081-TnSdi9 _adb-tls-connect._tcp 192.168.86.38:33015
studio-g@<xeYnap/ _adb-tls-pairing._tcp 192.168.86.39:55861
Note: At the moment, IPv6 addresses are resolved but not output by the command.
If a user starts a Pairing Server on the device (via
Settings > System > Developer options > Wireless debugging > Pair device with pairing code
), they
are presented with both a pairing code and the IPv4:port of the Wi-fi interface. In this case
the vector to exchange the TLS secret is the user who reads it on the device then types the pairing code on the host.
With the Pairing Server active, ADB Wifi is entirely configurable from the command-line, as follows.
$ adb pair 192.168.86.38:43811
Enter pairing code: 515109
$ adb connect 192.168.86.34:44643
$ adb devices
List of devices attached
adb-43081FDAS000VS-QXjCrW._adb-tls-connect._tcp device
Android Studio automates pairing with a pairing code thanks to its GUI.
The advantage compared to the CLI method
is that it relies on mDNS to detect devices with an active Pairing Server.
To this effect, Studio polls adb server for service instances of type _adb-tls-pairing
.
Studio also introduces a QR code system which is just an easy way to share the pairing code between the host and the device.
When a user clicks on "Pair device Using Wi-Fi", they are shown a QR code.
In the example code above Studio generated a QR code containing the string WIFI:T:ADB;S:studio-g@<xeYnap/;P:(Aq+v9>Cx>!/;;
.
The QR code piggyback on WPA3 Specification
which specifies the format as follows.
“WIFI:” [type “;”] [trdisable “;”] ssid “;” [hidden “;”] [id “;”] [password “;”] [publickey “;”] “;”
Tokens are ;
separated. The QR Code contains three tokens
-
Type (marked by
T:
prefix) indicates this is anADB
special string. -
The
ssid
field (marked byS:
prefix) is repurposed to request a specific service instance name for_adb-tls-pairing._tcp
. The device has a special Camera QR code handler which when it sees typeT:ADB
starts a Pairing Server with the requested instance name. Note that the part afterstudio-
is randomized. This is done so Studio can tell which phone just scanned the QR code (here the instance name requested isstudio-g@<xeYnap/
). -
The password (marked by
P:
prefix) to use with the Pairing Server (here:(Aq+v9>Cx>!/
). This is the second shared secret vector we mentioned earlier. Here the code is generated by Studio and read by the device's camera.