1. 程式人生 > 其它 >常州開發安卓系統公司分析藍芽協議棧 bluedroid 的使能流程

常州開發安卓系統公司分析藍芽協議棧 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點個贊科技致電留言一起討論。