0. 引子

对于蓝牙开发者来说,通过HCI log可以帮助我们更好地分析问题,理解蓝牙协议,就好像网络开发一定要会使用Wireshark分析网络协议一样。

本篇主要介绍HCI log的作用如何抓取一份HCI log,并结合一个实际的例子来说明如何分析HCI log

1. HCI log 介绍

1.1 HCI log 作用

HCI log是用来分析蓝牙设备之间的交互行为是否符合预期是否符合蓝牙规范。在日常的开发中,通常使用HCI log来做这样几件事:

  • 分析Bug:蓝牙打开后搜索不到设备,或者搜索到的设备没有名称只有蓝牙地址;Android手机不能向苹果手机传输文件 ... ...

  • 需求分析:手机需要适配一款蓝牙自拍杆来控制拍照,通过HCI log可以观察竞品在实现这个功能时,使用的是什么Bluetooth Profile?只要知道了使用的Bluetooth Profile,我们就有了实现这个功能的思路。

  • 蓝牙协议学习:通过HCI log辅助学习蓝牙协议,就好像学习TCP/IP时,通过wireshark抓包来学习TCP协议

1.2 蓝牙核心系统架构

说了这么多HCI log的用处,要想更好地理解HCI log,我们需要先来看下HCI在整个蓝牙核心系统架构中所处的位置。为了理解起来更简单,我这边将蓝牙核心系统架构抽象为3层

  • User Application(Host):User Application即应用层,也被称为Host,我们调用Bluetooth API就属于应用层,例如,BluetoothAdapter中提供的接口。

  • HCI (Host controller Interface):上层在调用蓝牙API时,不会直接操作蓝牙底层(Controller)相关接口,而是通过HCI下发对应操作的Command给Controller,然后底层执行命令后返回执行结果,即Controller发送Event给HCI,HCI再通知给应用层,HCI起到了一个中间层的作用。

  • Controller:Controller是在最底层,可以理解为我们手机上的蓝牙芯片。

抽象后的蓝牙架构

完整的蓝牙核心系统架构比较复杂,这里我们就不再深入,感兴趣的同学可以参考蓝牙规范Core_v4.2.pdf,里面有详细的定义和介绍。我们后面在分析HCI log时,也会参考这个规范中定义的内容。

完整的蓝牙架构

2. 如何抓取HCI log

在开发者选项中打开启用蓝牙HCI信息收集日志开关,Android系统就开始自动地收集HCI log并保存到手机上。

启用蓝牙HCI信息收集日志

不同的平台存放HCI log的路径会不一样,MTK存放HCI log的路径为/sdcard/mtklog/btlog/btsnoop_hci.log高通的存放路径为/sdcard/btsnoop_hci.log

 

MTK:/ $ ls -l /sdcard/mtklog/btlog/
total 816
-rw-rw---- 1 root sdcard_rw 412258 2016-02-28 00:39 btsnoop_hci.log

shell@Qualcomm:/ $ ls -l /sdcard/btsnoop_hci.log
-rw-rw---- root     sdcard_rw    12744 2017-06-16 15:43 btsnoop_hci.log

如果上面提到的路径下都没有HCI log,我们还可以通过手机上的蓝牙配置文件bt_stack.conf来查看路径,bt_stack.conf位于/etc/bluetooth/路径下。HCI log路径通过BtSnoopFileName=/sdcard/btsnoop_hci.log来进行设置的。

HCI log在手机上的路径

而bt_stack.conf是通过Android源码中的/system/bt/conf/bt_stack.conf来配置的。

 

// /system/bt/conf/bt_stack.conf
# BtSnoop log output file
BtSnoopFileName=/sdcard/btsnoop_hci.log

将抓取到的HCI log pull出来,直接用记事本打开,看到的都是乱码。我们还需要一个HCI log分析工具:Frontline ComProbe Protocol Analysis System

 

C:\Windows\System32>adb pull /sdcard/mtklog/btlog/btsnoop_hci.log C:\Users\admin\Desktop\hci
501 KB/s (4880 bytes in 0.009s)

3. HCI log分析工具

Frontline ComProbe Protocol Analysis System是Frontline提供的一款蓝牙协议log分析工具,Frontine这家公司主要是做抓取蓝牙Air sniff log设备的,我们后面再来说下什么是Air sniff log。购买他们的抓包工具就会附带log分析工具,也可以在Frontine官网上下载,下载的时候需要填一些信息,觉得麻烦的同学可以去其他非官网途径进行下载。

安装完成后,在开始菜单中找到Frontline ComProbe Protocol Analysis System,使用Capture File Viewer可以打开HCI log

 

ComProbe Protocol Analysis System

Step 1. 首先,选择要打开的HCI log,并选择log类型为BtSnoop Files,即以*.log结尾的文件。
还有一种方式是将btsnoop_hci.log的后缀修改为btsnoop_hci.cfa,就可以直接用Capture File Viewer打开。

Step 1. 打开的HCI log

 

选择log类型

Step 2. 打开log文件后,选择Frame Display就可以看到我们抓取的HCI log了

Step 2 . 选择Frame Display

Frame Display主界面

Step 3. Frame Display窗口中有很多Tab,将协议栈中各类协议分类显示,例如:HCI相关的log放在HCI的Tab中,Hands-Free(HFP)属于应用层的Bluetooth Profile,和HFP相关操作的log都放在Hands-Free这个Tab中。

Frame Display

  • Air sniff log
    Android设备上抓取的HCI log只能分析Host和Control之间的问题,当Host和Control之间交互是正常的,那就可能就是传输的过程中(Air Interface)出了问题,此时就需要分析Air sniff log。Air sniff log能够抓取的两个蓝牙设备在数据传输过程中的空中包,抓取Air sniff log需要专门的设备。

Air sniff log

4. HCI log 案例 - 蓝牙扫描设备过程分析

应用层在调用startDiscovery()进行设备扫描时,Host会通过HCI发送一个Inquiry HCI CommandController。接下来我们会通过分析HCI log,来学习Inquiry 的流程。在分析HCI log前,我们先来学习下HCI Command数据包的结构。

4.1 HCI Command 数据包结构

HCI Command数据包结构定义在蓝牙核心协议规范Core_v4.2.pdf中。

HCI Command数据包格式如下,开头的Opcode是区分不同类型的命令的唯一标识,Opcode由OpCode Group Field (OGF)OpCode Command Field (OCF)组成。根据OGF的值,可以将HCI commands进行分类。OpCode 的计算公式为:** OpCode = OGF << 6 + OCF 。有了OpCode计算的方式,我们就可以通过OpCode过滤**HCI log里面的指定类型的HCI Command。

HCI Command Packet

OpCode计算方法

4.2 过滤Inquiry Command

Inquiry CommandLink Control command类型的command,通过查询Bluetooth Core Specification的中Vol 2->Part E->7.1 LINK CONTROL COMMANDS小节,可知Link Control command的OCF值为0x0001

Bluetooth Core Specification目录

For the Link Control commands, the OGF is defined as 0x01

因此,Inquiry Command的Opcode为 0x0001 << 6 + 0x01 = 0x0401通过0x0401就确定某条command为Inquiry Command,该命令的名称为HCI_Inquiry

Inquiry Command

ComProbe Protocol Analysis System支持过滤功能,通过设置filter可以过滤出Opcode为0x0401的log,设置方法如下图:

 

过滤HCI_Inquiry

4.3 扫描过程分析

1. 发送Inquiry请求

  • Host发送HCI_Inquiry Command
    应用层要进行蓝牙设备扫描啦,Host先发一条HCI_Inquiry的Command通知Controller

Host: HCI_Inquiry

  • Controller回复HCI Event
    Controller在收到HCI_Inquiry这条Command后,会回复一条Command Status的HCI Event,来表示Controller执行HCI_Inquiry后的状态,即Status:Success。仔细观察可以发现这两条HCI log的Frame标号是挨着的,HCI_Inquiry的帧号是196,Command Status的帧号是197。

Controller:Command_status、

2. 扫描结果

扫描完成后,Controller会发送Event:HCI Extended Inquiry Result。以列表中搜索到的Jabra Classic v0.5.3为例,它的HCI Extended Inquiry Result数据包中会包含它的设备名称、它所支持的Service的UUID,和设备类型Wearable Headset device,因此,Jabra Classic v0.5.3的Icon是一个耳机的图标

扫描结果

Jabra Classic v0.5.3的HCI Extended Inquiry Result



作者:伤口不该结疤
链接:https://www.jianshu.com/p/73f7366161d1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐