安卓原生的蓝牙协议栈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 值时设置的错误值

安卓系统开发中分析蓝牙协议栈bluedroid 的使能流程-LMLPHP

该全局变量是第一次在开发者选项中打开snoop开关时创建的,所以从来没操作过snoop开关,则该全局变量就没有定义。如果操作过开发者选项中的snoop开关,则获取上述全局变量就可以获取到对应的值,从而错误值不再起作用。

2、通过指令:

adb shell setprop persist.bluetooth.btsnoopenabletrue,开启蓝牙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::spcallbacks=new BluetoothHciCallbacks();

btHci->initialize(callbacks);

HIDL:全称是HAL interface definitionlanguage(硬件抽象层接口定义语言),在此之前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)(constbt_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层的交互如下图:

安卓系统开发中分析蓝牙协议栈bluedroid 的使能流程-LMLPHPReset完成后协议栈会主动下发HCI命令读取本端的蓝牙名字,并将新的名字下发给芯片,同时通过JNI层的回调将本端的蓝牙名字和地址上报给服务层。如果存在配对的蓝牙设备,也会将该设备信息上报。

 

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

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

本篇协议栈使能的分析就到这儿了,感兴趣的访问常州开发APP公司点个赞科技http://www.66dianzan.com致电留言一起讨论。

10-17 16:02