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

【Bluedroid】蓝牙启动之 btm_acl_device_down 流程源码解析

本文详细分析Android蓝牙协议栈在设备故障时的处理流程。当蓝牙设备发生硬件故障或系统异常时,协议栈通过btm_acl_device_down触发多层次的资源清理和状态重置,包括ACL连接终止、L2CAP通道释放、SCO连接清理、BLE拓扑更新、设备数据库重置等关键操作,确保系统安全恢复。

一、概述

1.1 蓝牙核心控制块与故障处理框架

蓝牙协议栈通过全局控制块tBTM_CB实现跨模块状态管理,其整合了经典蓝牙(BR/EDR)和低功耗蓝牙(BLE)的控制逻辑,包含设备信息(devcb)、连接数据库(acl_cb_)、查询状态(btm_inq_vars)等关键模块。当本地设备被判定为故障(如硬件崩溃)时,btm_acl_device_down函数作为入口,触发全链路的状态清理流程。

1.2 故障处理核心流程

(1) ACL 连接清理机制

btm_acl_device_down遍历MAX_L2CAP_LINKS(默认 16 条)连接,通过l2c_link_hci_disc_comp通知 L2CAP 层断开连接。L2CAP 层进一步清理逻辑通道(CCB)、释放缓冲区,并根据传输类型(BLE / 经典蓝牙)执行差异化处理:

  • BLE:调整拓扑掩码(btm_ble_decrement_link_topology_mask)并尝试重连

  • 经典蓝牙:触发 SCO 链路移除(btm_sco_acl_removed)和固定通道释放

(2) 状态数据库重置

通过BTM_db_reset重置蓝牙管理数据库,包含:

  • 查询数据库重置(btm_inq_db_reset):清空发现的设备记录,终止活跃查询

  • 回调清理:通知上层应用(如远程名称查询、RSSI 查询)设备重置事件

  • 电源管理:清理pm_mode_db中的连接配置,优化功耗

(3) 辅助机制与数据记录

l2c_link_iot_store_disc_reason将故障原因(如HCI_ERR_HW_FAILURE)记录到 IoT 配置文件,为后续故障分析提供数据支撑,实现问题的可追溯性。

关键模块协作

  • L2CAP 层:作为链路层与上层的桥梁,处理 HCI 断开事件,协调逻辑通道清理与重连逻辑

  • BTM 模块:通过tBTM_CB维护全局状态,执行数据库重置与回调管理

  • SCO 与 BLE 模块:处理语音链路移除与低功耗连接拓扑调整,确保多模式兼容性

二、源码解析

btm_acl_device_down

packages/modules/Bluetooth/system/stack/acl/btm_acl.cc
/* Global BTM control block structure
*/
tBTM_CB btm_cb;/* The maximum number of simultaneous links that L2CAP can support. */
#ifndef MAX_L2CAP_LINKS
#define MAX_L2CAP_LINKS 16
#endif/********************************************************************************* Function         btm_acl_device_down** Description      This function is called when the local device is deemed*                  to be down. It notifies L2CAP of the failure.** Returns          void*******************************************************************************/
void btm_acl_device_down(void) {tACL_CONN* p = &btm_cb.acl_cb_.acl_db[0]; // 获取ACL连接数据库的起始指针uint16_t xx;for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) { // 遍历所有L2CAP连接if (p->in_use) {l2c_link_hci_disc_comp(p->hci_handle, HCI_ERR_HW_FAILURE);}}BTM_db_reset();  // 重置蓝牙管理数据库
}

当本地蓝牙设备因硬件故障或其他原因被判定为 “不可用”(如蓝牙芯片崩溃、驱动异常)时调用,作用是通知上层协议(L2CAP)清理所有活跃连接,并重置蓝牙状态。

tBTM_CB

packages/modules/Bluetooth/system/stack/btm/btm_int_types.h
typedef struct tBTM_CB {/*******************************************************      Control block for local device*****************************************************/tBTM_DEVCB devcb; // 经典蓝牙(BR/EDR)的设备控制块,存储本地设备的基础信息(如蓝牙地址、设备类、连接模式)和状态(如是否可发现、可连接)/*******************************************************      Control block for local LE device*****************************************************/tBTM_BLE_CB ble_ctr_cb; // 低功耗蓝牙(BLE)的核心控制块,管理 BLE 特有的操作(如扫描、广播、连接参数协商)和状态(如扫描模式、广播间隔、连接句柄)public:tBTM_BLE_VSC_CB cmn_ble_vsc_cb; // BLE 厂商特定命令(Vendor Specific Command)的公共控制块,用于处理厂商自定义的扩展操作(如私有数据传输、特殊功能配置)/* Packet types supported by the local device */// 记录本地设备支持的 SCO数据包类型(如 HV1、HV2、HV3 语音包)uint16_t btm_sco_pkt_types_supported{0};/*******************************************************      Inquiry*****************************************************/tBTM_INQUIRY_VAR_ST btm_inq_vars;/*******************************************************      SCO Management*****************************************************/// SCO 连接控制块,管理所有活跃的 SCO 连接(如语音通话),存储连接参数(如同步间隔、传输延迟)、状态标志(如连接中、已断开)和错误信息tSCO_CB sco_cb;#define BTM_SEC_MAX_RMT_NAME_CALLBACKS 2tBTM_RMT_NAME_CALLBACK* p_rmt_name_callback[BTM_SEC_MAX_RMT_NAME_CALLBACKS];uint16_t disc_handle{0};          /* for legacy devices */uint8_t disc_reason{0};           /* for legacy devices */fixed_queue_t* sec_pending_q{nullptr}; /* pending sequrity requests intBTM_SEC_QUEUE_ENTRY format */// BQR ReceivertBTM_BT_QUALITY_REPORT_RECEIVER* p_bqr_report_receiver{nullptr};#define BTM_CODEC_TYPE_MAX_RECORDS 32tBTM_BT_DYNAMIC_AUDIO_BUFFER_CBdynamic_audio_buffer_cb[BTM_CODEC_TYPE_MAX_RECORDS];// ACL连接控制块,管理所有 ACL 数据连接(如文件传输、数据通信)// acl_cb_存储每条 ACL 连接的 HCI 句柄、链路层状态、接收 / 发送缓冲区等关键信息tACL_CB acl_cb_;std::shared_ptr<TimestampedStringCircularBuffer> history_{nullptr};struct {struct {long long start_time_ms;unsigned long results;} classic_inquiry, le_scan, le_inquiry, le_observe, le_legacy_scan;std::unique_ptr<bluetooth::common::TimestampedCircularBuffer<tBTM_INQUIRY_CMPL>>inquiry_history_ = std::make_unique<bluetooth::common::TimestampedCircularBuffer<tBTM_INQUIRY_CMPL>>(kMaxInquiryScanHistory);} neighbor;void Init() {memset(&devcb, 0, sizeof(devcb));memset(&ble_ctr_cb, 0, sizeof(ble_ctr_cb));memset(&cmn_ble_vsc_cb, 0, sizeof(cmn_ble_vsc_cb));memset(&btm_inq_vars, 0, sizeof(btm_inq_vars));memset(&sco_cb, 0, sizeof(sco_cb));// 远程设备名称查询的回调函数数组。当通过蓝牙协议获取到远程设备的名称(如通过READ_REMOTE_NAME命令)时,触发注册的回调函数通知上层应用memset(p_rmt_name_callback, 0, sizeof(p_rmt_name_callback));acl_cb_ = {};// 邻居设备统计结构体,记录经典蓝牙查询(classic_inquiry)和 BLE 扫描(le_scan、le_inquiry等)的统计信息(如开始时间、结果数量),并通过inquiry_history_环形缓冲区存储历史查询事件,用于性能分析和调试neighbor = {};/* Initialize BTM component structures */// 设备查询(Inquiry)过程的状态变量,管理查询操作的核心参数(如查询模式、超时时间、已发现设备列表)btm_inq_vars.Init(); /* Inquiry Database and Structures */sco_cb.Init();       /* SCO Database and Structures (If included) */devcb.Init();history_ = std::make_shared<TimestampedStringCircularBuffer>(kBtmLogHistoryBufferSize);CHECK(history_ != nullptr);history_->Push(std::string("Initialized btm history"));}void Free() {history_.reset();devcb.Free();sco_cb.Free();btm_inq_vars.Free();}
} tBTM_CB;

tBTM_CB 是蓝牙协议栈的 “中央存储库”,所有蓝牙模块(如 ACL 连接、SCO 语音、设备发现、安全管理等)的运行状态和配置参数均存储于此。其设计特点是高度集成,将不同功能模块的控制块(如经典蓝牙的设备控制块 devcb、BLE 控制块 ble_ctr_cb)整合为一个统一结构,确保状态一致性和跨模块协作。

l2c_link_hci_disc_comp

packages/modules/Bluetooth/system/stack/l2cap/l2c_link.cc
/********************************************************************************* Function         l2c_link_hci_disc_comp** Description      This function is called when an HCI Disconnect Complete*                  event is received.** Returns          true if the link is known about, else false*******************************************************************************/
bool l2c_link_hci_disc_comp(uint16_t handle, tHCI_REASON reason) {// 查找 L2CAP 连接控制块(LCB)tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle);tL2C_CCB* p_ccb;bool status = true;bool lcb_is_free = true;/* If we don't have one, maybe an SCO link. Send to MM */if (!p_lcb) {status = false;} else {// 记录断开原因与状态标记l2c_link_iot_store_disc_reason(p_lcb->remote_bd_addr, reason);p_lcb->SetDisconnectReason(reason);/* Just in case app decides to try again in the callback context */p_lcb->link_state = LST_DISCONNECTING;/* Check for BLE and handle that differently */if (p_lcb->transport == BT_TRANSPORT_LE)btm_ble_decrement_link_topology_mask(p_lcb->LinkRole());/* Link is disconnected. For all channels, send the event through *//* their FSMs. The CCBs should remove themselves from the LCB     */for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;) {tL2C_CCB* pn = p_ccb->p_next_ccb;/* Keep connect pending control block (if exists)* Possible Race condition when a reconnect occurs* on the channel during a disconnect of link. This* ccb will be automatically retried after link disconnect* arrives*/if (p_ccb != p_lcb->p_pending_ccb) {l2c_csm_execute(p_ccb, L2CEVT_LP_DISCONNECT_IND, &reason);}p_ccb = pn;}// 经典蓝牙链路的 SCO 清理if (p_lcb->transport == BT_TRANSPORT_BR_EDR)/* Tell SCO management to drop any SCOs on this ACL */btm_sco_acl_removed(&p_lcb->remote_bd_addr);// 若当前链路仍有未完成的逻辑通道(如上层正在等待重连),则触发重连/* If waiting for disconnect and reconnect is pending start the reconnectnowrace condition where layer above issued connect request on link that wasdisconnecting*/if (p_lcb->ccb_queue.p_first_ccb != NULL || p_lcb->p_pending_ccb) {log::debug("l2c_link_hci_disc_comp: Restarting pending ACL request");/* Release any held buffers */while (!list_is_empty(p_lcb->link_xmit_data_q)) {BT_HDR* p_buf =static_cast<BT_HDR*>(list_front(p_lcb->link_xmit_data_q));list_remove(p_lcb->link_xmit_data_q, p_buf);osi_free(p_buf);}/* for LE link, always drop and re-open to ensure to get LE remote feature*/if (p_lcb->transport == BT_TRANSPORT_LE) { // BLE链路处理:移除ACL并尝试重连btm_acl_removed(handle);} else {  // 经典蓝牙链路处理:清理固定通道并尝试重连/* If we are going to re-use the LCB without dropping it, release allfixed channelshere */int xx;for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {if (p_lcb->p_fixed_ccbs[xx] &&p_lcb->p_fixed_ccbs[xx] != p_lcb->p_pending_ccb) {l2cu_release_ccb(p_lcb->p_fixed_ccbs[xx]);p_lcb->p_fixed_ccbs[xx] = NULL;(*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, p_lcb->remote_bd_addr, false,p_lcb->DisconnectReason(), p_lcb->transport);}}/* Cleanup connection state to avoid race conditions because* l2cu_release_lcb won't be invoked to cleanup */btm_acl_removed(p_lcb->Handle());p_lcb->InvalidateHandle();}if (p_lcb->transport == BT_TRANSPORT_LE) { // 触发重连if (l2cu_create_conn_le(p_lcb))lcb_is_free = false; /* still using this lcb */} else {l2cu_create_conn_br_edr(p_lcb);lcb_is_free = false; /* still using this lcb */}}p_lcb->p_pending_ccb = NULL;/* Release the LCB */if (lcb_is_free) l2cu_release_lcb(p_lcb);}// 处理等待连接的 LCB/* Now that we have a free acl connection, see if any lcbs are pending */if (lcb_is_free &&((p_lcb = l2cu_find_lcb_by_state(LST_CONNECT_HOLDING)) != NULL)) {/* we found one-- create a connection */l2cu_create_conn_br_edr(p_lcb);}return status;
}

处理 HCI断开完成事件(HCI Disconnect Complete Event)。当蓝牙底层(HCI)通知某条 ACL链路断开时,L2CAP 层需要清理该链路相关的所有资源(如逻辑通道、缓冲区),并协调上层(如蓝牙管理模块 BTM)处理可能的重连逻辑。

BLE 与经典蓝牙的差异处理:

  • BLE:直接调用btm_acl_removed通知 BTM 移除该 ACL 链路,然后通过l2cu_create_conn_le尝试基于原 LCB 重新建立 BLE 连接(确保获取最新的对端 LE 功能)。

  • 经典蓝牙:清理固定通道(如 L2CAP 的固定通道 0、1 等),释放对应的 CCB,并调用固定通道的回调函数通知上层通道断开。然后移除 ACL 链路并使句柄失效,最后通过l2cu_create_conn_br_edr触发经典蓝牙连接重建。

l2c_link_iot_store_disc_reason

packages/modules/Bluetooth/system/stack/l2cap/l2c_link.cc
// 定义了一个 IoT 配置键,用于存储 “连接超时导致断开” 的次数
#define IOT_CONF_KEY_GAP_DISC_CONNTIMEOUT_COUNT \"ProfileGap_DiscConnTimeoutCount"// IoT 配置操作宏
#define DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(addr, ...) \DEVICE_IOT_CONFIG_ADDR(int_add_one, addr, ##__VA_ARGS__)// 将蓝牙地址(addr)转换为字符串(ToString()),并调用名为 device_iot_config_<method> 的底层函数(如 device_iot_config_set_bin),参数为地址字符串和其他参数(...)
#define DEVICE_IOT_CONFIG_ADDR(method, addr, ...) \device_iot_config_##method((addr).ToString(), ##__VA_ARGS__)/*******************************************************************************
**
** Function         l2c_link_iot_store_disc_reason
**
** Description      iot store disconnection reason to local conf file
**
** Returns          void
**
*******************************************************************************/
static void l2c_link_iot_store_disc_reason(RawAddress& bda, uint8_t reason) {const char* disc_keys[] = {IOT_CONF_KEY_GAP_DISC_CONNTIMEOUT_COUNT,};const uint8_t disc_reasons[] = {HCI_ERR_CONNECTION_TOUT,};int i = 0;int num = sizeof(disc_keys) / sizeof(disc_keys[0]);if (reason == (uint8_t)-1) return;  // 无效原因,直接返回// 总断开次数统计DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(bda, IOT_CONF_KEY_GAP_DISC_COUNT);// 遍历特定原因,匹配则增加对应计数for (i = 0; i < num; i++) {if (disc_reasons[i] == reason) {DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(bda, disc_keys[i]);break;}}
}

记录蓝牙链路断开的原因到本地 IoT 配置文件,以便后续统计分析或故障诊断。其核心作用是通过统计不同设备的断开次数及具体原因(如连接超时),为蓝牙连接的稳定性优化提供数据支持。

触发场景

  • 触发条件:当蓝牙链路因异常(如连接超时、硬件故障)断开时,由 L2CAP 层的断开处理函数(如前文中的 l2c_link_hci_disc_comp)调用此函数,记录断开原因。

  • 核心目标:通过持久化存储断开事件的统计信息(总断开次数、特定原因的断开次数),帮助定位蓝牙连接的高频故障点(如某设备频繁因超时断开),从而优化连接策略或修复硬件 / 驱动问题。

btm_ble_decrement_link_topology_mask

packages/modules/Bluetooth/system/stack/btm/btm_ble_gap.cc
#define BTM_BLE_STATE_ALL_MASK 0x03ff// 通过位掩码机制高效标记 BLE 设备的拓扑状态,为协议栈提供统一的状态感知能力
/********************************************************************************* Function         btm_ble_set_topology_mask** Description      set BLE topology mask** Returns          true is request is allowed, false otherwise.*******************************************************************************/
bool btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state_mask) {request_state_mask &= BTM_BLE_STATE_ALL_MASK;btm_cb.ble_ctr_cb.cur_states |= (request_state_mask & BTM_BLE_STATE_ALL_MASK);return true;
}// 清除 BLE 拓扑状态的指定位掩码
/********************************************************************************* Function         btm_ble_clear_topology_mask** Description      Clear BLE topology bit mask** Returns          true is request is allowed, false otherwise.*******************************************************************************/
bool btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state_mask) {request_state_mask &= BTM_BLE_STATE_ALL_MASK; // 确保仅保留有效状态位btm_cb.ble_ctr_cb.cur_states &= ~request_state_mask; // 清除指定状态位return true;
}// 根据连接的建立或断开(increase),更新指定角色(link_role)的连接计数,并同步调整拓扑状态掩码和广告模式
/********************************************************************************* Function         btm_ble_update_link_topology_mask** Description      This function update the link topology mask** Returns          void*******************************************************************************/
static void btm_ble_update_link_topology_mask(uint8_t link_role, bool increase) {// 步骤1:清除所有连接相关的拓扑状态位btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_CONN_MASK);// 步骤2:更新对应角色的连接计数(中心或外围)if (increase)btm_cb.ble_ctr_cb.link_count[link_role]++;  // 连接建立,计数+1else if (btm_cb.ble_ctr_cb.link_count[link_role] > 0)btm_cb.ble_ctr_cb.link_count[link_role]--;  // 连接断开,计数-1(避免负数)// 步骤3:根据连接计数设置拓扑状态位if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_CENTRAL])btm_ble_set_topology_mask(BTM_BLE_STATE_CENTRAL_BIT);  // 有中心连接,标记对应位if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_PERIPHERAL])btm_ble_set_topology_mask(BTM_BLE_STATE_PERIPHERAL_BIT);  // 有外围连接,标记对应位// 步骤4:外围连接建立时,调整广告模式if (link_role == HCI_ROLE_PERIPHERAL && increase) {btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;  // 禁用广告btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_ADV_IND_EVT;  // 默认回退到非定向广告btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_ADV_MASK);  // 清除所有广告状态位}
}void btm_ble_decrement_link_topology_mask(uint8_t link_role) {btm_ble_update_link_topology_mask(link_role, false);
}

维护 BLE 设备的连接拓扑状态(如中心 / 外围角色的连接数)和广告状态。核心作用是通过计数和位掩码的方式,跟踪当前 BLE 设备作为中心(Central)或外围(Peripheral)的连接数量,并根据连接状态调整广告模式,确保资源合理分配。

触发场景:

当 BLE 设备建立或断开连接时(如调用 l2c_link_hci_disc_comp 处理链路断开后),通过这些函数更新拓扑状态,确保协议栈能感知当前连接角色(中心 / 外围)的数量,并调整广告等功能。

btm_sco_acl_removed

packages/modules/Bluetooth/system/stack/btm/btm_sco.cc
/********************************************************************************* Function         btm_sco_acl_removed** Description      This function is called when an ACL connection is*                  removed. If the BD address is NULL, it is assumed that*                  the local device is down, and all SCO links are removed.*                  If a specific BD address is passed, only SCO connections*                  to that BD address are removed.** Returns          void*******************************************************************************/
void btm_sco_acl_removed(const RawAddress* bda) {tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];uint16_t xx;for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {if (p->state != SCO_ST_UNUSED) {if ((!bda) || (p->esco.data.bd_addr == *bda && p->rem_bd_known)) {p->state = SCO_ST_UNUSED;p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */(*p->p_disc_cb)(xx);}}}
}

在 ACL链路移除时,清理关联的 SCO链路。核心作用是确保 SCO 链路(依赖 ACL 链路存在)随 ACL 链路的移除而终止,避免资源泄漏和状态不一致。

触发场景

  • 触发条件:当 ACL 链路因断开(如硬件故障、主动断开)被移除时调用此函数(例如前文中 l2c_link_hci_disc_comp 处理经典蓝牙链路断开时,会调用 btm_sco_acl_removed 清理 SCO 连接)。

  • 核心目标

    • 若本地设备故障(bdaNULL),清理所有 SCO 连接。

    • 若特定 ACL 链路移除(bda 为具体蓝牙地址),仅清理与该链路关联的 SCO 连接。

btm_acl_removed

packages/modules/Bluetooth/system/stack/btm/btm_sco.cc
/********************************************************************************* Function         btm_sco_acl_removed** Description      This function is called when an ACL connection is*                  removed. If the BD address is NULL, it is assumed that*                  the local device is down, and all SCO links are removed.*                  If a specific BD address is passed, only SCO connections*                  to that BD address are removed.** Returns          void*******************************************************************************/
void btm_sco_acl_removed(const RawAddress* bda) {tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];uint16_t xx;for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {if (p->state != SCO_ST_UNUSED) {if ((!bda) || (p->esco.data.bd_addr == *bda && p->rem_bd_known)) {p->state = SCO_ST_UNUSED;p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */(*p->p_disc_cb)(xx);}}}
}

连接移除的完整流程

  1. L2CAP 通知:当 ACL 连接需要移除时,L2CAP 层调用btm_acl_removed

  2. 状态标记:将连接标记为in_use = false,释放资源占用。

  3. 上层通知:通过NotifyAclLinkDown告知设备管理模块连接断开,触发上层业务逻辑(如重连、UI 更新)。

  4. 电源优化:针对经典蓝牙连接,清理电源模式配置,降低功耗。

  5. 状态重置:通过Reset方法将连接控制块的所有状态归零,为后续重用做准备。

设计核心原则

  • 资源管理:通过in_use标记和Reset方法确保连接资源可重复利用,避免内存泄漏。

  • 状态一致性:严格清理连接的所有状态数据,防止旧状态影响新连接的建立与管理。

  • 分层协作:通过NotifyAclLinkDownBTM_PM_OnDisconnected实现协议栈各层(ACL/L2CAP / 电源管理)的状态同步。

  • 错误处理:对无效句柄进行日志记录,确保异常情况可追溯。

btm_db_reset

packages/modules/Bluetooth/system/stack/btm/btm_devctl.cc
/* General callback function for notifying an application that a synchronous* BTM function is complete. The pointer contains the address of any returned* data.*/
typedef void(tBTM_CMPL_CB)(void* p1);/********************************************************************************* Function         btm_db_reset** Returns          void*******************************************************************************/
void BTM_db_reset(void) {tBTM_CMPL_CB* p_cb;// 1. 重置查询数据库btm_inq_db_reset();// 2. 处理远程名称查询完成回调if (btm_cb.devcb.p_rln_cmpl_cb) { // 若存在未完成的远程名称查询回调// 保存回调指针到临时变量 p_cb,并将原指针置为 NULL(避免重复调用)p_cb = btm_cb.devcb.p_rln_cmpl_cb;    btm_cb.devcb.p_rln_cmpl_cb = NULL;// 调用回调函数,传递 NULL 参数(表示名称查询因设备重置而终止)if (p_cb) (*p_cb)((void*)NULL);}// 3. 处理 RSSI 查询完成回调if (btm_cb.devcb.p_rssi_cmpl_cb) {// 保存回调指针并置空原指针p_cb = btm_cb.devcb.p_rssi_cmpl_cb;btm_cb.devcb.p_rssi_cmpl_cb = NULL;if (p_cb) {tBTM_RSSI_RESULT btm_rssi_result;btm_rssi_result.status = BTM_DEV_RESET;// 调用回调函数,传递该结构体(通知应用层 RSSI 查询因设备重置终止)(*p_cb)(&btm_rssi_result);}}// 4. 处理失败联系计数器回调// 失败联系计数器(Failed Contact Counter)查询的完成回调。该计数器记录与远程设备连接失败的次数,用于评估连接可靠性if (btm_cb.devcb.p_failed_contact_counter_cmpl_cb) { // 若存在未完成的失败联系计数器查询回调// 保存回调指针并置空原指针p_cb = btm_cb.devcb.p_failed_contact_counter_cmpl_cb;btm_cb.devcb.p_failed_contact_counter_cmpl_cb = NULL;if (p_cb) {tBTM_FAILED_CONTACT_COUNTER_RESULT btm_failed_contact_counter_result;btm_failed_contact_counter_result.status = BTM_DEV_RESET;(*p_cb)(&btm_failed_contact_counter_result);}}// 5. 处理自动刷新超时回调if (btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb) {p_cb = btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb;btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb = NULL;if (p_cb) {tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT btm_automatic_flush_timeout_result;btm_automatic_flush_timeout_result.status = BTM_DEV_RESET;(*p_cb)(&btm_automatic_flush_timeout_result);}}
}

重置蓝牙设备相关的状态数据库,并通知上层应用清理或更新状态。其核心作用是在蓝牙设备需要重置(如硬件故障、主动重启)时,确保系统状态一致性,避免残留无效数据。

回调管理:通过将未完成的回调指针置空并主动调用,避免悬垂指针(Dangling Pointer)导致的崩溃,并明确告知应用层操作终止的原因(BTM_DEV_RESET)。

触发场景

  • 触发条件:通常在蓝牙设备异常(如硬件故障)、系统重启或需要清空设备状态时调用。

  • 核心目标:清理设备相关的临时状态(如查询记录),并通知上层应用(通过回调)设备已重置,确保应用层与协议栈状态同步。

btm_inq_db_reset

packages/modules/Bluetooth/system/stack/btm/btm_devctl.cc
/* General callback function for notifying an application that a synchronous* BTM function is complete. The pointer contains the address of any returned* data.*/
typedef void(tBTM_CMPL_CB)(void* p1);/********************************************************************************* Function         btm_db_reset** Returns          void*******************************************************************************/
void BTM_db_reset(void) {tBTM_CMPL_CB* p_cb;// 1. 重置查询数据库btm_inq_db_reset();// 2. 处理远程名称查询完成回调if (btm_cb.devcb.p_rln_cmpl_cb) { // 若存在未完成的远程名称查询回调// 保存回调指针到临时变量 p_cb,并将原指针置为 NULL(避免重复调用)p_cb = btm_cb.devcb.p_rln_cmpl_cb;    btm_cb.devcb.p_rln_cmpl_cb = NULL;// 调用回调函数,传递 NULL 参数(表示名称查询因设备重置而终止)if (p_cb) (*p_cb)((void*)NULL);}// 3. 处理 RSSI 查询完成回调if (btm_cb.devcb.p_rssi_cmpl_cb) {// 保存回调指针并置空原指针p_cb = btm_cb.devcb.p_rssi_cmpl_cb;btm_cb.devcb.p_rssi_cmpl_cb = NULL;if (p_cb) {tBTM_RSSI_RESULT btm_rssi_result;btm_rssi_result.status = BTM_DEV_RESET;// 调用回调函数,传递该结构体(通知应用层 RSSI 查询因设备重置终止)(*p_cb)(&btm_rssi_result);}}// 4. 处理失败联系计数器回调// 失败联系计数器(Failed Contact Counter)查询的完成回调。该计数器记录与远程设备连接失败的次数,用于评估连接可靠性if (btm_cb.devcb.p_failed_contact_counter_cmpl_cb) { // 若存在未完成的失败联系计数器查询回调// 保存回调指针并置空原指针p_cb = btm_cb.devcb.p_failed_contact_counter_cmpl_cb;btm_cb.devcb.p_failed_contact_counter_cmpl_cb = NULL;if (p_cb) {tBTM_FAILED_CONTACT_COUNTER_RESULT btm_failed_contact_counter_result;btm_failed_contact_counter_result.status = BTM_DEV_RESET;(*p_cb)(&btm_failed_contact_counter_result);}}// 5. 处理自动刷新超时回调if (btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb) {p_cb = btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb;btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb = NULL;if (p_cb) {tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT btm_automatic_flush_timeout_result;btm_automatic_flush_timeout_result.status = BTM_DEV_RESET;(*p_cb)(&btm_automatic_flush_timeout_result);}}
}

重置蓝牙设备的查询(Inquiry)数据库及相关状态,确保在设备重置(如硬件故障、主动重启)时,查询模块回到初始状态,避免残留无效数据干扰后续操作。核心职责是清理查询相关的临时状态、终止未完成的查询操作,并通知上层应用。

系统性地清理查询模块的临时状态,确保设备重置后查询功能的正确性,具体体现为:

  • 状态一致性:通过重置 inq_activestate 等状态变量,避免后续查询操作因残留状态误判(如误判查询仍在进行)。

  • 资源清理:清空查询数据库(btm_clr_inq_db)和结果过滤器(btm_clr_inq_result_flt),避免旧设备信息干扰新查询。

  • 上层通知:通过调用查询完成回调(p_inq_cmpl_cb)和远程名称回调(p_remname_cmpl_cb),明确告知上层应用查询操作终止的原因(设备重置),确保应用层与协议栈状态同步。

  • 模式重置:将设备的可发现、可连接模式及扫描类型恢复为默认值,为后续手动或自动启用这些功能提供干净的初始状态。

触发场景

  • 触发条件:通常在蓝牙设备重置(如调用 BTM_db_reset)、查询模块异常或需要清空历史记录时调用。例如,当蓝牙硬件故障导致设备断开(如前文的 btm_acl_device_down 函数),或用户主动重启蓝牙功能时,会触发此函数。

  • 核心目标:清理查询数据库(存储发现的远程设备信息)、终止正在进行的查询或远程名称查询,并通过回调通知上层应用,确保协议栈与应用层状态同步。

三、总结

核心设计目标

  1. 状态一致性:通过全局控制块tBTM_CB和分层清理机制,确保协议栈各模块状态同步

  2. 资源高效管理:及时释放 ACL/SCO 连接、缓冲区等资源,避免内存泄漏

  3. 故障可追溯性:通过 IoT 配置记录断开原因,为稳定性优化提供数据支持

  4. 多模式兼容性:同时支持经典蓝牙与 BLE 的故障处理逻辑,确保跨模式一致性

四、流程图

五、时序图

http://www.lqws.cn/news/529579.html

相关文章:

  • 稳定币技术全解:从货币锚定机制到区块链金融基础设施
  • Java底层原理:深入理解线程与并发机制
  • GEO生成式引擎优化发展迅猛:热点数智化传播是GEO最佳路径
  • 人大金仓Kingbase数据库KSQL 常用命令指南
  • 【论文】云原生事件驱动架构在智能风控系统中的实践与思考
  • 小孙学变频学习笔记(八)变频器的输入电流(下)
  • RPC(Remote Procedure Call)技术解析
  • 计算机网络 网络层:控制平面(二)
  • WPF中Converter基础用法
  • 正则表达式,`[]`(字符类)和`|`(或操作符)
  • MFC制作动态波形图( ChartCtrl)
  • 【AI News | 20250626】每日AI进展
  • ​​Deepoc大模型在光电研发中的核心技术突破与应用​
  • 使用CSS泄露标签属性值 url路径遍历攻击 -- GPN CTF 2025 PAINting Dice
  • CSS 背景属性用于定义HTML元素的背景
  • 构思的股票交易模拟 3D 虚拟主题游戏《股海逐梦 3D》
  • c++17标准std::filesystem常用函数
  • HDFS(Hadoop分布式文件系统)总结
  • 面试破局:告别流水账,用“故事思维”重塑自我介绍
  • 【RESTful接口设计规范全解析】URL路径设计 + 动词名词区分 + 状态码 + 返回值结构 + 最佳实践 + 新手常见误区汇总
  • Word 中批量转换 LaTeX 公式为标准数学格式的终极方法(附宏设置教程)
  • 高弹性、高可靠!腾讯云 TDMQ RabbitMQ Serverless 版全新发布
  • DOA-BiLSTM+NSGAII+熵权TOPSIS,附气泡图!,梦境优化算法+深度学习+多目标优化+多属性决策!
  • Java底层原理:深入理解JVM性能调优与监控
  • Java设计模式->责任链模式的介绍
  • 什么是 MQTT?
  • Nordic nRF52832 寄存器级 UARTE 发送实现
  • Android-Layout Inspector使用手册
  • R语言机器学习算法实战系列(二十六)基于tidymodels的XGBoost二分类器全流程实战
  • ubuntu22.04系统kubeadm部署k8s高可用集群