安卓系統藍牙協議棧 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
在這裏插入圖片描述

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