关于 understanding-adb-architecture
面向 Android 开发者的 ADB 架构说明技能,梳理 CLI、主机端服务器与设备端守护进程的职责。它帮助定位版本冲突、端口占用和传输故障,并强调保留授权密钥。
主要功能
- 01说明 ADB 三部分架构
- 02讲解服务器生命周期与端口
- 03排查多个 adb 二进制冲突
- 04介绍环境变量与日志诊断
- 05说明 RSA 授权密钥的影响
适用场景
- 01判断首次启动服务器提示是否为错误
- 02排查 5037 端口冲突或版本不匹配
- 03配置 CI 的密钥和服务器端口
- 04诊断 Linux 上的 USB 传输问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ skydoves/ android-testing-skills --skill understanding-adb-architecture安装后在 Claude Code 中输入/understanding-adb-architecture确认已加载。
详细介绍
了解 ADB 架构——客户端、服务端、守护进程
ADB 是一个一身兼三职的二进制文件。大多数“adb 行为异常”的反馈,都是因为没有弄清楚究竟是哪个角色出了问题(本地 CLI、长期运行且监听 5037 端口的主机服务端,还是设备上的 adbd),或者是两个不同的 adb 二进制文件在争用同一个端口。本技能将帮助你建立正确的心智模型,为 ADB 技能集的其余部分打下稳固基础。
何时使用本技能
- 用户看到
* daemon not running; starting now at tcp:5037 *,并以为这是错误。 - Studio 更新其捆绑的 platform-tools 后,用户看到
adb server version (XX) doesn't match this client (YY); killing...。 - 用户想要启用详细的 ADB 日志(
ADB_TRACE),或设置预装供应商密钥的 CI 运行器。 - 用户询问为什么删除
~/.android/adbkey会导致其他所有已配对设备都无法使用。 - 用户正在排查 5037 端口冲突、多个 adb 安装版本,或 Linux 上与 libusb 相关的传输故障。
何时不要使用本技能
- 用户正在排查某台已连接设备的问题(USB 授权、
unauthorized、no permissions)——使用../../devices/connecting-to-devices/SKILL.md。 - 用户正在设置无线 / Wi-Fi ADB——使用
../../devices/connecting-over-wifi/SKILL.md。 - 用户正在运行
adb shell am instrument执行测试——使用../../tests/running-instrumented-tests-via-adb/SKILL.md。
前提条件
- 已安装 Android SDK Platform-Tools(路径解析规则见下文)。
- 可在工作站的 Shell 中访问命令行,且
adb位于$PATH中。 - 对于诊断流程:需要对
$TMPDIR(macOS/Linux)或%TEMP%(Windows)具有写入权限。
工作流
-
1. 理解由三部分组成的模型。 参阅 developer.android.com/tools/adb(Overview):
- 客户端(
adbCLI)——从终端调用。它会序列化命令,并通过本地 TCP 套接字将命令发送给服务端。 - 服务端(
adb-server)——主机端的后台进程。它会复用来自多个客户端的命令,跟踪已连接的传输,并将流量转发给adbd。默认在localhost上绑定 TCP 端口 5037。 - 守护进程(
adbd)——在设备上运行。在 userdebug/eng 构建中由init启动,在 user 构建中由系统启动。它通过 USB 或 TCP 接收来自主机服务端的命令,并在设备的用户空间中执行这些命令。
- 客户端(
-
2. 识别隐式的
start-server提示。 在全新的 Shell 中执行第一条adb命令时,会显示:* daemon not running; starting now at tcp:5037 * daemon started successfully这只是提示信息,不是错误——如果没有服务端在运行,
adb会自动启动服务端。忽略这一事实会浪费数小时来排查问题。 -
3. 有针对性地使用生命周期命令:
命令 效果 adb start-server确保服务端在端口 5037 上运行。如果已有兼容的服务端在运行,则不执行任何操作(幂等)。如果其他进程绑定了 5037(或运行着较旧且不兼容的 adb 服务端), start-server会失败——参见下文的端口冲突模式。adb kill-server终止本地服务端。下一条 adb命令会重新启动它。adb reconnect“从主机端断开连接以强制重新连接。”可用于卡住的 USB 传输。 adb reconnect device“从设备端断开连接。”要求 adbd断开连接并重新握手。adb reconnect offline“重置离线 / 未授权的设备以强制重新连接。”只针对行为异常的传输。 adb -P PORT ...覆盖服务端端口(默认值为 5037)。等同于 ANDROID_ADB_SERVER_PORT。卡住的传输恢复步骤:
adb reconnect offline # 如果失败: adb kill-server && adb start-server && adb devices -
4. 明确解析二进制文件路径。
adb随 Android SDK Platform-Tools 一起提供(android_sdk/platform-tools/)。检查实际加载的是哪个文件:adb --version which -a adb # 查找被遮蔽的副本adb --version输出示例解析:Android Debug Bridge version 1.0.41 # 线路协议版本(多年来保持稳定) Version 35.0.2-12147458 # platform-tools 版本 + Google 构建编号 Installed as /opt/homebrew/bin/adb # 操作系统实际解析到的文件 Running on Darwin 24.6.0 (arm64)线路协议版本号关系到跨版本兼容性:客户端和服务端必须一致,否则首条命令会终止较旧的服务端,并显示
adb server version (XX) doesn't match this client (YY); killing...。 -
5. 涉及 Android Studio 时,选定唯一的规范 adb。 Studio 会自带并自动更新自己的
platform-tools/。如果系统 / Homebrew 的 adb 也在$PATH中,就会出现三种故障模式:- 版本不匹配——任一方发出首条命令时,都会终止正在运行的服务端。
- 两个相互竞争的服务端在端口 5037 上来回争抢。
- 默认后端不同(libusb 与原生后端),导致设备枚举结果不一致。
经验规则:执行
export PATH="$ANDROID_HOME/platform-tools:$PATH",让 CLI 和 Studio 使用相同版本,然后执行一次adb kill-server。
-
6. 了解环境变量(原样摘自
adb help):变量 用途 ADB_TRACE以逗号或空格分隔的调试类别。标记: all,adb,sockets,packets,rwx,usb,sync,sysdeps,transport,jdwp,services,auth,fdevent,shell,incremental。ADB_VENDOR_KEYS以冒号分隔的 RSA 密钥文件 / 目录路径。可在 CI 中使用,以跳过“允许 USB 调试?”提示。 ANDROID_SERIAL默认设备序列号(等同于 -s)。可被-s覆盖。ANDROID_ADB_SERVER_PORT覆盖服务端端口(默认值为 5037)。等同于 -P PORT。ADB_LOCAL_TRANSPORT_MAX_PORT扫描模拟器时使用的最高奇数端口。默认值为 5585(16 个模拟器)。ADB_MDNS_AUTO_CONNECT允许自动连接的 mDNS 服务类型 CSV。默认值: adb-tls-connect。ADB_MDNS_OPENSCREEN1/0。强制使用 Openscreen mDNS 后端。ADB v34+ 在 Linux/Windows 上默认使用 Openscreen——公开文档尚未更新。ADB_LIBUSB1/0。强制使用 libusb USB 后端。ADB_BURST_MODE1/0。不等待 ACK 即对数据包进行流水线处理。实验性功能,适用于 ADB 36.0.0+。最大详细程度的诊断命令:
ADB_TRACE=all adb devices -l 2>~/adb-trace.log使用预装密钥和自定义端口的 CI 运行器:
export ADB_VENDOR_KEYS=/etc/adb/ci-key export ANDROID_ADB_SERVER_PORT=5038 export ADB_LOCAL_TRANSPORT_MAX_PORT=5617 adb start-server -
7. 出现问题时查找服务端日志。 服务端会保留一份日志,与每条命令的
ADB_TRACE输出和logcat不同:操作系统 路径 macOS $TMPDIR/adb.$UID.log(例如/var/folders/.../T/adb.501.log)Linux $TMPDIR/adb.$UID.log(例如/tmp/adb.1000.log)Windows %TEMP%\adb.log实用操作流程: adb kill-server ADB_TRACE=adb,transport,auth adb start-server adb devices -l ls -lh "$TMPDIR/adb.$UID.log" -
8. 将
~/.android/视为关键目录。 RSA 密钥对:~/.android/adbkey(私钥)、~/.android/adbkey.pub(公钥)。首次调用adb时生成。每次接受“允许 USB 调试?”对话框,都会将该公钥追加到设备上的/data/misc/adb/adb_keys。删除本地密钥会使用户之前授权的所有设备失效——请参见下方的 WRONG/RIGHT 示例。 -
9. 将 Linux 上 libusb v36 回归问题作为背景信息。 ADB v36.0.0(2025 年 4 月)发布了重写后的 libusb 后端,并加入热插拔功能。ADB v36.0.2(2025 年 9 月)因稳定性问题,撤销了将 libusb 设为 Linux 默认后端的更改。固定使用特定 platform-tools 版本的 CI 运行器需要确认自己使用的是回退前还是回退后的版本;如需保证可复现性,请通过
ADB_LIBUSB=0或=1显式指定后端。
模式
模式:错误做法与正确做法 — 从设备 unauthorized 或 offline 状态中恢复
# WRONG
rm -rf ~/.android/adbkey ~/.android/adbkey.pub
adb kill-server
adb start-server
# WRONG because: this rotates the host RSA keypair. Every previously authorized
# device now sees an unknown public key and re-prompts the "Allow USB debugging?"
# dialog. CI runners and headless test farms break silently because nobody is
# there to tap "Allow". Worse, the key on /data/misc/adb/adb_keys for the old
# pubkey lingers as orphan data.
# RIGHT
adb reconnect offline # try a targeted reset first
adb devices # confirm the state changed
# if still offline:
adb kill-server && adb start-server
# if still unauthorized: unlock the device, re-tap "Allow USB debugging?"
只有在密钥对确实丢失或损坏时才需要重新生成;此时,adb keygen ~/.android/adbkey 会主动重建密钥,用户也需要接受所有设备都必须重新授权。
模式:错误做法与正确做法 — 安装了两个相互冲突的 adb
# WRONG
brew install android-platform-tools # installs adb to /opt/homebrew/bin
# Studio also auto-updates ~/Library/Android/sdk/platform-tools/adb
# PATH puts /opt/homebrew/bin first.
# Studio's "Run" button uses ~/Library/Android/sdk/platform-tools/adb (different version).
# First command issued by either side prints:
# adb server version (41) doesn't match this client (40); killing...
# WRONG because: every Run-button invocation kills the server you started,
# yanks transports out from under Logcat, and reissues "daemon not running".
# RIGHT
# Pick one canonical adb. Easiest: prefer Studio's bundled platform-tools.
export ANDROID_HOME="$HOME/Library/Android/sdk"
export PATH="$ANDROID_HOME/platform-tools:$PATH"
adb kill-server # clear stale state once
adb --version # confirm path matches Studio's
模式:错误做法与正确做法 — 端口 5037 已被占用
# WRONG
# Some other tool (nc, a proxy, a stale adb-server zombie) is bound to 5037.
adb start-server # silently fails; subsequent adb devices hangs.
# RIGHT
lsof -nP -iTCP:5037 -sTCP:LISTEN # find the holder (macOS/Linux)
# kill the squatter, OR run a second adb server on a different port:
ANDROID_ADB_SERVER_PORT=5038 adb start-server
ANDROID_ADB_SERVER_PORT=5038 adb devices
强制规则
- 必须将
* daemon not running; starting now at tcp:5037 *视为提示信息,而非错误。 - 必须确保
$PATH中只有一个adb二进制文件排在最前面。混用不同版本的 Studio 捆绑版和系统安装版adb会导致服务器反复切换。 - 必须在迁移计算机时保留
~/.android/adbkey和~/.android/adbkey.pub;删除这些文件会悄无声息地导致所有先前已授权的设备失效。 - 不得将删除
~/.android/adbkey*作为解决unauthorized或offline设备问题的方法——请先使用adb reconnect offline。 - 不得同时在端口 5037 上运行两个
adb服务器。对于分片 CI,请使用ANDROID_ADB_SERVER_PORT(或-P PORT)。 - **优先做法:**在 shell 配置文件中添加
export PATH="$ANDROID_HOME/platform-tools:$PATH",以便命令行和 Studio 使用同一个二进制文件。 - **优先做法:**报告传输错误时,请附上服务器日志
$TMPDIR/adb.$UID.log(macOS/Linux)或%TEMP%\adb.log(Windows),以及使用ADB_TRACE=adb,transport,auth复现问题的步骤。
验证
-
adb --version显示单个二进制文件路径;which -a adb不列出被其他副本遮蔽的版本。 -
adb start-server具有幂等性——运行两次不会产生任何变化。 -
adb kill-server && adb start-server && adb devices可以恢复卡住的传输。 -
~/.android/adbkey和~/.android/adbkey.pub均存在,且不允许所有用户读取(chmod 600 ~/.android/adbkey)。 -
ADB_TRACE=adb adb devices -l会生成详细的传输日志,且没有错误。 - 如果运行多个 adb 服务器,每个服务器的
ANDROID_ADB_SERVER_PORT值都不同,并且lsof -iTCP:5037显示恰好有一个(或零个)监听器。 - 服务器日志文件存在于
$TMPDIR/adb.$UID.log(macOS/Linux)或%TEMP%\adb.log(Windows),且为近期生成。
参考资料
- ADB 用户指南(架构和生命周期):https://developer.android.com/tools/adb
- Platform-tools 发行说明(版本差异、libusb 默认设置):https://developer.android.com/tools/releases/platform-tools
- AOSP
adb手册页(规范的环境变量参考):https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/docs/user/adb.1.md - 在命令行上测试 Studio + AGP:https://developer.android.com/studio/test/command-line
- 真相源研究笔记(CORPUS §I,A1 报告):
tasks/research/A1-adb-architecture-devices.md— 三部分模型、环境变量表、libusb 在 v36 中的回退、ADB v34+ 中 Openscreen 与 Bonjour 默认设置的切换、服务日志路径、RSA 密钥对处理。docs/CORPUS.md§I.2(三部分架构)和 §I.10(关键发现:force-stop≠pm clear,只有使用-w时才会返回退出代码)。
- 同系列技能:
- 连接单台设备:
../../devices/connecting-to-devices/SKILL.md - 无线 ADB(Android 11+):
../../devices/connecting-over-wifi/SKILL.md - 安装 / 管理应用:
../../apps/installing-and-managing-apps/SKILL.md - 通过
am instrument运行插桩测试:../../tests/running-instrumented-tests-via-adb/SKILL.md
- 连接单台设备:
- 跨系列相关内容:
- 在 Android 上配置 JUnit4:
../../../jvm-tests/runner/configuring-junit4-on-android/SKILL.md - 使用
AndroidJUnit4运行插桩测试:../../../instrumentation/runner/running-instrumented-tests-with-androidjunit4/SKILL.md - 源集策略:
../../../fundamentals/strategies/organizing-test-source-sets/SKILL.md
- 在 Android 上配置 JUnit4: