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是在最底层,可以理解为我们手机上的蓝牙芯片。
![](https://i-blog.csdnimg.cn/blog_migrate/9719f5f5e384df357de0681a0aebc398.png)
完整的蓝牙核心系统架构比较复杂,这里我们就不再深入,感兴趣的同学可以参考蓝牙规范Core_v4.2.pdf,里面有详细的定义和介绍。我们后面在分析HCI log时,也会参考这个规范中定义的内容。
![](https://i-blog.csdnimg.cn/blog_migrate/c988324ec9b15bbeefa0fb45f0661dc8.png)
2. 如何抓取HCI log
在开发者选项中打开启用蓝牙HCI信息收集日志开关,Android系统就开始自动地收集HCI log并保存到手机上。
![](https://i-blog.csdnimg.cn/blog_migrate/04fd658eb41c13b8c3f2b6630a292bc5.png)
不同的平台存放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来进行设置的。
![](https://i-blog.csdnimg.cn/blog_migrate/686bc67db7329de324240d9864f1fc39.png)
而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
![](https://i-blog.csdnimg.cn/blog_migrate/d1663a0dca4e25ea1abdab272c260cb9.png)
Step 1. 首先,选择要打开的HCI log,并选择log类型为BtSnoop Files,即以*.log结尾的文件。
还有一种方式是将btsnoop_hci.log的后缀修改为btsnoop_hci.cfa,就可以直接用Capture File Viewer打开。
![](https://i-blog.csdnimg.cn/blog_migrate/30d02c2dfba4deb4cf4a7ca4fbd4259b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/83a49686da984885842961357f8ff25f.png)
Step 2. 打开log文件后,选择Frame Display就可以看到我们抓取的HCI log了
![](https://i-blog.csdnimg.cn/blog_migrate/2095ee71082f59cf5eedfa8246647dc9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7c9142de8737f7547661131c5f2ff938.png)
Step 3. Frame Display窗口中有很多Tab,将协议栈中各类协议分类显示,例如:HCI相关的log放在HCI的Tab中,Hands-Free(HFP)属于应用层的Bluetooth Profile,和HFP相关操作的log都放在Hands-Free这个Tab中。
![](https://i-blog.csdnimg.cn/blog_migrate/262b2100a12e932aa6ef3cc2466a6f87.png)
- Air sniff log
Android设备上抓取的HCI log只能分析Host和Control之间的问题,当Host和Control之间交互是正常的,那就可能就是传输的过程中(Air Interface)出了问题,此时就需要分析Air sniff log。Air sniff log能够抓取的两个蓝牙设备在数据传输过程中的空中包,抓取Air sniff log需要专门的设备。
![](https://i-blog.csdnimg.cn/blog_migrate/10d5acae806a1c61c18fe5e333447ec0.png)
4. HCI log 案例 - 蓝牙扫描设备过程分析
应用层在调用startDiscovery()进行设备扫描时,Host会通过HCI发送一个Inquiry HCI Command给Controller。接下来我们会通过分析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。
![](https://i-blog.csdnimg.cn/blog_migrate/70f847ae3bbd2d6744784524f34fb78e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8ccd67297d549ccb5907b1ab4a227aa7.png)
4.2 过滤Inquiry Command
Inquiry Command是Link Control command类型的command,通过查询Bluetooth Core Specification的中Vol 2->Part E->7.1 LINK CONTROL COMMANDS小节,可知Link Control command的OCF值为0x0001。
![](https://i-blog.csdnimg.cn/blog_migrate/dcbb9f59b213b4ba8ae85db490498f53.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4b8c192101cb8a65b5bee3d87c0f94e4.png)
因此,Inquiry Command的Opcode为 0x0001 << 6 + 0x01 = 0x0401 ,通过0x0401就确定某条command为Inquiry Command,该命令的名称为HCI_Inquiry
![](https://i-blog.csdnimg.cn/blog_migrate/10e1ca5a831bd3ec95770f09b1755501.png)
ComProbe Protocol Analysis System支持过滤功能,通过设置filter可以过滤出Opcode为0x0401的log,设置方法如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/0aae30db411630114b5ed9f96601fe86.webp?x-image-process=image/format,png)
4.3 扫描过程分析
1. 发送Inquiry请求
- Host发送HCI_Inquiry Command
应用层要进行蓝牙设备扫描啦,Host先发一条HCI_Inquiry的Command通知Controller
![](https://i-blog.csdnimg.cn/blog_migrate/76efab74e260f561c7906c402ae2b6c9.png)
- 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。
![](https://i-blog.csdnimg.cn/blog_migrate/600adb7bc549609f03bbb22fb043400e.png)
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是一个耳机的图标。
![](https://i-blog.csdnimg.cn/blog_migrate/6b2bb6515c8964e818afb644eb647d11.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3c1cf7250f457f4732a7f87532617b8a.png)
5. 参考
作者:伤口不该结疤
链接:https://www.jianshu.com/p/73f7366161d1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。