【Bluedroid】藍牙協議棧控制器能力解析與核心功能配置機制(decode_controller_support)

本文圍繞Bluedroid藍牙協議棧中控制器能力解析與核心功能配置的關鍵代碼展開,詳細闡述藍牙協議棧如何通過解析控制器硬件能力,構建 SCO/eSCO、ACL 數據包類型支持掩碼,配置鏈路策略、安全服務、查詢與掃描模式等核心功能。這些機制確保協議棧能適配硬件能力,初始化關鍵模塊,為藍牙設備的通信兼容性、安全性和高效性奠定基礎。

一、概述

藍牙協議棧的正常運行依賴于對控制器硬件能力的精準解析和適配。本文涉及的代碼集中實現了這一過程,主要包含以下核心模塊:

1. 控制器能力解析(decode_controller_support 作為入口函數,負責初始化協議棧核心配置:

  • 采用分層掩碼構建策略,先檢測基礎HVx支持,再添加EDR擴展類型

  • 物理層能力動態影響掩碼組合(如2M/3M PHY支持)

  • 示例:HV3基礎語音需要5.6ms時序精度,EV5寬帶語音需1.25ms精度

  • 觸發 ACL 鏈路初始化、安全模塊重置、查詢模式與掃描模式配置等后續流程。

2. ACL 鏈路配置(BTM_acl_after_controller_started及關聯函數) 完成 ACL 鏈路的核心配置:

  • 鏈路策略四重檢查機制確保硬件兼容性

  • 時隙分配采用漸進式:1-slot → 3-slot → 5-slot

  • EDR物理層動態適配(2M PHY理論速率2.1Mbps,3M PHY達3.2Mbps)

3. 鏈路策略管理(btm_set_default_link_policycheck_link_policy 確保鏈路策略合法有效:

  • check_link_policy校驗策略與硬件能力的匹配性,自動禁用不支持的功能(如角色切換、嗅探模式);

  • 通過 HCI 命令將策略同步至控制器,保證軟件配置與硬件執行一致。

4. 安全服務注冊(BTM_SetSecurityLevelAddService 管理服務級安全策略:

  • 注冊服務的安全級別(加密、認證等),根據連接發起方 / 接收方差異化配置策略;

  • 校驗并修正安全級別,確保符合藍牙規范(如加密依賴認證、認證需防中間人攻擊),存儲安全記錄供后續決策。

5. 查詢與掃描模式配置(BTM_SetInquiryModeBTM_EnableInterlacedPageScan等) 優化設備發現與連接可達性:

  • 配置查詢模式(標準、帶 RSSI、擴展),根據控制器能力選擇支持的模式;

  • 啟用交錯式頁面掃描與查詢掃描,平衡被發現概率與功耗,通過 HCI 命令同步模式至控制器。

二、源碼解析

decode_controller_support

modules/Bluetooth/system/stack/btm/btm_devctl.cc
static void decode_controller_support() {// 1. SCO/eSCO 數據包類型解析/* Create (e)SCO supported packet types mask */btm_cb.btm_sco_pkt_types_supported = 0;btm_cb.sco_cb.esco_supported = false;if (bluetooth::shim::GetController()->SupportsSco()) {btm_cb.btm_sco_pkt_types_supported = ESCO_PKT_TYPES_MASK_HV1;if (bluetooth::shim::GetController()->SupportsHv2Packets())btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_HV2;if (bluetooth::shim::GetController()->SupportsHv3Packets())btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_HV3;}// 2. eSCO 高級特性支持if (bluetooth::shim::GetController()->SupportsEv3Packets())btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_EV3;if (bluetooth::shim::GetController()->SupportsEv4Packets())btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_EV4;if (bluetooth::shim::GetController()->SupportsEv5Packets())btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_EV5;// 3. EDR 物理層相關配置if (btm_cb.btm_sco_pkt_types_supported & BTM_ESCO_LINK_ONLY_MASK) {btm_cb.sco_cb.esco_supported = true;/* Add in EDR related eSCO types */if (bluetooth::shim::GetController()->SupportsEsco2mPhy()) {if (!bluetooth::shim::GetController()->Supports3SlotEdrPackets())btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_NO_2_EV5;} else {btm_cb.btm_sco_pkt_types_supported |=(ESCO_PKT_TYPES_MASK_NO_2_EV3 + ESCO_PKT_TYPES_MASK_NO_2_EV5);}if (bluetooth::shim::GetController()->SupportsEsco3mPhy()) {if (!bluetooth::shim::GetController()->Supports3SlotEdrPackets())btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_NO_3_EV5;} else {btm_cb.btm_sco_pkt_types_supported |=(ESCO_PKT_TYPES_MASK_NO_3_EV3 + ESCO_PKT_TYPES_MASK_NO_3_EV5);}}log::verbose("Local supported SCO packet types: 0x{:04x}",btm_cb.btm_sco_pkt_types_supported);// 4. 啟動 ACL 連接管理模塊并重置安全設備狀態BTM_acl_after_controller_started(controller_get_interface());btm_sec_dev_reset();// 5. 掃描模式與高級功能配置if (bluetooth::shim::GetController()->SupportsRssiWithInquiryResults()) {if (bluetooth::shim::GetController()->SupportsExtendedInquiryResponse())BTM_SetInquiryMode(BTM_INQ_RESULT_EXTENDED);elseBTM_SetInquiryMode(BTM_INQ_RESULT_WITH_RSSI);}l2cu_set_non_flushable_pbf(bluetooth::shim::GetController()->SupportsNonFlushablePb());BTM_EnableInterlacedPageScan();BTM_EnableInterlacedInquiryScan();
}

解析和配置控制器支持功能的核心邏輯,主要完成 SCO/eSCO 數據包類型的掩碼構建及相關功能的初始化配置。核心職責是:

  1. 根據藍牙控制器能力,構建支持的 SCO/eSCO 數據包類型掩碼

  2. 初始化藍牙 ACL 連接、安全管理和掃描模式

  3. 配置與控制器能力相關的其他參數

BTM_acl_after_controller_started

packages/modules/Bluetooth/system/stack/acl/btm_acl.cc
void BTM_acl_after_controller_started(const controller_t* controller) {// 1. 默認鏈路策略配置internal_.btm_set_default_link_policy(HCI_ENABLE_CENTRAL_PERIPHERAL_SWITCH | HCI_ENABLE_HOLD_MODE |HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE);// 2. ACL 數據包類型掩碼構建/* Create ACL supported packet types mask */uint16_t btm_acl_pkt_types_supported =(HCI_PKT_TYPES_MASK_DH1 + HCI_PKT_TYPES_MASK_DM1); // 默認支持單時隙數據包 (DH1/DM1)if (bluetooth::shim::GetController()->Supports3SlotPackets())btm_acl_pkt_types_supported |=(HCI_PKT_TYPES_MASK_DH3 + HCI_PKT_TYPES_MASK_DM3);if (bluetooth::shim::GetController()->Supports5SlotPackets())btm_acl_pkt_types_supported |=(HCI_PKT_TYPES_MASK_DH5 + HCI_PKT_TYPES_MASK_DM5);// 3. EDR 物理層相關配置/* Add in EDR related ACL types */if (!bluetooth::shim::GetController()->SupportsClassic2mPhy()) {btm_acl_pkt_types_supported |=(HCI_PKT_TYPES_MASK_NO_2_DH1 + HCI_PKT_TYPES_MASK_NO_2_DH3 +HCI_PKT_TYPES_MASK_NO_2_DH5);}if (!bluetooth::shim::GetController()->SupportsClassic3mPhy()) {btm_acl_pkt_types_supported |=(HCI_PKT_TYPES_MASK_NO_3_DH1 + HCI_PKT_TYPES_MASK_NO_3_DH3 +HCI_PKT_TYPES_MASK_NO_3_DH5);}// 4. 時隙與速率組合檢查/* Check to see if 3 and 5 slot packets are available */if (bluetooth::shim::GetController()->SupportsClassic2mPhy() ||bluetooth::shim::GetController()->SupportsClassic3mPhy()) {if (!bluetooth::shim::GetController()->Supports3SlotEdrPackets())btm_acl_pkt_types_supported |=(HCI_PKT_TYPES_MASK_NO_2_DH3 + HCI_PKT_TYPES_MASK_NO_3_DH3);if (!bluetooth::shim::GetController()->Supports5SlotEdrPackets())btm_acl_pkt_types_supported |=(HCI_PKT_TYPES_MASK_NO_2_DH5 + HCI_PKT_TYPES_MASK_NO_3_DH5);}// 5. 設置默認支持類型internal_.set_default_packet_types_supported(btm_acl_pkt_types_supported);
}

ACL (Asynchronous Connection-Less) 鏈路初始化的核心邏輯,主要完成 ACL 數據包類型掩碼的構建和默認鏈路策略的配置。核心職責是:

  1. 配置藍牙 ACL 鏈路的默認鏈路策略參數

  2. 根據控制器能力,構建支持的 ACL 數據包類型掩碼

  3. 將構建的掩碼設置為系統默認支持的數據包類型

數據包類型說明:

  • DHx:高數據率非加密數據包

  • DMx:中等數據率加密數據包

  • 數字后綴表示時隙數,更多時隙意味著更高吞吐量

btm_set_default_link_policy
packages/modules/Bluetooth/system/stack/acl/btm_acl.cc
void StackAclBtmAcl::btm_set_default_link_policy(tLINK_POLICY settings) {check_link_policy(&settings);btm_cb.acl_cb_.btm_def_link_policy = settings;btsnd_hcic_write_def_policy_set(settings);
}

設置和管理藍牙設備的默認鏈路行為模式。核心職責是:

  1. 驗證傳入的鏈路策略參數合法性

  2. 更新本地鏈路策略配置

  3. 向BTC發送命令以同步鏈路策略設置

check_link_policy

packages/modules/Bluetooth/system/stack/acl/btm_acl.cc
typedef uint16_t tLINK_POLICY;static void check_link_policy(tLINK_POLICY* settings) {// 1. 角色切換功能檢查if ((*settings & HCI_ENABLE_CENTRAL_PERIPHERAL_SWITCH) &&(!bluetooth::shim::GetController()->SupportsRoleSwitch())) {*settings &= (~HCI_ENABLE_CENTRAL_PERIPHERAL_SWITCH);log::info("Role switch not supported (settings: 0x{:04x})", *settings);}// 2. 保持模式功能檢查if ((*settings & HCI_ENABLE_HOLD_MODE) &&(!bluetooth::shim::GetController()->SupportsHoldMode())) {*settings &= (~HCI_ENABLE_HOLD_MODE);log::info("hold not supported (settings: 0x{:04x})", *settings);}// 3. 嗅探模式功能檢查if ((*settings & HCI_ENABLE_SNIFF_MODE) &&(!bluetooth::shim::GetController()->SupportsSniffMode())) {*settings &= (~HCI_ENABLE_SNIFF_MODE);log::info("sniff not supported (settings: 0x{:04x})", *settings);}// 4. 駐留模式功能檢查if ((*settings & HCI_ENABLE_PARK_MODE) &&(!bluetooth::shim::GetController()->SupportsParkMode())) {*settings &= (~HCI_ENABLE_PARK_MODE);log::info("park not supported (settings: 0x{:04x})", *settings);}
}

根據底層硬件能力動態調整上層配置參數,確保系統不會嘗試啟用硬件不支持的功能。核心職責是

  1. 驗證每個鏈路策略設置是否與硬件能力匹配

  2. 自動禁用硬件不支持的鏈路策略選項

Hold模式原理:

  • 臨時降低連接頻率(如從 125ms 降低到 2s)

  • 保持 L2CAP 信道打開,無需重新協商參數

  • 適用于臨時無數據傳輸的場景(如音樂暫停)

駐留模式特性:

  • 設備進入深度睡眠狀態

  • 僅監聽特定喚醒信號(如特定 MAC 地址的分組)

  • 喚醒時間較長(典型值:10-50ms)

嗅探模式優化點:

  • 典型嗅探間隔:100ms-1.28s

  • 喚醒時間:<1ms(硬件特定)

  • 數據吞吐量與功耗的平衡公式:

Power_Saving = (1 - Sniff_Interval / Connection_Interval) * 100%

btsnd_hcic_write_def_policy_set

packages/modules/Bluetooth/system/stack/hcic/hcicmds.cc
void btsnd_hcic_write_def_policy_set(uint16_t settings) {BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);uint8_t* pp = (uint8_t*)(p + 1);p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET;p->offset = 0;UINT16_TO_STREAM(pp, HCI_WRITE_DEF_POLICY_SETTINGS);UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET);UINT16_TO_STREAM(pp, settings);btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}

將上層配置的鏈路策略設置通過 HCI 命令下發到藍牙控制器硬件。封裝 HCI 層 “設置默認鏈路策略” 命令,并發送給藍牙控制器,使上層配置的鏈路策略(如嗅探模式、角色切換等)在硬件層面生效。

HCI Write Default Link Policy Settings:

set_default_packet_types_supported
packages/modules/Bluetooth/system/stack/acl/btm_acl.cc
void set_default_packet_types_supported(uint16_t packet_types_supported) {btm_cb.acl_cb_.btm_acl_pkt_types_supported = packet_types_supported;
}

將經過硬件能力校驗、組合構建后的 ACL 數據包類型支持掩碼,持久化存儲到全局狀態中,作為后續藍牙連接協商的 “本地能力基準”。

btm_sec_dev_reset

packages/modules/Bluetooth/system/stack/btm/btm_sec.cc
/********************************************************************************* Function         btm_sec_dev_reset** Description      This function should be called after device reset** Returns          void*******************************************************************************/
void btm_sec_dev_reset(void) {ASSERT_LOG(bluetooth::shim::GetController()->SupportsSimplePairing(),"only controllers with SSP is supported");/* set the default IO capabilities */btm_sec_cb.devcb.loc_io_caps = btif_storage_get_local_io_caps();// 配置 RFCOMM 多路復用層的安全等級/* add mx service to use no security */BTM_SetSecurityLevel(false, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX,BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0);BTM_SetSecurityLevel(true, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX, BTM_SEC_NONE,BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0);log::verbose("btm_sec_dev_reset sec mode: {}", btm_sec_cb.security_mode);
}

在設備重置后調用,初始化安全模塊的設備相關狀態。藍牙設備重置(如控制器重啟、協議棧初始化)后,安全上下文(如配對信息、密鑰存儲、安全策略)需重新初始化,此函數正是這一過程的關鍵步驟,確保安全模塊從 “干凈狀態” 開始工作。

btif_storage_get_local_io_caps單獨分析。

BTM_SetSecurityLevel

packages/modules/Bluetooth/system/stack/btm/btm_sec.cc
/********************************************************************************* Function         BTM_SetSecurityLevel** Description      Register service security level with Security Manager** Parameters:      is_originator - true if originating the connection*                  p_name      - Name of the service relevant only if*                                authorization will show this name to user.*                                Ignored if BT_MAX_SERVICE_NAME_LEN is 0.*                  service_id  - service ID for the service passed to*                                authorization callback*                  sec_level   - bit mask of the security features*                  psm         - L2CAP PSM*                  mx_proto_id - protocol ID of multiplexing proto below*                  mx_chan_id  - channel ID of multiplexing proto below** Returns          true if registered OK, else false*******************************************************************************/
bool BTM_SetSecurityLevel(bool is_originator, const char* p_name,uint8_t service_id, uint16_t sec_level, uint16_t psm,uint32_t mx_proto_id, uint32_t mx_chan_id) {return btm_sec_cb.AddService(is_originator, p_name, service_id, sec_level,psm, mx_proto_id, mx_chan_id);
}

向安全管理器注冊服務的安全級別。藍牙協議棧中,不同服務(如 A2DP 音頻、HID 鍵盤、SPP 串口)的安全需求差異極大(例如:音頻需加密防竊聽,簡單傳感器數據可能無需安全)。此函數通過 “注冊” 機制,讓安全管理器提前知曉各服務的安全要求,從而在連接或數據傳輸時自動強制執行相應的安全措施(如要求加密、認證)。

AddService

packages/modules/Bluetooth/system/stack/btm/btm_sec_cb.cc
#define BTM_NO_AVAIL_SEC_SERVICES ((uint16_t)0xffff)
bool tBTM_SEC_CB::AddService(bool is_originator, const char* p_name,uint8_t service_id, uint16_t sec_level,uint16_t psm, uint32_t mx_proto_id,uint32_t mx_chan_id) {// 1. 服務記錄的查找與分配(資源管理)tBTM_SEC_SERV_REC* p_srec;uint16_t index;uint16_t first_unused_record = BTM_NO_AVAIL_SEC_SERVICES;bool record_allocated = false;log::verbose("sec_level:0x{:x}", sec_level);/* See if the record can be reused (same service name, psm, mx_proto_id,service_id, and mx_chan_id), or obtain the next unused record */p_srec = &sec_serv_rec[0];// 遍歷所有記錄,查找重復或分配新記錄for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++) {/* Check if there is already a record for this service */if (p_srec->security_flags & BTM_SEC_IN_USE) { // 記錄已使用// 檢查是否為重復服務(PSM、協議ID、服務ID、名稱匹配)if (p_srec->psm == psm && p_srec->mx_proto_id == mx_proto_id &&service_id == p_srec->service_id && p_name &&(!strncmp(p_name, (char*)p_srec->orig_service_name,/* strlcpy replaces end char with termination char*/BT_MAX_SERVICE_NAME_LEN - 1) ||!strncmp(p_name, (char*)p_srec->term_service_name,/* strlcpy replaces end char with termination char*/BT_MAX_SERVICE_NAME_LEN - 1))) {record_allocated = true; // 復用重復記錄break;}}/* Mark the first available service record */else if (!record_allocated) { // 記錄未使用,分配第一條可用記錄*p_srec = {}; // 清空舊數據record_allocated = true;first_unused_record = index;}}// 記錄耗盡時返回失敗if (!record_allocated) {log::warn("Out of Service Records ({})", BTM_SEC_MAX_SERVICE_RECORDS);return (record_allocated);}/* Process the request if service record is valid *//* If a duplicate service wasn't found, use the first available */if (index >= BTM_SEC_MAX_SERVICE_RECORDS) {index = first_unused_record;p_srec = &sec_serv_rec[index];}p_srec->psm = psm;p_srec->service_id = service_id;p_srec->mx_proto_id = mx_proto_id;// 2. 區分 “發起方” 與 “接收方” 的安全策略if (is_originator) {p_srec->orig_mx_chan_id = mx_chan_id; // 記錄發起方的多路復用通道IDstrlcpy((char*)p_srec->orig_service_name, p_name,BT_MAX_SERVICE_NAME_LEN + 1); // 存儲服務名稱// 清除舊的outgoing安全標志,避免干擾新設置/* clear out the old setting, just in case it exists */{p_srec->security_flags &=~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);}// 參數校驗:發起方不能設置incoming的安全要求(避免越權)/* Parameter validation.  Originator should not set requirements for* incoming connections */sec_level &= ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE |BTM_SEC_IN_MITM | BTM_SEC_IN_MIN_16_DIGIT_PIN);// 安全模式適配:SP(Simple Pairing)或SC(Secure Connections)模式下,認證需包含防中間人(MITM)if (security_mode == BTM_SEC_MODE_SP || security_mode == BTM_SEC_MODE_SC) {if (sec_level & BTM_SEC_OUT_AUTHENTICATE) sec_level |= BTM_SEC_OUT_MITM;}// 加密必須依賴認證(藍牙規范強制:加密密鑰生成需基于認證結果)/* Make sure the authenticate bit is set, when encrypt bit is set */if (sec_level & BTM_SEC_OUT_ENCRYPT) sec_level |= BTM_SEC_OUT_AUTHENTICATE;/* outgoing connections usually set the security level right before* the connection is initiated.* set it to be the outgoing service */p_out_serv = p_srec;} else {p_srec->term_mx_chan_id = mx_chan_id; // 記錄接收方的多路復用通道IDstrlcpy((char*)p_srec->term_service_name, p_name,BT_MAX_SERVICE_NAME_LEN + 1); // 存儲服務名稱// 清除舊的incoming安全標志/* clear out the old setting, just in case it exists */{p_srec->security_flags &=~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |BTM_SEC_IN_MIN_16_DIGIT_PIN);}// 參數校驗:接收方不能設置outgoing的安全要求/* Parameter validation.  Acceptor should not set requirements for outgoing* connections */sec_level &=~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);// 安全模式適配:SP/SC模式下,incoming認證需包含MITMif (security_mode == BTM_SEC_MODE_SP || security_mode == BTM_SEC_MODE_SC) {if (sec_level & BTM_SEC_IN_AUTHENTICATE) sec_level |= BTM_SEC_IN_MITM;}// 加密必須依賴認證(同發起方邏輯)/* Make sure the authenticate bit is set, when encrypt bit is set */if (sec_level & BTM_SEC_IN_ENCRYPT) sec_level |= BTM_SEC_IN_AUTHENTICATE;}// 3. 安全記錄的最終生效p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);log::debug("[{}]: id:{}, is_orig:{} psm:0x{:04x} proto_id:{} chan_id:{}  : ""sec:0x{:x} service_name:[{}] (up to {} chars saved)",index, service_id, logbool(is_originator).c_str(), psm, mx_proto_id,mx_chan_id, p_srec->security_flags, p_name, BT_MAX_SERVICE_NAME_LEN);return (record_allocated);
}

將服務的安全需求轉化為可執行的安全記錄,并確保策略符合藍牙安全規范與硬件能力。核心職責是:

  1. 管理有限的安全服務記錄資源(sec_serv_rec),處理重復注冊或新記錄分配。

  2. 根據服務是 “連接發起方” 還是 “接收方”,差異化設置安全策略(如 outgoing/incoming 安全標志)。

  3. 校驗并修正安全級別(sec_level),確保其符合藍牙安全規范(如加密必須依賴認證、認證需包含防中間人攻擊)。

  4. 將最終的安全策略存入服務記錄,為后續安全決策(如連接加密、認證)提供依據。

BTM_SetInquiryMode

packages/modules/Bluetooth/system/stack/btm/btm_inq.cc
/********************************************************************************* Function         BTM_SetInquiryMode** Description      This function is called to set standard or with RSSI*                  mode of the inquiry for local device.** Output Params:   mode - standard, with RSSI, extended** Returns          BTM_SUCCESS if successful*                  BTM_NO_RESOURCES if couldn't get a memory pool buffer*                  BTM_ILLEGAL_VALUE if a bad parameter was detected*                  BTM_WRONG_MODE if the device is not up.*******************************************************************************/
tBTM_STATUS BTM_SetInquiryMode(uint8_t mode) {log::verbose("");if (mode == BTM_INQ_RESULT_STANDARD) {/* 標準模式是藍牙規范強制要求的,所有控制器必須支持,無需額外檢查 *//* mandatory mode */} else if (mode == BTM_INQ_RESULT_WITH_RSSI) {if (!bluetooth::shim::GetController()->SupportsRssiWithInquiryResults())return (BTM_MODE_UNSUPPORTED);} else if (mode == BTM_INQ_RESULT_EXTENDED) {if (!bluetooth::shim::GetController()->SupportsExtendedInquiryResponse())return (BTM_MODE_UNSUPPORTED);} elsereturn (BTM_ILLEGAL_VALUE);if (!BTM_IsDeviceUp()) return (BTM_WRONG_MODE);btsnd_hcic_write_inquiry_mode(mode);return (BTM_SUCCESS);
}

設置本地設備在查詢過程中返回的結果模式(標準、帶 RSSI、擴展),直接影響設備發現時能獲取的信息粒度。從藍牙設備發現流程和協議棧實現視角,核心職責是:

  1. 驗證查詢模式(mode)的合法性,確保其符合藍牙規范和硬件能力。

  2. 檢查設備狀態(是否已啟動),確保配置在有效場景下執行。

  3. 通過 HCI 命令將查詢模式下發到BTC,使配置生效,為后續的設備查詢(Inquiry)提供結果格式依據。

藍牙查詢(Inquiry)是設備主動發現周圍藍牙設備的過程,不同模式決定了查詢結果包含的信息類型。函數支持 3 種模式,對應不同的信息粒度:

模式常量含義與信息范圍應用場景
BTM_INQ_RESULT_STANDARD標準模式(藍牙規范強制支持),僅返回設備地址(BD_ADDR)和設備類型(如 BR/EDR、LE)。基礎設備發現(僅需知道 “附近有哪些設備”),如簡單的藍牙掃描工具。
BTM_INQ_RESULT_WITH_RSSI帶 RSSI(接收信號強度指示)的模式,在標準信息基礎上增加信號強度值(單位:dBm)。需要估算設備距離的場景(如 “靠近解鎖”:RSSI 值越強,距離越近)。
BTM_INQ_RESULT_EXTENDED擴展模式,返回標準信息 + RSSI + 擴展查詢響應(EIR,如設備名稱、服務 UUID、廠商數據)。精細化設備發現(如 “顯示附近設備的名稱和支持的服務”),如手機藍牙列表顯示設備名。

btsnd_hcic_write_inquiry_mode

packages/modules/Bluetooth/system/stack/hcic/hcicmds.cc
void btsnd_hcic_write_inquiry_mode(uint8_t mode) {BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);uint8_t* pp = (uint8_t*)(p + 1);p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;p->offset = 0;UINT16_TO_STREAM(pp, HCI_WRITE_INQUIRY_MODE);UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);UINT8_TO_STREAM(pp, mode);btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}

將上層設置的 “查詢模式”(如標準模式、帶 RSSI 模式、擴展模式)封裝為 HCI 協議格式的命令,并下發到藍牙控制器硬件。

HCI Write Inquiry Mode:

【0x0045】HCI_Write_Inquiry_Mode詳解_hci mode-CSDN博客

l2cu_set_non_flushable_pbf

packages/modules/Bluetooth/system/stack/l2cap/l2c_utils.cc
/******************************************************************************** Function         l2cu_set_non_flushable_pbf** Description      set L2CAP_PKT_START_NON_FLUSHABLE if controller supoorts** Returns          void*******************************************************************************/
void l2cu_set_non_flushable_pbf(bool is_supported) {if (is_supported)l2cb.non_flushable_pbf =(L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT);elsel2cb.non_flushable_pbf = (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT);
}

根據藍牙控制器是否支持 “非可刷新數據包處理能力”,動態配置 L2CAP 層的數據包邊界標志(PBF,Packet Boundary Flag),為非可刷新鏈路的數據傳輸提供正確的協議標識。

在藍牙中,“非可刷新鏈路”(Non-Flushable Link)用于傳輸對實時性要求極高的數據(如 SCO/eSCO 語音數據),這類數據不允許被控制器緩存或延遲發送(否則會導致語音卡頓、控制指令延遲)。而 PBF 是 L2CAP 數據包頭部的關鍵標志位,用于告知控制器 “該數據包的邊界類型”(如 “新數據包起始”“續傳包” 等)。

藍牙鏈路分為 “可刷新”(Flushable)和 “非可刷新”(Non-Flushable)兩類,其差異直接影響數據傳輸的實時性:

鏈路類型特點應用場景PBF 標志來源
可刷新鏈路允許控制器緩存、延遲發送,擁塞時可丟棄文件傳輸、消息推送普通標志(L2CAP_PKT_START)
非可刷新鏈路禁止緩存,必須立即傳輸,不可丟棄語音通話(SCO/eSCO)、實時控制非可刷新標志(L2CAP_PKT_START_NON_FLUSHABLE)

BTM_EnableInterlacedPageScan

packages/modules/Bluetooth/system/stack/btm/btm_inq.cc
#ifndef PROPERTY_PAGE_SCAN_TYPE
#define PROPERTY_PAGE_SCAN_TYPE "bluetooth.core.classic.page_scan_type"
#endifvoid BTM_EnableInterlacedPageScan() {log::verbose("");// 1. 獲取系統配置的page scan類型uint16_t page_scan_type =osi_property_get_int32(PROPERTY_PAGE_SCAN_TYPE, BTM_SCAN_TYPE_INTERLACED);// 2. 啟用條件校驗if (!bluetooth::shim::GetController()->SupportsInterlacedInquiryScan() ||page_scan_type != BTM_SCAN_TYPE_INTERLACED ||btm_cb.btm_inq_vars.page_scan_type == BTM_SCAN_TYPE_INTERLACED) {return;}// 3. 啟用交錯式掃描并更新狀態btsnd_hcic_write_pagescan_type(BTM_SCAN_TYPE_INTERLACED);btm_cb.btm_inq_vars.page_scan_type = BTM_SCAN_TYPE_INTERLACED;
}

根據控制器硬件能力、系統配置和當前狀態,決定是否啟用交錯式pagescan模式,并通過 HCI 命令將模式設置到硬件,同時更新協議棧狀態。

Page Scan是藍牙設備的核心工作模式之一:當設備需要被其他設備發現并建立連接時(如耳機等待手機連接),會周期性地進入 “page scan窗口”,監聽來自其他設備的 “Page Request”。而 “交錯式(Interlaced)” 是Page Scan的一種優化類型,通過特殊的時序設計(如交替的掃描間隔和窗口),在 “被連接概率” 和 “功耗” 之間取得平衡(相比其他模式,交錯式能在相同功耗下提升被連接的成功率)。

btsnd_hcic_write_pagescan_type

packages/modules/Bluetooth/system/stack/hcic/hcicmds.cc
#define HCI_WRITE_PAGESCAN_TYPE (0x0047 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10) /* 0x0C00 */void btsnd_hcic_write_pagescan_type(uint8_t type) {BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);uint8_t* pp = (uint8_t*)(p + 1);p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;p->offset = 0;UINT16_TO_STREAM(pp, HCI_WRITE_PAGESCAN_TYPE);UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);UINT8_TO_STREAM(pp, type);btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}

封裝 HCI 層 “Write Page Scan Type” 命令(Opcode:0x0C47),將page scan類型參數打包為控制器可識別的二進制命令,并發送到本地經典藍牙(BR/EDR)控制器,使page scan模式在硬件層面生效。

HCI Write Page Scan Type:

【0x0047】HCI_Write_Page_Scan_Type詳解_hci write page scan type (type=interlaced)-CSDN博客

藍牙page scan有三種基本類型(定義于 HCI 規范),其核心差異在于掃描時序(間隔和窗口):

掃描類型時序特點功耗與響應速度平衡適用場景
標準(Standard)固定間隔(如 1.28s)和窗口(如 11.25ms),周期性掃描響應速度中等,功耗中等通用設備(如藍牙音箱)
交錯式(Interlaced)采用兩組交替的間隔 / 窗口(如短間隔 + 短窗口 與 長間隔 + 長窗口交替),提升被掃描到的概率響應速度接近標準模式,功耗略低于標準模式移動設備(如耳機、智能手表)
重復(Repeated)短間隔(如 31.25ms)和短窗口,高頻掃描響應速度最快,功耗最高實時性要求高的設備(如醫療設備)

BTM_EnableInterlacedInquiryScan

packages/modules/Bluetooth/system/stack/btm/btm_inq.cc
void BTM_EnableInterlacedInquiryScan() {log::verbose("");// 1. 獲取系統配置的查詢掃描類型uint16_t inq_scan_type =osi_property_get_int32(PROPERTY_INQ_SCAN_TYPE, BTM_SCAN_TYPE_INTERLACED);// 2. 啟用條件校驗if (!bluetooth::shim::GetController()->SupportsInterlacedInquiryScan() ||inq_scan_type != BTM_SCAN_TYPE_INTERLACED ||btm_cb.btm_inq_vars.inq_scan_type == BTM_SCAN_TYPE_INTERLACED) {return;}// 3. 啟用交錯式掃描并更新狀態btsnd_hcic_write_inqscan_type(BTM_SCAN_TYPE_INTERLACED);btm_cb.btm_inq_vars.inq_scan_type = BTM_SCAN_TYPE_INTERLACED;
}

根據控制器硬件能力、系統配置和當前狀態,決定是否啟用交錯式查詢掃描模式,并通過 HCI 命令將模式設置到硬件,同時更新協議棧狀態。

Inquiry Scan) 是藍牙設備主動發現周圍其他設備的核心機制:當設備需要搜索附近藍牙設備時(如手機點擊 “掃描” 按鈕),會周期性地發送 Inquiry Request,并在特定窗口監聽其他設備的 Inquiry Response。而 “交錯式(Interlaced)” 是查詢掃描的一種優化類型,通過特殊的時序設計(如交替的掃描間隔和窗口),在 “發現效率” 和 “功耗” 之間取得平衡。

btsnd_hcic_write_inqscan_type

packages/modules/Bluetooth/system/stack/hcic/hcicmds.cc
#define HCI_WRITE_INQSCAN_TYPE (0x0043 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10) /* 0x0C00 */void btsnd_hcic_write_inqscan_type(uint8_t type) {BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);uint8_t* pp = (uint8_t*)(p + 1);p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;p->offset = 0;UINT16_TO_STREAM(pp, HCI_WRITE_INQSCAN_TYPE);UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);UINT8_TO_STREAM(pp, type);btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}

封裝 HCI 層 “Write Inquiry Scan Type” 命令(Opcode:0x0C43),將Inquiry Scan 類型參數打包為控制器可識別的二進制命令,并發送到本地經典藍牙(BR/EDR)控制器,使查詢掃描模式在硬件層面生效。

HCI Write Inquiry Scan Type:

【0x0043】HCI_Write_Inquiry_Scan_Type詳解_hci write inquiry scan type (type=interlaced)-CSDN博客

藍牙查詢掃描有三種基本類型(定義于 HCI 規范),其核心差異在于掃描時序(間隔和窗口):

掃描類型時序特點功耗與發現效率平衡適用場景
標準(Standard)固定間隔(如 1.28s)和窗口(如 11.25ms),周期性發送查詢請求發現效率中等,功耗中等通用掃描(如手機日常掃描)
交錯式(Interlaced)采用兩組交替的間隔 / 窗口(如短間隔 + 短窗口 與 長間隔 + 長窗口交替),覆蓋更多頻率范圍發現效率接近標準模式,功耗略低于標準模式移動設備(如耳機配對場景)
增強(Enhanced)動態調整間隔和窗口,根據信號質量優化掃描策略發現效率最高,功耗較高

交錯式的核心優勢是通過 “交替時序” 覆蓋更多頻率范圍:藍牙工作在 2.4GHz ISM 頻段,存在多個信道,交錯式掃描通過交替使用不同的頻率組合,降低因信道干擾導致的掃描失敗概率,提升發現效率(尤其在復雜電磁環境中)。

三、流程圖

藍牙協議棧的控制器能力解析與核心功能配置機制體現了三層設計思想:

  1. 硬件適配層:通過bluetooth::shim::GetController()接口抽象硬件能力,確保協議棧與不同控制器兼容;

  2. 策略校驗層:通過check_link_policy、安全級別修正等邏輯,保證配置符合硬件能力與藍牙規范,避免非法操作;

  3. 功能執行層:通過 HCI 命令(如btsnd_hcic_write_inquiry_mode)將軟件配置同步至硬件,實現功能落地。

各模塊協同工作,從控制器能力解析到鏈路、安全、掃描等功能初始化,構建了完整的協議棧啟動流程,確保藍牙設備能高效、安全地與其他設備通信,同時平衡功耗與性能。


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

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

相關文章

小架構step系列07:查找日志配置文件

1 概述 日志這里采用logback&#xff0c;其為springboot默認的日志工具。其整體已經被springboot封裝得比較好了&#xff0c;扔個配置文件到classpath里就能夠使用。 但在實際使用中&#xff0c;日志配置文件有可能需要進行改動&#xff0c;比如日志的打印級別&#xff0c;平…

一文講清楚React Hooks

文章目錄一文講清楚React Hooks一、什么是 React Hooks&#xff1f;二、常用基礎 Hooks2.1 useState&#xff1a;狀態管理基本用法特點2.2 useEffect&#xff1a;副作用處理基本用法依賴數組說明2.3 useContext&#xff1a;上下文共享基本用法特點三、其他常用 Hooks3.1 useRed…

Apache http 強制 https

1. 修改一下文件配置 sudo nano /etc/apache2/sites-enabled/000-default.conf<VirtualHost *:80>ServerName hongweizhu.comServerAlias www.hongweizhu.comServerAdmin webmasterlocalhostDocumentRoot /var/www/html# 強制重定向到HTTPSRewriteEngine OnRewriteCond …

【讀代碼】GLM-4.1V-Thinking:開源多模態推理模型的創新實踐

一、基本介紹 1.1 項目背景 GLM-4.1V-Thinking是清華大學KEG實驗室推出的新一代開源視覺語言模型,基于GLM-4-9B-0414基礎模型構建。該項目通過引入"思維范式"和強化學習課程采樣(RLCS)技術,顯著提升了模型在復雜任務中的推理能力。其創新點包括: 64k超長上下文…

從代碼生成到智能運維的革命性變革

AI大模型重塑軟件開發&#xff1a;從代碼生成到智能運維的革命性變革 希望對大家有一定的幫助&#xff0c;進行參考 目錄AI大模型重塑軟件開發&#xff1a;從代碼生成到智能運維的革命性變革 希望對大家有一定的幫助&#xff0c;進行參考一、范式轉移&#xff1a;軟件開發進入&…

豆包編寫Java程序小試

今天下載了一本第四版電氣工程師手冊&#xff0c;非常棒的一本書&#xff0c;在給PDF添加目錄的時候&#xff0c;由于目錄有將近60頁&#xff0c;使用老馬開發的PdgCntEditor有點卡頓&#xff0c;不過補充下&#xff0c;老馬這個PdgCntEditor還是非常好的。所以我決定用Java編一…

SpringBoot整合騰訊云新一代行為驗證碼

一 產品介紹 騰訊云官方介紹鏈接 騰訊云新一代行為驗證碼&#xff08;Captcha&#xff09;&#xff0c;基于十道安全防護策略&#xff0c;為網頁、App、小程序開發者打造立體、全面的人機驗證。在保護注冊登錄、活動秒殺、點贊發帖、數據保護等各大場景下業務安全的同時&…

SenseGlove新一代外骨骼力反饋手套Rembrand來襲!亞毫米級手部動捕+指尖觸覺力采集+5Dof主動力反饋多模態

在遠程機器人操作領域&#xff0c;精準的觸覺感知與靈活的動作控制始終是核心需求。SenseGlove 新推出的 Rembrandt 力反饋外骨骼數據手套&#xff0c;以先進技術為支撐&#xff0c;為遠程操控人形機器人手部提供了無縫解決方案&#xff0c;讓操作更精準、更高效。值得一提的是…

Linux 信號機制:操作系統的“緊急電話”系統

想象一下&#xff0c;你正在電腦前專心工作&#xff0c;突然手機響了——這是一個通知&#xff0c;要求你立即處理一件新事情&#xff08;比如接電話&#xff09;。 Linux 系統中的信號&#xff08;Signal&#xff09;?? 機制&#xff0c;本質上就是操作系統內核或進程之間用…

論文略讀:Prefix-Tuning: Optimizing Continuous Prompts for Generation

2021 ACL固定預訓練LM&#xff0c;為LM添加可訓練&#xff0c;任務特定的前綴這樣就可以為不同任務保存不同的前綴這種前綴可以看成連續可微的soft prompt&#xff0c;相比于離散的token&#xff0c;更好優化&#xff0c;效果更好訓練的時候只需要更新prefix部分的參數&#xf…

CSS基礎選擇器、文本屬性、引入方式及Chorme調試工具

CSS基礎 1.1 CSS簡介 CSS 是層疊樣式表 ( Cascading Style Sheets ) 的簡稱. 有時我們也會稱之為 CSS 樣式表或級聯樣式表。 CSS 是也是一種標記語言 CSS 主要用于設置 HTML 頁面中的文本內容&#xff08;字體、大小、對齊方式等&#xff09;、圖片的外形&#xff08;寬高、邊…

RabbitMQ 高級特性之事務

1. 簡介與 MySQL、Redis 一樣&#xff0c;RabbitMQ 也支持事務。事務中的消息&#xff0c;要么全都發送成功&#xff0c;要么全部發送失敗&#xff0c;不會出現一部分成功一部分失敗的情況。2. 使用事務發送消息spring 中使用 RabbitMQ 開啟事務需要兩步&#xff1a;第一步&…

iframe 的同源限制與反爬機制的沖突

一、事件背景A域名接入了動態防護&#xff08;Bot 防護、反爬蟲機制&#xff09;&#xff0c;同時第三方業務B域名通過內嵌iframe的方式調用了A域名下的一個鏈接。二、動態防護介紹&#xff1a;動態防護&#xff08;也稱為 Bot 防護、反爬蟲機制&#xff09;是網站為了防止自動…

Rust 的 Copy 語義:深入淺出指南

在 Rust 中&#xff0c;Copy 是一個關鍵的特性&#xff0c;它定義了類型的復制行為。理解 Copy 語義對于掌握 Rust 的所有權系統和編寫高效代碼至關重要。一、核心概念&#xff1a;Copy vs Move特性Copy 類型非 Copy 類型 (Move)賦值行為按位復制 (bitwise copy)所有權轉移 (ow…

Qt的信號與槽(二)

Qt的信號與槽&#xff08;二&#xff09;1.自定義槽2.通過圖形化界面來生成自定義槽3.自定義信號3.信號和槽帶參數4.參數數量5.connect函數的設計&#x1f31f;hello&#xff0c;各位讀者大大們你們好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f680;系列專欄&#xf…

Java研學-MongoDB(三)

三 文檔相關 7 文檔統計查詢① 語法&#xff1a; // 精確統計文檔數 慢 準 dahuang> db.xiaohuang.countDocuments({條件}) 4 // 粗略統計文檔數 快 大致準 dahuang> db.xiaohuang.estimatedDocumentCount({條件}) 4② 例子&#xff1a; // 精確統計文檔數 name為奔波兒灞…

TCP協議格式與連接釋放

TCP報文段格式 TCP雖然是面向字節流的&#xff0c;但TCP傳送帶數據單元確是報文段。TCP報文段分為首部和數據段部分&#xff0c;而TCP的全部功能體現在它在首部中各字段的作用。因此&#xff0c;只有弄清TCP首部各字段的作用才能掌握TCP的工作原理。 TCP報文段首部的前20字節是…

CSS05:結構偽類選擇器和屬性選擇器

結構偽類選擇器 /*ul的第一個子元素*/ ul li:first-child{background: #0af6f6; }/*ul的最后一個子元素*/ ul li:last-child{background: #d27bf3; } /*選中p1&#xff1a;定位到父元素&#xff0c;選擇當前的第一個元素 選擇當前p元素的父級元素&#xff0c;選中父級元素的第…

使用策略模式 + 自動注冊機制來構建旅游點評系統的搜索模塊

? 目標&#xff1a; 搜索模塊支持不同內容類型&#xff08;攻略、達人、游記等&#xff09;每種搜索邏輯用一個策略類表示自動注冊&#xff08;基于注解 Spring 容器&#xff09;新增搜索類型時&#xff0c;只需添加一個類 一個注解&#xff0c;無需改工廠、注冊表等&#x…

第八十九篇 大數據開發中的數據算法:貪心策略 - 生活中的“精打細算”藝術

在資源有限的世界里&#xff0c;貪心算法教會我們&#xff1a;局部最優的累積&#xff0c;往往是通往全局最高效的捷徑。本文通過3個生活化場景原創圖表&#xff0c;揭示大數據開發中最實用的優化策略。目錄一、貪心算法核心思想&#xff1a;當下即最優二、三大核心應用場景詳解…