【Bluedroid】蓝牙HID Host disconnect流程源码解析

本文基于 Android 蓝牙 HID(Human Interface Device)Host 模块的源码,深入解析 HID 设备断开连接的完整流程。重点覆盖从应用层触发断开请求,到 BTIF 层(接口适配层)状态校验与异步传递、BTA 层(协议栈适配层)状态机驱动、HID 协议栈执行物理断连,最终通过 BTA/BTIF 层回调通知应用层的全链路逻辑。揭示各层级如何通过状态校验、事件传递、资源清理和状态同步,确保断开操作的健壮性、可诊断性和用户体验的一致性。

一、流程概述

蓝牙 HID Host 模块的断开连接流程可分为6 大核心环节,贯穿应用层、BTIF 层、BTA 层和 HID 协议栈,各层级协作完成状态校验、物理断连和状态通知:

1.1 应用层触发断开请求(BTIF 层:disconnect 函数)

  • 状态校验:BTIF 层首先校验模块状态(是否已禁用 / 禁用中)和设备状态(是否存在、是否已连接 / 连接中),避免无效操作。

  • 异步传递:通过btif_transfer_context将断开请求(BTIF_HH_DISCONNECT_REQ_EVT)异步传递至 BTIF 线程,确保操作在统一上下文执行。

1.2 BTIF 层发起断开(BTIF 层:btif_hh_handle_evt/btif_hh_disconnect)

  • 事件处理:BTIF 线程接收BTIF_HH_DISCONNECT_REQ_EVT后,调用btif_hh_disconnect触发断开。

  • 底层接口调用:通过BTA_HhClose通知 BTA 层执行断开,传递设备句柄(dev_handle)。

1.3 BTA 层状态机驱动(BTA 层:BTA_HhClose→状态机→bta_hh_api_disc_act)

  • 事件封装:BTA 层将断开请求封装为BTA_HH_API_CLOSE_EVT事件,通过消息队列传递至状态机。

  • 设备类型分发:根据设备类型(LE / 传统蓝牙)调用bta_hh_le_api_disc_act或直接调用 HID 协议栈接口HID_HostCloseDev执行物理断连。

1.4 HID 协议栈执行物理断开(HID 协议栈:HID_HostCloseDev→hidh_conn_disconnect)

  • 多级校验:校验模块注册状态、设备句柄有效性、连接状态,确保断开操作仅作用于合法已连接设备。

  • 物理断连:关闭 L2CAP 控制 / 中断通道(优先断开中断通道),设置 ACL 链路空闲超时为 0 触发立即断开,清理定时器并重试标志。

1.5 BTA 层处理断开完成事件(BTA 层:bta_hh_cback→状态机→bta_hh_close_act)

  • 事件转换:HID 协议栈通过HID_HDEV_EVT_CLOSE通知断开完成,BTA 层将其转换为状态机事件BTA_HH_INT_CLOSE_EVT

  • 资源清理与通知:解析断开原因(L2CAP 层 / 协议层错误码),更新连接计数,通知角色管理器协同清理,触发上层回调(BTA_HH_CLOSE_EVT)。

1.6 BTIF 层同步状态并通知应用层(BTIF 层:bte_hh_evt→btif_hh_upstreams_evt)

  • 上下文转移:BTA 层通过bte_hh_evtBTA_HH_CLOSE_EVT事件异步传递至 BTIF 线程。

  • 应用层通知:BTIF 层查找目标设备,更新本地状态(BTHH_CONN_STATE_DISCONNECTED),通过HAL_CBACK触发应用层回调,通知设备已断开(预通知→最终通知)。

二、源码解析

disconnect

packages/modules/Bluetooth/system/btif/src/btif_hh.cc
/********************************************************************************* Function         disconnect** Description      disconnect from hid device** Returns         bt_status_t*******************************************************************************/
static bt_status_t disconnect(RawAddress* bd_addr) {CHECK_BTHH_INIT();log::verbose("BTHH");btif_hh_device_t* p_dev;tAclLinkSpec link_spec;// 1.  状态校验(模块级)if (btif_hh_cb.status == BTIF_HH_DISABLED ||btif_hh_cb.status == BTIF_HH_DISABLING) {log::warn("Error, HH status = {}", btif_hh_cb.status);return BT_STATUS_UNHANDLED;}// 2. 设备存在性检查link_spec.addrt.bda = *bd_addr;// Todo: fill with params receivedlink_spec.addrt.type = BLE_ADDR_PUBLIC;link_spec.transport = BT_TRANSPORT_AUTO;p_dev = btif_hh_find_connected_dev_by_bda(link_spec);if (!p_dev) {log::error("Error, device {} not opened.",ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));return BT_STATUS_UNHANDLED;}// 3. 设备状态校验(设备级)if (p_dev->dev_status == BTHH_CONN_STATE_DISCONNECTED ||p_dev->dev_status == BTHH_CONN_STATE_DISCONNECTING) {log::error("Error, device {} already disconnected.",ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));return BT_STATUS_DONE; // 已断开或断开中,无需操作} else if (p_dev->dev_status == BTHH_CONN_STATE_CONNECTING) {log::error("Error, device {} is busy with (dis)connecting.",ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));return BT_STATUS_BUSY; // 设备正忙(连接中),无法断开}// 4. 异步传递断开请求return btif_transfer_context(btif_hh_handle_evt, BTIF_HH_DISCONNECT_REQ_EVT,(char*)&link_spec, sizeof(tAclLinkSpec), NULL);
}

蓝牙 HID Host 模块中断开 HID 设备连接的核心接口,主要负责连接状态校验、设备存在性检查,并通过异步机制触发后续断开操作。核心流程:

btif_transfer_context(BTIF_HH_DISCONNECT_REQ_EVT)

packages/modules/Bluetooth/system/btif/src/btif_hh.cc
/********************************************************************************* Function         btif_hh_handle_evt** Description      Switches context for immediate callback** Returns          void*******************************************************************************/static void btif_hh_handle_evt(uint16_t event, char* p_param) {CHECK(p_param != nullptr);tAclLinkSpec* p_link_spec = (tAclLinkSpec*)p_param;switch (event) {...case BTIF_HH_DISCONNECT_REQ_EVT: {log::debug("Disconnect request received remote:{}",ADDRESS_TO_LOGGABLE_CSTR((*p_link_spec)));btif_hh_disconnect(p_link_spec);HAL_CBACK(bt_hh_callbacks, connection_state_cb, &p_link_spec->addrt.bda,BTHH_CONN_STATE_DISCONNECTING);} break;...

btif_hh_disconnect

packages/modules/Bluetooth/system/btif/src/btif_hh.cc
/********************************************************************************* Function         btif_hh_disconnect** Description      disconnection initiated from the BTIF thread context** Returns          void*******************************************************************************/
void btif_hh_disconnect(tAclLinkSpec* link_spec) {CHECK(link_spec != nullptr);const btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(*link_spec);if (p_dev == nullptr) {log::debug("Unable to disconnect unknown HID device:{}",ADDRESS_TO_LOGGABLE_CSTR((*link_spec)));return;}log::debug("Disconnect and close request for HID device:{}",ADDRESS_TO_LOGGABLE_CSTR((*link_spec)));BTA_HhClose(p_dev->dev_handle);
}

校验设备存在性并调用底层接口(BTA_HhClose)触发物理层断开,确保断开操作的合法性和有序性。

BTA_HhClose

/packages/modules/Bluetooth/system/bta/hh/bta_hh_api.cc
/********************************************************************************* Function         BTA_HhClose** Description      Disconnect a connection.** Returns          void*******************************************************************************/
void BTA_HhClose(uint8_t dev_handle) {BT_HDR* p_buf = (BT_HDR*)osi_calloc(sizeof(BT_HDR));p_buf->event = BTA_HH_API_CLOSE_EVT; // 事件类型:API 层断开请求p_buf->layer_specific = (uint16_t)dev_handle;bta_sys_sendmsg(p_buf);
}

蓝牙 HID Host 模块中BTA 层的断开连接接口,其核心作用是将上层(如 BTIF 模块)的断开请求封装为事件消息,并通过系统消息队列异步传递给 HID 状态机,触发实际的断开逻辑。

bta_hh_better_state_machine(BTA_HH_API_CLOSE_EVT)

    ...case BTA_HH_CONN_ST:switch (event) {case BTA_HH_API_CLOSE_EVT:bta_hh_api_disc_act(p_cb, p_data);break;...

bta_hh_api_disc_act

packages/modules/Bluetooth/system/bta/hh/bta_hh_act.cc
/********************************************************************************* Function         bta_hh_api_disc_act** Description      HID Host initiate a disconnection.*** Returns          void*******************************************************************************/
void btif_hh_remove_device(tAclLinkSpec link_spec);
void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {CHECK(p_cb != nullptr);// 设备类型判断(LE vs 传统蓝牙)if (p_cb->is_le_device) {log::debug("Host initiating close to le device:{}",ADDRESS_TO_LOGGABLE_CSTR(p_cb->link_spec));bta_hh_le_api_disc_act(p_cb);} else { // 传统蓝牙设备断开逻辑const uint8_t hid_handle =(p_data != nullptr) ? static_cast<uint8_t>(p_data->hdr.layer_specific): p_cb->hid_handle;tHID_STATUS status = HID_HostCloseDev(hid_handle); // 关闭指定设备的连接// 结果处理与上层回调if (status != HID_SUCCESS) {log::warn("Failed closing classic device:{} status:{}",ADDRESS_TO_LOGGABLE_CSTR(p_cb->link_spec),hid_status_text(status));} else {log::debug("Host initiated close to classic device:{}",ADDRESS_TO_LOGGABLE_CSTR(p_cb->link_spec));}tBTA_HH bta_hh = {.dev_status = {.status =(status == HID_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR,.handle = hid_handle},};(*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, &bta_hh);}
}

根据设备类型(LE 或传统蓝牙)分发断开请求,调用底层协议栈接口关闭连接,并通过回调通知上层断开结果。

HID_HostCloseDev

packages/modules/Bluetooth/system/stack/hid/hidh_api.cc
/********************************************************************************* Function         HID_HostCloseDev** Description      This function disconnects the device.** Returns          void*******************************************************************************/
tHID_STATUS HID_HostCloseDev(uint8_t dev_handle) {// 1. 模块注册状态校验if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);// 2. 设备句柄有效性校验if ((dev_handle >= HID_HOST_MAX_DEVICES) ||(!hh_cb.devices[dev_handle].in_use)) {log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_INVALID_PARAM_AT_HOST_CLOSE_DEV,1);return HID_ERR_INVALID_PARAM;}// 3. 设备连接状态校验if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED) {log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_NO_CONNECTION_AT_HOST_CLOSE_DEV,1);return HID_ERR_NO_CONNECTION;}// 4. 清理准备:取消定时器与禁止重连alarm_cancel(hh_cb.devices[dev_handle].conn.process_repage_timer);hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY + 1;// 5. 执行底层断开操作return hidh_conn_disconnect(dev_handle);
}

负责多级状态校验和连接资源清理,确保断开操作仅作用于合法、已连接的设备。

核心逻辑可概括为:校验模块状态 → 校验设备句柄 → 校验连接状态 → 清理准备 → 执行断开。

hidh_conn_disconnect

packages/modules/Bluetooth/system/stack/hid/hidh_conn.cc
/********************************************************************************* Function         hidh_conn_disconnect** Description      This function disconnects a connection.** Returns          true if disconnect started, false if already disconnected*******************************************************************************/
tHID_STATUS hidh_conn_disconnect(uint8_t dhandle) {// 1. 获取连接结构体tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;// 2. 通道存在性检查if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) { // 存在有效通道,执行断开逻辑// 3. 标记断开中状态p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;// 4. 设置 ACL 链路立即断开/* Set l2cap idle timeout to 0 (so ACL link is disconnected* immediately after last channel is closed) */L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0,BT_TRANSPORT_BR_EDR);// 5. 断开 L2CAP 通道(中断→控制)/* Disconnect both interrupt and control channels */if (p_hcon->intr_cid)hidh_l2cif_disconnect(p_hcon->intr_cid);else if (p_hcon->ctrl_cid)hidh_l2cif_disconnect(p_hcon->ctrl_cid);BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnecting","local initiated");} else { // 无通道,标记为未使用p_hcon->conn_state = HID_CONN_STATE_UNUSED;}return HID_SUCCESS;
}

负责关闭控制 / 中断通道、释放 ACL 链路并更新连接状态。

调用 L2CAP 接口 L2CA_SetIdleTimeoutByBdAddr,将目标设备的 ACL 链路空闲超时时间设为 0。

作用:ACL 链路是 L2CAP 通道的物理承载,当最后一个 L2CAP 通道关闭后,空闲超时时间为 0 可触发 ACL 链路立即断开,避免残留的物理连接占用资源。

优先断开中断通道:HID 设备通常使用两个 L2CAP 通道:

  • 控制通道(ctrl_cid:用于传输 HID 协议命令(如设备配置)。

  • 中断通道(intr_cid:用于实时数据上报(如键盘按键、鼠标移动)。

中断通道的实时性要求更高,优先断开可减少数据残留,避免断开过程中仍有数据上报导致的状态混乱。

hidh_l2cif_disconnect

packages/modules/Bluetooth/system/stack/hid/hidh_conn.cc
static void hidh_l2cif_disconnect(uint16_t l2cap_cid) {// 1. 触发 L2CAP 层断开请求L2CA_DisconnectReq(l2cap_cid);// 2. 查找设备句柄(dhandle)/* Find CCB based on CID */const uint8_t dhandle = find_conn_by_cid(l2cap_cid);if (dhandle == kHID_HOST_MAX_DEVICES) {log::warn("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x{:x}", l2cap_cid);return;}// 3. 清理通道状态(控制 / 中断通道)tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;if (l2cap_cid == p_hcon->ctrl_cid) {p_hcon->ctrl_cid = 0; // 控制通道断开,清除 CID} else {p_hcon->intr_cid = 0; // 中断通道断开,清除 CIDif (p_hcon->ctrl_cid) {  // 若控制通道仍存在,主动断开log::verbose("HID-Host Initiating L2CAP Ctrl disconnection");L2CA_DisconnectReq(p_hcon->ctrl_cid);p_hcon->ctrl_cid = 0;}}// 4. 所有通道断开后的状态更新与通知if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;p_hcon->conn_state = HID_CONN_STATE_UNUSED;BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnected");hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,p_hcon->disc_reason, NULL); // 通知上层断开完成}
}

负责触发 L2CAP 层断开请求、清理通道状态,并在所有通道断开后通知上层完成断开。

核心逻辑概括为:触发 L2CAP 断开 → 查找设备 → 清理通道状态 → 同步断开关联通道 → 更新状态并通知上层。

bta_hh_cback(HID_HDEV_EVT_CLOSE)

packages/modules/Bluetooth/system/bta/hh/bta_hh_act.cc
/********************************************************************************* Function         bta_hh_cback** Description      BTA HH callback function.*** Returns          void*******************************************************************************/
static void bta_hh_cback(uint8_t dev_handle, const RawAddress& addr,uint8_t event, uint32_t data, BT_HDR* pdata) {uint16_t sm_event = BTA_HH_INVALID_EVT;uint8_t xx = 0;log::verbose("HID_event [{}]", bta_hh_hid_event_name(event));switch (event) {case HID_HDEV_EVT_OPEN:sm_event = BTA_HH_INT_OPEN_EVT;break;case HID_HDEV_EVT_CLOSE:sm_event = BTA_HH_INT_CLOSE_EVT;break;case HID_HDEV_EVT_INTR_DATA:sm_event = BTA_HH_INT_DATA_EVT;break;case HID_HDEV_EVT_HANDSHAKE:sm_event = BTA_HH_INT_HANDSK_EVT;break;case HID_HDEV_EVT_CTRL_DATA:sm_event = BTA_HH_INT_CTRL_DATA;break;case HID_HDEV_EVT_RETRYING:break;case HID_HDEV_EVT_INTR_DATC:case HID_HDEV_EVT_CTRL_DATC:/* Unhandled events: Free buffer for DATAC */osi_free_and_reset((void**)&pdata);break;case HID_HDEV_EVT_VC_UNPLUG:for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {if (bta_hh_cb.kdev[xx].hid_handle == dev_handle) {bta_hh_cb.kdev[xx].vp = true;break;}}break;}if (sm_event != BTA_HH_INVALID_EVT) {tBTA_HH_CBACK_DATA* p_buf = (tBTA_HH_CBACK_DATA*)osi_malloc(sizeof(tBTA_HH_CBACK_DATA) + sizeof(BT_HDR));p_buf->hdr.event = sm_event;p_buf->hdr.layer_specific = (uint16_t)dev_handle;p_buf->data = data;p_buf->link_spec.addrt.bda = addr;p_buf->link_spec.addrt.type = BLE_ADDR_PUBLIC;p_buf->link_spec.transport = BT_TRANSPORT_BR_EDR;p_buf->p_data = pdata;bta_sys_sendmsg(p_buf);}
}

HID_HDEV_EVT_CLOSE 事件的处理是蓝牙 HID Host 断开流程中底层协议栈向 BTA 层传递断开完成信号的关键环节。其核心作用是将 HID 协议栈的断开完成事件(HID_HDEV_EVT_CLOSE)转换为 BTA 层状态机可识别的内部事件(BTA_HH_INT_CLOSE_EVT),并通过消息机制触发 BTA 层的状态更新和上层通知。

bta_hh_better_state_machine(BTA_HH_INT_CLOSE_EVT)

    ...case BTA_HH_CONN_ST:switch (event) {...case BTA_HH_INT_CLOSE_EVT:p_cb->state = BTA_HH_IDLE_ST;bta_hh_close_act(p_cb, p_data);break;...

bta_hh_close_act

packages/modules/Bluetooth/system/bta/hh/bta_hh_act.cc
/********************************************************************************* Function         bta_hh_close_act** Description      HID Host process a close event*** Returns          void*******************************************************************************/
void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0};// 1. 解析断开原因(核心诊断信息)uint32_t reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */const bool l2cap_conn_fail = reason & HID_L2CAP_CONN_FAIL;const bool l2cap_req_fail = reason & HID_L2CAP_REQ_FAIL;const bool l2cap_cfg_fail = reason & HID_L2CAP_CFG_FAIL;const tHID_STATUS hid_status = static_cast<tHID_STATUS>(reason & 0xff); // HID状态码(低8位)// 2. 确定事件类型(虚拟拔插 vs 正常断开)/* if HID_HDEV_EVT_VC_UNPLUG was received, report BTA_HH_VC_UNPLUG_EVT */uint16_t event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT;// 3. 准备上层回调数据disc_dat.handle = p_cb->hid_handle;disc_dat.status = to_bta_hh_status(p_data->hid_cback.data);std::string overlay_fail =base::StringPrintf("%s %s %s", (l2cap_conn_fail) ? "l2cap_conn_fail" : "",(l2cap_req_fail) ? "l2cap_req_fail" : "",(l2cap_cfg_fail) ? "l2cap_cfg_fail" : "");BTM_LogHistory(kBtmLogTag, p_cb->link_spec.addrt.bda, "Closed",base::StringPrintf("%s reason %s %s",(p_cb->is_le_device) ? "le" : "classic",hid_status_text(hid_status).c_str(),overlay_fail.c_str()));// 5. 通知角色管理器(资源协同清理)/* inform role manager */bta_sys_conn_close(BTA_ID_HH, p_cb->app_id, p_cb->link_spec.addrt.bda);// 6. 更新连接计数(系统状态跟踪)/* update total conn number */bta_hh_cb.cnt_num--;if (disc_dat.status) disc_dat.status = BTA_HH_ERR; // 非零状态标记为错误// 7. 触发上层回调(状态同步关键)(*bta_hh_cb.p_cback)(event, (tBTA_HH*)&disc_dat);// 8. 虚拟拔插处理(彻底移除设备)/* if virtually unplug, remove device */if (p_cb->vp) {HID_HostRemoveDev(p_cb->hid_handle); // 从HID协议栈移除设备bta_hh_clean_up_kdev(p_cb); // 清理BTA层的设备控制块}bta_hh_trace_dev_db();// 9. 清理控制块(保留重连可能)/* clean up control block, but retain SDP info and device handle */p_cb->vp = false; // 重置虚拟拔插标志p_cb->w4_evt = 0; // 重置“等待事件”标志(避免后续误触发)// 10. 检查是否禁用服务(资源回收)/* if no connection is active and HH disable is signaled, disable service */if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) {bta_hh_disc_cmpl();   // 完成服务禁用}return;
}

解析断开原因、通知上层状态变化并清理连接资源,确保断开操作的完整闭环和系统资源的有效管理。

核心逻辑可概括为:解析原因→分类事件→记录日志→协同清理→通知上层→资源回收。

核心流程:

bta_sys_conn_close处理逻辑见【Bluedroid】蓝牙HID Device disconnect流程源码分析-CSDN博客

bta_hh_disc_cmpl处理流程见​​​​​​​​​​​​​​【Bluedroid】 蓝牙HID Device register_app流程源码解析_human interface device可以禁用吗-CSDN博客

(*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT)

bte_hh_evt(BTA_HH_CLOSE_EVT)

packages/modules/Bluetooth/system/btif/src/btif_hh.cc
/********************************************************************************* Function         bte_hh_evt** Description      Switches context from BTE to BTIF for all HH events** Returns          void*******************************************************************************/static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) {bt_status_t status;int param_len = 0;tBTIF_COPY_CBACK* p_copy_cback = NULL;if (BTA_HH_ENABLE_EVT == event)param_len = sizeof(tBTA_HH_STATUS);else if (BTA_HH_OPEN_EVT == event)param_len = sizeof(tBTA_HH_CONN);else if (BTA_HH_DISABLE_EVT == event)param_len = sizeof(tBTA_HH_STATUS);else if (BTA_HH_CLOSE_EVT == event)param_len = sizeof(tBTA_HH_CBDATA);else if (BTA_HH_GET_DSCP_EVT == event)param_len = sizeof(tBTA_HH_DEV_DSCP_INFO);else if ((BTA_HH_GET_PROTO_EVT == event) || (BTA_HH_GET_IDLE_EVT == event))param_len = sizeof(tBTA_HH_HSDATA);else if (BTA_HH_GET_RPT_EVT == event) {BT_HDR* hdr = p_data->hs_data.rsp_data.p_rpt_data;param_len = sizeof(tBTA_HH_HSDATA);if (hdr != NULL) {p_copy_cback = btif_hh_hsdata_rpt_copy_cb;param_len += BT_HDR_SIZE + hdr->offset + hdr->len;}} else if ((BTA_HH_SET_PROTO_EVT == event) || (BTA_HH_SET_RPT_EVT == event) ||(BTA_HH_VC_UNPLUG_EVT == event) || (BTA_HH_SET_IDLE_EVT == event))param_len = sizeof(tBTA_HH_CBDATA);else if ((BTA_HH_ADD_DEV_EVT == event) || (BTA_HH_RMV_DEV_EVT == event))param_len = sizeof(tBTA_HH_DEV_INFO);else if (BTA_HH_API_ERR_EVT == event)param_len = 0;/* switch context to btif task context (copy full union size for convenience)*/// 上下文转移(BTA → BTIF 线程)status = btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event,(char*)p_data, param_len, p_copy_cback);/* catch any failed context transfers */ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
}

BTA_HH_CLOSE_EVT 事件的处理是蓝牙 HID 断开流程中BTA 层向 BTIF 层(接口层)传递断开事件的关键环节。其核心作用是将 BTA 层的断开完成事件(BTA_HH_CLOSE_EVT)转换为 BTIF 层可处理的上下文,并通过线程切换确保事件在 BTIF 任务上下文中执行,最终通知应用层设备已断开。

btif_hh_upstreams_evt(BTA_HH_CLOSE_EVT)

/********************************************************************************* Function         btif_hh_upstreams_evt** Description      Executes HH UPSTREAMS events in btif context** Returns          void*******************************************************************************/
static void btif_hh_upstreams_evt(uint16_t event, char* p_param) {tBTA_HH* p_data = (tBTA_HH*)p_param;btif_hh_device_t* p_dev = NULL;int i;int len, tmplen;log::verbose("event={} dereg = {}", dump_hh_event(event),btif_hh_cb.service_dereg_active);switch (event) {...case BTA_HH_CLOSE_EVT:log::verbose("BTA_HH_CLOSE_EVT: status = {}, handle = {}",p_data->dev_status.status, p_data->dev_status.handle);// 1. 查找设备对象(定位目标设备)p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);if (p_dev != NULL) {// 2. 触发 “断开中” HAL 回调(应用层预通知)HAL_CBACK(bt_hh_callbacks, connection_state_cb,&(p_dev->link_spec.addrt.bda), BTHH_CONN_STATE_DISCONNECTING);log::verbose("uhid fd={} local_vup={}", p_dev->fd, p_dev->local_vup);// 3. 停止虚拟拔插定时器(避免残留事件)btif_hh_stop_vup_timer(&(p_dev->link_spec));// 4. 处理本地虚拟拔插或服务变更(特殊场景清理)/* If this is a locally initiated VUP, remove the bond as ACL got*  disconnected while VUP being processed.*/if (p_dev->local_vup) {p_dev->local_vup = false;BTA_DmRemoveDevice(p_dev->link_spec.addrt.bda); // 移除设备绑定} else if (p_data->dev_status.status == BTA_HH_HS_SERVICE_CHANGED) {// 断开原因是 HID 设备的服务变更(BTA_HH_HS_SERVICE_CHANGED,如设备固件升级后服务配置变化)/* Local disconnection due to service change in the HOGP device.HID descriptor would be read again, so remove it from cache. */log::warn("Removing cached descriptor due to service change, handle = {}",p_data->dev_status.handle);btif_storage_remove_hid_info(p_dev->link_spec.addrt.bda); // 清除HID描述符缓存}// 5. 更新 BTIF 层设备状态(内部状态同步)btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;// 6. 关闭协同连接(多协议清理)bta_hh_co_close(p_dev);//7. 触发 “已断开” HAL 回调(应用层最终通知)HAL_CBACK(bt_hh_callbacks, connection_state_cb,&(p_dev->link_spec.addrt.bda), p_dev->dev_status);} else {log::warn("Error: cannot find device with handle {}",p_data->dev_status.handle);}break;...

BTA_HH_CLOSE_EVT 事件的处理是蓝牙 HID 断开流程的最终环节,负责同步 BTIF 层设备状态并通知应用层设备已断开。核心作用是将 BTA 层传递的断开事件转换为应用层可感知的状态变化,确保整个系统状态的一致性。

其核心逻辑可概括为:定位设备→预通知应用层→清理特殊场景资源→同步内部状态→关闭协同连接→最终通知应用层。BTIF 层实现了从协议栈到应用层的状态同步,确保断开操作的完整性和用户体验的一致性。

三、时序图

四、总结

蓝牙 HID Host 模块的断开流程是多层级协作、状态同步和资源管理的典型案例,核心设计特点如下:

  • 多层校验机制:从 BTIF 层的设备存在性检查,到 HID 协议栈的句柄 / 状态校验,确保断开操作的合法性。

  • 异步事件传递:通过btif_transfer_context和消息队列,避免跨线程并发问题,保证操作原子性。

  • 资源高效清理:关闭 L2CAP 通道、设置 ACL 链路立即断开、清理虚拟拔插定时器,避免资源残留。

  • 状态同步闭环:通过两次应用层回调(断开中→已断开),确保用户及时感知状态变化,提升体验一致性。

流程通过严格的状态管理和层级协作,为蓝牙 HID 设备的稳定断开提供了关键保障。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/906667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python定时删除指定索引

脚本 import logging from datetime import datetime, timedelta from elasticsearch import Elasticsearch# 配置日志记录 logging.basicConfig(filenamedelete_uat_indices.log,levellogging.INFO,format%(asctime)s - %(levelname)s - %(message)s )# Elasticsearch 集群的…

GESP编程等级认证C++三级7-字符、字符数组与字符串2

2.3 用字符串定义字符数组的好处 使用字符串定义字符数组需要额外考虑其末尾的“\0”&#xff0c;为什么还要使用这种看上去“麻烦”的方法呢&#xff1f;从图5所示的代码就能看出原因。 图5 用字符串定义字符数组好处的代码 从图5中可以看出&#xff0c;a4是用字符串进行初始…

EasyRTC音视频实时通话WebP2P技术赋能的全场景实时通信解决方案

一、技术背景 在数字化浪潮席卷全球的当下&#xff0c;实时通信技术凭借其即时性、高效性的优势&#xff0c;已然成为推动各行业创新发展的核心动能。EasyRTC深度融合WebP2P技术&#xff0c;构建起去中心化的通信架构&#xff0c;实现了低延迟、高可靠的数据传输&#xff0c;为…

Claude MCP协议从入门到精通

目录 一、什么是MCP协议? 二、Function Calling 和 MCP 协议的区别? 三、MCP相关网站 3.1 官方文档 3.2 综合型 MCP 资源聚合平台 3.3 垂直领域 MCP Server 工具 3.4 开发者工具与社区 3.5 企业级服务与数据库集成 3.6 新手友好型平台 四、MCP 架构 4.1. MCP Hosts…

YOLOv11改进 | Conv/卷积篇 | 2024 ECCV最新大感受野的小波卷积WTConv助力YOLOv11有效涨点

YOLOv11改进 | Conv/卷积篇 | 2024 ECCV最新大感受野的小波卷积WTConv助力YOLOv11有效涨点 引言 在计算机视觉领域&#xff0c;卷积神经网络&#xff08;CNN&#xff09;的核心操作——卷积运算正经历着革命性的变革。2024年ECCV会议提出的**小波卷积&#xff08;WTConv, Wav…

英伟达CEO黄仁勋COMPUTEX 2025演讲实录:AI工厂时代已来,Blackwell架构全面投产

5月19日&#xff0c;英伟达创始人兼首席执行官黄仁勋在台北国际电脑展&#xff08;COMPUTEX 2025&#xff09;发表主题演讲&#xff0c;系统阐述了英伟达从芯片设计向AI基础设施服务商的战略转型&#xff0c;并披露了包括Blackwell架构升级、新一代AI计算平台及机器人技术在内的…

RabbitMQ的核心原理及应用

在分布式系统架构中&#xff0c;消息中间件是实现服务解耦、流量缓冲的关键组件。RabbitMQ 作为基于 AMQP 协议的开源消息代理&#xff0c;凭借高可靠性、灵活路由和跨平台特性&#xff0c;被广泛应用于企业级开发和微服务架构中。本文将系统梳理 RabbitMQ 的核心知识&#xff…

服务攻防矩阵

4.1 中间件漏洞利用 WebLogic反序列化漏洞&#xff08;CVE-2023-21839&#xff09; 漏洞原理&#xff1a; T3协议反序列化未严格校验&#xff0c;攻击者可注入恶意序列化对象执行任意代码。 攻击流程&#xff1a; 使用ysoserial生成CommonsCollections6 payload&#xff1…

PictureThis 解锁高级会员版_v5.3.0 拍植物知名称和植物百科

PictureThis 解锁高级会员版_v5.3.0 拍植物知名称和植物百科 PictureThis是一款创新的植物识别与园艺指导应用程序&#xff0c;旨在帮助用户快速识别植物种类、了解植物信息&#xff0c;并提供专业的园艺养护建议…

大模型 Agent 就是文字艺术吗?

最近在技术圈里有一个很有趣的争论&#xff1a;大模型 Agent 是不是就是各种 Prompt 的堆叠&#xff1f;像 Manus 这样看起来很智能的 Agent&#xff0c;本质上是不是就是用巧妙的 Prompt 约束大模型生成更好的输出&#xff1f;换句话说&#xff0c;这是不是一门文字艺术&#…

LeetCode 1340. 跳跃游戏 V(困难)

题目描述 给你一个整数数组 arr 和一个整数 d 。每一步你可以从下标 i 跳到&#xff1a; i x &#xff0c;其中 i x < arr.length 且 0 < x < d 。i - x &#xff0c;其中 i - x > 0 且 0 < x < d 。 除此以外&#xff0c;你从下标 i 跳到下标 j 需要满…

三相电压的优势,应用场景,功率测量

三相系统概述 我国三相系统&#xff0c;由频率相同&#xff0c;幅度类似的三个交流电压组成&#xff0c;每个电压相差120度。 三相系统的优势 启动电机&#xff1a;三个矢量间隔的电压&#xff0c;在电机中产生旋转磁场&#xff0c;不需要额外绕组就可以启动电机。 减少线损…

[原创](计算机数学)(The Probability Lifesaver)(P14): 推导计算 In(1-u) 约等于 -u

[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…

Android12 Rom定制去掉剪贴板复制成功的Toast

Android12Rom定制去掉剪贴板复制成功的Toast提示 1.前言&#xff1a; 最近在rom定制化开发时&#xff0c;测试提了一个bug&#xff0c;在浏览器或者文本里面使用剪贴板复制成功后会有一个Toast提示&#xff0c;这种体验不是很好&#xff0c;因为每次复制成功都有一个提示&…

SOC-ESP32S3部分:9-GPIO输入按键状态读取

飞书文档https://x509p6c8to.feishu.cn/wiki/L6IGwHKV6ikQ08kqwAwcAvhznBc 前面我们学习了GPIO的输出&#xff0c;GPIO输入部分其实也是一样的&#xff0c;这里我们使用按键作为GPIO输入例程讲解&#xff0c;分三步走。 查看板卡原理图&#xff0c;确定使用的是哪个GPIO查看G…

高可用集群keepalived

1.不同操作系统的安装 1.1 不同系统编译安装 ubuntu环境 apt-get - y install libssl-dev libpopt-dev daemon build-essential libssl-dev openssl libpopt-dev libsnmp-dev libnl-3-dev libnl-genl-3-dev centos环境 &#xff08;其他的下同&#xff09; yum install - y…

SpringCloud - 整合MQ实现消息总线服务

一、背景介绍 每当修改配置文件内容&#xff0c;如果需要客户端也同步更新&#xff0c;就需要手动调用/refresh接口&#xff0c;以便客户端能获取到最新的配置内容。 当客户端越来越多的时候&#xff0c;通过人工进行处理显然非常鸡肋。有没有一种更加高效的办法&#xff0c;…

测试W5500的第3步_使用ioLibrary库创建TCPServer

W5500是一款具有8个Socket的网络芯片&#xff0c;支持TCP Server模式&#xff0c;最多可同时连接8个客户端。本文介绍了基于STM32F10x和W5500的TCP Server实现&#xff0c;包括SPI初始化、W5500复位、网络参数配置、Socket状态管理等功能&#xff0c;适用于需要多客户端连接的嵌…

Web攻防-SQL注入数据库类型用户权限架构分层符号干扰利用过程发现思路

知识点&#xff1a; 1、Web攻防-SQL注入-产生原理&应用因素 2、Web攻防-SQL注入-各类数据库类型利用 演示案例-WEB攻防-SQL注入-数据库类型&架构分层&符号干扰 一、数据库知识 1、数据库名&#xff0c;表名&#xff0c;列名&#xff0c;数据 2、自带数据库&…

手机合集(不定期更新)

一、华为手机&#xff1a; 1.华为手机自助维修的方法&#xff1a; https://blog.csdn.net/humors221/article/details/145946128 2.华为手机实用功能介绍&#xff1a; https://blog.csdn.net/humors221/article/details/132514011 3.华为手机清理大数据的方法&#xff1a;…