Напомню архитектуру из первой главы. Клиент adb (то, что вы набираете в терминале) общается с сервером adb, фоновым процессом на вашем компьютере, который слушает TCP-порт 5037. Сервер держит соединения с демонами adbd на устройствах. Все команды этой главы крутятся вокруг этой троицы.
adb devices: кто подключен и в каком состоянии:
Самая частая команда. Показывает серийники всех устройств, которые видит сервер, и их состояние:
Код: Выделить всё
$ adb devices
List of devices attached
RF8N20XXXXX device
emulator-5554 deviceКод: Выделить всё
* daemon not running; starting now at tcp:5037
* daemon started successfully
List of devices attached
RF8N20XXXXX deviceКод: Выделить всё
$ adb devices -l
List of devices attached
RF8N20XXXXX device usb:1-2 product:a52qnsxx model:SM_A525F device:a52q transport_id:1
192.168.1.42:5555 device product:redfin model:Pixel_5 device:redfin transport_id:3Теперь состояния, их больше, чем кажется.
device. Нормальное рабочее состояние: adbd отвечает, авторизация пройдена, команды выполняются. Нюанс: device не означает, что Android полностью загрузился. Состояние появляется еще в процессе загрузки, поэтому в скриптах после ребута дополнительно проверяют свойство sys.boot_completed (разберем в главах 5 и 22).
offline. Сервер знает про устройство, но демон не отвечает или соединение протухло. Типичные причины: плохой кабель или USB-хаб, старый adb против свежего Android, уснувшее устройство при подключении по Wi-Fi. Лечение по нарастающей:
Код: Выделить всё
$ adb reconnect offline
$ adb kill-server && adb devicesunauthorized. Устройство на месте, но ваш компьютер не авторизован. На экране телефона в этот момент висит (или должен висеть) диалог "Разрешить отладку по USB?" с отпечатком RSA-ключа. Примите его, лучше с галкой "Всегда разрешать с этого компьютера". Пара ключей лежит на компьютере в ~/.android/adbkey и adbkey.pub, на устройстве принятые ключи хранятся в /data/misc/adb/adb_keys. Любая команда при этом честно ругается:
Код: Выделить всё
$ adb shell
adb: device unauthorized.
This adb server's $ADB_VENDOR_KEYS is not set
Try 'adb kill-server' if that seems wrong.
Otherwise check for a confirmation dialog on your device.recovery. Устройство загружено в recovery, и его adbd доступен. Со стоковым recovery такое бывает редко, а кастомные (TWRP, OrangeFox) поднимают adbd сразу, и можно работать с файлами даже без загруженной системы. Попасть туда: adb reboot recovery (глава 5).
Реже встречаются: sideload (устройство в recovery ждет OTA-пакет через adb sideload, глава 27), authorizing (переходное состояние на пару секунд, пока идет обмен ключами), no permissions (специфика Linux, у пользователя нет прав на USB-устройство, лечится правилами udev из главы 2).
Для скриптов есть adb get-state, выводит состояние одной строкой и возвращает ненулевой код выхода, если устройств нет:
Код: Выделить всё
$ adb get-state
deviceСервер стартует сам при первой же команде, поэтому явный запуск нужен нечасто. Но в скриптах и CI его запускают отдельно, чтобы служебные строки про daemon не смешивались с полезным выводом:
Код: Выделить всё
$ adb start-server
* daemon not running; starting now at tcp:5037
* daemon started successfullyОстановка:
Код: Выделить всё
$ adb kill-serverКод: Выделить всё
$ adb kill-server && adb start-serverПро конфликт версий подробнее, это классика. На машине часто живет несколько копий adb: одна в Platform Tools, другие приехали с прошивальщиками или фирменными ассистентами (HiSuite, Mi Assistant). Когда клиент одной версии обращается к серверу другой, происходит вот что:
Код: Выделить всё
$ adb devices
adb server version (40) doesn't match this client (41); killing...
* daemon started successfully
List of devices attached
RF8N20XXXXX deviceКод: Выделить всё
$ adb version
Android Debug Bridge version 1.0.41
Version 36.0.0-13206524
Installed as /opt/platform-tools/adb
Running on Linux 6.8.0 (x86_64)Другая ошибка запуска, занятый порт 5037:
Код: Выделить всё
$ adb start-server
* daemon not running; starting now at tcp:5037
ADB server didn't ACK
Full server startup log: /tmp/adb.1000.log
Server had pid: 41203
error: could not install *smartsocket* listener: Address already in useКод: Выделить всё
$ lsof -i :5037 # Linux/macOS
> netstat -ano | findstr 5037 # Windows, затем tasklist | findstr PIDКод: Выделить всё
$ adb -P 5038 start-server
$ adb -P 5038 devicesКод: Выделить всё
$ export ANDROID_ADB_SERVER_PORT=5038
$ adb devices # теперь все команды ходят на 5038Код: Выделить всё
$ adb kill-server
$ adb server nodaemonКод: Выделить всё
$ adb -P 5040 --one-device RF8N20XXXXX start-serverКод: Выделить всё
$ adb --helpКод: Выделить всё
$ adb --help | grep -A2 reconnect
reconnect kick connection from host side to force reconnect
reconnect device kick connection from device side to force reconnect
reconnect offline reset offline/unauthorized devices to force reconnectОтдельных страниц справки по подкомандам нет, зато многие команды печатают usage при неверном вызове: adb install без аргументов покажет список своих флагов. Справка по командам внутри устройства это другая история (adb shell cmd package help и подобные), о ней в главах 7 и 28.
Флаги адресации: -d, -e, -s, -t:
Пока устройство одно, adb сам понимает, куда слать команды. Как только их два, любая команда без адресата падает:
Код: Выделить всё
$ adb shell getprop ro.build.version.release
adb: more than one device/emulator-d (device): команда единственному устройству на USB. Сработает, только если USB-устройство ровно одно, иначе та же ошибка more than one:
Код: Выделить всё
$ adb -d shell getprop ro.build.version.release
15Код: Выделить всё
$ adb -e shell getprop ro.boot.qemu
1Код: Выделить всё
$ adb -s RF8N20XXXXX install -r app-debug.apk
Performing Streamed Install
Success
$ adb -s 192.168.1.42:5555 logcat -d -t 5Код: Выделить всё
$ export ANDROID_SERIAL=RF8N20XXXXX
$ adb shell echo ok
ok-t ID: адресация по transport_id из adb devices -l. Зачем, если есть -s? Затем, что серийники не уникальны. У дешевых планшетов и безымянных приставок серийник бывает прошит одинаковый на всю партию, легендарный 0123456789ABCDEF встречается до сих пор. Два таких устройства по -s не различить, а transport_id сервер раздает сам, каждому соединению свой:
Код: Выделить всё
$ adb devices -l
List of devices attached
0123456789ABCDEF device usb:1-2 product:tab10 model:Tab10 device:tab10 transport_id:5
0123456789ABCDEF device usb:1-3 product:tab10 model:Tab10 device:tab10 transport_id:6
$ adb -t 6 shell getprop ro.product.model
Tab10И частая ошибка с любым из этих флагов: поставить его после команды. adb shell -s SERIAL не сработает, -s уедет аргументом внутрь shell. Правильно только adb -s SERIAL shell.
Чек-лист на закрепление:
Код: Выделить всё
adb devices -l # кто подключен: состояния, серийники, transport_id
adb get-state # состояние единственного устройства, удобно в скриптах
adb reconnect offline # оживить offline/unauthorized без перезапуска сервера
adb kill-server # остановить сервер
adb start-server # явно поднять сервер
adb version # версия клиента и путь к бинарнику
adb -s SERIAL ... # команда конкретному устройству
adb -t ID ... # то же, но по transport_id