当前位置: 首页 > news >正文

【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.dtcms.com/a/272424.html

相关文章:

  • git中的fork指令解释
  • Linux - firewall 防火墙
  • 强缓存和协商缓存详解
  • 机器学习核心算法:PCA与K-Means解析
  • Java从入门到精通!第三天(数组)
  • Shell 中的重定向
  • C++实习面试题
  • 如何看待java开发和AI的关系?
  • GO启动一个视频下载接口 前端可以边下边放
  • 【PyTorch】PyTorch中的数据预处理操作
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | DoubleVerticalSlider(双垂直滑块)
  • 图解LeetCode:79递归实现单词搜索
  • Django+DRF 实战:自定义异常处理流程
  • 20.4 量子安全加密算法
  • 案例分享--福建洋柄水库大桥智慧桥梁安全监测(二)之数字孪生和系统平台
  • 机器学习13——支持向量机下
  • TCP传输控制层协议深入理解
  • 当CCLinkIE撞上Modbus TCP:照明控制系统的“方言战争”终结术
  • VIP可读
  • 线性回归与正则化
  • Django专家成长路线知识点——AI教你学Django
  • 【PTA数据结构 | C语言版】顺序栈的3个操作
  • 【深度学习系列--经典论文解读】Gradient-Based Learning Applied to Document Recognition
  • LINUX710 MYSQL
  • linux-用户与用户组管理
  • serialVersionUID
  • 配置 msvsmon.exe 以无身份验证启动
  • 力扣打卡第23天 二叉搜索树中的众数
  • 算法题(171):组合型枚举
  • Shusen Wang推荐系统学习 --召回 矩阵补充 双塔模型