21、蓝牙调试:Bluedroid、HCI日志、配对问题、BLE调试

蓝牙调试,说难不难,说简单也不简单。我见过不少同事,一遇到蓝牙连不上、配对失败,就直接抓个 log 扔给芯片原厂。其实很多问题我们自己就能定位,关键是要知道从哪下手。

今天我就把蓝牙调试的几个核心模块拆开来讲。Bluedroid 架构、HCI 日志怎么抓、配对流程怎么跟、BLE 低功耗调试的要点,咱们一个一个过。

21.1 Bluedroid 架构概览

Android 从 4.2 开始就用 Bluedroid 替代了 BlueZ。说白了,Bluedroid 是 Google 和 Broadcom 一起搞的蓝牙协议栈。它分两层:

  • 上层(BTA / BTU):处理蓝牙 profile、配对、连接管理。跑在 app 进程或 system_server 里。
  • 下层(HCI / VND):直接跟蓝牙芯片打交道。通过 HCI 命令、事件、数据通道通信。

我个人习惯,遇到蓝牙问题先判断是上层还是下层。怎么判断?看 log 里的 tag。

关键日志 Tag 速查表

Tag所属模块典型问题
bt_btif蓝牙接口层profile 注册失败、回调未执行
bt_btu蓝牙任务层协议栈内部状态机异常
bt_hciHCI 层命令超时、ACL 数据断流
bt_vendor厂商适配层固件加载失败、波特率不匹配

举个例子。有一次我遇到手机连不上车载蓝牙,log 里全是 bt_btif 的 "state mismatch"。我一看就知道是上层状态机乱了,直接查 profile 连接流程,最后发现是车载端发了两次连接请求,上层没处理好。

21.2 HCI 日志:蓝牙调试的“黑匣子”

HCI 日志是蓝牙调试的基石。它记录了主机和蓝牙芯片之间的所有命令、事件、数据包。你想想看,没有 HCI 日志,你就像蒙着眼睛修车。

怎么抓 HCI 日志?我推荐两种方式:

  1. 开发者选项抓取:打开「开发者选项」→「开启蓝牙 HCI 信息收集日志」。抓到的文件在 /sdcard/btsnoop_hci.log
  2. adb 命令实时抓取adb shell cat /sys/kernel/debug/bluetooth/hci0/snoop(需要 root)。

抓到的日志可以用 Wireshark 打开。我个人习惯用 Wireshark 的过滤器:

# 只看配对相关事件
btl2cap.cid == 0x0001

# 只看 HCI 命令和事件
hci_h4.type == 0x01 || hci_h4.type == 0x04

# 过滤特定蓝牙地址
btcommon.bd_addr == xx:xx:xx:xx:xx:xx

我的小技巧:抓 HCI 日志时,最好同时抓 logcat -b all。把系统日志和 HCI 日志放在一起看,能快速定位是上层没发命令,还是芯片没响应。

21.3 配对问题:从 HCI 日志看完整流程

配对失败是蓝牙调试里最常见的坑。我遇到过好多次,用户说“手机搜不到设备”或者“配对码输对了还是连不上”。

正常的配对流程,从 HCI 日志看是这样的:

  1. Inquiry / LE Scan:发现设备。
  2. Create Connection / LE Create Connection:建立 ACL 连接。
  3. IO Capability Request / Reply:交换配对能力(是否支持输入输出)。
  4. Simple Pairing (SSP) 或 Legacy Pairing:生成密钥。
  5. Link Key Notification:密钥存储。
  6. Authentication Complete:配对完成。

如果卡在第三步,通常是 IO Capability 不匹配。比如手机显示“需要输入 PIN 码”,但设备没有键盘。我曾经调试过一个智能门锁,它上报的 IO Capability 是 NoInputNoOutput,但手机端要求 KeyboardOnly,结果配对一直失败。解决办法是让设备端改上报 DisplayYesNo

注意:有些国产芯片在配对完成后,不会主动发送 Link Key Notification。这时候手机端会认为配对没完成,下次连接又要重新配对。遇到这种情况,可以抓 HCI 日志确认芯片是否真的生成了密钥。

21.4 BLE 调试:连接参数与 MTU

BLE 调试和经典蓝牙不太一样。BLE 更关注功耗和吞吐量。我调试 BLE 时,最常看三个东西:

  • 连接参数(Connection Interval / Latency / Timeout):影响功耗和响应速度。
  • MTU 大小:影响单次传输的数据量。
  • GATT 操作:读写、通知、指示。

连接参数协商,在 HCI 日志里对应 LE Connection Update Complete 事件。如果手机端请求的参数和设备端不匹配,连接可能不稳定。我遇到过一款手环,它只支持 30ms 的连接间隔,但手机端请求了 7.5ms,结果手环直接断开连接。

MTU 协商也很关键。默认 MTU 是 23 字节,但大部分 BLE 芯片支持 512 字节以上。如果 app 需要传输大量数据,一定要主动请求 MTU 更新。代码示例:

// 请求 MTU 为 512
BluetoothGatt gatt = device.connectGatt(context, false, callback);
gatt.requestMtu(512);

在 HCI 日志里,MTU 协商对应 Exchange MTU RequestExchange MTU Response。如果 app 没有发这个请求,那数据包就会被拆成很多小包,效率极低。

21.5 实战:用 HCI 日志定位 BLE 断连问题

我记得有一次,客户反馈他们的 BLE 设备每隔几分钟就断连一次。我抓了 HCI 日志,发现每次断连前都有一个 Disconnection Complete 事件,原因是 0x08(Connection Timeout)。

这说明设备端没有在连接超时时间内收到手机端的包。进一步看日志,发现手机端每隔 100ms 发一次 Empty PDU,但设备端每隔 200ms 才回复一次。手机端的连接超时设置是 500ms,设备端的超时设置是 1s。手机端因为没收到回复,主动断开了连接。

解决办法:让设备端把连接超时设置改为 2s,或者让手机端把连接间隔调大。嗯,这里要注意,连接超时不能设得太长,否则断连后手机要等很久才能发现。

BLE 调试常用 HCI 命令

命令Opcode用途
LE Read Remote Features0x0016读取对端设备支持的特性
LE Connection Update0x0018更新连接参数
LE Read Buffer Size0x0002查看蓝牙芯片的 buffer 大小

21.6 知识体系:蓝牙调试核心逻辑

下面这张图是我自己总结的蓝牙调试思路。从问题现象出发,先判断是上层还是下层,再选择对应的调试工具。

蓝牙问题现象 上层问题(bt_btif/bt_btu) 下层问题(bt_hci/bt_vendor) 抓 logcat,查 profile 状态机 抓 HCI 日志,用 Wireshark 分析 检查配对流程 / GATT 操作 分析 HCI 事件 / 连接参数 / MTU 定位根因,修复问题

这张图的核心逻辑就是:先看 logcat 里的 tag,再决定抓什么日志。我个人习惯,遇到蓝牙问题第一件事就是开 HCI 日志,因为它是“铁证”,不会骗人。

21.7 避坑指南

最后分享几个我踩过的坑:

  • HCI 日志没抓到:有些手机在开发者选项里开启了 HCI 日志,但实际没写入文件。我建议用 adb 命令实时抓,确保数据落盘。
  • 配对码显示问题:如果手机显示 6 位数字,但设备只支持 4 位,配对会失败。可以在 HCI 日志里看 IO Capability Response 里的 OOB Data 字段。
  • BLE 连接参数协商失败:有些芯片对连接参数有严格限制,比如连接间隔必须是 10 的倍数。手机端请求 11.25ms,芯片直接拒绝。解决办法是让 app 端先读取设备支持的参数范围。

我的经验:如果你不确定问题出在哪,先抓一份正常的 HCI 日志做对比。我电脑里存了好几份不同芯片的“黄金日志”,遇到问题直接 diff,效率很高。

蓝牙调试其实没那么玄乎。掌握 HCI 日志,理解配对和 BLE 的流程,大部分问题都能自己搞定。嗯,今天就聊到这,希望这些内容对你有帮助。

专注资料整理