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

【Bluedroid】蓝牙HID DEVICE错误报告处理全流程源码解析

本文基于Android蓝牙协议栈代码,深入解析HID设备在接收非法指令(如无效的SET_REPORT)时的错误处理全流程,涵盖错误映射、协议封装、传输控制三大核心模块。重点剖析以下机制:

  1. HID协议规范错误码的动态转换策略

  2. 控制通道的优先级保障与拥塞回避机制

  3. 错误报告与正常数据报文的差异化处理逻辑

  4. 跨层级状态同步与连接恢复机制

一、流程概述

1.1 错误触发与协议栈传递

①应用层检测

上层应用通过report_error()触发错误处理,传入原始错误码(如HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID)。

②协议栈封装

BTA_HdReportError():分配tBTA_HD_REPORT_ERR结构体,封装BTA_HD_API_REPORT_ERROR_EVT事件,通过bta_sys_sendmsg投递到系统队列。

③事件路由

bta_hd_hdl_event():将事件路由至状态机,触发bta_hd_report_error_act动作函数。

1.2 协议规范转换

①错误码标准化

HID_DevReportError():将原始错误码映射为HID协议定义的7种标准错误类型(如未知错误强制转换为HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN)。

②消息构建

构建HID_TRANS_HANDSHAKE类型报文,参数字段携带标准错误码,通过控制通道(CID=0x0040)发送。

1.3 物理层传输控制

①通道选择

强制使用控制通道(HID_CHANNEL_CTRL),确保错误报文优先传输。

②拥塞检测

hidd_conn_send_data()检查HID_CONN_FLAGS_CONGESTED标志,若通道拥塞直接返回HID_ERR_CONGESTED

③断连恢复

若检测到连接断开,丢弃待发错误报文(不同于数据报文的缓存机制),避免无效重传。

二、源码解析

report_error

packages/modules/Bluetooth/system/btif/src/btif_hd.cc
/********************************************************************************* Function         report_error** Description      Sends HANDSHAKE with error info for invalid SET_REPORT** Returns          bt_status_t*******************************************************************************/
static bt_status_t report_error(uint8_t error) {log::verbose("");// 状态检查:确保应用已注册if (!btif_hd_cb.app_registered) {log::warn("application not yet registered");return BT_STATUS_NOT_READY;}// 状态检查:确保蓝牙HID设备已启用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层API发送错误报告BTA_HdReportError(error);return BT_STATUS_SUCCESS;
}

向 HID 主机发送错误报告,用于响应无效的 SET_REPORT 命令。

BTA_HdReportError

packages/modules/Bluetooth/system/bta/hd/bta_hd_api.cc
/********************************************************************************* Function         BTA_HdReportError** Description      This function is called when reporting error for set report** Returns          void*******************************************************************************/
void BTA_HdReportError(uint8_t error) {log::verbose("");tBTA_HD_REPORT_ERR* p_buf =(tBTA_HD_REPORT_ERR*)osi_malloc(sizeof(tBTA_HD_REPORT_ERR));p_buf->hdr.event = BTA_HD_API_REPORT_ERROR_EVT;p_buf->error = error;bta_sys_sendmsg(p_buf);
}

生成并发送包含错误信息的 HANDSHAKE 消息。

bta_hd_hdl_event(BTA_HD_API_REPORT_ERROR_EVT)

packages/modules/Bluetooth/system/bta/hd/bta_hd_api.cc
/********************************************************************************* Function         bta_hd_hdl_event** Description      HID device main event handling function.** Returns          void*******************************************************************************/
bool bta_hd_hdl_event(const BT_HDR_RIGID* p_msg) {log::verbose("p_msg->event={}", p_msg->event);switch (p_msg->event) {case BTA_HD_API_ENABLE_EVT:bta_hd_api_enable((tBTA_HD_DATA*)p_msg);break;case BTA_HD_API_DISABLE_EVT:if (bta_hd_cb.state == BTA_HD_CONN_ST) {log::warn("host connected, disconnect before disabling");// unregister (and disconnect)bta_hd_cb.disable_w4_close = TRUE;bta_hd_better_state_machine(BTA_HD_API_UNREGISTER_APP_EVT,(tBTA_HD_DATA*)p_msg);} else {bta_hd_api_disable();}break;default:bta_hd_better_state_machine(p_msg->event, (tBTA_HD_DATA*)p_msg);}return (TRUE);
}

负责接收和分发来自上层应用或下层协议栈的各种事件。作为 HID 设备状态机的入口点,根据不同的事件类型执行相应的处理逻辑。

bta_hd_better_state_machine

   ...case BTA_HD_CONN_ST:...case BTA_HD_API_REPORT_ERROR_EVT:bta_hd_report_error_act(p_data);break;...

bta_hd_report_error_act

packages/modules/Bluetooth/system/bta/hd/bta_hd_act.cc
/********************************************************************************* Function         bta_hd_report_error_act** Description** Returns          void*******************************************************************************/
void bta_hd_report_error_act(tBTA_HD_DATA* p_data) {tBTA_HD_REPORT_ERR* p_report = (tBTA_HD_REPORT_ERR*)p_data;tHID_STATUS ret;log::verbose("error = {}", p_report->error);ret = HID_DevReportError(p_report->error);if (ret != HID_SUCCESS) {log::warn("HID_DevReportError returned {}", ret);}
}

将错误信息封装为 HID 协议规范的错误报告并发送给主机设备。

HID_DevReportError

packages/modules/Bluetooth/system/stack/hid/hidd_api.cc
/********************************************************************************* Function         HID_DevReportError** Description      Reports error for Set Report via HANDSHAKE** Returns          tHID_STATUS*******************************************************************************/
tHID_STATUS HID_DevReportError(uint8_t error) {uint8_t handshake_param;log::verbose("error = {}", error);// 错误码映射switch (error) {case HID_PAR_HANDSHAKE_RSP_SUCCESS:case HID_PAR_HANDSHAKE_RSP_NOT_READY:case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID:case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ:case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM:case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN:case HID_PAR_HANDSHAKE_RSP_ERR_FATAL:handshake_param = error;break;default:handshake_param = HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN;break;}// 构建 HANDSHAKE 消息return hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, handshake_param, 0, 0,NULL);
}

负责将错误信息封装为 HID 协议规范的 HANDSHAKE 消息发送给主机设备。当设备接收到无效的 SET_REPORT 命令或其他错误条件时,通过此函数向主机反馈具体的错误类型。

对应 HID 协议规范中的标准错误类型:

错误码常量描述
HID_PAR_HANDSHAKE_RSP_SUCCESS0x00成功
HID_PAR_HANDSHAKE_RSP_NOT_READY0x01设备未准备好
HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID0x02无效的报告 ID
HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ0x03不支持的请求
HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM0x04无效的参数
HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN0x14未知错误
HID_PAR_HANDSHAKE_RSP_ERR_FATAL0x15致命错误

hidd_conn_send_data

packages/modules/Bluetooth/system/stack/hid/hidd_conn.cc
/********************************************************************************* Function         hidd_conn_send_data** Description      Sends data to host** Returns          tHID_STATUS*******************************************************************************/
tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type,uint8_t param, uint8_t data, uint16_t len,uint8_t* p_data) {BT_HDR* p_buf;uint8_t* p_out;uint16_t cid;uint16_t buf_size;log::verbose("channel({}), msg_type({}), len({})", channel, msg_type, len);tHID_CONN* p_hcon = &hd_cb.device.conn;// 1. 拥塞检查if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_CONGESTED_AT_FLAG_CHECK,1);return HID_ERR_CONGESTED;}// 2. 通道和缓冲区分配switch (msg_type) {case HID_TRANS_HANDSHAKE:case HID_TRANS_CONTROL:cid = p_hcon->ctrl_cid;buf_size = HID_CONTROL_BUF_SIZE;break;case HID_TRANS_DATA:if (channel == HID_CHANNEL_CTRL) {cid = p_hcon->ctrl_cid;buf_size = HID_CONTROL_BUF_SIZE;} else {cid = p_hcon->intr_cid;buf_size = HID_INTERRUPT_BUF_SIZE;}break;default:log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_INVALID_PARAM,1);return (HID_ERR_INVALID_PARAM);}// 3. 消息封装p_buf = (BT_HDR*)osi_malloc(buf_size);if (p_buf == NULL) {log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NO_RESOURCES, 1);return (HID_ERR_NO_RESOURCES);}p_buf->offset = L2CAP_MIN_OFFSET;p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;*p_out = HID_BUILD_HDR(msg_type, param); // 构建HID头部p_out++;p_buf->len = 1;  // start with header only// add report id prefix only if non-zero (which is reserved)if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {*p_out = data;  // report_idp_out++;p_buf->len++;}if (len > 0 && p_data != NULL) {memcpy(p_out, p_data, len);  // 添加数据负载p_buf->len += len;}// 4. 连接状态检查// check if connectedif (hd_cb.device.state != HIDD_DEV_CONNECTED) {// for DATA on intr we hold transfer and try to reconnectif (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {  // 保存待发送数据并尝试重新连接// drop previous data, we do not queue it for nowif (hd_cb.pending_data) {osi_free(hd_cb.pending_data);}hd_cb.pending_data = p_buf;if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {hidd_conn_initiate();}return HID_SUCCESS;}log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NO_CONNECTION_AT_SEND_DATA,1);return HID_ERR_NO_CONNECTION;}log::verbose("report sent");// 5. 数据发送if (!L2CA_DataWrite(cid, p_buf)) {log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_CONGESTED_AT_DATA_WRITE,1);return (HID_ERR_CONGESTED);}return (HID_SUCCESS);
}

负责将 HID 消息(如输入报告、控制命令、握手消息等)封装为 L2CAP 数据包并通过蓝牙物理层发送给主机设备。实现了数据发送的核心逻辑,包括通道选择、消息封装、连接状态检查和拥塞控制等功能。

三、关键机制解析

①错误码映射策略

  • 严格过滤:将用户输入的任意错误码映射到HID协议定义的7种类型,防止协议违规。

  • 安全兜底:未定义错误码统一转换为HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN,保障协议兼容性。

②控制通道保障机制

  • 独立缓冲区:使用固定512字节控制缓冲区(HID_CONTROL_BUF_SIZE),与数据通道隔离。

  • 优先级抢占:控制报文可中断正在传输的数据报文,确保错误及时反馈。

③差异化重传策略

报文类型重传机制缓存策略
数据报文自动重试3次保留最新数据
错误报文立即丢弃不缓存

④状态同步设计

  • 跨层状态机:通过bta_hd_cb.state同步应用层与协议栈状态,避免在禁用状态发送错误。

  • 原子化操作:错误处理全程关闭中断,通过osi_malloc保证内存操作的原子性。

四、时序图

五、总结

蓝牙 HID 协议中的错误报告机制是确保设备与主机之间可靠通信的重要组成部分。通过多层级的组件协作和标准化的消息格式,系统能够准确地将错误信息反馈给主机。核心代码实现采用了事件驱动架构、状态机模式和适配器模式,确保了系统的可扩展性和可维护性。

该流程体现了蓝牙HID设备错误处理的核心设计哲学:

  1. 协议合规性优先:通过严格的错误码映射和通道选择,确保符合HID 1.11规范。

  2. 故障弱化原则:在连接异常时主动丢弃错误报告,避免协议栈状态不一致。

  3. 实时性保障:控制通道的独立缓冲区设计和优先级机制,确保关键错误信息毫秒级送达。

  4. 状态驱动架构:通过事件-状态机模型实现跨层级状态同步,提升系统健壮性。


相关文章:

  • 操作系统之EXT文件系统
  • 互联网大厂Java面试:从Spring Boot到微服务架构的技术深挖
  • C++学习:六个月从基础到就业——C++20:范围(Ranges)基础
  • 影刀处理 Excel:智能工具带来的高效变革
  • 【图像生成大模型】Step-Video-T2V:下一代文本到视频生成技术
  • ollama调用千问2.5-vl视频图片UI界面小程序分享
  • .NET外挂系列:1. harmony 基本原理和骨架分析
  • Linux配置vimplus
  • 数字人技术的核心:AI与动作捕捉的双引擎驱动(210)
  • 赋予AI更强的“思考”能力
  • 【通用大模型】Serper API 详解:搜索引擎数据获取的核心工具
  • 基于 STM32 的手持式安检金属探测器设计与实现
  • 【 Redis | 实战篇 秒杀优化 】
  • 基于simulink搭建的模块化多电平MMC仿真模型
  • 柔性直流输电系统介绍及simulink模型的搭建
  • 逆变器的输出外特性分析
  • 基于simulink的LCC-HVDC输电模型
  • 如何给PSCAD添加库文件
  • LC滤波器的参数设计
  • PWM整流器双闭环PI参数的整定
  • 鸿蒙电脑正式发布,国产操作系统在个人电脑领域实现重要突破
  • 一周人物|收藏家瓦尔特捐出藏品,女性艺术家“对话”摄影
  • 西浦国际教育创新论坛举行,聚焦AI时代教育本质的前沿探讨
  • 持续降雨存在落石风险,贵州黄果树景区水帘洞将封闭至6月初
  • 浙江美术馆馆长人民日报撰文:打开更辽阔的审美场域
  • 《制止滥用行政权力排除、限制竞争行为规定(修订草案征求意见稿)》公开征求意见