ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

小米手机HCI log抓取与Wireshark解析:蓝牙协议栈问题排查实战

小米手机HCI log抓取与Wireshark解析:蓝牙协议栈问题排查实战 蓝牙协议栈的问题排查最让人头疼的就是看不见——设备连不上、数据发不出、连接莫名其妙断开光看应用层日志根本定位不到问题出在哪一层。HCI log就是解决这个问题的关键抓手它记录的是主机Host和控制器Controller之间所有的命令、事件和数据包交互相当于把蓝牙通信的底牌全部摊开给你看。小米手机在这块的支持算是比较友好的澎湃OS和MIUI都内置了抓取入口不需要root也不需要额外装驱动几分钟就能把log拿到手。这篇内容主要面向做蓝牙外设对接、Android蓝牙应用开发、以及需要排查连接兼容性问题的工程师从抓取、解析到常见问题排查把整条链路讲透顺带把几个高频踩坑点一并说清楚。1. 先搞清楚HCI log到底记录了什么1.1 蓝牙协议栈的分层与HCI的位置要理解HCI log的价值得先知道蓝牙协议栈是怎么分层的。从下往上大致是物理层Radio、基带层Baseband、链路控制层Link Controller、主机控制器接口HCI、L2CAP、RFCOMM/SDP/ATT/GATT再到上层的应用Profile。HCI正好卡在中间是硬件控制器和软件主机之间的那道门。所有上层应用发出的请求最终都要变成HCI Command发给控制器控制器收到数据或状态变化会通过HCI Event上报实际的数据传输则走HCI ACL Data和SCO Data。所以一份完整的HCI log等于把整条蓝牙通信链路的关键节点全部记录下来了。这也是为什么排查蓝牙问题时HCI log比应用层log有用得多。应用层只能告诉你连接失败了而HCI log能告诉你是扫描没扫到、是发起连接后控制器返回了错误码、还是连接建立了但服务发现超时。定位精度完全不是一个量级。1.2 HCI log里常见的包类型抓下来的log里你会看到几种主要的包类型认识它们才能看懂log包类型方向作用HCI CommandHost → Controller主机下发的指令如扫描、连接、断开HCI EventController → Host控制器上报的事件如扫描结果、连接完成、错误ACL Data双向实际的数据传输GATT读写都走这里SCO Data双向语音通话类的同步数据ISO Data双向LE Audio相关的同步数据排查连接问题时重点看Command和Event的配对关系。比如你发了LE Create Connection命令正常应该收到LE Connection Complete事件如果收到的是LE Connection Complete但status字段非0那就是连接失败错误码会直接告诉你是超时、还是被拒绝。1.3 为什么小米手机适合做蓝牙调试小米手机在开发者选项里直接提供了启用蓝牙HCI信息收集日志的开关打开之后系统会自动把HCI log写到指定目录不需要root权限也不需要外接抓包设备。这一点比很多品牌都方便——有些机型要么没这个开关要么需要工程模式才能开启。澎湃OS和较新的MIUI版本里这个开关的位置基本一致抓出来的log是标准的btsnoop格式可以直接用Wireshark打开解析。对于做蓝牙外设对接的团队来说手边有一台小米手机当调试机能省掉很多折腾。2. 小米手机上抓取HCI log的完整操作2.1 开启开发者选项与HCI日志开关第一步进入设置 → 关于手机 → 全部参数与信息连续点击MIUI版本或OS版本七次直到提示您已处于开发者模式。这一步是常规操作但要注意澎湃OS的部分版本把入口改到了我的设备 → 全部参数与信息找不到的话在设置里直接搜版本更快。第二步进入设置 → 更多设置 → 开发者选项找到启用蓝牙HCI信息收集日志英文机型是Enable Bluetooth HCI snoop log打开它。打开之后建议重启一次蓝牙或者直接重启手机确保开关生效——这一点很多人会忽略不重启的话有时候log抓不到内容。提示部分机型在开发者选项里还有蓝牙数据包日志或类似名称的选项功能是一样的看到就打开。2.2 复现问题并生成日志文件开关打开后正常操作你的蓝牙应用把出问题的场景完整复现一遍。比如设备连不上就重复几次扫描和连接操作数据传输出错就把读写流程走一遍。操作完成后关闭蓝牙再重新打开或者直接关闭HCI日志开关系统会把这段时间的log落盘。log文件的位置通常在/sdcard/btsnoop_hci.log或者分片存储的目录/sdcard/Android/data/.../files/ 下的btsnoop相关文件不同系统版本路径略有差异如果找不到可以用文件管理器搜索btsnoop关键字。澎湃OS有些版本会把log放在/data/misc/bluetooth/logs/下但这个目录普通用户访问不了需要用下面的方法导出。2.3 把log导出到电脑的几种方式最直接的方式是用USB线连接电脑把手机存储挂载为MTP设备然后在文件管理器里找到btsnoop文件复制出来。如果文件在系统保护目录里MTP看不到可以用adb命令导出adb pull /sdcard/btsnoop_hci.log ./如果提示权限不足先执行adb shell su -c cp /data/misc/bluetooth/logs/btsnoop_hci.log /sdcard/ adb pull /sdcard/btsnoop_hci.log ./没有root的话su会失败这时候只能依赖/sdcard/下的那份。实测下来绝大多数场景/sdcard/btsnoop_hci.log就够用了系统保护目录里的那份主要是给深度调试用的。还有一种方式是抓完log后直接在手机上分享通过邮件或文件传输工具发出来适合没有电脑在身边的场景。2.4 抓取时的几个实操细节抓log之前建议先把之前的旧log删掉避免新旧混在一起不好分析。抓取过程中不要频繁开关蓝牙否则log会被截断成多段。如果问题偶发可以多抓几轮每轮之间记录一下操作时间点方便后续在Wireshark里按时间定位。另外HCI log会记录附近所有蓝牙设备的交互数据量可能很大。如果只是排查特定设备抓完后在Wireshark里用btaddr过滤只保留目标设备的地址能大幅减少干扰。3. 用Wireshark解析HCI log的正确姿势3.1 打开log与基础过滤Wireshark原生支持btsnoop格式直接文件 → 打开选择btsnoop_hci.log即可。打开后你会看到一长串包第一件事是设置过滤条件不然根本看不过来。常用的过滤表达式btatt # 只看GATT相关的ATT协议数据 bthci_cmd # 只看HCI命令 bthci_evt # 只看HCI事件 btl2cap # 只看L2CAP层 btaddr xx:xx:xx:xx:xx:xx # 只看指定设备排查连接问题时我一般先用bthci_cmd || bthci_evt把命令和事件过滤出来快速看连接流程是否正常然后再切到btatt看数据交互。3.2 读懂连接建立的关键流程一个典型的BLE连接建立流程在HCI log里是这样的LE Set Scan ParametersLE Set Scan Enable配置并开启扫描LE Advertising Report控制器上报扫描到的广播LE Set Scan Enable (Disable)停止扫描LE Create Connection发起连接LE Connection Complete连接完成status为0表示成功后续的ATT Read By Group Type Request/Response服务发现如果卡在某一步问题就定位到了。比如一直收不到LE Advertising Report说明扫描没扫到设备可能是广播参数问题或设备没在广播如果LE Connection Complete的status非0错误码会告诉你具体原因。3.3 常见错误码的含义HCI Event里的status字段是排查问题的金钥匙几个高频错误码错误码含义常见原因0x00Success正常0x01Unknown HCI Command命令不被控制器支持0x02Unknown Connection Identifier连接句柄无效0x03Hardware Failure控制器硬件异常0x08Connection Timeout连接超时设备不在范围或未响应0x13Remote User Terminated Connection对端主动断开0x16Connection Terminated By Local Host本机主动断开0x3EConnection Failed to be Established连接建立失败常见于参数不匹配看到0x08先检查设备是否在广播、距离是否过远看到0x3E重点看连接参数interval、latency、timeout是否和对端兼容。3.4 用Wireshark追踪一次完整的GATT交互服务发现和数据读写是蓝牙应用开发的核心。在Wireshark里你可以跟着一次完整的GATT交互走一遍ATT Read By Group Type Request→ATT Read By Group Type Response发现Primary ServiceATT Find By Type Value Request→Response发现CharacteristicATT Read Request→ATT Read Response读特征值ATT Write Request→ATT Write Response写特征值ATT Handle Value Notification服务端主动通知如果某个Request发出去了但迟迟没有Response要么是对端没处理要么是MTU不够导致分包出了问题。这时候看ACL Data层的分包情况能进一步定位。4. 高频问题排查从现象到根因4.1 扫描不到设备现象是应用层一直回调不到设备HCI log里看不到LE Advertising Report。排查顺序先确认LE Set Scan Enable命令发出去了且enable参数为1。如果命令发了但没报告检查扫描参数——LE Set Scan Parameters里的scan window和scan interval设置是否合理window必须小于等于interval否则扫描占空比异常。再确认广播类型。有些设备用非连接广播或定向广播普通扫描可能扫不到。如果设备用的是扩展广播Extended Advertising需要确认手机是否支持并开启了对应的扫描类型。还有一种情况是手机蓝牙缓存了旧的设备信息导致扫描行为异常。可以在开发者选项里找清除蓝牙缓存或者直接重启蓝牙。4.2 连接建立后立即断开log里能看到LE Connection Complete成功但紧接着就是Disconnection Complete。这种情况通常是连接参数协商失败或者对端对服务发现超时有要求。重点看LE Connection Update相关的命令和事件。如果主机发起了连接参数更新但对端拒绝了或者更新后的参数超出了对端能接受的范围对端可能直接断开。另外如果服务发现耗时太长比如超过了对端设定的超时时间对端也会主动断开这时候log里会看到Remote User Terminated Connection0x13。解决思路是优化服务发现流程减少不必要的特征读取或者调整连接参数到双方都兼容的区间。4.3 数据写入成功但对端没反应应用层显示write成功但对端没执行预期动作。这种情况要看ATT层的Write类型——是Write Request需要Response还是Write Command不需要Response。如果是Write Command主机发出去就不管了对端有没有收到、有没有处理主机完全不知道。这时候要确认对端的特征是否支持Write Without Response以及数据是否真的到达了对端。如果是Write Request看有没有收到Write Response。收到了说明对端ATT层处理了但业务层可能没响应问题在对端固件没收到Response可能是MTU协商问题导致数据被截断或者链路层丢包。4.4 连接不稳定、频繁重连log里反复出现连接建立和断开间隔很短。先看断开的原因码如果是0x08超时说明链路质量差或距离过远如果是0x3E看连接参数是否过于激进。BLE的连接参数里connection interval太短会增加功耗但响应快太长则省电但延迟高。如果interval设得很短比如7.5ms而设备又处于弱信号环境丢包率会上升导致监督超时supervision timeout触发断开。适当放宽interval和timeout稳定性会明显改善。另外Android系统本身对连接参数有偏好应用层设置的参数不一定被采纳实际生效的参数要看LE Connection Update Complete事件里的值。4.5 抓不到log或log为空开关打开了但log文件是空的或者根本没有生成文件。几个常见原因一是开关没生效需要重启蓝牙或重启手机。二是log路径不对不同系统版本路径有差异用文件管理器全局搜btsnoop。三是存储权限问题部分系统版本需要给文件管理器或相关应用存储权限才能看到文件。四是抓取时间太短系统还没落盘多操作一会儿再关闭开关。如果以上都排除了还是抓不到可以尝试用adb命令直接触发log dump或者换一台机型对比测试确认是不是特定系统版本的问题。5. 提升排查效率的几个实战习惯5.1 建立自己的错误码速查表HCI错误码有几十个常用的就那么十几个。建议把高频错误码整理成一张表贴在工位上排查时直接对照比每次去翻规范快得多。我自己的表里除了错误码还标注了每个码对应的典型场景和首选排查动作用久了基本能形成条件反射。5.2 抓log时同步记录操作时间线光有log不够还得知道每个时间点你做了什么操作。抓取时用手机备忘录或者纸笔记录一下几点几分开始扫描、几点几分点击连接、几点几分出现异常。分析时在Wireshark里按时间戳定位能快速缩小范围。这个习惯看起来笨但实际排查效率提升非常明显。5.3 用显示过滤器而不是捕获过滤器Wireshark的捕获过滤器在抓包时生效显示过滤器在分析时生效。分析HCI log时建议保留完整log用显示过滤器逐步缩小范围而不是一开始就过滤掉大量数据。因为蓝牙问题往往是连锁反应被过滤掉的包可能正是根因所在。5.4 对比正常和异常的log同一个操作抓一份正常的log和一份异常的log逐包对比差异点往往就是问题所在。这种方法在排查兼容性问题时特别有效——同样的应用代码在这台设备上正常在那台上异常两份log一对比差异立刻显现。5.5 注意Android版本和系统定制的影响不同Android版本对蓝牙协议栈的实现有差异小米的澎湃OS和MIUI在标准协议栈之上也有一些定制。同样的代码在不同系统版本上表现可能不同排查时要把系统版本作为一个变量考虑进去。遇到诡异问题时换一台不同版本的设备对比能快速判断是应用问题还是系统问题。蓝牙调试这件事工具和方法固然重要但更关键的是对协议流程的熟悉程度。HCI log只是把底层交互暴露出来能不能看懂、能不能定位到根因还是取决于你对蓝牙协议栈的理解深度。多抓、多看、多对比慢慢就能从一堆十六进制里读出问题所在。
返回列表