0. 引子
對(duì)于藍(lán)牙開(kāi)發(fā)者來(lái)說(shuō),通過(guò)HCI log可以幫助我們更好地分析問(wèn)題,理解藍(lán)牙協(xié)議,就好像網(wǎng)絡(luò)開(kāi)發(fā)一定要會(huì)使用Wireshark分析網(wǎng)絡(luò)協(xié)議一樣。
本篇主要介紹HCI log的作用、如何抓取一份HCI log,并結(jié)合一個(gè)實(shí)際的例子來(lái)說(shuō)明如何分析HCI log。
1. HCI log 介紹
1.1 HCI log 作用
HCI log是用來(lái)分析藍(lán)牙設(shè)備之間的交互行為是否符合預(yù)期,是否符合藍(lán)牙規(guī)范。在日常的開(kāi)發(fā)中,通常使用HCI log來(lái)做這樣幾件事:
分析Bug:藍(lán)牙打開(kāi)后搜索不到設(shè)備,或者搜索到的設(shè)備沒(méi)有名稱(chēng)只有藍(lán)牙地址;Android手機(jī)不能向蘋(píng)果手機(jī)傳輸文件 ... ...
需求分析:手機(jī)需要適配一款藍(lán)牙自拍桿來(lái)控制拍照,通過(guò)HCI log可以觀察競(jìng)品在實(shí)現(xiàn)這個(gè)功能時(shí),使用的是什么Bluetooth Profile?只要知道了使用的Bluetooth Profile,我們就有了實(shí)現(xiàn)這個(gè)功能的思路。
藍(lán)牙協(xié)議學(xué)習(xí):通過(guò)HCI log輔助學(xué)習(xí)藍(lán)牙協(xié)議,就好像學(xué)習(xí)TCP/IP時(shí),通過(guò)wireshark抓包來(lái)學(xué)習(xí)TCP協(xié)議
1.2 藍(lán)牙核心系統(tǒng)架構(gòu)
說(shuō)了這么多HCI log的用處,要想更好地理解HCI log,我們需要先來(lái)看下HCI在整個(gè)藍(lán)牙核心系統(tǒng)架構(gòu)中所處的位置。為了理解起來(lái)更簡(jiǎn)單,我這邊將藍(lán)牙核心系統(tǒng)架構(gòu)抽象為3層:
User Application(Host):User Application即應(yīng)用層,也被稱(chēng)為Host,我們調(diào)用Bluetooth API就屬于應(yīng)用層,例如,BluetoothAdapter中提供的接口。
HCI (Host controller Interface):上層在調(diào)用藍(lán)牙API時(shí),不會(huì)直接操作藍(lán)牙底層(Controller)相關(guān)接口,而是通過(guò)HCI下發(fā)對(duì)應(yīng)操作的Command給Controller,然后底層執(zhí)行命令后返回執(zhí)行結(jié)果,即Controller發(fā)送Event給HCI,HCI再通知給應(yīng)用層,HCI起到了一個(gè)中間層的作用。
Controller:Controller是在最底層,可以理解為我們手機(jī)上的藍(lán)牙芯片。

完整的藍(lán)牙核心系統(tǒng)架構(gòu)比較復(fù)雜,這里我們就不再深入,感興趣的同學(xué)可以參考藍(lán)牙規(guī)范Core_v4.2.pdf,里面有詳細(xì)的定義和介紹。我們后面在分析HCI log時(shí),也會(huì)參考這個(gè)規(guī)范中定義的內(nèi)容。

2. 如何抓取HCI log
在開(kāi)發(fā)者選項(xiàng)中打開(kāi)啟用藍(lán)牙HCI信息收集日志開(kāi)關(guān),Android系統(tǒng)就開(kāi)始自動(dòng)地收集HCI log并保存到手機(jī)上。

不同的平臺(tái)存放HCI log的路徑會(huì)不一樣,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
如果上面提到的路徑下都沒(méi)有HCI log,我們還可以通過(guò)手機(jī)上的藍(lán)牙配置文件bt_stack.conf來(lái)查看路徑,bt_stack.conf位于/etc/bluetooth/路徑下。HCI log路徑通過(guò)BtSnoopFileName=/sdcard/btsnoop_hci.log來(lái)進(jìn)行設(shè)置的。

而bt_stack.conf是通過(guò)Android源碼中的/system/bt/conf/bt_stack.conf來(lái)配置的。
// /system/bt/conf/bt_stack.conf
# BtSnoop log output file
BtSnoopFileName=/sdcard/btsnoop_hci.log
將抓取到的HCI log pull出來(lái),直接用記事本打開(kāi),看到的都是亂碼。我們還需要一個(gè)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提供的一款藍(lán)牙協(xié)議log分析工具,F(xiàn)rontine這家公司主要是做抓取藍(lán)牙Air sniff log設(shè)備的,我們后面再來(lái)說(shuō)下什么是Air sniff log。購(gòu)買(mǎi)他們的抓包工具就會(huì)附帶log分析工具,也可以在Frontine官網(wǎng)上下載,下載的時(shí)候需要填一些信息,覺(jué)得麻煩的同學(xué)可以去其他非官網(wǎng)途徑進(jìn)行下載。
安裝完成后,在開(kāi)始菜單中找到Frontline ComProbe Protocol Analysis System,使用Capture File Viewer可以打開(kāi)HCI log

Step 1. 首先,選擇要打開(kāi)的HCI log,并選擇log類(lèi)型為BtSnoop Files,即以*.log結(jié)尾的文件。
還有一種方式是將btsnoop_hci.log的后綴修改為btsnoop_hci.cfa,就可以直接用Capture File Viewer打開(kāi)。


Step 2. 打開(kāi)log文件后,選擇Frame Display就可以看到我們抓取的HCI log了


Step 3. Frame Display窗口中有很多Tab,將協(xié)議棧中各類(lèi)協(xié)議分類(lèi)顯示,例如:HCI相關(guān)的log放在HCI的Tab中,Hands-Free(HFP)屬于應(yīng)用層的Bluetooth Profile,和HFP相關(guān)操作的log都放在Hands-Free這個(gè)Tab中。

-
Air sniff log
Android設(shè)備上抓取的HCI log只能分析Host和Control之間的問(wèn)題,當(dāng)Host和Control之間交互是正常的,那就可能就是傳輸?shù)倪^(guò)程中(Air Interface)出了問(wèn)題,此時(shí)就需要分析Air sniff log。Air sniff log能夠抓取的兩個(gè)藍(lán)牙設(shè)備在數(shù)據(jù)傳輸過(guò)程中的空中包,抓取Air sniff log需要專(zhuān)門(mén)的設(shè)備。

4. HCI log 案例 - 藍(lán)牙掃描設(shè)備過(guò)程分析
應(yīng)用層在調(diào)用startDiscovery()進(jìn)行設(shè)備掃描時(shí),Host會(huì)通過(guò)HCI發(fā)送一個(gè)Inquiry HCI Command給Controller。接下來(lái)我們會(huì)通過(guò)分析HCI log,來(lái)學(xué)習(xí)Inquiry 的流程。在分析HCI log前,我們先來(lái)學(xué)習(xí)下HCI Command數(shù)據(jù)包的結(jié)構(gòu)。
4.1 HCI Command 數(shù)據(jù)包結(jié)構(gòu)
HCI Command數(shù)據(jù)包結(jié)構(gòu)定義在藍(lán)牙核心協(xié)議規(guī)范Core_v4.2.pdf中。
HCI Command數(shù)據(jù)包格式如下,開(kāi)頭的Opcode是區(qū)分不同類(lèi)型的命令的唯一標(biāo)識(shí),Opcode由OpCode Group Field (OGF) 和 OpCode Command Field (OCF)組成。根據(jù)OGF的值,可以將HCI commands進(jìn)行分類(lèi)。OpCode 的計(jì)算公式為:** OpCode = OGF << 6 + OCF 。有了OpCode計(jì)算的方式,我們就可以通過(guò)OpCode過(guò)濾**HCI log里面的指定類(lèi)型的HCI Command。


4.2 過(guò)濾Inquiry Command
Inquiry Command是Link Control command類(lèi)型的command,通過(guò)查詢(xún)Bluetooth Core Specification的中Vol 2->Part E->7.1 LINK CONTROL COMMANDS小節(jié),可知Link Control command的OCF值為0x0001。


因此,Inquiry Command的Opcode為 0x0001 << 6 + 0x01 = 0x0401 ,通過(guò)0x0401就確定某條command為Inquiry Command,該命令的名稱(chēng)為HCI_Inquiry

ComProbe Protocol Analysis System支持過(guò)濾功能,通過(guò)設(shè)置filter可以過(guò)濾出Opcode為0x0401的log,設(shè)置方法如下圖:

4.3 掃描過(guò)程分析
1. 發(fā)送Inquiry請(qǐng)求
-
Host發(fā)送HCI_Inquiry Command
應(yīng)用層要進(jìn)行藍(lán)牙設(shè)備掃描啦,Host先發(fā)一條HCI_Inquiry的Command通知Controller

-
Controller回復(fù)HCI Event
Controller在收到HCI_Inquiry這條Command后,會(huì)回復(fù)一條Command Status的HCI Event,來(lái)表示Controller執(zhí)行HCI_Inquiry后的狀態(tài),即Status:Success。仔細(xì)觀察可以發(fā)現(xiàn)這兩條HCI log的Frame標(biāo)號(hào)是挨著的,HCI_Inquiry的幀號(hào)是196,Command Status的幀號(hào)是197。

2. 掃描結(jié)果
掃描完成后,Controller會(huì)發(fā)送Event:HCI Extended Inquiry Result。以列表中搜索到的Jabra Classic v0.5.3為例,它的HCI Extended Inquiry Result數(shù)據(jù)包中會(huì)包含它的設(shè)備名稱(chēng)、它所支持的Service的UUID,和設(shè)備類(lèi)型:Wearable Headset device,因此,Jabra Classic v0.5.3的Icon是一個(gè)耳機(jī)的圖標(biāo)。

