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

【Bluedroid】HID DEVICE 连接的源码分析

本文分析Android Bluetooth协议栈中HID device设备连接流程的完整实现,从应用层接口到协议栈底层的交互细节。通过关键函数(如connect()BTA_HdConnect()HID_DevConnect()等)的代码解析,重点关注btifbtaHID协议栈三层的协同机制,揭示BTA_HD_CONN_STATE_EVT事件传递和HAL_CBACK回调触发原理,为蓝牙HID开发提供系统性技术参考。

一、概述

1.1 连接触发与初始校验

  • 应用层入口connect()函数作为上层接口,首先校验应用注册状态(app_registered)和HID模块启用状态(BTIF_HD_ENABLED),确保基础条件满足后调用底层BTA_HdConnect()

  • BTA层封装BTA_HdConnect()分配内存缓冲区,封装连接事件类型(BTA_HD_API_CONNECT_EVT)和目标地址,通过bta_sys_sendmsg()将消息传递至协议栈。

1.2 协议栈状态机驱动

  • 状态机入口bta_hd_connect_act()处理连接请求,首先调用HID_DevPlugDevice()建立虚拟线缆(标记设备为in_use),随后通过HID_DevConnect()发起物理连接。

  • 严格状态检查

    • 注册状态:若设备未注册(!hd_cb.reg_flag),直接返回HID_ERR_NOT_REGISTERED

    • 设备占用:检查虚拟线缆是否已建立(hd_cb.device.in_use)。

    • 连接状态:防止重复连接(hd_cb.device.state != HIDD_DEV_NO_CONN)。

1.3 L2CAP连接初始化

  • 底层连接hidd_conn_initiate()初始化控制/中断通道CID,调用L2CA_ConnectReq2()启动L2CAP连接,参数包含HID协议PSM(HID_PSM_CONTROL)和安全要求(认证/加密)。

  • 连接状态跟踪:根据L2CAP返回结果更新连接状态(HID_CONN_STATE_CONNECTING_CTRL),失败时通过回调通知上层。

1.4 事件上报与回调通知

  • 上下文切换bte_hd_evt()将协议栈事件(如BTA_HD_CONN_STATE_EVT)通过btif_transfer_context()切换至BTIF线程。

  • HAL回调btif_hd_upstreams_evt()最终触发connection_state_cb,向应用层传递连接状态(如BTHD_CONN_STATE_CONNECTING)。

二、源码分析

connect

packages/modules/Bluetooth/system/btif/src/btif_hd.cc
/********************************************************************************* Function         connect** Description      Connects to host** Returns          bt_status_t*******************************************************************************/
static bt_status_t connect(RawAddress* bd_addr) {log::verbose("");if (!btif_hd_cb.app_registered) {log::warn("application not yet registered");return BT_STATUS_NOT_READY;}if (btif_hd_cb.status != BTIF_HD_ENABLED) {log::warn("BT-HD not enabled, status={}", btif_hd_cb.status);return BT_STATUS_NOT_READY;}BTA_HdConnect(*bd_addr); // 发起连接请求return BT_STATUS_SUCCESS;
}

尝试连接到指定的蓝牙主机设备。在进行连接操作之前,先检查应用程序是否已经注册以及蓝牙 HID 设备(BT - HD)是否已经启用。若条件满足,则调用 BTA_HdConnect 函数发起连接请求。

BTA_HdConnect

packages/modules/Bluetooth/system/bta/hd/bta_hd_api.cc
/********************************************************************************* Function         BTA_HdConnect** Description      This function is called when connection to host shall be
*made** Returns          void*******************************************************************************/
void BTA_HdConnect(const RawAddress& addr) {log::verbose("");tBTA_HD_DEVICE_CTRL* p_buf =(tBTA_HD_DEVICE_CTRL*)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL));p_buf->hdr.event = BTA_HD_API_CONNECT_EVT;p_buf->addr = addr;bta_sys_sendmsg(p_buf);
}

发起与hid host的连接请求。分配一块内存用于存储连接事件的相关信息,设置事件类型和目标设备地址,然后将该消息发送出去,以触发后续的连接操作。

bta_hd_better_state_machine(BTA_HD_API_CONNECT_EVT)

bta_hd_connect_act

packages/modules/Bluetooth/system/bta/hd/bta_hd_act.cc
/********************************************************************************* Function         bta_hd_connect_act** Description      Connect to device (must be virtually plugged)** Returns          void*******************************************************************************/
void bta_hd_connect_act(tBTA_HD_DATA* p_data) {tHID_STATUS ret;tBTA_HD_DEVICE_CTRL* p_ctrl = (tBTA_HD_DEVICE_CTRL*)p_data;tBTA_HD cback_data;log::verbose("");// 设备插入操作ret = HID_DevPlugDevice(p_ctrl->addr);if (ret != HID_SUCCESS) {log::warn("HID_DevPlugDevice returned {}", ret);return;}// 设备连接操作ret = HID_DevConnect();if (ret != HID_SUCCESS) {log::warn("HID_DevConnect returned {}", ret);return;}//设置回调数据cback_data.conn.bda = p_ctrl->addr;cback_data.conn.status = BTHD_CONN_STATE_CONNECTING;// 调用回调函数bta_hd_cb.p_cback(BTA_HD_CONN_STATE_EVT, &cback_data);
}

连接到一个蓝牙设备,前提是该设备必须处于虚拟插入状态。首先尝试对设备进行插入操作,接着发起连接请求,若这两个步骤都成功,会调用回调函数通知连接状态变为 “正在连接”。

HID_DevPlugDevice

packages/modules/Bluetooth/system/stack/hid/hidd_api.cc
/********************************************************************************* Function         HID_DevPlugDevice** Description      Establishes virtual cable to given host** Returns          tHID_STATUS*******************************************************************************/
tHID_STATUS HID_DevPlugDevice(const RawAddress& addr) {hd_cb.device.in_use = TRUE;hd_cb.device.addr = addr;return HID_SUCCESS;
}

建立与给定主机的虚拟线缆连接,并设置设备的相关状态。

HID_DevConnect

packages/modules/Bluetooth/system/stack/hid/hidd_api.cc
/********************************************************************************* Function         HID_DevConnect** Description      Connects to device** Returns          tHID_STATUS*******************************************************************************/
tHID_STATUS HID_DevConnect(void) {if (!hd_cb.reg_flag) { // 检查设备注册状态log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NOT_REGISTERED_AT_CONNECT,1);return HID_ERR_NOT_REGISTERED;}if (!hd_cb.device.in_use) { // 检查设备使用状态log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_DEVICE_NOT_IN_USE_AT_CONNECT,1);return HID_ERR_INVALID_PARAM;}if (hd_cb.device.state != HIDD_DEV_NO_CONN) { //  检查设备连接状态log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_ALREADY_CONN, 1);return HID_ERR_ALREADY_CONN;}return hidd_conn_initiate(); // 发起连接操作
}

在真正发起连接之前,会对设备的注册状态、使用状态以及连接状态进行检查,若不符合要求则记录相应的错误指标并返回对应的错误状态码;若所有检查都通过,则调用 hidd_conn_initiate 函数来实际发起连接。

hidd_conn_initiate

packages/modules/Bluetooth/system/stack/hid/hidd_conn.cc
/********************************************************************************* Function         hidd_conn_initiate** Description      Initiates HID connection to plugged device** Returns          HID_SUCCESS*******************************************************************************/
tHID_STATUS hidd_conn_initiate(void) {tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;log::verbose("");// 1. 设备使用状态检查if (!p_dev->in_use) {log::warn("no virtual cable established");log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NOT_REGISTERED_AT_INITIATE,1);return (HID_ERR_NOT_REGISTERED);}// 2. 连接状态检查if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {log::warn("connection already in progress");log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_CONN_IN_PROCESS,1);return (HID_ERR_CONN_IN_PROCESS);}// 3. 连接参数初始化p_dev->conn.ctrl_cid = 0;p_dev->conn.intr_cid = 0;p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;// 4. 启动 L2CAP 连接请求/* Check if L2CAP started the connection process */if ((p_dev->conn.ctrl_cid =L2CA_ConnectReq2(HID_PSM_CONTROL, p_dev->addr,BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) == 0) {log::warn("could not start L2CAP connection");hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED,NULL);log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_L2CAP_FAILED_INITIATE,1);} else {p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;}return (HID_SUCCESS);
}

发起与已插入的 HID的连接。在发起连接前,会对设备的使用状态和连接状态进行检查,确保设备处于可连接的状态。若检查通过,会初始化连接相关的参数,尝试启动 L2CAP连接请求,并根据连接结果更新设备的连接状态。

bte_hd_evt(BTA_HD_CONN_STATE_EVT)

/packages/modules/Bluetooth/system/btif/src/btif_hd.cc
/********************************************************************************* Function         bte_hd_evt** Description      Switches context from BTE to BTIF for all BT-HD events** Returns          void*******************************************************************************/static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD* p_data) {bt_status_t status;int param_len = 0;tBTIF_COPY_CBACK* p_copy_cback = NULL;log::verbose("event={}", event);switch (event) {case BTA_HD_ENABLE_EVT:case BTA_HD_DISABLE_EVT:case BTA_HD_UNREGISTER_APP_EVT:param_len = sizeof(tBTA_HD_STATUS);break;case BTA_HD_REGISTER_APP_EVT:param_len = sizeof(tBTA_HD_REG_STATUS);break;case BTA_HD_OPEN_EVT:case BTA_HD_CLOSE_EVT:case BTA_HD_VC_UNPLUG_EVT:case BTA_HD_CONN_STATE_EVT:param_len = sizeof(tBTA_HD_CONN);break;case BTA_HD_GET_REPORT_EVT:param_len += sizeof(tBTA_HD_GET_REPORT);break;case BTA_HD_SET_REPORT_EVT:param_len = sizeof(tBTA_HD_SET_REPORT) + p_data->set_report.len;p_copy_cback = set_report_copy_cb;break;case BTA_HD_SET_PROTOCOL_EVT:param_len += sizeof(p_data->set_protocol);break;case BTA_HD_INTR_DATA_EVT:param_len = sizeof(tBTA_HD_INTR_DATA) + p_data->intr_data.len;p_copy_cback = intr_data_copy_cb;break;}status = btif_transfer_context(btif_hd_upstreams_evt, (uint16_t)event,(char*)p_data, param_len, p_copy_cback);ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
}

根据不同的蓝牙 HID事件,计算相关参数的长度,并调用 btif_transfer_context 函数进行上下文切换,将事件从 BTE 切换到 BTIF。

btif_hd_upstreams_evt(BTA_HD_CONN_STATE_EVT)

/********************************************************************************* Function         btif_hd_upstreams_evt** Description      Executes events in btif context** Returns          void*******************************************************************************/
static void btif_hd_upstreams_evt(uint16_t event, char* p_param) {tBTA_HD* p_data = (tBTA_HD*)p_param;log::verbose("event={}", dump_hd_event(event));switch (event) {case BTA_HD_ENABLE_EVT:...case BTA_HD_CONN_STATE_EVT:HAL_CBACK(bt_hd_callbacks, connection_state_cb,(RawAddress*)&p_data->conn.bda,(bthd_connection_state_t)p_data->conn.status);break;default:log::warn("unknown event ({})", event);break;}
}

BTA_HD_CONN_STATE_EVT 事件处理部分的核心是调用 HAL_CBACK 宏,将蓝牙设备的地址和连接状态信息传递给 connection_state_cb 回调函数。这样,上层应用程序可以根据连接状态的变化做出相应的处理,例如更新 UI 显示、处理设备连接或断开等操作。

三、时序图

四、总结

蓝牙 HID 设备连接的实现涉及多个函数的协同工作,每个函数都承担着特定的任务,如连接请求的发起、设备状态的检查、连接参数的初始化以及连接状态变化的处理等。通过对设备注册、使用和连接状态的严格检查,确保了连接操作的正确性和稳定性。上下文切换和回调函数的运用,使得上层应用能够及时感知连接状态的变化并做出相应处理,提高了系统的可扩展性和用户体验。

http://www.xdnf.cn/news/5308.html

相关文章:

  • MIT XV6 - 1.5 Lab: Xv6 and Unix utilities - xargs
  • Qt—多线程基础
  • 医药研发加速器!AI如何助力新药问世?
  • Unity中AssetBundle使用整理(一)
  • 模型过拟合是什么?
  • 【东枫科技】使用LabVIEW进行NVIDIA CUDA GPU 开发
  • AI智慧公园管理方案:用科技重塑市民的“夜游体验”
  • 【C++】内存管理 —— new 和 delete
  • Lora原理及实现浅析
  • 【C++】特殊类设计
  • 支持向量机与逻辑回归的区别及 SVM 在图像分类中的应用
  • matlab中的积分函数
  • 【Java学习日记34】:this关键字和成员变量
  • armv7 backtrace
  • LoRA(Low-Rank Adaptation)原理详解
  • 【ajax基础】
  • 深入理解深度Q网络DQN:基于python从零实现
  • OB Cloud 云数据库V4.3:SQL +AI全新体验
  • redis主从同步于对象模型
  • 【基于 LangChain 的异步天气查询2】GeoNames实现地区实时气温查询
  • EDITPLUS配置CTags实现函数跳转
  • 技术方案模型需要兼顾战略规划、技术实现与落地可行性
  • 《操作系统真象还原》第十三章——编写硬盘驱动程序
  • SQL注入问题
  • powerbuilder9.0中文版
  • 7、系统开发
  • 计算机网络 4-2-1 网络层(IPv4)
  • 每日算法-250510
  • 深入理解Embedding技术-什么是Embedding?
  • 使用fdisk 、gdisk管理分区