本文深入剖析Android蓝牙协议栈中HID设备(BT-HD)服务的初始化与启用流程,从接口初始化、服务掩码管理、服务请求路由到属性回调通知,完整展现蓝牙HID服务激活的技术路径。通过代码逻辑梳理,揭示服务启用的核心机制,包括服务状态掩码更新、跨模块调用链及线程安全的属性传递设计。
一、概述
蓝牙 HID 设备(如键盘、鼠标)的服务启用与状态同步是蓝牙协议栈的核心功能之一。整个流程涉及多个模块协作,包括服务初始化、协议栈请求分发、属性获取及跨线程通知,具体可分为以下阶段:
1.1 服务初始化与启用
-
初始化接口:通过
init
函数完成 BT-HD 接口初始化,配置回调函数并调用btif_enable_service(BTA_HIDD_SERVICE_ID)
启用 HID 服务。 -
服务掩码更新:
btif_enable_service
将目标服务(BTA_HIDD_SERVICE_ID
)添加到全局服务掩码(btif_enabled_services
),若蓝牙已激活(btif_is_enabled()
),则触发服务启用请求。
1.2 协议栈请求分发
-
服务请求执行:
btif_dm_enable_service
调用btif_in_execute_service_request
执行服务启用请求。若成功,触发属性变更通知流程。 -
请求路由:
btif_in_execute_service_request
根据服务类型分发请求:SDP 服务特殊处理,其他服务通过toggleProfile
路由到具体服务模块(如 HID 服务由btif_hd_execute_service
处理)。
1.3 服务状态同步与属性通知
-
属性填充与获取:
-
通过宏
BTIF_STORAGE_FILL_PROPERTY
初始化bt_property_t
结构体,指定属性类型(如BT_PROPERTY_UUIDS
)。 -
btif_storage_get_adapter_property
根据属性类型从控制器或存储中获取具体值(如蓝牙地址、已配对设备列表、已启用服务的 UUID 列表)。
-
-
跨线程回调通知:
invoke_adapter_properties_cb
通过深拷贝(property_deep_copy_array
)确保属性数据线程安全,结合do_in_jni_thread
将变更事件异步传递到 JNI 线程,触发上层回调(如 Java 层)并释放资源。
二、源码解析
init
packages/modules/Bluetooth/system/btif/src/btif_hd.cc
/*******************************************************************************
*
* Function init
*
* Description Initializes BT-HD interface
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
btif_hd_cb_t btif_hd_cb;
static bt_status_t init(bthd_callbacks_t* callbacks) {
log::verbose("");
bt_hd_callbacks = callbacks;
memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));
btif_enable_service(BTA_HIDD_SERVICE_ID); // 启用 HID 服务
return BT_STATUS_SUCCESS;
}
初始化蓝牙 HID 设备(BT-HD)接口,配置回调函数并启用 HID 服务。
btif_enable_service(BTA_HIDD_SERVICE_ID)
packages/modules/Bluetooth/system/btif/src/btif_core.cc
/*******************************************************************************
*
* Function btif_enable_service
*
* Description Enables the service 'service_ID' to the service_mask.
* Upon BT enable, BTIF core shall invoke the BTA APIs to
* enable the profiles
*
******************************************************************************/
void btif_enable_service(tBTA_SERVICE_ID service_id) {
btif_enabled_services |= (1 << service_id); // 服务掩码更新
log::verbose("current services:0x{:x}", btif_enabled_services);
if (btif_is_enabled()) {
btif_dm_enable_service(service_id, true);
}
}
将指定的蓝牙服务添加到已启用服务掩码中,并在蓝牙已激活时立即启动该服务。
btif_dm_enable_service
packages/modules/Bluetooth/system/btif/src/btif_dm.cc
void btif_dm_enable_service(tBTA_SERVICE_ID service_id, bool enable) {
// 执行服务请求
bt_status_t status = btif_in_execute_service_request(service_id, enable);
if (status == BT_STATUS_SUCCESS) {
// 准备 UUID 属性
bt_property_t property;
Uuid local_uuids[BT_MAX_NUM_UUIDS]; // 存储设备支持的 UUID 列表
/* Now send the UUID_PROPERTY_CHANGED event to the upper layer */
// 从存储中获取当前设备的 UUID 属性
BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,
sizeof(local_uuids), local_uuids);
btif_storage_get_adapter_property(&property);
// 通过回调通知上层应用适配器属性已变更
GetInterfaceToProfiles()->events->invoke_adapter_properties_cb(
BT_STATUS_SUCCESS, 1, &property);
}
return;
}
通过蓝牙协议栈执行服务启用 / 禁用请求,并在成功时通知上层应用。
btif_in_execute_service_request
packages/modules/Bluetooth/system/btif/src/btif_dm.cc
bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
bool b_enable) {
log::verbose("service_id:{}", service_id);
if (service_id == BTA_SDP_SERVICE_ID) { // SDP 服务特殊处理
btif_sdp_execute_service(b_enable);
return BT_STATUS_SUCCESS;
}
// 通用服务处理
return GetInterfaceToProfiles()->toggleProfile(service_id, b_enable);
}
将上层的服务启用 / 禁用请求路由到对应的处理模块。
toggleProfile(BTA_HIDD_SERVICE_ID)
packages/modules/Bluetooth/system/btif/src/bluetooth.cc
bt_status_t toggleProfile(tBTA_SERVICE_ID service_id, bool enable) override {
/* Check the service_ID and invoke the profile's BT state changed API */
switch (service_id) {
case BTA_HFP_SERVICE_ID:
case BTA_HSP_SERVICE_ID: {
bluetooth::headset::ExecuteService(enable);
} break;
case BTA_A2DP_SOURCE_SERVICE_ID: {
btif_av_source_execute_service(enable);
} break;
case BTA_A2DP_SINK_SERVICE_ID: {
btif_av_sink_execute_service(enable);
} break;
case BTA_HID_SERVICE_ID: {
btif_hh_execute_service(enable);
} break;
case BTA_HFP_HS_SERVICE_ID: {
btif_hf_client_execute_service(enable);
} break;
case BTA_HIDD_SERVICE_ID: {
btif_hd_execute_service(enable);
} break;
case BTA_PBAP_SERVICE_ID:
case BTA_PCE_SERVICE_ID:
case BTA_MAP_SERVICE_ID:
case BTA_MN_SERVICE_ID: {
/**
* Do nothing; these services were started elsewhere. However, we need
* to flow through this codepath in order to properly report back the
* local UUIDs back to adapter properties in Java. To achieve this, we
* need to catch these service IDs in order for {@link
* btif_in_execute_service_request} to return {@code BT_STATUS_SUCCESS},
* so that in {@link btif_dm_enable_service} the check passes and the
* UUIDs are allowed to be passed up into the Java layer.
*/
} break;
default:
log::error("Unknown service {} being {}", service_id,
(enable) ? "enabled" : "disabled");
return BT_STATUS_FAIL;
}
return BT_STATUS_SUCCESS;
}
将通用的服务启用 / 禁用请求转发到具体的服务处理模块。
btif_hd_execute_service
packages/modules/Bluetooth/system/btif/src/btif_hd.cc
/*******************************************************************************
*
* Function btif_hd_execute_service
*
* Description Enabled/disables BT-HD service
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
bt_status_t btif_hd_execute_service(bool b_enable) {
log::verbose("b_enable={}", b_enable);
if (!b_enable) BTA_HdDisable();
return BT_STATUS_SUCCESS;
}
控制蓝牙 HID 设备服务的开启与关闭。
BTIF_STORAGE_FILL_PROPERTY
/modules/Bluetooth/system/btif/include/btif_storage.h
#define BTIF_STORAGE_FILL_PROPERTY(p_prop, t, l, p_v) \
do { \
(p_prop)->type = (t); \
(p_prop)->len = (l); \
(p_prop)->val = (p_v); \
} while (0)
初始化bt_property_t
结构体的三个核心字段。
btif_storage_get_adapter_property
packages/modules/Bluetooth/system/btif/src/btif_storage.cc
/*******************************************************************************
*
* Function btif_storage_get_adapter_property
*
* Description BTIF storage API - Fetches the adapter property->type
* from NVRAM and fills property->val.
* Caller should provide memory for property->val and
* set the property->val
*
* Returns BT_STATUS_SUCCESS if the fetch was successful,
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btif_storage_get_adapter_property(bt_property_t* property) {
/* Special handling for adapter address and BONDED_DEVICES */
if (property->type == BT_PROPERTY_BDADDR) { // 蓝牙地址获取
RawAddress* bd_addr = (RawAddress*)property->val;
/* Fetch the local BD ADDR */
const controller_t* controller = controller_get_interface();
if (!controller->get_is_ready()) {
log::error("Controller not ready! Unable to return Bluetooth Address");
*bd_addr = RawAddress::kEmpty;
return BT_STATUS_FAIL;
} else {
log::info("Controller ready!");
*bd_addr = *controller->get_address(); // 从蓝牙控制器获取本地设备地址
}
property->len = RawAddress::kLength;
return BT_STATUS_SUCCESS;
} else if (property->type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) { // 已配对设备列表获取
btif_bonded_devices_t bonded_devices;
// 获取已配对设备列表
btif_in_fetch_bonded_devices(&bonded_devices, 0);
log::verbose(
"BT_PROPERTY_ADAPTER_BONDED_DEVICES: Number of bonded devices={}",
bonded_devices.num_devices);
property->len = bonded_devices.num_devices * RawAddress::kLength;
// 将设备地址复制到属性值缓冲区
memcpy(property->val, bonded_devices.devices, property->len);
/* if there are no bonded_devices, then length shall be 0 */
return BT_STATUS_SUCCESS;
} else if (property->type == BT_PROPERTY_UUIDS) { // UUID 列表生成
/* publish list of local supported services */
Uuid* p_uuid = reinterpret_cast<Uuid*>(property->val);
uint32_t num_uuids = 0;
uint32_t i;
tBTA_SERVICE_MASK service_mask = btif_get_enabled_services_mask();
log::info("Service_mask=0x{:x}", service_mask);
// 根据已启用服务掩码生成对应的 UUID 列表
for (i = 0; i < BTA_MAX_SERVICE_ID; i++) {
/* This should eventually become a function when more services are enabled
*/
if (service_mask & (tBTA_SERVICE_MASK)(1 << i)) {
switch (i) {
case BTA_HFP_SERVICE_ID: {
*(p_uuid + num_uuids) =
Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
num_uuids++;
}
FALLTHROUGH_INTENDED; /* FALLTHROUGH */
/* intentional fall through: Send both BFP & HSP UUIDs if HFP is
* enabled */
case BTA_HSP_SERVICE_ID: {
*(p_uuid + num_uuids) =
Uuid::From16Bit(UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY);
num_uuids++;
} break;
case BTA_A2DP_SOURCE_SERVICE_ID: {
*(p_uuid + num_uuids) =
Uuid::From16Bit(UUID_SERVCLASS_AUDIO_SOURCE);
num_uuids++;
} break;
case BTA_A2DP_SINK_SERVICE_ID: {
*(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_AUDIO_SINK);
num_uuids++;
} break;
case BTA_PBAP_SERVICE_ID: {
*(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_PBAP_PSE);
num_uuids++;
} break;
case BTA_HFP_HS_SERVICE_ID: {
*(p_uuid + num_uuids) =
Uuid::From16Bit(UUID_SERVCLASS_HF_HANDSFREE);
num_uuids++;
} break;
case BTA_MAP_SERVICE_ID: {
*(p_uuid + num_uuids) =
Uuid::From16Bit(UUID_SERVCLASS_MESSAGE_ACCESS);
num_uuids++;
} break;
case BTA_MN_SERVICE_ID: {
*(p_uuid + num_uuids) =
Uuid::From16Bit(UUID_SERVCLASS_MESSAGE_NOTIFICATION);
num_uuids++;
} break;
case BTA_PCE_SERVICE_ID: {
*(p_uuid + num_uuids) = Uuid::From16Bit(UUID_SERVCLASS_PBAP_PCE);
num_uuids++;
} break;
}
}
}
property->len = (num_uuids) * sizeof(Uuid);
return BT_STATUS_SUCCESS;
}
/* fall through for other properties */
// 通用属性处理
if (!cfg2prop(NULL, property)) {
return btif_dm_get_adapter_property(property);
}
return BT_STATUS_SUCCESS;
}
根据属性类型从 NVRAM 或控制器中获取适配器属性值。
invoke_adapter_properties_cb
/packages/modules/Bluetooth/system/btif/src/bluetooth.cc
void invoke_adapter_properties_cb(bt_status_t status, int num_properties,
bt_property_t* properties) {
do_in_jni_thread(FROM_HERE,
base::BindOnce( // 创建一次性回调(避免重复执行)
[](bt_status_t status, int num_properties,
bt_property_t* properties) {
// 步骤1:触发上层回调(HAL层注册的回调)
HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status,
num_properties, properties);
if (properties) {
// 步骤2:释放深拷贝的内存(避免泄漏)
osi_free(properties);
}
},
status, num_properties,
property_deep_copy_array(num_properties, properties))); //深拷贝属性数组
}
// callback reporting helpers
bt_property_t* property_deep_copy_array(int num_properties,
bt_property_t* properties) {
bt_property_t* copy = nullptr;
if (num_properties > 0) {
// 1:计算所有属性值的总长度(用于分配内存)
size_t content_len = 0;
for (int i = 0; i < num_properties; i++) {
auto len = properties[i].len;
if (len > 0) {
content_len += len;
}
}
//2:一次性分配连续内存(结构体数组 + 属性值内容)
copy = (bt_property_t*)osi_calloc((sizeof(bt_property_t) * num_properties) + content_len);
ASSERT(copy != nullptr);
// 3:复制属性结构体,并将属性值指向新分配的内容区
uint8_t* content = (uint8_t*)(copy + num_properties);
for (int i = 0; i < num_properties; i++) {
auto len = properties[i].len;
copy[i].type = properties[i].type;
copy[i].len = len;
if (len <= 0) {
continue;
}
copy[i].val = content; // 指向新内容区
memcpy(content, properties[i].val, len);
content += len; // 移动到下一个属性值位置
}
}
return copy;
}
蓝牙适配器属性回调的跨线程调用机制,确保从 HAL 层到 JNI 层的属性通知能够正确处理。
三、时序图
四、总结
①模块化设计
-
流程严格分层:接口初始化→服务管理→请求路由→具体实现→属性通知,各模块职责单一(如
btif_hd
专注HID逻辑,btif_dm
处理通用服务管理)。
②状态驱动机制
-
通过服务掩码
btif_enabled_services
全局追踪服务状态,结合btif_is_enabled()
判断实时激活状态,避免无效操作。
③线程安全与内存管理
-
属性回调采用深拷贝(
property_deep_copy_array
)与osi_free
释放,确保跨线程(如JNI)数据传递安全性。
④扩展性设计
-
服务ID与UUID映射表(如
BTA_HFP_SERVICE_ID
→UUID_SERVCLASS_AG_HANDSFREE
)支持快速扩展新服务,仅需修改映射逻辑。
通过服务掩码与回调机制的协同,实现蓝牙服务的动态启用与上层应用的实时同步,为HID设备(如键盘、游戏手柄)的即插即用提供底层支持。