开始前,扯点题外话:本人不爱写网络文档,从2009年开始做蓝牙到现在(这13年都是在本地PC 写文档,自己写自己看,或分享给公司同仁,但从没想过上传网络),还是从去年(2021)年开始挑点文档上传到网络(受刺激了...),希望对大家有用;

本文将详细介绍Android Bluetooth HID Host从初始化、连接及最后接收Report Data 并如何写入Android 节点"/dev/uhid"的全过程;

本文继续以问答形式展开;

问题点1关于原生HID的类名;

关于原生HID, 其在Android 9是一个分界线;

在Android 8(O),

Framework层的HID Device 类是:BluetoothInputHost;

Framework层的HID Host类是:  BluetoothInputDevice;

以上类命名和我们理解是反向的;

从Android 9 开始,HID 的命名符合常规:

Framework层的HID Device 类是: BluetoothHidDevice;

Framework层的HID Host类是:BluetoothHidHost;

其分别对应的Service

HidDeviceService.java 和HidHostService.java

其分别对应的JNI层接口是:

com_android_bluetooth_hid_device.cpp 和com_android_bluetooth_hid_host.cpp

其分别对应的BlueDroid层接口是:

btif_hd.cc 和btif_hh.cc

以下Tracing 基于Android 9开始,重点Tracing HID Host部分;

问题点2关于HID Host的初始化流程;

-->Profile 的初始化属于Server APK 中的HidHostService中的start 方法,在此方法里调用JNI函数initializeNative;

Android UUID连接蓝牙 安卓蓝牙hid_Android UUID连接蓝牙

-->通过JNI 函数,回归到com_android_bluetooth_hid_host.cpp中的:

Android UUID连接蓝牙 安卓蓝牙hid_API_02

 执行到com_android_bluetooth_hid_host.cpp中的函数initializeNative;

-->在com_android_bluetooth_hid_host.cpp中的函数initializeNative,在此函数里通过HAL层接口,获取到了BlueDroid 中定义的HID Host 结构体bthh_interface_t接口;随后开始调用init函数;

Android UUID连接蓝牙 安卓蓝牙hid_android_03

 -->因函数指针结构体bthh_interface_t的实作在btif_hh.cc (system\bt\btif\src),

所以执行init将对应到到btif_hh.cc中的init函数指针的实作函数

static bt_status_t init(bthh_callbacks_t* callbacks)

通过此实作函数,并把com_android_bluetooth_hid_host.cpp中的callback

“sBluetoothHidCallbacks”注册到了BlueDroid层;

Android UUID连接蓝牙 安卓蓝牙hid_android_04

在此函数中开始执行BlueDroid层的profile service初始化

“btif_enable_service(BTA_HID_SERVICE_ID);”

这里注册HID Host的Service 使用的宏定义是BTA_HID_SERVICE_ID,

而HID Device对应的是BTA_HIDD_SERVICE_ID

-->最终执行到HID_HostInit;

Android UUID连接蓝牙 安卓蓝牙hid_API_05

问题点3HID HostSDP 注册在哪;

在Android 原生BT 中,定义HID UUID 是:

#define UUID_SERVCLASS_HUMAN_INTERFACE 0X1124         /* HID profile */

Android UUID连接蓝牙 安卓蓝牙hid_Android_06

从当前checking,以及结合SDP注册相关API,我们没有在HID Host中发现其SDP注册的实现;就Android作为手机时,基本都是主动搜索并进行连接,而作为HID Device 的几乎都是无界面设备,基本是等待被搜索并连接;---所以原生Android无HID Host注册的行为目前只能基于场景猜想;

延伸问题点:Andorid Bluetooth HID Device SDP 注册 ;

目前我们找到HID Device 添加Service 的API 是:HID_DevAddRecord,在

hidd_api.h/hidd_api.cc中

Android UUID连接蓝牙 安卓蓝牙hid_android_07

问题点4原生BT HID Host如何问询remote SDP并解析;

SDP API定义在sdp_api.h中

-->HID Host中执行SDP 问询的API是HID_HostGetSDPRecord,API 内部执行

SDP_InitDiscoveryDb 和 SDP_ServiceSearchRequest;

Android UUID连接蓝牙 安卓蓝牙hid_Android UUID连接蓝牙_08

-->通过API SDP_ServiceSearchRequest,注册SDP callback API hidh_search_callback

Note :关于查询HID Device 的SDP,重点是找到SDP中附带注册的report descriptor(报告描述符),基于HID Spec,其Attribute ID 是0x0206;

-->找到SDP callback中的报告描述符相关,

#define ATTR_ID_HID_DESCRIPTOR_LIST 0x0206;

有一个现象需留意: 在APIhidh_search_callback中,能看到其记录了SDP中的report descriptor ” p_nvi->dscp_info.dsc_list”, 并没有在hidh_search_callback中看到对SDP中包含的报告描述符的解析,;----具体原因请参考“问题点6”

Android UUID连接蓝牙 安卓蓝牙hid_API_09