第2章 抓取协议日志:hci log、controller trace、app callback 日志采集方法
在多BLE连接写入冲突场景中,协议日志是定位根本原因的必备数据。本章将系统介绍三类关键日志的采集方法:HCI Log(Host-Controller 接口)、Controller Trace(控制器内部状态)、App Callback(应用层回调)。按照问题排查型课程六步法组织:现象识别 → 数据采集 → 原因定位 → 修复动作 → 复测 → 预防。
1. 现象识别
当多连接写入冲突发生时,终端行为会呈现以下典型现象,每种现象对应必须采集的日志类型:
| 现象 | 需采集日志 | 冲突线索 |
|---|---|---|
| 写入操作返回错误码(如 0x12) | HCI Log + App Callback | HCI_LE_Connection_Update 时序异常 |
| 对端设备无响应或断开连接 | Controller Trace + HCI Log | Controller 内部调度冲突 |
| 应用层回调延迟或丢失 | App Callback + Controller Trace | 回调栈溢出或被冲刷 |
| 写入数据出现乱序或覆盖 | 三者全量 | ATT_WRITE_REQ 乱序 |
提示: 若无法一次性采集全部日志,优先抓取 HCI Log + App Callback,因为两者覆盖 Host 与 Application 边界,多数冲突体现在该交界处。
2. 数据采集
正确、同步地采集三类日志是后续分析的基础。以下分别说明各日志的采集工具、命令和关键配置。
2.1 HCI Log 采集
HCI Log 记录 Host 与 Controller 之间所有 HCI 命令、事件和 ACL/ISO 数据包。推荐使用 btmon(BlueZ 内置)或 hcidump。
# btmon 实时抓取(默认输出到终端,可重定向到文件)
sudo btmon -w /tmp/hci_冲突场景.log
# 指定控制器(如 hci0)
sudo btmon -i hci0 -w /tmp/hci0_trace.log
# 过滤事件类型(写入冲突关注 ATT 和 L2CAP 事件)
sudo btmon -i hci0 -w /tmp/att_trace.log --filter "type=EVT_LE_META_EVENT"
关键参数:
-w 指定输出文件;-i 选择控制器;Android 平台需使用 hci_snoop 或 bt_stack.conf 开启 BTSNOOP。
2.2 Controller Trace 采集
Controller Trace 直接读取 BLE 控制器内部寄存器、调度状态、连接间隔冲突信号。通常通过厂商专用工具获取(如 TI Packet Sniffer、Nordic nRF Sniffer、Dialog SmartBond Trace)。
// 示例:使用 TI CC2540 USB 嗅探器
// 1. 硬件连接:嗅探器天线靠近目标设备
// 2. 打开 TI SmartRF Studio,选择 BLE 模式
// 3. 设置捕获通道(如 37/38/39 + 数据通道)
// 4. 点击 Start Capture,保存为 .pcap 或 .csa 文件
// 或使用 nRF Sniffer for BLE
// 命令行模式(Python 脚本)
python sniffer.py -c 38 -f /tmp/ctrl_trace.pcap
| 厂商 | 工具 | 输出格式 | 注意事项 |
|---|---|---|---|
| Nordic | nRF Sniffer | .pcap | 需要 nRF 52840 DK 或 USB 嗅探器 |
| TI | Packet Sniffer | .psd / .csa | CC2540USB 硬件 |
| Dialog | SmartBond Toolbox | .csv / .txt | 需 UART 接口 |
2.3 App Callback 日志采集
App Callback 日志是应用层收到 BLE 事件(如 onWrite、onConnectionUpdate、onError)时由开发者主动打印的日志。以下为典型代码段:
// Android (Java)
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
Log.d("BLE_APP", String.format("onWrite connId=%d uuid=%s status=0x%02X",
gatt.getConnectionId(),
characteristic.getUuid(),
status));
}
// iOS (Swift)
func peripheral(_ peripheral: CBPeripheral,
didWriteValueFor characteristic: CBCharacteristic,
error: Error?) {
print("[BLE_APP] didWrite conn=\(peripheral.identifier.uuidString) " +
"char=\(characteristic.uuid.uuidString) err=\(error?.localizedDescription ?? "nil")")
}
// Zephyr (C)
static void on_write(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
const void *data, uint16_t len,
uint16_t offset, uint8_t flags) {
printk("[APP_CALLBACK] on_write conn=%p attr=%p len=%d\n", conn, attr, len);
}
注意: App Callback 日志必须包含 连接标识符(connId / peripheral UUID / bt_conn 指针)和 返回状态码,否则无法与 HCI Log / Controller Trace 关联。
3. 原因定位(基于日志的初步排查)
采集到日志后,按以下判断规则快速过滤写入冲突相关信号:
| 日志类型 | 关键字段 | 冲突指示 |
|---|---|---|
| HCI Log | HCI_LE_Connection_Update Complete 参数;ATT_Write_Req / Rsp 序列 | 连接参数更新重叠、ATT 写入序号错乱 |
| Controller Trace | Connection Event 调度偏移、Sequence Number 冲突 | 两个连接事件在时间上重叠 |
| App Callback | status 值(0x00成功,否则异常);重入次数 | 连续多个 callback 返回 0x12 (insufficient resources) |
判断规则: 将三个日志按时间戳对齐,若同一时间窗口内 HCI 命令与 Controller Trace 的事件偏移量 > 0.5 ms,且 App Callback 出现错误码,则高度怀疑写入冲突。
4. 修复动作(日志采集异常时的处理)
- 问题: HCI Log 文件为空或只有少量事件。
→ 检查btmon权限,使用sudo;或确认蓝牙适配器是否为 HCI 模式。 - 问题: Controller Trace 无法捕获连接事件。
→ 调整嗅探器天线位置,确保与目标设备在同一频道;或增大抓包缓冲区大小。 - 问题: App Callback 日志缺少连接标识。
→ 在日志打印中加入connId、timestamp、status;若使用 NRF Connect,开启详细日志。 - 问题: 三个日志时间戳无法对齐。
→ 使用 NTP 同步设备时钟;或在每个日志打印时写入同一系统 tick 值。
5. 复测
执行以下验证步骤,确认日志采集正确可用:
- 复现一次简单的单连接写入操作,检查 HCI Log 中是否有对应的
ATT_Write_Req和Write_Rsp事件。 - 检查 Controller Trace 中是否存在该连接的 Connection Event 记录。
- 验证 App Callback 打印的
onWrite日志与 HCI Log 中该写入的 ACK 时间差在 10 ms 以内。 - 进行两次连续写入(间隔 < 7.5ms),观察三个日志中是否出现并行队列而非串行执行。
验证指标: 若上述四步均能正确捕获且时钟偏差 < 1ms,则可进入原因定位阶段(第3章)。否则返回数据采集步骤调整参数。
6. 预防
为避免在问题排查时反复补采日志,建议在项目开发期建立下列规范:
- 默认开启
btmon日志轮转(btmon -w /data/ble_trace_%Y%m%d_%H%M%S.log),覆盖写入冲突场景复现。 - 在固件中增加 写入冲突检测计数器,当检测到重入或超时自动触发 Controller Trace 快照。
- 制定“日志三件套”同步采集检查单:将 HCI Log、Controller Trace、App Callback 日志文件名、时间戳范围记录在排查报告中。
- 对 App Callback 日志采用结构化格式(如 JSON 行),便于后续自动化对齐分析。