安卓系统蓝牙协议栈 bluedroid 的使能

安卓系统蓝牙协议栈 bluedroid 使能流程分析

在这里插入图片描述

本文承接上篇文章《安卓中蓝牙系统服务层的使能流程分析》,接续分析协议栈层相关的使能流程,所以蓝牙协议栈bluedroid的使能始于JNI层enableNative()中调用协议栈接口enable()函数。
在这里插入图片描述

话不多说,还是按照老规矩我们先从整体上对协议栈的使能有个印象,参考如下时序图。
在这里插入图片描述

安卓原生的蓝牙协议栈bluedroid在分层上被分为btif、bta、stack、hci这四层,每层的作用各不相同,但实际程序运行是在不同的线程运行的,为了方便大家对使能流程有更为深刻的了解,所以上述的使能时序图是以线程为依据。接下来就按照上述时序分别作出说明。

蓝牙服务层JNI使能协议栈bluedroid,通过interface函数接口下发指令到达协议栈入口。

stack_manager_get_interface()->start_up_stack_async();将使能指令下发到协议栈管理模块,模块内部通过线程stack_manage继续处理。

依次使能btif_config、btsnoop、hci等模块

btsnoop模块:
判断snoop开关是否打开,从而决定是否创建snoop文件来记录hci的交互信息。
snoop开关位置在开发者选项中,打开该关开,则persist.bluetooth.btsnoopenable全局变量会被置为true;反之开关关闭,该变量会被置为false。
snoop文件默认存储位置:/data/misc/bluetooth/logs/

由于打开snoop开关的步骤比较复杂,一般用户根本不会进到开发者选项中,连从哪儿打开开发者选项都是一个难题,所以蓝牙开发过程中可以修改源码或重置persist.bluetooth.btsnoopenable的值来达到创建snoop文件记录hci的交互信息的目的。现提供如下两种方法

  1. 修改源码中获取 persist.bluetooth.btsnoopenable 值时设置的错误值
    在这里插入图片描述
    该全局变量是第一次在开发者选项中打开snoop开关时创建的,所以从来没操作过snoop开关,则该全局变量就没有定义。如果操作过开发者选项中的snoop开关,则获取上述全局变量就可以获取到对应的值,从而错误值不再起作用。
  2. 通过指令:
    adb shell setprop persist.bluetooth.btsnoopenable true,开启蓝牙hci-snoop的开关。
    persist.bluetooth.btsnoopenable 全局变量的存储路径因安卓版本而有些许差异:
    Android 8的存储路径:/data/property/persist.bluetooth.btsnoopenable/
    Android 9的存储路径:/data/property/persistent_properties/

HCI模块:
创建hci_thread线程,专门处理hci相关的流程,并同时初始化蓝牙芯片。
通过HIDL技术获取芯片Controller模块对外提供的接口:

btHci = IBluetoothHci::getService();
android::sp<IBluetoothHciCallbacks> callbacks = new BluetoothHciCallbacks();
btHci->initialize(callbacks);

HIDL:全称是HAL interface definition language(硬件抽象层接口定义语言),在此之前Android 有AIDL,架构在Android binder 之上,用来定义Android 基于Binder通信的Client 与Service之间的接口。HIDL也是类似的作用,只不过定义的是Android Framework与Android HAL实现之间的接口。

Android HAL的实现方式由于芯片厂商的不同而有差异,实现内容都是类似于安卓源码中hardware\interfaces\bluetooth\1.0\中的实现方式。厂商再在HAL的实现中与自家芯片进行交互。这样通过统一的HAL接口就可以实现软硬件分离,安卓系统就可以集成不同厂家的蓝牙芯片。

芯片模块初始化完成后会通过回调告知android层,这样蓝牙协议栈才会继续后面的使能流程。

随着HCI模块使能完成就进入BTU_StartUp( )函数中开始初始化BTU控制模块,包括BTU、BTM、L2CAP、SDP等协议栈关键模块

使能controller模块,实际上就是通过一组HCI命令从芯片层获取支持的功能参数

typedef struct {
  BT_HDR* (*make_reset)(void);
  BT_HDR* (*make_read_buffer_size)(void);
  BT_HDR* (*make_host_buffer_size)(uint16_t acl_size, uint8_t sco_size, uint16_t acl_count, uint16_t sco_count);
  BT_HDR* (*make_read_local_version_info)(void);
  BT_HDR* (*make_read_bd_addr)(void);
  BT_HDR* (*make_read_local_supported_commands)(void);
  BT_HDR* (*make_read_local_extended_features)(uint8_t page_number);
  BT_HDR* (*make_write_simple_pairing_mode)(uint8_t mode);
  BT_HDR* (*make_write_secure_connections_host_support)(uint8_t mode);
  BT_HDR* (*make_set_event_mask)(const bt_event_mask_t* event_mask);
  BT_HDR* (*make_ble_write_host_support)(uint8_t supported_host, uint8_t simultaneous_host);
  BT_HDR* (*make_ble_read_white_list_size)(void);
  BT_HDR* (*make_ble_read_buffer_size)(void);
  BT_HDR* (*make_ble_read_supported_states)(void);
  BT_HDR* (*make_ble_read_local_supported_features)(void);
  BT_HDR* (*make_ble_read_resolving_list_size)(void);
  BT_HDR* (*make_ble_read_suggested_default_data_length)(void);
  BT_HDR* (*make_ble_read_maximum_data_length)(void);
  BT_HDR* (*make_ble_read_maximum_advertising_data_length)(void);
  BT_HDR* (*make_ble_read_number_of_supported_advertising_sets)(void);
  BT_HDR* (*make_ble_set_event_mask)(const bt_event_mask_t* event_mask);
  BT_HDR* (*make_read_local_supported_codecs)(void);
}

HCI层的交互如下图:
在这里插入图片描述

Reset完成后协议栈会主动下发HCI命令读取本端的蓝牙名字,并将新的名字下发给芯片,同时通过JNI层的回调将本端的蓝牙名字和地址上报给服务层。如果存在配对的蓝牙设备,也会将该设备信息上报。

紧接着会初始化协议栈的socket模块,这部分主要是为建立OBEX连接和数据交互做准备的。

协议栈所有使能工作完成,通过HAL bt_hal_cbacks->adapter_state_changed_cb回调将蓝牙使能成功的消息上报到JNI层。至此蓝牙协议栈bluedroid的使能流程的全部过程就分析完毕。

本篇协议栈使能的分析就到这儿了,感兴趣的小伙伴欢迎私信留言一起讨论。

更多互联互通技术,欢迎关注微信公众号:Connectivity
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章