传统蓝牙搜索流程分析
本期承接上篇分享《传统蓝牙BR/EDR的搜索Inquiry》来聊聊安卓系统中传统蓝牙搜索是如何实现的。
安卓系统中应用Application通过蓝牙适配器接口BluetoothAdapter.startDiscovery() 的调用触发搜索流程的开始,我们的分析也就从这里开启。
安卓源码版本:Android 9,P(Pie馅饼)版本
在分析之前对第三方应用有如下几个要求:
Application通过满足上述三个条件后,只要触发搜索流程开启就可以等待设备信息的上报再做进一步处理,先让我们整体看下搜索流程的时序图:
以上就是传统蓝牙查询的完整流程,其实在开始传统蓝牙查询的同时,安卓系统也会开启低功耗蓝牙BLE的scan流程,时序图中将这部分内容去掉了,留待以后分析BLE扫描时再做分析(挖个坑…)。
从时序图中可以看出应用Application调用完BluetoothAdapter.startDiscovery() 后不需要其他操作了,只需耐心等待相关的系统广播即可。
指令一直被下发到协议栈bluedroid后,开始封装数据,并且中间的处理过程都是在协议栈中进行的,所以接下来重点分析下协议栈内部是如何玩转扫描流程的。
1、 首先指令到达协议栈btif_dm_start_discovery()处理函数中,设置了查询必要的相关参数
filter_type设置为0,传统蓝牙的查询Inquiry过滤关闭。
2、 指令进一步被下发到协议栈的stack层中的 BTM_StartInquiry() 继续处理,在这里判断查询模式参数如果包含ble,则发起ble的scan扫描。
3、 首先通过HCI指令 HCI_SET_EVENT_FILTER 设置Inquiry的过滤器
4、 设置过滤器的完成事件处理中调用 btm_initiate_inquiry() 开启真正的查询
5、 btm_acl_update_busy_level()中 event= BTM_BLI_INQ_EVT 更新当前协议栈的繁忙等级,并且通过JNI层的回调上报蓝牙服务层传统蓝牙查询开始。
6、 通过设置的查询模式确定Inquiry指令中的查询访问代码LAP值
7、 安卓系统蓝牙协议栈bluedroid中默认采用One-Time Inquiry查询方式,且该方式的查询结果上报的数量限制默认为 0 ,也就是不限制上报的数量。
8、 蓝牙控制器Controller通过(Inquiry Result、Inquiry Result with RSSI或者Extended Inquiry Result)三种上报事件中的一种依次上报查询到的设备结果到协议栈
9、 协议栈解析出设备信息后最后在btif_dm_search_devices_evt()函数中通过 event= BTA_DM_INQ_RES_EVT 将查询到的设备信息上报到蓝牙服务层
10、 服务层的RemoteDevices远端蓝牙设备管理类通过广播 “android.bluetooth.device.action.FOUND” 将设备信息广播出去
11、 查询时间12.8s触发,控制器Controller通过Inquiry Complete事件通知协议栈查询Inquiry流程完成。但协议栈在收到该完成事件时,不会立即上报服务层查询结束。
12、 协议栈会先通过查询记录对每一个设备发起Discovery流程(主要通过请求远端名)。
13、 最后所有查询记录中的设备都Discovery完成后,才会上报传统蓝牙查询结束。
经过以上这些步骤,安卓系统中的搜索流程成功完成。流程对应的HCI交互如下:
本篇流程的分析主要看上述的那幅时序图就可以了,其他细枝末节的问题可以参照安卓源码或协议再分析,这里就不做分析了。感兴趣的小伙伴欢迎私信留言一起讨论。