用途
本技能解决通过 ADB 连接 Android 设备或模拟器时的常见问题:设备列举、选择与等待。典型触发场景包括:运行 adb shell 时出现 error: more than one device/emulator;设备显示为 unauthorized、offline 或 no permissions;CI 脚本需要在设备完成启动后再运行测试;误用不存在的 adb wait-for-device-online;Linux 上新插入的手机不出现在 adb devices 中。
不适用场景:需要了解 ADB 高层架构、服务器生命周期或环境变量时,应参考架构相关技能;需要 Wi-Fi 无线调试时,应参考无线连接技能;需要在已连接设备上安装或清除应用状态时,应参考应用管理技能。
主要能力
- 使用
adb devices和adb devices -l列出所有传输,-l会额外显示 product、model、device、transport_id 以及 USB 总线路径。 - 使用选择器区分多设备:
-s <serial>指定序列号(支持 USB 序列号、模拟器如emulator-5554、TCP 设备如192.168.1.42:5555,并覆盖$ANDROID_SERIAL);-d选择唯一 USB 设备;-e选择唯一 TCP/IP 设备;-t <transport_id>使用adb devices -l中的数字传输 ID。注意-t是传输 ID,不是超时标志。 - 在脚本中过滤就绪设备:
adb devices | awk '$2=="device"{print $1}'。 - 使用规范的等待语法
wait-for[-TRANSPORT]-STATE,其中 TRANSPORT 可为 usb、local、any(默认 any),STATE 可为 device、recovery、rescue、sideload、bootloader、disconnect。常见形式包括adb wait-for-device、adb wait-for-usb-device、adb wait-for-local-device、adb wait-for-bootloader、adb wait-for-recovery、adb wait-for-sideload、adb wait-for-rescue、adb wait-for-disconnect。文档未定义wait-for-device-online形式。 wait-for-*仅检查传输状态,不检查启动完成,需配合轮询sys.boot_completed:
adb wait-for-device
until [[ "$(adb shell getprop sys.boot_completed | tr -d '\r')" == "1" ]]; do
sleep 1
done
adb shell input keyevent 82 # 解锁 AOSP 上滑屏幕
- 围绕重启的复合流程:
adb shell reboot
adb wait-for-disconnect
adb wait-for-device
- 正确解读设备状态:device(在线,adbd 响应,但不代表启动完成)、offline(传输存在但 adbd 无响应,可尝试
adb reconnect offline后重新插拔)、unauthorized(主机 RSA 密钥未被设备接受,需解锁设备并点击允许)、recovery、sideload、bootloader、rescue、connecting(无线 TLS 握手瞬态)、no permissions(仅 Linux,缺少 udev 规则)。 - 首次连接时接受 RSA 指纹对话框:Android 4.2.2(API 17)及以上会弹出“允许 USB 调试?”对话框,显示工作站密钥指纹;在用户点击允许前,
adb devices报告 unauthorized;接受后公钥追加到设备/data/misc/adb/adb_keys,勾选“始终允许”可跳过后续提示;可通过设置 → 开发者选项 → 撤销 USB 调试授权来撤销旧工作站权限。 - Linux 下安装 udev 规则,规范文件为
/etc/udev/rules.d/51-android.rules,最小示例(每个 OEM 一行):
# Google
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0660", GROUP="plugdev", TAG+="uaccess"
# Samsung
SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0660", GROUP="plugdev", TAG+="uaccess"
无需重启即可应用:
sudo udevadm control --reload-rules
sudo udevadm trigger
# 拔下并重新插入设备
多数发行版也提供 android-udev / android-sdk-platform-tools-common 包,会将相同文件放入 /lib/udev/rules.d/。
- Windows 下安装厂商 USB 驱动:Pixel / Nexus / 通用 AOSP 设备使用 SDK Manager → SDK Tools → Google USB Driver(文件位于
android_sdk\extras\google\usb_driver\);其他 OEM 需从 https://developer.android.com/tools/extras/oem-usb 获取厂商驱动。macOS 和 Linux 不需要厂商驱动。 - 多设备扇出:ADB 没有内置
--all标志,可用顺序或并行模式:
# 顺序
for s in $(adb devices | awk '$2=="device"{print $1}'); do
adb -s "$s" install -r app.apk
done
# 并行(每次 4 个任务)
adb devices | awk '$2=="device"{print $1}' \
| xargs -I{} -P 4 adb -s {} install -r app.apk
对于每个运行器独占一台手机的分片 CI,可将服务器锁定到单个设备:
adb --one-device 0a388e93 start-server
使用方式
- 每次先运行
adb devices,脚本中加-l。 - 根据情况选择选择器:
-s、-d、-e或-t。 - 脚本中过滤就绪设备。
- 使用规范的
wait-for-*形式,并在需要系统完全启动时轮询sys.boot_completed。 - 正确解读设备状态并处理异常。
- 首次连接时接受 RSA 指纹对话框。
- Linux 下安装 udev 规则;Windows 下安装厂商 USB 驱动。
- 多设备时使用顺序或并行扇出。
适用场景
- CI 脚本等待设备就绪后再运行测试。
- 多设备调试时区分目标设备。
- Linux 上新设备因缺少 udev 规则无法识别。
- 设备显示 unauthorized、offline 或 no permissions 时排查。
- 模拟器启动竞态条件处理。
限制
wait-for-*仅检查传输状态,不检查启动完成,必须额外轮询sys.boot_completed。- 不存在
wait-for-device-online形式。 -t是传输 ID,不是超时标志;实际超时需用 shell 的timeout或gtimeout。- 多设备时每个非服务器 adb 命令必须显式指定选择器或设置
$ANDROID_SERIAL。 - 不得通过删除
~/.android/adbkey*来“修复” unauthorized。 - 模拟器在特定条件下可能不出现在
adb devices中,需在启动模拟器前先运行adb start-server。
验证
adb devices -l列出所有传输且状态为 device。adb devices | awk '$2=="device"{print $1}'每个就绪设备返回一行。adb -s <serial> get-state输出 device。adb wait-for-device在至少一个传输处于 device 状态时立即返回。- 全新启动后
adb shell getprop sys.boot_completed输出 1。 adb -d shell echo ok(或-e、-s)成功且不报 more than one device/emulator。- Linux 上应用 udev 规则后,
lsusb显示设备且adb devices报告 device(而非 no permissions)。