【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
繁體地址,請注明出處:http://hk.pswp.cn/news/906667.shtml
英文地址,請注明出處:http://en.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;…