DimaSOS

ADB

Шпаргалка по adb для отладки и прогона автотестов. Везде, где есть <pkg>, подставляется имя пакета, например com.example.app.

#Подключение и устройства

Если устройств больше одного, любая команда требует -s <serial>, иначе adb ругнётся more than one device.

adb devices -l

Список устройств с моделью, транспортом и device-id. unauthorized — не принят RSA-ключ на устройстве, offline — висит транспорт.

adb -s emulator-5554 shell
adb -d shell   # единственное USB-устройство
adb -e shell   # единственный эмулятор

Выбор цели. -d и -e удобнее, когда подключены ровно одно устройство и один эмулятор.

adb kill-server && adb start-server

Первое, что стоит сделать при offline, залипшем списке устройств или после смены USB-порта.

adb wait-for-device shell getprop sys.boot_completed

Блокируется до появления устройства. В CI полезнее дождаться именно sys.boot_completed=1, а не просто транспорта.

Готовность эмулятора: adb wait-for-device shell 'while [ "$(getprop sys.boot_completed)" != 1 ]; do sleep 1; done'

adb pair 192.168.1.50:37891      # код из «Отладка по Wi-Fi»
adb connect 192.168.1.50:5555

Wireless debugging начиная с Android 11: сначала одноразовое спаривание с PIN-кодом, затем подключение. Порты у пары и подключения разные, оба показаны в настройках.

adb tcpip 5555
adb connect 192.168.1.50:5555
adb usb          # вернуться на USB

Старый путь через USB: переключить демон на TCP, затем отсоединить кабель. Работает и на Android 10 и ниже.

adb disconnect                    # все сетевые
adb disconnect 192.168.1.50:5555

Отключение сетевых транспортов. USB не затрагивает.

adb root
adb unroot
adb remount

Работает только на userdebug/eng-сборках и эмуляторах без Google Play. remount делает /system записываемым.

adb reboot
adb reboot bootloader
adb reboot recovery

Перезагрузка в нужный режим.

#Информация об устройстве

adb shell getprop ro.build.version.release   # версия Android
adb shell getprop ro.build.version.sdk       # API level
adb shell getprop ro.product.model
adb shell getprop ro.product.cpu.abi         # arm64-v8a и т.п.

Точечное чтение свойств. Без аргумента getprop вывалит весь список — удобно грепать.

adb shell wm size
adb shell wm density
adb shell wm size 1080x1920      # переопределить
adb shell wm size reset

Разрешение и плотность. Переопределение полезно, чтобы воспроизвести баг вёрстки на «чужом» экране.

adb shell dumpsys battery
adb shell dumpsys battery set level 15
adb shell dumpsys battery unplug
adb shell dumpsys battery reset

Подмена состояния батареи — единственный вменяемый способ протестировать поведение при низком заряде.

adb shell settings get global auto_time
adb shell settings put system accelerometer_rotation 0
adb shell settings list global

Пространства: global, system, secure. Часть значений требует WRITE_SECURE_SETTINGS и не пишется на release-сборке.

adb shell date
adb shell getprop persist.sys.timezone

Время и таймзона устройства. Расхождение с сервером — классическая причина падений тестов на токенах и подписях.

#Пакеты и приложения

adb install app.apk
adb install -r app.apk            # переустановить, данные сохранить
adb install -g app.apk            # выдать все runtime-разрешения
adb install -t app.apk            # разрешить test-only сборку
adb install -d app.apk            # разрешить downgrade

-g — то, что нужно почти всегда в автотестах: снимает диалоги разрешений на старте.

adb install-multiple base.apk split_config.arm64_v8a.apk split_config.ru.apk

Установка split-APK. Из .aab набор сплитов получается через bundletool.

adb uninstall <pkg>
adb uninstall -k <pkg>           # снести, но оставить данные и кеш

Удаление. -k оставляет каталог данных.

adb shell pm list packages -3          # только сторонние
adb shell pm list packages -s          # только системные
adb shell pm list packages -d          # отключённые
adb shell pm list packages -f <pkg>    # с путём к apk
adb shell pm list packages | grep -i example

Поиск пакета, когда точное имя неизвестно.

adb shell pm path <pkg>

Пути к установленным apk. Дальше можно вытащить боевую сборку с устройства через adb pull.

adb shell pm clear <pkg>

Полный сброс: данные, кеш, разрешения, аккаунты. Самый надёжный способ привести приложение к состоянию «первый запуск» между тестами.

Дешевле и стабильнее, чем переустановка: не требует apk и не ломает подпись.

adb shell pm disable-user --user 0 <pkg>
adb shell pm enable <pkg>
adb shell pm hide <pkg>

Отключить приложение, не удаляя. Годится, чтобы убрать мешающий системный компонент на время прогона.

adb shell dumpsys package <pkg>

Всё про пакет: версия, подпись, разрешения (и запрошенные, и выданные), activity, receiver'ы, флаги установки.

adb shell dumpsys package <pkg> | grep -A2 versionName

Быстрая проверка, какая версия реально стоит на устройстве.

#Запуск, activity и deep links

adb shell am start -n <pkg>/.MainActivity
adb shell am start -n <pkg>/<pkg>.ui.MainActivity

Явный запуск. Точка в начале — сокращение до applicationId, но при разных applicationId и package нужно полное имя класса.

adb shell monkey -p <pkg> -c android.intent.category.LAUNCHER 1

Запуск «как из лаунчера», когда имя activity неизвестно.

adb shell am start -W -a android.intent.action.VIEW -d "myapp://profile/42" <pkg>

Проверка deep link. -W ждёт запуска и печатает TotalTime — удобная метрика холодного старта.

Ссылки с & обязательно в кавычках, иначе shell порежет на части.

adb shell am start -a android.intent.action.VIEW -d "https://example.com/x"

App Links. Если открылся браузер, а не приложение — смотри верификацию: adb shell pm get-app-links <pkg>.

adb shell am start -n <pkg>/.MainActivity --es key value --ei num 42 --ez flag true

Передача extras: --es строка, --ei int, --ez boolean, --el long, --ef float.

adb shell am force-stop <pkg>
adb shell am kill <pkg>

force-stop гарантированно валит процесс и сбрасывает стек activity. kill мягче — только если процесс в фоне.

adb shell am broadcast -a com.example.ACTION --es payload test

Отправка broadcast. Учти ограничения на неявные broadcast'ы начиная с Android 8.

adb shell dumpsys window | grep -E 'mCurrentFocus|mFocusedApp'

Что сейчас на экране. Самая частая команда при разборе «тест не находит элемент» — часто оказывается, что сверху чужой диалог.

adb shell dumpsys activity activities | grep -E 'ResumedActivity'

Текущая resumed-activity. Альтернатива предыдущей команде, стабильнее парсится.

adb shell am start-foreground-service -n <pkg>/.SyncService
adb shell am startservice -n <pkg>/.SyncService

Запуск сервиса напрямую.

#Логи

adb logcat

Поток целиком. Практически всегда нужен один из фильтров ниже.

adb logcat -c        # очистить буфер
adb logcat -d        # дампнуть и выйти
adb logcat -t 200    # последние 200 строк и выйти

Связка -c перед действием и -d после — базовый приём: в выводе только то, что относится к проверяемому шагу.

adb logcat --pid=$(adb shell pidof -s <pkg>)

Только логи своего приложения. Самый полезный фильтр: убирает системный шум целиком.

После force-stop или краша PID меняется — команду надо перезапустить.

adb logcat MyTag:D *:S

Только тег MyTag уровня Debug и выше, всё остальное заглушить. Уровни: V D I W E F S.

adb logcat -v threadtime
adb logcat -v time
adb logcat -v color

threadtime добавляет PID и TID — без него невозможно разбирать многопоточные гонки.

adb logcat -b crash
adb logcat -b events
adb logcat -b all

Отдельные буферы. crash — только падения, events — системные события (запуски activity, ANR, GC).

adb logcat -e 'HTTP [45][0-9][0-9]'

Фильтр по регулярке на стороне устройства. Дешевле, чем гонять весь поток через grep на хосте.

adb logcat -G 16M

Увеличить кольцевой буфер. Нужно, когда приложение логирует много, а падение случается редко.

adb logcat *:E > errors.log

Только ошибки в файл. На длинных прогонах — базовый артефакт.

adb shell setprop log.tag.OkHttp VERBOSE

Включить подробность конкретного тега без пересборки, если в коде используется Log.isLoggable.

adb bugreport bugreport.zip

Полный срез состояния системы: логи, dumpsys, ANR-трейсы. Тяжёлый, но незаменим при разборе ANR и утечек.

adb shell dumpsys dropbox --print | tail -100
adb shell ls /data/anr/

ANR-трейсы и системные крашдампы.

#Файлы, скриншоты, запись экрана

adb push local.txt /sdcard/Download/
adb pull /sdcard/Download/report.json ./

Обмен файлами. Каталог приложения /data/data/<pkg> напрямую недоступен без root.

adb shell run-as <pkg> ls -la /data/data/<pkg>/databases
adb shell run-as <pkg> cat /data/data/<pkg>/shared_prefs/prefs.xml

Доступ к приватным данным без root — работает для debuggable-сборок. Способ проверить, что реально записалось в prefs и БД.

adb exec-out run-as <pkg> cat /data/data/<pkg>/databases/app.db > app.db

Вытащить базу приложения на хост и открыть в любом SQLite-клиенте.

exec-out вместо shell — принципиально: shell портит бинарные данные заменой переводов строк.

adb exec-out screencap -p > screen.png

Скриншот прямо в файл на хосте, без промежуточного файла на устройстве.

adb shell screenrecord --time-limit 30 --bit-rate 4000000 /sdcard/rec.mp4
adb pull /sdcard/rec.mp4

Запись экрана, максимум 180 секунд. Звук не пишется.

adb shell screenrecord --size 720x1280 --output-format=h264 - > rec.h264

Стрим записи на хост без файла на устройстве.

adb shell ls -la /sdcard/
adb shell rm -r /sdcard/test-artifacts
adb shell mkdir -p /sdcard/test-artifacts

Обычные файловые операции внутри shell.

adb shell df -h /data
adb shell du -sh /data/data/<pkg>

Свободное место и размер данных приложения. Забитый /data — частая причина необъяснимых падений на длинных прогонах.

#Сеть и прокси

adb reverse tcp:8080 tcp:8080

Устройство видит localhost:8080 как порт 8080 на хосте. Так приложение подключается к локальному моку API без правки конфигов и без выяснения IP хоста.

Для автотестов это удобнее, чем прописывать IP: работает одинаково на эмуляторе и физическом устройстве.

adb forward tcp:9222 localabstract:chrome_devtools_remote
adb forward --list
adb forward --remove-all

Обратное направление: порт хоста проксируется на устройство. Пример — отладка WebView через Chrome DevTools.

adb shell settings put global http_proxy 10.0.2.2:8888
adb shell settings delete global http_proxy

Системный прокси — так трафик заворачивается в Charles или mitmproxy. 10.0.2.2 — хост со стороны эмулятора.

HTTPS без установленного CA будет отвергаться. Начиная с Android 7 приложение обязано явно доверять пользовательским CA через network_security_config.

adb shell ip addr show wlan0
adb shell ip route
adb shell ping -c 3 8.8.8.8

Диагностика сети с устройства.

adb shell svc wifi disable
adb shell svc wifi enable
adb shell svc data disable

Управление радио. Так тестируется поведение в offline без ковыряния в настройках руками.

adb shell cmd connectivity airplane-mode enable
adb shell cmd connectivity airplane-mode disable

Режим полёта. Надёжнее, чем гасить интерфейсы поодиночке.

adb shell dumpsys connectivity | head -40
adb shell dumpsys netstats | head -40

Состояние подключений и счётчики трафика по UID.

#Разрешения

adb shell pm grant <pkg> android.permission.CAMERA
adb shell pm revoke <pkg> android.permission.ACCESS_FINE_LOCATION

Выдача и отзыв runtime-разрешений. Только для тех, что объявлены в манифесте, иначе SecurityException.

adb shell pm reset-permissions

Сброс всех разрешений в исходное состояние. Полезно перед проверкой сценария первого запуска.

adb shell dumpsys package <pkg> | sed -n '/runtime permissions/,/^$/p'

Что реально выдано прямо сейчас.

adb shell appops set <pkg> RUN_IN_BACKGROUND deny
adb shell appops get <pkg>

App ops — более тонкий слой, чем разрешения: фоновая работа, доступ к уведомлениям, наложение поверх окон.

adb shell appops set <pkg> SYSTEM_ALERT_WINDOW allow

Наложение поверх других окон — без него часть инструментов автоматизации не работает.

#Ввод и дерево UI

adb shell input tap 540 1200
adb shell input swipe 540 1600 540 600 300      # последнее — длительность, мс
adb shell input text 'hello%sworld'                # %s вместо пробела
adb shell input keyevent KEYCODE_BACK

Синтетический ввод. Координаты зависят от разрешения, так что для тестов это скорее отладочный инструмент, чем основа.

adb shell input keyevent 4     # BACK
adb shell input keyevent 3     # HOME
adb shell input keyevent 26    # POWER
adb shell input keyevent 82    # MENU
adb shell input keyevent 66    # ENTER
adb shell input keyevent 187   # APP_SWITCH (недавние)

Частые keycode. Полный список — в KeyEvent из Android SDK.

adb shell uiautomator dump /sdcard/ui.xml
adb pull /sdcard/ui.xml
# или одной командой:
adb exec-out uiautomator dump /dev/tty > ui.xml

Дамп дерева UI с resource-id, text, content-desc и границами. Основной способ понять, за что цепляться селектором.

adb shell settings put global window_animation_scale 0
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0

Отключение анимаций. Убирает целый класс флаки-падений на ожиданиях и ускоряет прогон.

Обязательный шаг в подготовке устройства под автотесты. Сбрасывается значением 1.

adb shell settings put secure show_ime_with_hard_keyboard 0
adb shell ime list -s
adb shell ime disable com.google.android.inputmethod.latin

Экранная клавиатура умеет перекрывать элементы и ломать тесты. На тестовых устройствах её обычно отключают.

#Инструментальные тесты и профилирование

adb shell pm list instrumentation

Какие раннеры установлены на устройстве.

adb shell am instrument -w <pkg>.test/androidx.test.runner.AndroidJUnitRunner

Запуск всего набора инструментальных тестов. -w ждёт завершения и печатает результат.

adb shell am instrument -w -e class com.example.LoginTest#validCredentials \
  <pkg>.test/androidx.test.runner.AndroidJUnitRunner

Один тест или один класс — быстрый цикл при отладке падения.

adb shell am instrument -w -e package com.example.smoke \
  -e annotation androidx.test.filters.LargeTest \
  <pkg>.test/androidx.test.runner.AndroidJUnitRunner

Фильтры по пакету и аннотации. Так набирается smoke-набор без пересборки.

adb shell dumpsys meminfo <pkg>

Память по категориям. Растущий Private Dirty между итерациями одного сценария — признак утечки.

adb shell dumpsys gfxinfo <pkg> framestats

Тайминги отрисовки кадров. Из этого считаются пропущенные кадры и janky frames.

adb shell top -b -n 1 -o %CPU,RES,CMDLINE | head -15
adb shell pidof <pkg>

Кто ест CPU и память прямо сейчас.

adb shell am start -W -n <pkg>/.MainActivity

Замер времени старта: ThisTime, TotalTime, WaitTime в мс. Дешёвая метрика для отслеживания регрессий холодного старта.

adb shell cmd package compile -m speed -f <pkg>

Принудительная AOT-компиляция. Убирает разброс первых прогонов при замерах производительности.

#Подготовка устройства к прогону

Последовательность, которая снимает большинство нестабильных падений. Годится и как скрипт в CI.

#!/usr/bin/env bash
set -euo pipefail
PKG="com.example.app"

adb wait-for-device
adb shell 'while [ "$(getprop sys.boot_completed)" != 1 ]; do sleep 1; done'

# анимации — главный источник флаки
adb shell settings put global window_animation_scale 0
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0

# экран не должен гаснуть посреди прогона
adb shell svc power stayon true
adb shell settings put system screen_off_timeout 1800000

# автоповорот выключен, ориентация фиксирована
adb shell settings put system accelerometer_rotation 0

# чистый старт приложения
adb shell pm clear "$PKG"

# буфер логов пуст, чтобы в артефакт попало только своё
adb logcat -c

echo "устройство готово: $(adb shell getprop ro.product.model)"

Идемпотентный скрипт подготовки: можно запускать перед каждым прогоном.

adb shell settings put global window_animation_scale 1
adb shell settings put global transition_animation_scale 1
adb shell settings put global animator_duration_scale 1
adb shell svc power stayon false

Возврат устройства в человеческое состояние после прогона.

СимптомЧто смотреть первым
Элемент не найден, хотя виденdumpsys window | grep mCurrentFocus — сверху чужой диалог
Тест флакует на ожиданияханимации не отключены
Падает только первый прогон после установкидиалоги разрешений — ставить с -g
Работает локально, падает в CIтаймзона и время устройства, adb shell date
more than one device-s <serial> или ANDROID_SERIAL
device unauthorizedпринять RSA-ключ на экране; adb kill-server
Приложение не видит мок APIadb reverse tcp:PORT tcp:PORT сбрасывается при реконнекте
Длинный прогон падает к концуdf -h /data — кончилось место под артефакты