本文深入剖析Android藍牙協議棧中HID設備(BT-HD)服務的初始化與啟用流程,從接口初始化、服務掩碼管理、服務請求路由到屬性回調通知,完整展現藍牙HID服務激活的技術路徑。通過代碼邏輯梳理,揭示服務啟用的核心機制,包括服務狀態掩碼更新、跨模塊調用鏈及線程安全的屬性傳遞設計。
一、概述
藍牙 HID 設備(如鍵盤、鼠標)的服務啟用與狀態同步是藍牙協議棧的核心功能之一。整個流程涉及多個模塊協作,包括服務初始化、協議棧請求分發、屬性獲取及跨線程通知,具體可分為以下階段:
1.1 服務初始化與啟用
-
初始化接口:通過
init
函數完成 BT-HD 接口初始化,配置回調函數并調用btif_enable_service(BTA_HIDD_SERVICE_ID)
啟用 HID 服務。 -
服務掩碼更新:
btif_enable_service
將目標服務(BTA_HIDD_SERVICE_ID
)添加到全局服務掩碼(btif_enabled_services
),若藍牙已激活(btif_is_enabled()
),則觸發服務啟用請求。
1.2 協議棧請求分發
-
服務請求執行:
btif_dm_enable_service
調用btif_in_execute_service_request
執行服務啟用請求。若成功,觸發屬性變更通知流程。 -
請求路由:
btif_in_execute_service_request
根據服務類型分發請求:SDP 服務特殊處理,其他服務通過toggleProfile
路由到具體服務模塊(如 HID 服務由btif_hd_execute_service
處理)。
1.3 服務狀態同步與屬性通知
-
屬性填充與獲取:
-
通過宏
BTIF_STORAGE_FILL_PROPERTY
初始化bt_property_t
結構體,指定屬性類型(如BT_PROPERTY_UUIDS
)。 -
btif_storage_get_adapter_property
根據屬性類型從控制器或存儲中獲取具體值(如藍牙地址、已配對設備列表、已啟用服務的 UUID 列表)。
-
-
跨線程回調通知:
invoke_adapter_properties_cb
通過深拷貝(property_deep_copy_array
)確保屬性數據線程安全,結合do_in_jni_thread
將變更事件異步傳遞到 JNI 線程,觸發上層回調(如 Java 層)并釋放資源。
二、源碼解析
init
packages/modules/Bluetooth/system/btif/src/btif_hd.cc
/********************************************************************************* Function init** Description Initializes BT-HD interface** Returns BT_STATUS_SUCCESS*******************************************************************************/
btif_hd_cb_t btif_hd_cb;static bt_status_t init(bthd_callbacks_t* callbacks) {log::verbose("");bt_hd_callbacks = callbacks;memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));btif_enable_service(BTA_HIDD_SERVICE_ID); // 啟用 HID 服務return BT_STATUS_SUCCESS;
}
初始化藍牙 HID 設備(BT-HD)接口,配置回調函數并啟用 HID 服務。
btif_enable_service(BTA_HIDD_SERVICE_ID)
packages/modules/Bluetooth/system/btif/src/btif_core.cc
/********************************************************************************* Function btif_enable_service** Description Enables the service 'service_ID' to the service_mask.* Upon BT enable, BTIF core shall invoke the BTA APIs to* enable the profiles*******************************************************************************/
void btif_enable_service(tBTA_SERVICE_ID service_id) {btif_enabled_services |= (1 << service_id); // 服務掩碼更新log::verbose("current services:0x{:x}", btif_enabled_services);if (btif_is_enabled()) {btif_dm_enable_service(service_id, true);}
}
將指定的藍牙服務添加到已啟用服務掩碼中,并在藍牙已激活時立即啟動該服務。
btif_dm_enable_service
packages/modules/Bluetooth/system/btif/src/btif_dm.cc
void btif_dm_enable_service(tBTA_SERVICE_ID service_id, bool enable) {// 執行服務請求bt_status_t status = btif_in_execute_service_request(service_id, enable);if (status == BT_STATUS_SUCCESS) {// 準備 UUID 屬性bt_property_t property;Uuid local_uuids[BT_MAX_NUM_UUIDS]; // 存儲設備支持的 UUID 列表/* Now send the UUID_PROPERTY_CHANGED event to the upper layer */// 從存儲中獲取當前設備的 UUID 屬性BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,sizeof(local_uuids), local_uuids);btif_storage_get_adapter_property(&property);// 通過回調通知上層應用適配器屬性已變更GetInterfaceToProfiles()->events->invoke_adapter_properties_cb(BT_STATUS_SUCCESS, 1, &property);}return;
}
通過藍牙協議棧執行服務啟用 / 禁用請求,并在成功時通知上層應用。
btif_in_execute_service_request
packages/modules/Bluetooth/system/btif/src/btif_dm.cc
bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,bool b_enable) {log::verbose("service_id:{}", service_id);if (service_id == BTA_SDP_SERVICE_ID) { // SDP 服務特殊處理btif_sdp_execute_service(b_enable);return BT_STATUS_SUCCESS;}// 通用服務處理return GetInterfaceToProfiles()->toggleProfile(service_id, b_enable);
}
將上層的服務啟用 / 禁用請求路由到對應的處理模塊。
toggleProfile(BTA_HIDD_SERVICE_ID)
packages/modules/Bluetooth/system/btif/src/bluetooth.ccbt_status_t toggleProfile(tBTA_SERVICE_ID service_id, bool enable) override {/* Check the service_ID and invoke the profile's BT state changed API */switch (service_id) {case BTA_HFP_SERVICE_ID:case BTA_HSP_SERVICE_ID: {bluetooth::headset::ExecuteService(enable);} break;case BTA_A2DP_SOURCE_SERVICE_ID: {btif_av_source_execute_service(enable);} break;case BTA_A2DP_SINK_SERVICE_ID: {btif_av_sink_execute_service(enable);} break;case BTA_HID_SERVICE_ID: {btif_hh_execute_service(enable);} break;case BTA_HFP_HS_SERVICE_ID: {btif_hf_client_execute_service(enable);} break;case BTA_HIDD_SERVICE_ID: {btif_hd_execute_service(enable);} break;case BTA_PBAP_SERVICE_ID:case BTA_PCE_SERVICE_ID:case BTA_MAP_SERVICE_ID:case BTA_MN_SERVICE_ID: {/*** Do nothing; these services were started elsewhere. However, we need* to flow through this codepath in order to properly report back the* local UUIDs back to adapter properties in Java. To achieve this, we* need to catch these service IDs in order for {@link* btif_in_execute_service_request} to return {@code BT_STATUS_SUCCESS},* so that in {@link btif_dm_enable_service} the check passes and the* UUIDs are allowed to be passed up into the Java layer.*/} break;default:log::error("Unknown service {} being {}", service_id,(enable) ? "enabled" : "disabled");return BT_STATUS_FAIL;}return BT_STATUS_SUCCESS;}
將通用的服務啟用 / 禁用請求轉發到具體的服務處理模塊。
btif_hd_execute_service
packages/modules/Bluetooth/system/btif/src/btif_hd.cc
/********************************************************************************* Function btif_hd_execute_service** Description Enabled/disables BT-HD service** Returns BT_STATUS_SUCCESS*******************************************************************************/
bt_status_t btif_hd_execute_service(bool b_enable) {log::verbose("b_enable={}", b_enable);if (!b_enable) BTA_HdDisable();return BT_STATUS_SUCCESS;
}
控制藍牙 HID 設備服務的開啟與關閉。
BTIF_STORAGE_FILL_PROPERTY
/modules/Bluetooth/system/btif/include/btif_storage.h
#define BTIF_STORAGE_FILL_PROPERTY(p_prop, t, l, p_v) \do { \(p_prop)->type = (t); \(p_prop)->len = (l); \(p_prop)->val = (p_v); \} while (0)
初始化bt_property_t
結構體的三個核心字段。
btif_storage_get_adapter_property
packages/modules/Bluetooth/system/btif/src/btif_storage.cc
/********************************************************************************* Function btif_storage_get_adapter_property** Description BTIF storage API - Fetches the adapter property->type* from NVRAM and fills property->val.* Caller should provide memory for property->val and* set the property->val** Returns BT_STATUS_SUCCESS if the fetch was successful,* BT_STATUS_FAIL otherwise*******************************************************************************/
bt_status_t btif_storage_get_adapter_property(bt_property_t* property) {/* Special handling for adapter address and BONDED_DEVICES */if (property->type == BT_PROPERTY_BDADDR) { // 藍牙地址獲取RawAddress* bd_addr = (RawAddress*)property->val;/* Fetch the local BD ADDR */const controller_t* controller = controller_get_interface();if (!controller->get_is_ready()) {log::error("Controller not ready! Unable to return Bluetooth Address");*bd_addr = RawAddress::kEmpty;return BT_STATUS_FAIL;} else {log::info("Controller ready!");*bd_addr = *controller->get_address(); // 從藍牙控制器獲取本地設備地址}property->len = RawAddress::kLength;return BT_STATUS_SUCCESS;} else if (property->type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) { // 已配對設備列表獲取btif_bonded_devices_t bonded_devices;// 獲取已配對設備列表btif_in_fetch_bonded_devices(&bonded_devices, 0);log::verbose("BT_PROPERTY_ADAPTER_BONDED_DEVICES: Number of bonded devices={}",bonded_devices.num_devices);property->len = bonded_devices.num_devices * RawAddress::kLength;// 將設備地址復制到屬性值緩沖區memcpy(property->val, bonded_devices.devices, property->len);/* if there are no bonded_devices, then length shall be 0 */return BT_STATUS_SUCCESS;} else if (property->type == BT_PROPERTY_UUIDS) { // UUID 列表生成/* publish list of local supported services */Uuid* p_uuid = reinterpret_cast<Uuid*>(property->val);uint32_t num_uuids = 0;uint32_t i;tBTA_SERVICE_MASK service_mask = btif_get_enabled_services_mask();log::info("Service_mask=0x{:x}", service_mask);// 根據已啟用服務掩碼生成對應的 UUID 列表for (i = 0; i < BTA_MAX_SERVICE_ID; i++) {/* This should eventually become a function when more services are enabled*/if (service_mask & (tBTA_SERVICE_MASK)(1 << i)) {switch (i) {case BTA_HFP_SERVICE_ID: {*(p_uuid + num_uuids) =Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);num_uuids++;}FALLTHROUGH_INTENDED; /* FALLTHROUGH *//* intentional fall through: Send both BFP & HSP UUIDs if HFP is* enabled */case BTA_HSP_SERVICE_ID: {*(p_uuid + num_uuids) =Uuid::From16Bit(UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY);num_uuids++;} break;case BTA_A2DP_SOURCE_SERVICE_ID: {*(p_uuid + num_uuids) =Uuid::From16Bit(UUID_SERVCLASS_AUDIO_SOURCE);num_uuids++;} break;case BTA_A2DP_SINK_SERVICE_ID: {*(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_AUDIO_SINK);num_uuids++;} break;case BTA_PBAP_SERVICE_ID: {*(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_PBAP_PSE);num_uuids++;} break;case BTA_HFP_HS_SERVICE_ID: {*(p_uuid + num_uuids) =Uuid::From16Bit(UUID_SERVCLASS_HF_HANDSFREE);num_uuids++;} break;case BTA_MAP_SERVICE_ID: {*(p_uuid + num_uuids) =Uuid::From16Bit(UUID_SERVCLASS_MESSAGE_ACCESS);num_uuids++;} break;case BTA_MN_SERVICE_ID: {*(p_uuid + num_uuids) =Uuid::From16Bit(UUID_SERVCLASS_MESSAGE_NOTIFICATION);num_uuids++;} break;case BTA_PCE_SERVICE_ID: {*(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_PBAP_PCE);num_uuids++;} break;}}}property->len = (num_uuids) * sizeof(Uuid);return BT_STATUS_SUCCESS;}/* fall through for other properties */// 通用屬性處理if (!cfg2prop(NULL, property)) {return btif_dm_get_adapter_property(property);}return BT_STATUS_SUCCESS;
}
根據屬性類型從 NVRAM 或控制器中獲取適配器屬性值。
invoke_adapter_properties_cb
/packages/modules/Bluetooth/system/btif/src/bluetooth.cc
void invoke_adapter_properties_cb(bt_status_t status, int num_properties,bt_property_t* properties) {do_in_jni_thread(FROM_HERE,base::BindOnce( // 創建一次性回調(避免重復執行)[](bt_status_t status, int num_properties,bt_property_t* properties) {// 步驟1:觸發上層回調(HAL層注冊的回調)HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status,num_properties, properties);if (properties) {// 步驟2:釋放深拷貝的內存(避免泄漏)osi_free(properties);}},status, num_properties,property_deep_copy_array(num_properties, properties))); //深拷貝屬性數組
}// callback reporting helpersbt_property_t* property_deep_copy_array(int num_properties,bt_property_t* properties) {bt_property_t* copy = nullptr;if (num_properties > 0) {// 1:計算所有屬性值的總長度(用于分配內存)size_t content_len = 0;for (int i = 0; i < num_properties; i++) {auto len = properties[i].len;if (len > 0) {content_len += len;}}//2:一次性分配連續內存(結構體數組 + 屬性值內容)copy = (bt_property_t*)osi_calloc((sizeof(bt_property_t) * num_properties) + content_len);ASSERT(copy != nullptr);// 3:復制屬性結構體,并將屬性值指向新分配的內容區uint8_t* content = (uint8_t*)(copy + num_properties); for (int i = 0; i < num_properties; i++) {auto len = properties[i].len;copy[i].type = properties[i].type;copy[i].len = len;if (len <= 0) {continue;}copy[i].val = content; // 指向新內容區memcpy(content, properties[i].val, len);content += len; // 移動到下一個屬性值位置}}return copy;
}
藍牙適配器屬性回調的跨線程調用機制,確保從 HAL 層到 JNI 層的屬性通知能夠正確處理。
三、時序圖
四、總結
①模塊化設計
-
流程嚴格分層:接口初始化→服務管理→請求路由→具體實現→屬性通知,各模塊職責單一(如
btif_hd
專注HID邏輯,btif_dm
處理通用服務管理)。
②狀態驅動機制
-
通過服務掩碼
btif_enabled_services
全局追蹤服務狀態,結合btif_is_enabled()
判斷實時激活狀態,避免無效操作。
③線程安全與內存管理
-
屬性回調采用深拷貝(
property_deep_copy_array
)與osi_free
釋放,確保跨線程(如JNI)數據傳遞安全性。
④擴展性設計
-
服務ID與UUID映射表(如
BTA_HFP_SERVICE_ID
→UUID_SERVCLASS_AG_HANDSFREE
)支持快速擴展新服務,僅需修改映射邏輯。
通過服務掩碼與回調機制的協同,實現藍牙服務的動態啟用與上層應用的實時同步,為HID設備(如鍵盤、游戲手柄)的即插即用提供底層支持。