本文圍繞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_policy
、check_link_policy
) 確保鏈路策略合法有效:
-
check_link_policy
校驗策略與硬件能力的匹配性,自動禁用不支持的功能(如角色切換、嗅探模式); -
通過 HCI 命令將策略同步至控制器,保證軟件配置與硬件執行一致。
4. 安全服務注冊(BTM_SetSecurityLevel
、AddService
) 管理服務級安全策略:
-
注冊服務的安全級別(加密、認證等),根據連接發起方 / 接收方差異化配置策略;
-
校驗并修正安全級別,確保符合藍牙規范(如加密依賴認證、認證需防中間人攻擊),存儲安全記錄供后續決策。
5. 查詢與掃描模式配置(BTM_SetInquiryMode
、BTM_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 數據包類型的掩碼構建及相關功能的初始化配置。核心職責是:
-
根據藍牙控制器能力,構建支持的 SCO/eSCO 數據包類型掩碼
-
初始化藍牙 ACL 連接、安全管理和掃描模式
-
配置與控制器能力相關的其他參數
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 數據包類型掩碼的構建和默認鏈路策略的配置。核心職責是:
-
配置藍牙 ACL 鏈路的默認鏈路策略參數
-
根據控制器能力,構建支持的 ACL 數據包類型掩碼
-
將構建的掩碼設置為系統默認支持的數據包類型
數據包類型說明:
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);
}
設置和管理藍牙設備的默認鏈路行為模式。核心職責是:
-
驗證傳入的鏈路策略參數合法性
-
更新本地鏈路策略配置
-
向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);}
}
根據底層硬件能力動態調整上層配置參數,確保系統不會嘗試啟用硬件不支持的功能。核心職責是:
-
驗證每個鏈路策略設置是否與硬件能力匹配
-
自動禁用硬件不支持的鏈路策略選項
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);
}
將服務的安全需求轉化為可執行的安全記錄,并確保策略符合藍牙安全規范與硬件能力。核心職責是:
-
管理有限的安全服務記錄資源(
sec_serv_rec
),處理重復注冊或新記錄分配。 -
根據服務是 “連接發起方” 還是 “接收方”,差異化設置安全策略(如 outgoing/incoming 安全標志)。
-
校驗并修正安全級別(
sec_level
),確保其符合藍牙安全規范(如加密必須依賴認證、認證需包含防中間人攻擊)。 -
將最終的安全策略存入服務記錄,為后續安全決策(如連接加密、認證)提供依據。
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、擴展),直接影響設備發現時能獲取的信息粒度。從藍牙設備發現流程和協議棧實現視角,核心職責是:
-
驗證查詢模式(
mode
)的合法性,確保其符合藍牙規范和硬件能力。 -
檢查設備狀態(是否已啟動),確保配置在有效場景下執行。
-
通過 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 頻段,存在多個信道,交錯式掃描通過交替使用不同的頻率組合,降低因信道干擾導致的掃描失敗概率,提升發現效率(尤其在復雜電磁環境中)。
三、流程圖
藍牙協議棧的控制器能力解析與核心功能配置機制體現了三層設計思想:
-
硬件適配層:通過
bluetooth::shim::GetController()
接口抽象硬件能力,確保協議棧與不同控制器兼容; -
策略校驗層:通過
check_link_policy
、安全級別修正等邏輯,保證配置符合硬件能力與藍牙規范,避免非法操作; -
功能執行層:通過 HCI 命令(如
btsnd_hcic_write_inquiry_mode
)將軟件配置同步至硬件,實現功能落地。
各模塊協同工作,從控制器能力解析到鏈路、安全、掃描等功能初始化,構建了完整的協議棧啟動流程,確保藍牙設備能高效、安全地與其他設備通信,同時平衡功耗與性能。