mcpField
U
understanding-adb-architecture

understanding-adb-architecture

github.com/skydoves开发33963 次安装22 周前更新
代码仓库

关于 understanding-adb-architecture

面向 Android 开发者的 ADB 架构说明技能,梳理 CLI、主机端服务器与设备端守护进程的职责。它帮助定位版本冲突、端口占用和传输故障,并强调保留授权密钥。

主要功能

  1. 01说明 ADB 三部分架构
  2. 02讲解服务器生命周期与端口
  3. 03排查多个 adb 二进制冲突
  4. 04介绍环境变量与日志诊断
  5. 05说明 RSA 授权密钥的影响

适用场景

  1. 01判断首次启动服务器提示是否为错误
  2. 02排查 5037 端口冲突或版本不匹配
  3. 03配置 CI 的密钥和服务器端口
  4. 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):

    • 客户端(adb CLI)——从终端调用。它会序列化命令,并通过本地 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 中,就会出现三种故障模式:

    1. 版本不匹配——任一方发出首条命令时,都会终止正在运行的服务端。
    2. 两个相互竞争的服务端在端口 5037 上来回争抢。
    3. 默认后端不同(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

评论

支持 Markdown