常州開發安卓系統公司分析藍芽協議棧 bluedroid 的使能流程
安卓原生的藍芽協議棧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.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=newBluetoothHciCallbacks();
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_tsupported_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)(constbt_event_mask_t* event_mask);
BT_HDR* (*make_read_local_supported_codecs)(void);}
HCI層的互動如下圖:
Reset完成後協議棧會主動下發HCI命令讀取本端的藍芽名字,並將新的名字下發給晶片,同時通過JNI層的回撥將本端的藍芽名字和地址上報給服務層。如果存在配對的藍芽裝置,也會將該裝置資訊上報。
緊接著會初始化協議棧的socket模組,這部分主要是為建立OBEX連線和資料互動做準備的。
協議棧所有使能工作完成,通過HALbt_hal_cbacks->adapter_state_changed_cb回撥將藍芽使能成功的訊息上報到JNI層。至此藍芽協議棧bluedroid的使能流程的全部過程就分析完畢。
本篇協議棧使能的分析就到這兒了,感興趣的訪問常州開發APP公司https://www.66dianzan.com點個贊科技致電留言一起討論。