尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

macOS下ADB无线调试从连接到端口冲突的完整排查指南

macOS下ADB无线调试从连接到端口冲突的完整排查指南 去年底帮团队里一位做集成测试的同事排查无线调试的问题折腾了大半天最后发现不过是 5555 端口被系统里的某个服务悄悄占住了。但正是这一趟排查让我把 macOS 下 ADB 无线调试从连接建立、协议握手到端口冲突的整条链路重新捋了一遍。这篇文章就按我实际排查的顺序来写把 macOS 环境下 ADB 无线调试会踩的那些坑——连接失败、Protocol Fault、端口占用——从头到尾讲清楚适合正在做 Android 开发、自动化测试或者经常需要在真机上调试的朋友参考。先说结论macOS 上的 ADB 无线调试问题绝大多数不是玄学而是链路中的某个状态不对。所谓链路就是 adb client 到 adb server 的本地通信、adb server 到设备端 adbd 的 TCP 连接以及设备端 adbd 的监听状态这三段。只要把这三段逐个排查再顽固的问题也能揪出来。1. 先摸清链路ADB 无线调试到底是怎么连上的1.1 一次无线调试的完整握手过程很多人在 macOS 上做无线调试习惯性敲两条命令adb tcpip 5555然后adb connect 192.168.x.x:5555。连不上就开始怀疑手机、怀疑路由器但其实流程远不止这两条命令这么简单。要理解无线调试先得明白 adb 是三层结构。最上层是 adb client也就是你在终端里敲的adb命令中间是 adb server默认监听本机 TCP 5037 端口负责管理所有设备和命令路由最底层是设备端守护进程 adbd。无线调试的本质是让 adbd 不再只通过 USB 枚举出来的虚拟端口工作而是直接在设备的某个 TCP 端口上监听。传统方式的流程是这样手机通过 USB 连上电脑后你执行adb tcpip 5555这实际上是让设备端的 adbd 在本机 5555 端口启动一个 TCP 监听服务。此时 USB 连接还不能拔因为这条命令是通过 USB 通道发出去的。等 adbd 在 5555 端口起来之后你执行adb connect 192.168.x.x:5555adb server 就会主动向设备 IP 的 5555 端口发起 TCP 连接然后双方做一次 RSA 密钥交换和协议握手。握手通过设备在adb devices里的状态就会从offline变成device。Android 11 之后系统自带的“无线调试”功能提供了另一种方式。你不再需要先插 USB 执行adb tcpip而是直接在开发者选项里打开“无线调试”系统会显示一个配对 IP 和端口以及一个 6 位配对码。你在电脑上执行adb pair ip:port输入配对码配对成功后再根据屏幕上显示的连接端口执行adb connect ip:port。这里很容易踩一个坑配对端口和连接端口通常不一样一个是随机高位端口另一个也是随机高位端口而且每次开关无线调试都可能变化。1.2 macOS 在这条链路里容易埋雷的三个环节我帮同事排查的时候第一步就是问他你确定 adb server 是干净的很多人在 macOS 上装过多个工具链比如 Android Studio 自带的 platform-tools、Homebrew 装的 android-platform-tools还有各种各样模拟器自带的老版本 adb。这些工具如果同时存在很容易出现 adb server 的版本和你命令行里调用的 adb client 版本不一致导致连接时握手异常。第二个容易出问题的地方是 adb server 的本地端口 5037。macOS 上如果你装过手机助手类软件、虚拟化工具或者某些终端管控软件5037 端口可能会被其他进程占用。一旦 5037 被占用adb server 起不来你敲什么命令都会提示cannot bind to 127.0.0.1:5037但很多人第一反应是去检查手机方向就错了。第三个环节是系统防火墙和网络权限。macOS 自带的防火墙默认是关闭的但如果你手动开过并且没有允许 adb 接受传入连接就会表现为 TCP 连接能建立但数据一交换就断。还有一种情况是电脑上运行了代理或抓包类工具比如 Surge、Charles 这类带虚拟网卡或系统级代理的软件它们默认会接管本机网络流量ADB 的协议在这种环境下经常被截断或改写出现各种奇怪的 Protocol Fault。2. Protocol Fault 不是玄学背后是状态的破坏2.1 Protocol Fault 出现的典型现场在我排查的所有无线调试问题里Protocol Fault 是最让人抓狂的。因为它往往出现在连接“看似成功”之后然后突然给你一个下马威。你执行adb connect 192.168.1.8:5555终端短暂停顿紧接着出现一行failed to connect to 192.168.1.8:5555: Protocol fault (couldnt read status): connection succeeded注意这个connection succeeded说明 TCP 层连接已经建立成功了但 ADB 协议层没能从设备端读取到正确的状态信息。有人会把它理解成“连接成功但没握手完成”然后反复重试结果还是一样。这时候如果你去看adb devices设备可能根本不在列表里也可能显示为offline。如果把设备端的 adbd 日志打开你会看到服务端一直在等待握手报文但接收到的内容无法解析连接就被判定为协议错误。2.2 从 ADB 服务端视角理清 Protocol Fault 的常见诱因从 adb server 的角度看Protocol Fault 的直接原因只有一个连接建立后期望读到 ADB 协议定义的 CNXNconnect报文但实际读到的内容不符合协议格式或者连接被对端重置导致读不到完整状态。那为什么会在 macOS 上频繁出现结合我的实际经验排在前面的诱因有这几个第一是 adb 版本不一致。ADB 协议本身有版本号新版 adb server 对协议做了严格校验。如果你电脑上有多个 adb 版本命令行里调用的 client 是新的但后台驻留的 server 是旧的或者设备端 ROM 里的 adbd 比较老都会导致握手字段解析失败。我处理过一个案例同事的 Android Studio 自带 adb 版本是 34但之前用 Homebrew 装过一个旧版他所在 shell 的 PATH 里旧版靠前导致 server 一直是旧版本怎么连都是 Protocol fault。第二是网络链路中有东西干预了 TCP 数据。macOS 上最常见的元凶就是系统级代理和抓包工具。它们一旦开启增强模式或虚拟网卡模式会截获所有 TCP 流量。ADB 这条连接如果被代理工具误认为普通流量做了转发报文的顺序和内容就可能被改写握手自然失败。这里要强调不是所有代理工具都会这样但确实出现过排查时最稳妥的手段是临时彻底退出这些工具再试。第三是设备端 adbd 状态机残留。adbd 跟所有网络服务一样也有连接状态管理。如果上一次无线连接没有正常断开比如电脑休眠、网络切换、手机锁屏adbd 里的连接表可能残留着半开连接。此时电脑再次发起连接adbd 端可能还在处理上一个连接的状态导致新连接得不到正常的 CNXN 响应。2.3 先做这组“三连”操作能解决一半问题遇到 Protocol Fault我强烈建议先做“三连”能省下一大半排查时间第一步重启本地 adb serveradb kill-server adb start-server adb devices第二步删除本地 RSA 密钥重新生成。这里很多人会犹豫怕影响之前授权的设备但 macOS 上~/.android/adbkey和~/.android/adbkey.pub这两个文件如果权限异常或者被其他工具改动握手时就会出现读取密钥失败的问题。建议先备份再删除cd ~/.android mv adbkey adbkey.bak mv adbkey.pub adbkey.pub.bak adb kill-server adb start-server重新生成的密钥会让所有设备需要重新授权手机端弹窗时点“允许”即可。第三步重启设备端的 adbd。最直接的方式是拔掉 USB 重插或者重启手机。如果你不想重启可以在 root 设备上执行adb shell setprop service.adb.tcp.port 5555 adb shell stop adbd adb shell start adbd这组操作的目的很明确把本地 server 的内存状态清干净把密钥文件重新生成把设备端连接状态机重置。三者同时做能解决我遇到的一半以上 Protocol Fault 问题。如果还不行再考虑版本对齐和网络工具干扰的问题。3. 端口占用5555 被谁吃了怎么找出来3.1 为什么 macOS 上端口容易被占macOS 不同于 Linux 桌面环境它本身有很多系统服务默认监听 TCP 端口。比如隔空播放接收器AirPlay Receiver在 macOS Monterey 之后默认开启会监听 5000 和 7000 端口虽然 5000 离 5555 还差着一段但不少人排查时看到 5000 端口被占用就误以为是自己的 5555 被占了白折腾一场。真正会占用 5555 的情况也很多。最常见的是 Docker Desktop 的端口映射如果你在 macOS 上跑着 Docker 容器容器里又启动了某个监听 5555 的服务并且用-p 5555:5555做了端口映射宿主机 5555 就会被 Docker 的代理进程占住。其次是 Android 模拟器夜神、MuMu 这类第三方模拟器自己内置了 adb它们默认连接宿主机端口通常不只是 5554/5555运行多个模拟器时端口会递增很容易和你要用的真机无线端口撞车。另外还有一种情况容易被忽略macOS 的 AirDrop 和 Handoff 依赖蓝牙和 Wi-Fi 的 mDNS但这些一般不会占用 5555真正占端口的更多是系统里的后台服务。如果你装了企业终端管理软件、安全防护类工具它们也可能在 5555 上做端口监听导致你adb connect连到的根本不是手机。3.2 用 lsof 快速定位罪魁祸首macOS 上排查端口占用我首选 lsof 而不是 netstat。因为 macOS 的 netstat 和 Linux 不一样参数差异很大而且默认不显示进程 PID用起来非常别扭。lsof 就直观多了# 查看 5555 端口被谁监听 lsof -nP -iTCP:5555 -sTCP:LISTEN # 查看 5037 端口被谁监听 lsof -nP -iTCP:5037 -sTCP:LISTEN执行之后如果端口被占用你会看到类似这样的输出COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME Docker 1234 user 32u IPv4 0x123456789abcdef 0t0 TCP *:5555 (LISTEN)如果输出为空说明没有进程监听这个端口那问题就不在端口占用而是别的环节。注意lsof 默认只能看到你自己权限范围内的进程如果查询结果为空但连接依旧失败可以用 sudo 再试一次sudo lsof -nP -iTCP:5555 -sTCP:LISTEN找到占用 5555 的进程后如果确认它不是你要用的服务直接杀掉kill -9 1234杀完之后再执行adb kill-server adb start-server重置 adb server然后重新adb connect。这个过程我用一句话总结先看端口死没死再决定要不要重启 adb server。3.3 如果 5555 实在腾不出来换端口方案有些场景下5555 是系统级服务或者公司统一安装的软件占用的你杀了它会引发别的问题。这种情况下我建议直接换端口不做无畏的对抗。传统方式换端口很简单手机 USB 连上后adb tcpip 18888然后拔掉 USB执行adb connect 192.168.1.8:18888注意adb tcpip后面跟的端口随便你定只要在 1024 到 65535 之间且没有被占用就行。但有一个细节要先确认macOS 上如果要连接 18888 这种高位端口记得顺便检查一下本地防火墙是否允许 adb 访问网络。如果你是 Android 11 及以上用的是系统自带的“无线调试”那端口就不是你指定的了是系统动态分配的。这种情况如果遇到端口被占用通常是系统把端口分配到了一个已被占用的区间比较少见。真遇到了先关闭再重新打开“无线调试”系统会重新分配一组端口。4. 从零到一一次完整的排查操作实录4.1 排查前准备把环境状态收敛干净在动手之前我习惯先把环境收敛干净避免排查过程中被其他因素干扰。这一步很多人会跳过但恰恰是这一步决定了后面的排障效率。首先把电脑上所有代理、抓包、网络分流类工具完全退出。不只是关闭开关而是右键退出托盘确保没有任何网络接管进程在运行。其次关掉 Android Studio 里的 Logcat 窗口和正在跑的其他 adb 进程。模拟器如果有在跑的尽量先退出避免模拟器自带的 adb 和真机调试产生端口冲突。然后确认手机和电脑连接到同一个路由器并且两者都能互相 ping 通。如果你不确定可以先在电脑上 ping 一下手机 IPping -c 3 192.168.1.8如果 ping 不通先解决网络问题再继续。网络通但不一定说明端口通你还可以用 nc 探测一下设备端的 5555 端口nc -vz 192.168.1.8 5555这个命令会告诉你 TCP 层是否能连上能帮你快速区分问题出在传输层还是 adb 协议层。如果 TCP 能通后面报 Protocol Fault那就往 adb 版本和密钥方向查如果 TCP 都连不上那就往端口占用、防火墙、网络隔离方向查。4.2 标准排查步骤速查我整理了一份在 macOS 上排查无线调试问题的标准步骤每次遇到问题我都按这个顺序执行命中率很高。第一步用 USB 连上手机执行adb devices确认 USB 通道是正常的。如果 USB 下设备状态就是unauthorized或offline先解决有线连接的问题。无线排障必须建立在有线正常的基础上。第二步执行adb kill-server adb start-server重置本地 adb server。接着执行lsof -nP -iTCP:5037 -sTCP:LISTEN确认 5037 端口被干净的 adb server 监听。第三步执行adb tcpip 5555拔掉 USB执行adb connect 192.168.1.8:5555。如果这里出现 Protocol Fault继续往下走如果 timeout检查网络和防火墙。第四步验证连接。连接成功后不要只看adb devices最好执行一条实际命令确认设备可响应adb -s 192.168.1.8:5555 shell echo ok如果输出ok说明无线调试真正可用了。第五步如果你用的是 Android 11 的系统无线调试不是传统tcpip模式那就走adb pair流程。先执行adb pair 192.168.1.8:39783根据提示输入屏幕上的配对码配对成功后再执行adb connect 192.168.1.8:39747这里再次强调pair 端口和 connect 端口不同一定要以手机屏幕显示为准。4.3 实测中为什么有时候必须重启手机排障到后面你会发现最难搞的不是协议错误而是设备端 adbd 的状态。我已经不止一次遇到这种情况电脑端一切正常lsof 查端口也干净代理也退了adb server 也重启了但连接就是失败或者连上了也很快掉线。这种情况十有八九是设备端 adbd 卡死了。adbd 跟 macOS 上的 adb server 一样也有自己的状态管理。多次连接、多次断开、切换 Wi-Fi、USB 拔插太快都会让 adbd 里的状态残留。电脑端adb kill-server只能重置 host 端管不到设备端。所以该重启手机的时候别犹豫这是最直接、最可靠的 adbd 重置方式。我实测过重启手机后重新开启无线调试大部分顽固的连接问题都会消失。如果不想重启整机也可以尝试在开发者选项里关闭再打开“USB 调试”开关这个操作会强制重启 adbd效果等同于重启手机但速度快很多。对于华为、小米、OPPO 等定制 ROM有些版本在开发者选项里还有独立的“无线调试”开关修改之后也需要让 adbd 重启才会生效。另外有些定制 ROM 对无线调试有自己的策略。比如小天才手表这类设备虽然内置的是 ADB但厂商自定义了校验机制ADB 连接时需要的不是标准的 RSA 指纹授权而是专门的校验码。这类设备如果你用标准流程去连始终会卡在授权阶段这不是你能在 macOS 端解决的问题而是得先搞清设备的定制逻辑。5. 常见问题速查表与经验心得5.1 常见问题速查表为了方便以后快速定位我把 macOS 下 ADB 无线调试最常见的现象整理成一张速查表大家可以收藏起来遇到问题对着查。现象可能原因处理动作adb devices里没有设备不在同一网段、AP 隔离开启让手机和电脑连同一路由器关闭 AP 隔离connect一直 timeout防火墙拦截、系统代理干扰退出代理工具检查 macOS 防火墙是否放行 adbconnect后 Protocol Faultadb 版本不一致、~/.android/adbkey异常升级/对齐 platform-tools删除 adbkey 后重新授权connect后 unauthorizedRSA 指纹未授权手机弹窗点“始终允许”或删除 adbkey 重新配对设备状态 offlineadbd 状态机异常、屏幕锁定休眠解锁屏幕重启 adbd 或重启手机adb devices显示两个设备USB 和无线同时连着同一台手机拔掉 USB或执行adb disconnectcannot bind to 127.0.0.1:50375037 端口被其他进程占用lsof -nP -iTCP:5037 -sTCP:LISTEN找到并杀掉占用进程模拟器连接不稳定模拟器自带 adb 与本地 adb 版本冲突退出模拟器或统一使用新版 platform-tools 的 adb无线调试能配对上但连不上连接端口写成了配对端口以手机屏幕显示的连接端口为准重新adb connectmDNS 自动发现不到设备macOS Bonjour 与 adb mdns 兼容问题不用adb mdns自动发现手动adb connect IP:端口这张表里的每一种情况我都实际遇到过。其中最常见的两个误判一个是把 Pair 端口当成连接端口另一个是检查了所有网络配置却忽略了系统代理。5.2 几个只有踩过坑才懂的经验第一macOS 上如果你经常同一个账号切换终端工具要注意~/.android/adbkey的权限。有些终端工具或者同步软件会把.android目录的权限改成不可读导致 adb server 启动时读取密钥失败而现象不是提示权限错误而是连接时直接 Protocol Fault。遇到这种情况重置密钥权限chmod 600 ~/.android/adbkey chmod 644 ~/.android/adbkey.pub第二无线调试不要依赖锁屏状态。很多机型的 adbd 在屏幕熄灭后会进入省电休眠TCP 连接不活跃就会断开而且不会主动重连。做长时间自动化测试时建议在开发者选项里开启“不锁定屏幕”或者至少把屏幕超时时间拉长否则测到一半设备掉线所有脚本都得重跑。第三团队多人共用一台 Mac 时尽量给每个开发账号配置独立的ANDROID_ADB_SERVER_PORT。比如 A 同学用 5037B 同学用 5038通过环境变量隔离各自的 adb serverexport ANDROID_ADB_SERVER_PORT5038这样可以避免多人同时操作时一方kill-server把另一方的设备连接全部打断。这个坑在团队协同调试时尤其常见两个同事同时跑脚本结果因为共享同一个 adb server互相把对方的连接踢掉了。第四如果你只是偶尔需要无线调试用完记得执行adb disconnect把无线连接断开并把设备端 adbd 退回 USB 模式adb disconnect adb usb这样做一是省电二是避免设备长时间暴露在局域网的可连接状态减少不必要的风险。做 Android 调试这些年我的体会是无线调试本身不复杂真正复杂的从来都是环境。macOS 的环境变量、系统服务、代理工具、端口状态每一个都在暗中影响 ADB 的链路。遇到 Protocol Fault 和端口占用这类问题别急着怀疑手机先把本地链路从头到尾过一遍你会发现大多数问题都出在自己这台 Mac 上。
返回列表