【Bluedroid】藍牙 HID DEVICE 初始化流程源碼解析

本文深入剖析Android藍牙協議棧中HID設備(BT-HD)服務的初始化與啟用流程,從接口初始化、服務掩碼管理、服務請求路由到屬性回調通知,完整展現藍牙HID服務激活的技術路徑。通過代碼邏輯梳理,揭示服務啟用的核心機制,包括服務狀態掩碼更新、跨模塊調用鏈及線程安全的屬性傳遞設計。

一、概述

藍牙 HID 設備(如鍵盤、鼠標)的服務啟用與狀態同步是藍牙協議棧的核心功能之一。整個流程涉及多個模塊協作,包括服務初始化、協議棧請求分發、屬性獲取及跨線程通知,具體可分為以下階段:

1.1 服務初始化與啟用

  1. 初始化接口:通過init函數完成 BT-HD 接口初始化,配置回調函數并調用btif_enable_service(BTA_HIDD_SERVICE_ID)啟用 HID 服務。

  2. 服務掩碼更新btif_enable_service將目標服務(BTA_HIDD_SERVICE_ID)添加到全局服務掩碼(btif_enabled_services),若藍牙已激活(btif_is_enabled()),則觸發服務啟用請求。

1.2 協議棧請求分發

  1. 服務請求執行btif_dm_enable_service調用btif_in_execute_service_request執行服務啟用請求。若成功,觸發屬性變更通知流程。

  2. 請求路由btif_in_execute_service_request根據服務類型分發請求:SDP 服務特殊處理,其他服務通過toggleProfile路由到具體服務模塊(如 HID 服務由btif_hd_execute_service處理)。

1.3 服務狀態同步與屬性通知

  1. 屬性填充與獲取

    1. 通過宏BTIF_STORAGE_FILL_PROPERTY初始化bt_property_t結構體,指定屬性類型(如BT_PROPERTY_UUIDS)。

    2. btif_storage_get_adapter_property根據屬性類型從控制器或存儲中獲取具體值(如藍牙地址、已配對設備列表、已啟用服務的 UUID 列表)。

  2. 跨線程回調通知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_IDUUID_SERVCLASS_AG_HANDSFREE)支持快速擴展新服務,僅需修改映射邏輯。

通過服務掩碼與回調機制的協同,實現藍牙服務的動態啟用與上層應用的實時同步,為HID設備(如鍵盤、游戲手柄)的即插即用提供底層支持。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/80621.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/80621.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/80621.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2025年項目管理軟件革命:中國技術主權與全球創新浪潮的交鋒

全球項目管理軟件市場正在經歷一場由多重技術疊加引發的結構性變革。根據Gartner最新預測&#xff0c;到2025年項目管理工具市場規模將突破220億美元&#xff0c;其中中國市場增速達38%&#xff0c;遠超全球平均水平。這場變革不僅關乎工具功能迭代&#xff0c;更深刻影響著企業…

計算機組成與體系結構:組相聯映射(Set-Associative Mapping)

目錄 &#x1f9e9; 映射方式問題回顧 &#x1f3d7;? 組相聯映射 工作流程 地址結構 ?? 替換策略 示例&#xff1a; 優點 ?? 與其他映射方式對比 &#x1f9e9; 映射方式問題回顧 直接映射的問題&#xff1a; 優點&#xff1a;實現簡單&#xff0c;查找速度快…

機器學習第八講:向量/矩陣 → 數據表格的數學表達,如Excel表格轉數字陣列

機器學習第八講&#xff1a;向量/矩陣 → 數據表格的數學表達&#xff0c;如Excel表格轉數字陣列 資料取自《零基礎學機器學習》。 查看總目錄&#xff1a;學習大綱 關于DeepSeek本地部署指南可以看下我之前寫的文章&#xff1a;DeepSeek R1本地與線上滿血版部署&#xff1a;…

基于Spring AI實現多輪對話系統架構設計

文章目錄 基于Spring AI實現多輪對話系統架構設計 前言 一、多輪對話系統核心架構 1.1 架構概覽 1.2 Spring AI核心優勢 二、ChatClient與多輪對話設計 2.1 ChatClient的特性與角色 2.2 實現多輪對話方法 三、Advisors攔截器機制 3.1 Advisors概念與工作原理 3.2 對…

C++中的虛表和虛表指針的原理和示例

一、基本概念 1. 什么是虛函數&#xff08;virtual function&#xff09;&#xff1f; 虛函數是用 virtual 關鍵字修飾的成員函數&#xff0c;支持運行時多態&#xff08;dynamic polymorphism&#xff09;。通過基類指針或引用調用派生類重寫的函數。 class Base { public:…

FPGA:XILINX FPGA產品線以及器件選型建議

本文將詳細介紹Xilinx&#xff08;現為AMD的一部分&#xff09;當前的FPGA產品線及其主要特點&#xff0c;并提供器件選型的建議。以下內容基于Xilinx FPGA的最新信息&#xff0c;涵蓋產品系列、特性及選型指導。由于Xilinx已被AMD收購&#xff0c;產品線以AMD Xilinx品牌為主&…

【C++】多線程和多進程

在C++中,多線程通信(同一進程內的線程間交互)和進程間通信(IPC,不同進程間的數據交換)是構建并發系統的核心技術。以下是兩種通信機制的詳細介紹和典型實現: 一、多線程通信(線程間同步與數據共享) 1. 共享內存與同步原語 通過全局變量或對象成員變量實現數據共享,…

PC Cleaner軟件,它能幫助用戶輕松清理和優化電腦,提升系統性能。

不用破解就能用&#xff01;這款超神的電腦清理 Pro 版&#xff0c;絕了&#xff01; 寶子們&#xff0c;我是你們的數碼小助手藍木云&#xff01;不知道大家有沒有這種感覺&#xff0c;電腦用久了&#xff0c;就像住久了沒打掃的屋子&#xff0c;越來越 “亂”&#xff0c;運…

linux中fork()函數的小問題

問題描述&#xff1a;分析下列代碼&#xff0c;分別能產生多少a // 1 for(int i0; i<3; i){ printf("a\n"); fork(); }// 2 for(int i0; i<3; i){ fork(); printf("a\n"); }// 3 for(int i0; i<3; i){ fork(); printf("a"); } fflus…

阿克曼-幻宇機器人系列教程2- 機器人交互實踐(Topic)

在上一篇文章中&#xff0c;我們介紹了兩種登錄機器人的方式&#xff0c;接下來我們介紹登錄機器人之后&#xff0c;我們如何通過topic操作命令實現與機器人的交互。 1. 啟動 & 獲取topic 在一個終端登錄樹莓派后&#xff0c;執行下列命令運行機器人 roslaunch huanyu_r…

51c嵌入式~電路~合集27

我自己的原文哦~ 一、7805應用電路 簡介 如上圖&#xff0c;7805 集成穩壓電路。 7805是串聯式三端穩壓器&#xff0c;三個端口分別是電壓輸入端&#xff08;IN&#xff09;&#xff0c;地線&#xff08;GND&#xff09;&#xff0c;穩壓輸出&#xff08;OUT&#xff09;…

Vitrualbox完美顯示系統界面(只需三步)

目錄 1.使用vitrualbox的增強功能&#xff1a;?編輯 2.安裝增強功能&#xff08;安裝完后要重啟虛擬機&#xff09;&#xff1a; 3. 調整界面尺寸&#xff08;如果一個選項不行的話&#xff0c;就多試試其他不同的百分比&#xff09;&#xff1a; 先看看原來的&#xff0c;…

2025年第十六屆藍橋杯軟件賽省賽C/C++大學A組個人解題

文章目錄 題目A題目C&#xff1a;抽獎題目D&#xff1a;紅黑樹題目E&#xff1a;黑客題目F&#xff1a;好串的數目 https://www.dotcpp.com/oj/train/1166/ 題目A 找到第2025個素數 #include <iostream> #include <vector> using namespace std; vector<i…

電機控制儲備知識學習(一) 電機驅動的本質分析以及與磁相關的使用場景

目錄 電機控制儲備知識學習&#xff08;一&#xff09;一、電機驅動的本質分析以及與磁相關的使用場景1&#xff09;電機為什么能夠旋轉2&#xff09;電磁原理的學習重要性 二、電磁學理論知識1&#xff09;磁場基礎知識2&#xff09;反電動勢的公式推導 附學習參考網址歡迎大家…

JMeter同步定時器 模擬多用戶并發訪問場景

同步定時器 JMter同步定時器的作用主要在于模擬多用戶并發訪問的場景&#xff0c;確保多個線程能夠同時執行某個操作&#xff0c;達到真正的并發效果。 當多個線程同時啟動時&#xff0c;它們可能會在不同的時間間隔內執行&#xff0c;這樣就無法達到真正的并發效果。&#xff…

C++11異步編程 --- async

C11異步編程 — async和future C11引入了async和future機制&#xff0c;用于簡化異步編程和并發操作。這兩個組件位于<future>頭文件中&#xff0c;提供了高級的異步任務管理接口。 一、async 1.定義 std::async std::async是一個函數模板&#xff0c;用于啟動一個異…

(七)深度學習---神經網絡原理與實現

分類問題回歸問題聚類問題各種復雜問題決策樹√線性回歸√K-means√神經網絡√邏輯回歸√嶺回歸密度聚類深度學習√集成學習√Lasso回歸譜聚類條件隨機場貝葉斯層次聚類隱馬爾可夫模型支持向量機高斯混合聚類LDA主題模型 一.神經網絡原理概述 二.神經網絡的訓練方法 三.基于Ker…

[Java實戰]Spring Boot 整合 Swagger2 (十六)

[Java實戰]Spring Boot 整合 Swagger2 &#xff08;十六&#xff09; 一、Swagger 的價值與痛點 為什么需要 API 文檔工具&#xff1f; 開發階段&#xff1a;前后端高效協作&#xff0c;實時驗證接口測試階段&#xff1a;提供標準化測試用例維護階段&#xff1a;降低新人理解…

系統穩定性之上線三板斧

&#x1f4d5;我是廖志偉&#xff0c;一名Java開發工程師、《Java項目實戰——深入理解大型互聯網企業通用技術》&#xff08;基礎篇&#xff09;、&#xff08;進階篇&#xff09;、&#xff08;架構篇&#xff09;清華大學出版社簽約作家、Java領域優質創作者、CSDN博客專家、…

題海拾貝:P1833 櫻花

Hello大家好&#xff01;很高興我們又見面啦&#xff01;給生活添點passion&#xff0c;開始今天的編程之路&#xff01; 我的博客&#xff1a;<但凡. 我的專欄&#xff1a;《編程之路》、《數據結構與算法之美》、《題海拾貝》、《C修煉之路》 歡迎點贊&#xff0c;關注&am…