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

蓝牙 HID(Human Interface Device)协议中的虚拟拔插(Virtual UnPlug, VUP)是实现设备低功耗管理、状态重置的核心功能。本文基于 Android Bluedroid 源码,从上层应用触发virtual_unplug接口开始,深入解析 VUP 的全流程实现,涵盖异步事件传递、设备能力适配(虚拟线缆支持与否)、定时器监控、协议栈消息封装、L2CAP 数据发送等关键环节,并对比不同设备的差异化处理策略(虚拟暂停 vs 物理断开),最后总结 VUP 设计的核心目标与工程实践要点。

一、流程梳理

虚拟拔插流程可分为 6大阶段,涉及BTIF、BTA、HID Host三层模块交互,完整调用链如下:

1.1 上层触发与基础校验

  • 入口函数: virtual_unplug()

    • 校验模块状态: 检查BTIF_HH_INIT确保HID主机模块已初始化,拒绝BTIF_HH_DISABLED状态。

    • 设备查找: 通过btif_hh_find_dev_by_bda验证目标设备是否存在且已连接。

    • 异步事件投递: 调用btif_transfer_contextBTIF_HH_VUP_REQ_EVT事件抛至协议栈线程,确保非阻塞。

1.2 事件分发与策略决策

  • 事件处理: btif_hh_handle_evt(BTIF_HH_VUP_REQ_EVT)

    • 设备能力判断: 在btif_hh_virtual_unplug中,根据设备的HID_VIRTUAL_CABLE属性选择策略:

      • 分支1(支持VUP):

        • 启动3秒超时定时器btif_hh_start_vup_timer),防止设备无响应。

        • 标记local_vup=true,标识本地主动发起的VUP。

        • 调用BTA_HhSendCtrl(p_dev->dev_handle, BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)发送控制命令。

      • 分支2(不支持VUP): 直接触发物理断开(BTA_HhClose),走标准断开流程。

1.3 控制命令下发与协议封装

  • BTA层转发: BTA_HhSendCtrlbta_hh_snd_write_dev

    • 消息封装: 构建tBTA_HH_CMD_DATA结构,指定传输类型为HID_TRANS_CONTROL,参数为BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG

    • 协议栈投递: 通过bta_sys_sendmsg将消息发送至BTA任务队列。

1.4 HID协议栈处理

  • BTA任务处理: bta_hh_write_dev_act

    • 参数转换: 将BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG转换为HID协议定义的HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG

    • 底层调用: 执行HID_HostWriteDev,通过L2CAP通道发送控制数据包。

1.5 L2CAP数据传输

  • 数据分段与发送: hidh_conn_snd_data

    • 通道选择: 使用Control Channel(CID=0x11)传输VUP指令。

    • 协议头构造: 生成HID_BUILD_HDR(HID_TRANS_CONTROL, HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG)

    • MTU适配: 若数据超MTU则分段发送,标记HID_TRANS_DATAC后续包。

1.7 超时监控与状态同步

  • 定时器回调: btif_hh_timer_timeout

    • 超时处理: 3秒内未收到设备响应,强制标记连接断开,回调connection_state_cb通知上层。

  • 成功响应: 设备返回Handshake包后,更新设备状态为BTHH_CONN_STATE_DISCONNECTED,清理定时器。

二、源码解析

virtual_unplug

packages/modules/Bluetooth/system/btif/src/btif_hh.cc
/*******************************************************************************
 *
 * Function         virtual_unplug
 *
 * Description      Virtual UnPlug (VUP) the specified HID device.
 *
 * Returns         bt_status_t
 *
 ******************************************************************************/
static bt_status_t virtual_unplug(RawAddress* bd_addr) {
  // 1. 初始化与模块状态检查
  CHECK_BTHH_INIT();
  log::verbose("BTHH");
  btif_hh_device_t* p_dev;
  tAclLinkSpec link_spec;
  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
    log::error("Error, HH status = {}", btif_hh_cb.status);
    return BT_STATUS_FAIL;
  }
  
  // 2. 设备查找参数准备
  link_spec.addrt.bda = *bd_addr;
  // Todo: fill with params received
  link_spec.addrt.type = BLE_ADDR_PUBLIC;
  link_spec.transport = BT_TRANSPORT_AUTO;

  // 3. 设备存在性验证
  p_dev = btif_hh_find_dev_by_bda(link_spec);
  if (!p_dev) {
    log::error("Error, device {} not opened.",
               ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));
    return BT_STATUS_FAIL;
  }
  
  // 4. 异步触发虚拟拔插事件
  btif_transfer_context(btif_hh_handle_evt, BTIF_HH_VUP_REQ_EVT,
                        (char*)&link_spec, sizeof(tAclLinkSpec), NULL);
  return BT_STATUS_SUCCESS;
}

验证模块状态和设备存在性后,异步触发虚拟拔插流程,确保操作的非阻塞性。

虚拟拔插(Virtual UnPlug, VUP) 是蓝牙蓝牙 HID(Human Interface Device) 协议中的关键功能,设计目的包括:

  • 模拟物理断开:在不实际断开蓝牙底层连接(ACL 链路)的情况下,暂停 HID 设备的输入输出(如键盘停止发送按键数据)。

  • 低功耗管理:临时停止 HID 数据传输,降低设备和主机的功耗。

  • 状态重置:清除 HID 设备的临时状态(如报告描述符缓存),便于重新初始化。

btif_hh_handle_evt(BTIF_HH_VUP_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_CONNECT_REQ_EVT: {
      log::debug("Connect request received remote:{}",
                 ADDRESS_TO_LOGGABLE_CSTR((*p_link_spec)));
      if (btif_hh_connect(p_link_spec) == BT_STATUS_SUCCESS) {
        HAL_CBACK(bt_hh_callbacks, connection_state_cb, &p_link_spec->addrt.bda,
                  BTHH_CONN_STATE_CONNECTING);
      } else
        HAL_CBACK(bt_hh_callbacks, connection_state_cb, &p_link_spec->addrt.bda,
                  BTHH_CONN_STATE_DISCONNECTED);
    } break;

    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;

    case BTIF_HH_VUP_REQ_EVT: {
      log::debug("Virtual unplug request received remote:{}",
                 ADDRESS_TO_LOGGABLE_CSTR((*p_link_spec)));
      if (btif_hh_virtual_unplug(p_link_spec) != BT_STATUS_SUCCESS) {
        log::warn("Unable to virtual unplug device remote:{}",
                  ADDRESS_TO_LOGGABLE_CSTR((*p_link_spec)));
      }
    } break;

    default: {
      log::warn("Unknown event received:{} remote:{}", event,
                ADDRESS_TO_LOGGABLE_CSTR((*p_link_spec)));
    } break;
  }
}

BTIF_HH_VUP_REQ_EVT 是蓝牙 HID 主机模块(BTHH)中处理虚拟拔插(VUP)请求的核心事件。其作用是触发实际的虚拟拔插操作,暂停 HID 设备的逻辑连接(保持底层蓝牙链路)。

btif_hh_virtual_unplug

packages/modules/Bluetooth/system/btif/src/btif_hh.cc
/*******************************************************************************
 *
 * Function         btif_hh_virtual_unplug
 *
 * Description      Virtual unplug initiated from the BTIF thread context
 *                  Special handling for HID mouse-
 *
 * Returns          void
 *
 ******************************************************************************/

bt_status_t btif_hh_virtual_unplug(const tAclLinkSpec* link_spec) {
  log::verbose("");
  
  // 1. 设备查找与基础校验
  btif_hh_device_t* p_dev;
  p_dev = btif_hh_find_dev_by_bda(*link_spec);
  
  // 2. 分支 1:支持虚拟线缆(HID_VIRTUAL_CABLE)的设备
  if ((p_dev != NULL) && (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED) &&
      (p_dev->attr_mask & HID_VIRTUAL_CABLE)) {
    log::verbose("Sending BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG for: {}",
                 ADDRESS_TO_LOGGABLE_CSTR(*link_spec));
    /* start the timer */
    btif_hh_start_vup_timer(link_spec); // 启动VUP定时器
    p_dev->local_vup = true; // 标记本地发起的VUP
    BTA_HhSendCtrl(p_dev->dev_handle, BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG); // 发送虚拟拔插控制命令
    return BT_STATUS_SUCCESS;
  } 
  
  // 3. 分支 2:不支持虚拟线缆的设备
  else if ((p_dev != NULL) &&
             (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED)) {
    log::error("Virtual unplug not supported, disconnecting device: {}",
               ADDRESS_TO_LOGGABLE_CSTR(*link_spec));
    /* start the timer */
    btif_hh_start_vup_timer(link_spec);
    p_dev->local_vup = true;
    BTA_HhClose(p_dev->dev_handle);  // 关闭设备连接(物理断开)
    return BT_STATUS_SUCCESS;
  }
  
   // 4. 分支 3:设备未连接或不存在
   else {
    log::error("Error, device {} not opened, status = {}",
               ADDRESS_TO_LOGGABLE_CSTR(*link_spec), btif_hh_cb.status);
    if ((btif_hh_cb.pending_link_spec.addrt.bda == link_spec->addrt.bda) &&
        (btif_hh_cb.status == BTIF_HH_DEV_CONNECTING)) {
      btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED; // 更新全局状态为断开
      btif_hh_cb.pending_link_spec = {}; // 清除挂起的连接参数

     // 通知上层设备已断开(通过JNI线程)
      /* need to notify up-layer device is disconnected to avoid
       * state out of sync with up-layer */
      do_in_jni_thread(base::Bind(
          [](RawAddress bd_addrcb) {
            HAL_CBACK(bt_hh_callbacks, connection_state_cb, &bd_addrcb,
                      BTHH_CONN_STATE_DISCONNECTED);
          },
          link_spec->addrt.bda));
    }
    return BT_STATUS_FAIL;
  }
}

根据设备能力选择不同的拔插策略(虚拟暂停或物理断开),并维护状态同步。

分支 1:支持虚拟线缆(HID_VIRTUAL_CABLE)的设备

btif_hh_start_vup_timer
packages/modules/Bluetooth/system/btif/src/btif_hh.cc
#define BTIF_TIMEOUT_VUP_MS (3 * 1000)

/*******************************************************************************
 *
 * Function      btif_hh_start_vup_timer
 *
 * Description  start virtual unplug timer
 *
 * Returns      void
 ******************************************************************************/
static void btif_hh_start_vup_timer(const tAclLinkSpec* link_spec) {
  log::verbose("");

  btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(*link_spec);
  CHECK(p_dev != NULL);

  alarm_free(p_dev->vup_timer);
  p_dev->vup_timer = alarm_new("btif_hh.vup_timer"); //  创建新定时器实例
 
  // 启动定时器并设置超时回调
  alarm_set_on_mloop(p_dev->vup_timer, BTIF_TIMEOUT_VUP_MS,
                     btif_hh_timer_timeout, p_dev);
}

HID 虚拟拔插(VUP)流程中的超时监控模块,用于为虚拟拔插操作设置超时定时器,确保设备无响应时能及时触发异常处理。

将定时器添加到系统主事件循环(mloop)中,启动计时。若设备在 3 秒内未完成虚拟拔插操作(如未响应控制命令),则触发超时回调(btif_hh_timer_timeout)。

核心流程可概括为 “设备查找→定时器清理→定时器创建→定时器启动”

BTA_HhSendCtrl
packages/modules/Bluetooth/system/bta/hh/bta_hh_api.cc
/*******************************************************************************
 *
 * Function         BTA_HhSendCtrl
 *
 * Description      Send a control command to HID device.
 *
 * Returns          void
 *
 ******************************************************************************/
void BTA_HhSendCtrl(uint8_t dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type) {
  bta_hh_snd_write_dev(dev_handle, HID_TRANS_CONTROL, (uint8_t)c_type, 0, 0,
                       NULL);
}
bta_hh_snd_write_dev
packages/modules/Bluetooth/system/bta/hh/bta_hh_api.cc
/*******************************************************************************
 *
 * Function  bta_hh_snd_write_dev
 *
 ******************************************************************************/
static void bta_hh_snd_write_dev(uint8_t dev_handle, uint8_t t_type,
                                 uint8_t param, uint16_t data, uint8_t rpt_id,
                                 BT_HDR* p_data) {
  tBTA_HH_CMD_DATA* p_buf =
      (tBTA_HH_CMD_DATA*)osi_calloc(sizeof(tBTA_HH_CMD_DATA));

  p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT;
  p_buf->hdr.layer_specific = (uint16_t)dev_handle;
  p_buf->t_type = t_type; // 传输类型(如HID控制/中断传输)
  p_buf->data = data;
  p_buf->param = param;
  p_buf->p_data = p_data;
  p_buf->rpt_id = rpt_id;

  bta_sys_sendmsg(p_buf);
}
  • 将上层应用的写设备请求(如发送 HID 输出报告、控制命令)封装为内部消息。

  • 通过协议栈的消息队列(bta_sys_sendmsg)异步传递给处理线程,确保操作的非阻塞性。

bta_hh_better_state_machine(BTA_HH_API_WRITE_DEV_EVT)
packages/modules/Bluetooth/system/bta/hh/bta_hh_main.cc
   ...
   case BTA_HH_CONN_ST:
      switch (event) {
        ...
        case BTA_HH_API_WRITE_DEV_EVT:
          bta_hh_write_dev_act(p_cb, p_data);
          break;
          ...
bta_hh_write_dev_act
packages/modules/Bluetooth/system/bta/hh/bta_hh_act.cc
/*******************************************************************************
 *
 * Function         bta_hh_write_dev_act
 *
 * Description      Write device action. can be SET/GET/DATA transaction.
 *
 * Returns          void
 *
 ******************************************************************************/
static uint8_t convert_api_sndcmd_param(const tBTA_HH_CMD_DATA& api_sndcmd) {
  uint8_t api_sndcmd_param = api_sndcmd.param;
  if (api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) {
    api_sndcmd_param = (api_sndcmd.param == BTA_HH_PROTO_RPT_MODE)
                           ? HID_PAR_PROTOCOL_REPORT
                           : HID_PAR_PROTOCOL_BOOT_MODE;
  }
  return api_sndcmd_param;
}

void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
  // 1. 事件类型计算
  uint16_t event =
      (p_data->api_sndcmd.t_type - HID_TRANS_GET_REPORT) + BTA_HH_GET_RPT_EVT;

  // 2. LE 设备分支处理
  if (p_cb->is_le_device)
    bta_hh_le_write_dev_act(p_cb, p_data);
  else {
    // 3. 参数转换(适配 HID 协议)
    /* match up BTE/BTA report/boot mode def */
    const uint8_t api_sndcmd_param =
        convert_api_sndcmd_param(p_data->api_sndcmd);

    // 4. 执行 HID 写操作
    tHID_STATUS status = HID_HostWriteDev(p_cb->hid_handle,
                                          p_data->api_sndcmd.t_type,
                                          api_sndcmd_param,
                                          p_data->api_sndcmd.data,
                                          p_data->api_sndcmd.rpt_id,
                                          p_data->api_sndcmd.p_data);
    // 5. 错误处理
    if (status != HID_SUCCESS) {
      log::error("HID_HostWriteDev Error, status:{}", status);

      if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
          p_data->api_sndcmd.t_type != HID_TRANS_DATA) {
        BT_HDR cbhdr = {
          .event = BTA_HH_GET_RPT_EVT,
          .len = 0,
          .offset = 0,
          .layer_specific = 0,
        };
        tBTA_HH cbdata = {
          .hs_data = {
            .status = BTA_HH_ERR,
            .handle = p_cb->hid_handle,
            .rsp_data = {
              .p_rpt_data = &cbhdr,
            },
          },
        };
        (*bta_hh_cb.p_cback)(event, &cbdata);
      } else if (api_sndcmd_param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) {
        tBTA_HH cbdata = {
          .dev_status = {
            .status = BTA_HH_ERR,
            .handle = p_cb->hid_handle,
          },
        };
        (*bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, &cbdata);
      } else {
        log::error(
            "skipped executing callback in hid host error handling. command "
            "type:{}, param:{}",
            p_data->api_sndcmd.t_type, p_data->api_sndcmd.param);
      }
    } 
    
    // 6. 成功处理
    else {
      switch (p_data->api_sndcmd.t_type) {
        case HID_TRANS_SET_PROTOCOL:
          FALLTHROUGH_INTENDED; /* FALLTHROUGH */
        case HID_TRANS_GET_REPORT:
          FALLTHROUGH_INTENDED; /* FALLTHROUGH */
        case HID_TRANS_SET_REPORT:
          FALLTHROUGH_INTENDED; /* FALLTHROUGH */
        case HID_TRANS_GET_PROTOCOL:
          FALLTHROUGH_INTENDED; /* FALLTHROUGH */
        case HID_TRANS_GET_IDLE:
          FALLTHROUGH_INTENDED;  /* FALLTHROUGH */
        case HID_TRANS_SET_IDLE: /* set w4_handsk event name for callback
                                    function use */
          p_cb->w4_evt = event;
          break;
        case HID_TRANS_DATA: /* output report */
          FALLTHROUGH_INTENDED; /* FALLTHROUGH */
        case HID_TRANS_CONTROL:
          /* no handshake event will be generated */
          /* if VC_UNPLUG is issued, set flag */
          if (api_sndcmd_param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
            p_cb->vp = true;

          break;
        /* currently not expected */
        case HID_TRANS_DATAC:
        default:
          log::verbose("cmd type={}", p_data->api_sndcmd.t_type);
          break;
      }

      /* if not control type transaction, notify PM for energy control */
      if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) {
        /* inform PM for mode change */
        bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->link_spec.addrt.bda);
        bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->link_spec.addrt.bda);
      } else if (api_sndcmd_param == BTA_HH_CTRL_SUSPEND) {
        bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->link_spec.addrt.bda);
      } else if (api_sndcmd_param == BTA_HH_CTRL_EXIT_SUSPEND) {
        bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->link_spec.addrt.bda);
      }
    }
  }
  return;
}

负责处理 HID 设备的控制 / 数据传输(如设置协议模式、发送输出报告),并与上层应用及电源管理模块同步状态。整体流程可分为分支判断→参数转换→操作执行→结果处理四大阶段。

HID_HostWriteDev
packages/modules/Bluetooth/system/stack/hid/hidh_api.cc
/*******************************************************************************
 *
 * Function         HID_HostWriteDev
 *
 * Description      This function is called when the host has a report to send.
 *
 *                  report_id: is only used on GET_REPORT transaction if is
 *                              specified. only valid when it is non-zero.
 *
 * Returns          void
 *
 ******************************************************************************/
tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type, uint8_t param,
                             uint16_t data, uint8_t report_id, BT_HDR* pbuf) {
  tHID_STATUS status = HID_SUCCESS;

  // 1. 模块注册状态校验
  if (!hh_cb.reg_flag) {
    log::error("HID_ERR_NOT_REGISTERED");
    status = HID_ERR_NOT_REGISTERED;
  }

  // 2. 设备句柄有效性校验
  if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
      (!hh_cb.devices[dev_handle].in_use)) {
    log::error("HID_ERR_INVALID_PARAM");
    log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
                            HIDH_ERR_INVALID_PARAM_AT_HOST_WRITE_DEV,
                        1);
    status = HID_ERR_INVALID_PARAM;
  }

  // 3. 设备连接状态校验
  else if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED) {
    log::error("HID_ERR_NO_CONNECTION dev_handle {}", dev_handle);
    log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
                            HIDH_ERR_NO_CONNECTION_AT_HOST_WRITE_DEV,
                        1);
    status = HID_ERR_NO_CONNECTION;
  }

  // 4. 数据发送与错误处理
  if (status != HID_SUCCESS)
    osi_free(pbuf);
  else
    status =
        hidh_conn_snd_data(dev_handle, t_type, param, data, report_id, pbuf);

  return status;
}

负责校验操作合法性(模块注册状态、设备有效性、连接状态),并最终通过底层通道发送数据。

hidh_conn_snd_data
packages/modules/Bluetooth/system/stack/hid/hidh_conn.cc
/*******************************************************************************
 *
 * Function         hidh_conn_snd_data
 *
 * Description      This function is sends out data.
 *
 * Returns          tHID_STATUS
 *
 ******************************************************************************/
tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type,
                               uint8_t param, uint16_t data, uint8_t report_id,
                               BT_HDR* buf) {
  tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
  BT_HDR* p_buf;
  uint8_t* p_out;
  uint16_t bytes_copied;
  bool seg_req = false;
  uint16_t data_size;
  uint16_t cid;
  uint16_t buf_size;
  uint8_t use_data = 0;
  bool blank_datc = false;

  // 1. 连接状态校验
  // 校验ACL连接是否存在(传统蓝牙BR/EDR)
  if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr,
                             BT_TRANSPORT_BR_EDR)) {
    osi_free(buf);
    log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
                            HIDH_ERR_NO_CONNECTION_AT_SEND_DATA,
                        1);
    return HID_ERR_NO_CONNECTION;
  }

  // 校验连接是否拥塞(避免发送数据导致队列堆积)
  if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
    osi_free(buf);
    log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
                            HIDH_ERR_CONGESTED_AT_FLAG_CHECK,
                        1);
    return HID_ERR_CONGESTED;
  }

  // 2. 传输类型路由
  switch (trans_type) {
    case HID_TRANS_CONTROL: // 控制传输(如设置协议)
    case HID_TRANS_GET_REPORT: // 获取报告
    case HID_TRANS_SET_REPORT:
    case HID_TRANS_GET_PROTOCOL:
    case HID_TRANS_SET_PROTOCOL:
    case HID_TRANS_GET_IDLE:
    case HID_TRANS_SET_IDLE:
      cid = p_hcon->ctrl_cid;
      buf_size = HID_CONTROL_BUF_SIZE;
      break;
    case HID_TRANS_DATA:  // 中断传输(如输出报告)
      cid = p_hcon->intr_cid;
      buf_size = HID_INTERRUPT_BUF_SIZE;
      break;
    default:
      log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
                              HIDH_ERR_INVALID_PARAM_AT_SEND_DATA,
                          1);
      return (HID_ERR_INVALID_PARAM);
  }

  if (trans_type == HID_TRANS_SET_IDLE)
    use_data = 1;
  else if ((trans_type == HID_TRANS_GET_REPORT) && (param & 0x08))
    use_data = 2;

   // 3. 数据分段处理
   do {
    if (buf == NULL || blank_datc) {
      p_buf = (BT_HDR*)osi_malloc(buf_size);

      p_buf->offset = L2CAP_MIN_OFFSET;
      seg_req = false;
      data_size = 0;
      bytes_copied = 0;
      blank_datc = false;
    } else if ((buf->len > (p_hcon->rem_mtu_size - 1))) { // 数据长度超过对端 MTU,需分段
      p_buf = (BT_HDR*)osi_malloc(buf_size);

      p_buf->offset = L2CAP_MIN_OFFSET;
      seg_req = true;
      data_size = buf->len;
      bytes_copied = p_hcon->rem_mtu_size - 1;
    } else {
      p_buf = buf;
      p_buf->offset -= 1;
      seg_req = false;
      data_size = buf->len;
      bytes_copied = buf->len;
    }

    p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
    *p_out++ = HID_BUILD_HDR(trans_type, param);

    /* If report ID required for this device */
    if ((trans_type == HID_TRANS_GET_REPORT) && (report_id != 0)) {
      *p_out = report_id;
      data_size = bytes_copied = 1;
    }

    if (seg_req) {
      memcpy(p_out, (((uint8_t*)(buf + 1)) + buf->offset), bytes_copied);
      buf->offset += bytes_copied;
      buf->len -= bytes_copied;
    } else if (use_data == 1) {
      *(p_out + bytes_copied) = data & 0xff;
    } else if (use_data == 2) {
      *(p_out + bytes_copied) = data & 0xff;
      *(p_out + bytes_copied + 1) = (data >> 8) & 0xff;
    }

    p_buf->len = bytes_copied + 1 + use_data;
    data_size -= bytes_copied;

    // 4. L2CAP 数据发送
    /* Send the buffer through L2CAP */
    if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) ||
        (!L2CA_DataWrite(cid, p_buf))) {
      log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
                              HIDH_ERR_CONGESTED_AT_SEND_DATA,
                          1);
      return (HID_ERR_CONGESTED);
    }

    if (data_size)
      trans_type = HID_TRANS_DATAC;
    else if (bytes_copied == (p_hcon->rem_mtu_size - 1)) {
      trans_type = HID_TRANS_DATAC;
      blank_datc = true;
    }

  } while ((data_size != 0) || blank_datc);

  return (HID_SUCCESS);
}

HID 主机协议栈中数据发送的核心执行单元,负责将 HID 消息(控制命令、报告数据等)通过 L2CAP 通道发送至设备。其核心逻辑是处理数据分段、构建 HID 协议头,并与底层 L2CAP 交互完成数据传输

分支 2:不支持虚拟线缆的设备

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;
  p_buf->layer_specific = (uint16_t)dev_handle;

  bta_sys_sendmsg(p_buf);
}

通过异步消息机制将 “关闭连接” 请求传递给协议栈后台线程处理。HID 主机模块(BTA_HH)主动断开设备连接的流程同【Bluedroid】蓝牙HID Host disconnect流程源码解析-CSDN博客

三、时序图

【Bluedroid】蓝牙HID Host virtual_unplug全流程源码解析_第1张图片

四、总结

4.1 分层架构

  • BTIF层:负责与Java层的JNI交互,处理异步事件转发。

  • BTA层:协议栈核心逻辑,处理设备状态机与控制命令封装。

  • HID Host层:实现HID协议细节,管理L2CAP通道与数据传输。

4.2 异步非阻塞设计

通过btif_transfer_contextbta_sys_sendmsg实现跨线程通信,避免阻塞UI或系统主线程。

4.3 兼容性策略

  • 对支持VUP的设备:仅断开逻辑连接,保持ACL链路,便于快速重连。

  • 对老旧设备:降级为物理断开,牺牲效率保证功能可用性。

4.4 可靠性增强

  • 双保险机制:定时器兜底 + 设备响应确认,防止协议栈状态死锁。

  • 拥塞控制:L2CAP层检查HID_CONN_FLAGS_CONGESTED标志,避免数据堆积。

4.5 功耗优化

虚拟拔插后,HID主机与设备可进入Sniff或Hold模式,减少射频活动,延长电池寿命。


你可能感兴趣的:(蓝牙技术探索与应用,c++,Bluedroid,HID)