本篇解析Android蓝牙子系统加载配对HID设备的核心流程,通过btif_storage_load_bonded_hid_info
实现从NVRAM读取设备属性、验证绑定状态、构造描述符并注册到BTA_HH模块。重点剖析基于ConfigCache
的三层存储架构(全局配置/持久设备/临时设备),其通过动态持久化判定策略和LRU淘汰机制,在保证数据可靠性的同时实现高效内存管理。系统采用递归锁保障线程安全,支持多层级密钥解密校验,为蓝牙HID设备管理提供标准化解决方案。
-
作用:从NVRAM加载已配对蓝牙HID设备的信息,并将其注册到蓝牙HID主机模块(BTA_HH)
-
触发场景:系统启动时或需要重新加载HID设备信息时调用
btif_storage_load_bonded_hid_info
packages/modules/Bluetooth/system/btif/src/btif_profile_storage.cc
/*******************************************************************************
*
* Function btif_storage_load_bonded_hid_info
*
* Description BTIF storage API - Loads hid info for all the bonded devices
* from NVRAM and adds those devices to the BTA_HH.
*
* Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btif_storage_load_bonded_hid_info(void) {
// 1. 遍历所有已配对设备
for (const auto& bd_addr : btif_config_get_paired_devices()) {
auto name = bd_addr.ToString();
tAclLinkSpec link_spec; // 用于存储设备的连接信息
log::verbose("Remote device:{}", ADDRESS_TO_LOGGABLE_CSTR(bd_addr));
int value;
// 2. 获取 HID 属性掩码
if (!btif_config_get_int(name, BTIF_STORAGE_KEY_HID_ATTR_MASK, &value))
continue;
uint16_t attr_mask = (uint16_t)value;
// 3. 检查设备是否已绑定
if (btif_in_fetch_bonded_device(name) != BT_STATUS_SUCCESS) {
btif_storage_remove_hid_info(bd_addr); // 移除该设备的 HID 信息
continue;
}
// 4. 初始化设备描述信息结构体
tBTA_HH_DEV_DSCP_INFO dscp_info;
memset(&dscp_info, 0, sizeof(dscp_info));
// 5. 获取设备描述信息
btif_config_get_int(name, BTIF_STORAGE_KEY_HID_SUB_CLASS, &value);
uint8_t sub_class = (uint8_t)value;
btif_config_get_int(name, BTIF_STORAGE_KEY_HID_APP_ID, &value);
uint8_t app_id = (uint8_t)value;
btif_config_get_int(name, BTIF_STORAGE_KEY_HID_VENDOR_ID, &value);
dscp_info.vendor_id = (uint16_t)value;
btif_config_get_int(name, BTIF_STORAGE_KEY_HID_PRODUCT_ID, &value);
dscp_info.product_id = (uint16_t)value;
btif_config_get_int(name, BTIF_STORAGE_KEY_HID_VERSION, &value);
dscp_info.version = (uint16_t)value;
btif_config_get_int(name, BTIF_STORAGE_KEY_HID_COUNTRY_CODE, &value);
dscp_info.ctry_code = (uint8_t)value;
value = 0;
btif_config_get_int(name, BTIF_STORAGE_KEY_HID_SSR_MAX_LATENCY, &value);
dscp_info.ssr_max_latency = (uint16_t)value;
value = 0;
btif_config_get_int(name, BTIF_STORAGE_KEY_HID_SSR_MIN_TIMEOUT, &value);
dscp_info.ssr_min_tout = (uint16_t)value;
// 6. 获取设备描述符
size_t len =
btif_config_get_bin_length(name, BTIF_STORAGE_KEY_HID_DESCRIPTOR);
if (len > 0) {
dscp_info.descriptor.dl_len = (uint16_t)len;
dscp_info.descriptor.dsc_list = (uint8_t*)alloca(len);
btif_config_get_bin(name, BTIF_STORAGE_KEY_HID_DESCRIPTOR,
(uint8_t*)dscp_info.descriptor.dsc_list, &len);
}
// 7. 添加设备到 BTA_HH 模块
// add extracted information to BTA HH
link_spec.addrt.bda = bd_addr;
link_spec.addrt.type = BLE_ADDR_PUBLIC;
link_spec.transport = BT_TRANSPORT_AUTO;
if (btif_hh_add_added_dev(link_spec, attr_mask)) {
BTA_HhAddDev(link_spec, attr_mask, sub_class, app_id, dscp_info);
}
}
return BT_STATUS_SUCCESS;
}
从非易失性随机访问存储器(NVRAM)里加载所有已配对蓝牙 HID(Human Interface Device,人机接口设备)设备的信息,并且将这些设备添加到 BTA_HH(Bluetooth Application - Human Interface Device Host)模块中。
核心流程:
btif_config_get_paired_devices
/packages/modules/Bluetooth/system/btif/src/btif_config.cc
std::vector<RawAddress> btif_config_get_paired_devices() {
std::vector<std::string> names;
CHECK(bluetooth::shim::is_gd_stack_started_up());
// 获取持久化存储的设备名称
names = bluetooth::shim::BtifConfigInterface::GetPersistentDevices();
std::vector<RawAddress> result;
result.reserve(names.size());
// 遍历设备名称并转换为地址
for (const auto& name : names) {
RawAddress addr = {};
// Gather up known devices from configuration section names
if (RawAddress::FromString(name, addr)) {
result.emplace_back(addr);
}
}
return result;
}
获取所有已配对蓝牙设备的地址,返回一个包含 RawAddress 对象的向量。借助 bluetooth::shim::BtifConfigInterface 来获取持久化存储的设备名称,然后将这些名称转换为 RawAddress 对象。
GetPersistentDevices
/packages/modules/Bluetooth/system/main/shim/config.cc
std::vector<std::string> BtifConfigInterface::GetPersistentDevices() {
return GetStorage()->GetPersistentSections();
}
GetPersistentSections
packages/modules/Bluetooth/system/gd/storage/storage_module.cc
std::vector<std::string> StorageModule::GetPersistentSections() const {
std::lock_guard<std::recursive_mutex> lock(mutex_);
return pimpl_->cache_.GetPersistentSections();
}
ConfigCache::GetPersistentSections
/packages/modules/Bluetooth/system/gd/storage/config_cache.cc
std::vector<std::string> ConfigCache::GetPersistentSections() const {
std::lock_guard<std::recursive_mutex> lock(mutex_);
std::vector<std::string> paired_devices;
paired_devices.reserve(persistent_devices_.size());
// 遍历持久化设备并添加名称到容器中
for (const auto& elem : persistent_devices_) {
paired_devices.emplace_back(elem.first);
}
return paired_devices;
}
获取所有持久化设备的名称(可能代表设备的 MAC 地址等标识),并将这些名称存储在一个 std::vector<std::string> 类型的容器中返回。
btif_config_get_int
packages/modules/Bluetooth/system/btif/src/btif_config.cc
bool btif_config_get_int(const std::string& section, const std::string& key,
int* value) {
CHECK(bluetooth::shim::is_gd_stack_started_up());
return bluetooth::shim::BtifConfigInterface::GetInt(section, key, value);
}
BtifConfigInterface::GetInt
packages/modules/Bluetooth/system/main/shim/config.cc
bool BtifConfigInterface::GetInt(const std::string& section,
const std::string& property, int* value) {
ASSERT(value != nullptr);
auto ret = GetStorage()->GetInt(section, property);
if (ret) {
*value = *ret;
}
return ret.has_value();
}
从配置存储中获取指定部分(section)下指定属性(property)的整数值,并将该值存储到传入的指针 value 所指向的内存位置。若成功获取到值,则返回 true;若未获取到值,则返回 false。
packages/modules/Bluetooth/system/gd/storage/storage_module.cc
std::optional<int> StorageModule::GetInt(
const std::string& section, const std::string& property) const {
std::lock_guard<std::recursive_mutex> lock(mutex_);
return ConfigCacheHelper::FromConfigCache(pimpl_->cache_).GetInt(section, property);
}
ConfigCacheHelper::GetInt
/packages/modules/Bluetooth/system/gd/storage/config_cache_helper.cc
std::optional<int> ConfigCacheHelper::GetInt(const std::string& section, const std::string& property) const {
// 1. 获取属性的字符串值
auto value_str = config_cache_.GetProperty(section, property);
if (!value_str) {
return std::nullopt;
}
// 2. 获取属性的 int64_t 类型值
auto large_value = GetInt64(section, property);
if (!large_value) {
return std::nullopt;
}
// 3. 检查值是否在 int 类型的数值范围内
if (!common::IsNumberInNumericLimits<int>(*large_value)) {
return std::nullopt;
}
return static_cast<uint32_t>(*large_value);
}
从配置缓存中获取指定部分(section)和属性(property)对应的整数值。如果获取成功且该值在 int 类型的数值范围内,函数将返回该整数值;否则,返回 std::nullopt 表示未获取到有效的 int 类型值。
ConfigCache::GetProperty
/packages/modules/Bluetooth/system/gd/storage/config_cache.cc
std::optional<std::string> ConfigCache::GetProperty(const std::string& section, const std::string& property) const {
// 加锁以保证线程安全
std::lock_guard<std::recursive_mutex> lock(mutex_);
// 1. 在 information_sections_ 中查找属性
auto section_iter = information_sections_.find(section);
if (section_iter != information_sections_.end()) {
auto property_iter = section_iter->second.find(property);
if (property_iter != section_iter->second.end()) {
return property_iter->second;
}
}
// 2. 在 persistent_devices_ 中查找属性
section_iter = persistent_devices_.find(section);
if (section_iter != persistent_devices_.end()) {
auto property_iter = section_iter->second.find(property);
if (property_iter != section_iter->second.end()) {
std::string value = property_iter->second;
if (os::ParameterProvider::GetBtKeystoreInterface() != nullptr && value == kEncryptedStr) {
return os::ParameterProvider::GetBtKeystoreInterface()->get_key(section + "-" + property);
}
return value;
}
}
// 3. 在 temporary_devices_ 中查找属性
section_iter = temporary_devices_.find(section);
if (section_iter != temporary_devices_.end()) {
auto property_iter = section_iter->second.find(property);
if (property_iter != section_iter->second.end()) {
return property_iter->second;
}
}
return std::nullopt;
}
从配置缓存里获取指定部分(section)和属性(property)的值。若能找到对应的值,就返回该值;若找不到,则返回 std::nullopt。
get_key
packages/modules/Bluetooth/system/btif/src/btif_keystore.cc
std::string get_key(std::string prefix) override {
log::verbose("prefix: {}", prefix);
// 检查回调函数指针是否为空
if (!callbacks) {
log::warn("callback isn't ready. prefix: {}", prefix);
return "";
}
// 用于存储解密后的密钥字符串
std::string decryptedString;
// 尝试在 key_map 中查找以 prefix 为键的元素
std::map<std::string, std::string>::iterator iter = key_map.find(prefix);
if (iter == key_map.end()) {
// 如果在 key_map 中未找到对应的元素
// 调用回调函数从外部获取密钥
decryptedString = callbacks->get_key(prefix);
// 将获取到的密钥存储到 key_map 中,以便后续使用
key_map[prefix] = decryptedString;
log::verbose("get key from bluetoothkeystore.");
} else {
// 如果在 key_map 中找到了对应的元素
// 直接从 key_map 中获取解密后的密钥
decryptedString = iter->second;
}
// 返回解密后的密钥字符串
return decryptedString;
}
根据给定的前缀 prefix
来获取对应的密钥。先尝试从本地的 key_map
中查找该密钥,如果找不到,会通过回调函数 callbacks->get_key
从外部(如蓝牙密钥存储库)获取密钥,并将其保存到 key_map
中,以便后续使用。
IsNumberInNumericLimits
packages/modules/Bluetooth/system/gd/common/numbers.h
// Check if input is within numeric limits of RawType
template <typename RawType, typename InputType>
bool IsNumberInNumericLimits(InputType input) {
// Only arithmetic types are supported
static_assert(std::is_arithmetic_v<RawType> && std::is_arithmetic_v<InputType>);
// Either both are signed or both are unsigned
static_assert(
(std::is_signed_v<RawType> && std::is_signed_v<InputType>) ||
(std::is_unsigned_v<RawType> && std::is_unsigned_v<InputType>));
// 检查输入类型的最大值是否超过目标类型的最大值
if (std::numeric_limits<InputType>::max() > std::numeric_limits<RawType>::max()) {
if (input > std::numeric_limits<RawType>::max()) {
return false;
}
}
// 检查输入类型的最小值是否低于目标类型的最小值
if (std::numeric_limits<InputType>::lowest() < std::numeric_limits<RawType>::lowest()) {
if (input < std::numeric_limits<RawType>::lowest()) {
return false;
}
}
// 如果输入值在目标类型的数值范围内,返回 true
return true;
}
IsNumberInNumericLimits 是一个模板函数,其作用是检查输入值 input 是否处于 RawType 类型所规定的数值范围之内。借助 C++ 的类型特性和数值极限工具,保证仅对算术类型(如整数、浮点数)进行操作,并且会对输入类型和目标类型的有符号性进行检查。
btif_config_get_bin_length
packages/modules/Bluetooth/system/btif/src/btif_config.cc
size_t btif_config_get_bin_length(const std::string& section,
const std::string& key) {
CHECK(bluetooth::shim::is_gd_stack_started_up());
return bluetooth::shim::BtifConfigInterface::GetBinLength(section, key);
}
/packages/modules/Bluetooth/system/main/shim/config.cc
size_t BtifConfigInterface::GetBinLength(const std::string& section,
const std::string& property) {
auto value_vec = GetStorage()->GetBin(section, property);
if (!value_vec) {
return 0;
}
return value_vec->size();
}
packages/modules/Bluetooth/system/gd/storage/storage_module.cc
std::optional<int> StorageModule::GetInt(
const std::string& section, const std::string& property) const {
std::lock_guard<std::recursive_mutex> lock(mutex_);
return ConfigCacheHelper::FromConfigCache(pimpl_->cache_).GetInt(section, property);
}
btif_hh_add_added_dev
packages/modules/Bluetooth/system/btif/src/btif_hh.cc
/*******************************************************************************
* Static variables
******************************************************************************/
btif_hh_cb_t btif_hh_cb;
/*******************************************************************************
*
* Function btif_hh_add_added_dev
*
* Description Add a new device to the added device list.
*
* Returns true if add successfully, otherwise false.
******************************************************************************/
bool btif_hh_add_added_dev(const tAclLinkSpec& link_spec,
tBTA_HH_ATTR_MASK attr_mask) {
int i;
// 第一次遍历:检查设备是否已经存在于已添加设备列表中
for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
if (btif_hh_cb.added_devices[i].link_spec.addrt.bda ==
link_spec.addrt.bda) {
// 如果设备已经存在,返回 false
log::warn("Device {} already added", ADDRESS_TO_LOGGABLE_STR(link_spec));
return false;
}
}
// 第二次遍历:寻找列表中的空位来添加新设备
for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
if (btif_hh_cb.added_devices[i].link_spec.addrt.bda.IsEmpty()) {
// 找到空位后,记录添加设备的日志
log::warn("Added device {}", ADDRESS_TO_LOGGABLE_STR(link_spec));
// 将新设备的链接规格信息赋值给该空位
btif_hh_cb.added_devices[i].link_spec = link_spec;
// 初始化设备句柄为无效句柄
btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
// 赋值设备属性掩码
btif_hh_cb.added_devices[i].attr_mask = attr_mask;
// 添加成功,返回 true
return true;
}
}
// 如果列表已满,没有空位,记录错误日志并返回 false
log::warn("Error, out of space to add device");
return false;
}
将一个新的设备添加到已添加设备列表中。先检查设备是否已经存在于列表中,如果存在则不添加并返回 false;若不存在,会尝试在列表中找到一个空位来添加该设备,若成功添加则返回 true;如果列表已满,无法添加新设备,也会返回 false。
BTA_HhAddDev
packages/modules/Bluetooth/system/bta/hh/bta_hh_api.cc
/*******************************************************************************
*
* Function BTA_HhAddDev
*
* Description Add a virtually cabled device into HID-Host device list
* to manage and assign a device handle for future API call,
* host applciation call this API at start-up to initialize its
* virtually cabled devices.
*
* Returns void
*
******************************************************************************/
void BTA_HhAddDev(const tAclLinkSpec& link_spec, tBTA_HH_ATTR_MASK attr_mask,
uint8_t sub_class, uint8_t app_id,
tBTA_HH_DEV_DSCP_INFO dscp_info) {
// 1. 计算所需内存大小
size_t len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len;
// 2. 分配内存
tBTA_HH_MAINT_DEV* p_buf = (tBTA_HH_MAINT_DEV*)osi_calloc(len);
// 3. 设置消息头信息
p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
p_buf->sub_event = BTA_HH_ADD_DEV_EVT;
p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE;
// 4. 设置设备属性
p_buf->attr_mask = (uint16_t)attr_mask;
p_buf->sub_class = sub_class;
p_buf->app_id = app_id;
p_buf->link_spec = link_spec;
// 5. 复制描述符信息
memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO));
if (dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list) {
p_buf->dscp_info.descriptor.dl_len = dscp_info.descriptor.dl_len;
p_buf->dscp_info.descriptor.dsc_list = (uint8_t*)(p_buf + 1);
memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list,
dscp_info.descriptor.dl_len);
} else {
p_buf->dscp_info.descriptor.dsc_list = NULL;
p_buf->dscp_info.descriptor.dl_len = 0;
}
// 6. 发送消息
bta_sys_sendmsg(p_buf);
}
将一个虚拟有线设备添加到 HID - Host(人机接口设备主机)设备列表中进行管理,并为未来的 API 调用分配一个设备句柄。主机应用程序在启动时会调用此 API 来初始化其虚拟有线设备。
class ConfigCache
namespace bluetooth {
namespace storage {
class Mutation;
// A memory operated section-key-value structured config
//
// A section can be either persistent or temporary. When a section becomes persistent, all its properties are
// written to disk.
//
// A section becomes persistent when a property that is part of persistent_property_names_ is written to config cache;
// A section becomes temporary when all properties that are part of persistent_property_names_ is removed
//
// The definition of persistent sections is up to the user and is defined through the |persistent_property_names|
// argument. When these properties are link key properties, then persistent sections is equal to bonded devices
//
// This class is thread safe
class ConfigCache {
public:
ConfigCache(size_t temp_device_capacity, std::unordered_set<std::string_view> persistent_property_names);
ConfigCache(const ConfigCache&) = delete;
ConfigCache& operator=(const ConfigCache&) = delete;
virtual ~ConfigCache() = default;
// no copy
// can move
ConfigCache(ConfigCache&& other) noexcept;
ConfigCache& operator=(ConfigCache&& other) noexcept;
// comparison operators, callback doesn't count
bool operator==(const ConfigCache& rhs) const;
bool operator!=(const ConfigCache& rhs) const;
// observers
virtual bool HasSection(const std::string& section) const;
virtual bool HasProperty(const std::string& section, const std::string& property) const;
// Get property, return std::nullopt if section or property does not exist
virtual std::optional<std::string> GetProperty(const std::string& section, const std::string& property) const;
// Returns a copy of persistent device MAC addresses
virtual std::vector<std::string> GetPersistentSections() const;
// Return true if a section is persistent
virtual bool IsPersistentSection(const std::string& section) const;
// Return true if a section has one of the properties in |property_names|
virtual bool HasAtLeastOneMatchingPropertiesInSection(
const std::string& section, const std::unordered_set<std::string_view>& property_names) const;
// Return true if a property is part of persistent_property_names_
virtual bool IsPersistentProperty(const std::string& property) const;
// Serialize to legacy config format
virtual std::string SerializeToLegacyFormat() const;
// Return a copy of pair<section_name, property_value> with property
struct SectionAndPropertyValue {
std::string section;
std::string property;
bool operator==(const SectionAndPropertyValue& rhs) const {
return section == rhs.section && property == rhs.property;
}
bool operator!=(const SectionAndPropertyValue& rhs) const {
return !(*this == rhs);
}
};
virtual std::vector<SectionAndPropertyValue> GetSectionNamesWithProperty(const std::string& property) const;
// modifiers
// Commit all mutation entries in sequence while holding the config mutex
virtual void Commit(std::queue<MutationEntry>& mutation);
virtual void SetProperty(std::string section, std::string property, std::string value);
virtual bool RemoveSection(const std::string& section);
virtual bool RemoveProperty(const std::string& section, const std::string& property);
virtual void ConvertEncryptOrDecryptKeyIfNeeded();
// TODO: have a systematic way of doing this instead of specialized methods
// Remove sections with |property| set
virtual void RemoveSectionWithProperty(const std::string& property);
// remove all content in this config cache, restore it to the state after the explicit constructor
virtual void Clear();
// Set a callback to notify interested party that a persistent config change has just happened
virtual void SetPersistentConfigChangedCallback(std::function<void()> persistent_config_changed_callback);
// Device config specific methods
// TODO: methods here should be moved to a device specific config cache if this config cache is supposed to be generic
// Legacy stack has device type inconsistencies, this method is trying to fix it
virtual bool FixDeviceTypeInconsistencies();
// static methods
// Check if section is formatted as a MAC address
static bool IsDeviceSection(const std::string& section);
// constants
static const std::string kDefaultSectionName;
private:
mutable std::recursive_mutex mutex_;
// A callback to notify interested party that a persistent config change has just happened, empty by default
std::function<void()> persistent_config_changed_callback_;
// A set of property names that if set would make a section persistent and if non of these properties are set, a
// section would become temporary again
std::unordered_set<std::string_view> persistent_property_names_;
// Common section that does not relate to remote device, will be written to disk
common::ListMap<std::string, common::ListMap<std::string, std::string>> information_sections_;
// Information about persistent devices, normally paired, will be written to disk
common::ListMap<std::string, common::ListMap<std::string, std::string>> persistent_devices_;
// Information about temporary devices, normally unpaired, will not be written to disk, will be evicted automatically
// if capacity exceeds given value during initialization
common::LruCache<std::string, common::ListMap<std::string, std::string>> temporary_devices_;
// Convenience method to check if the callback is valid before calling it
inline void PersistentConfigChangedCallback() const {
if (persistent_config_changed_callback_) {
persistent_config_changed_callback_();
}
}
};
} // namespace storage
} // namespace bluetooth
ConfigCache 类用于管理配置信息,这些信息以部分(section)和键值对的形式存储。部分可以是持久的(persistent)或临时的(temporary)。当写入属于 persistent_property_names_ 集合的属性时,部分会变为持久的;当移除所有属于 persistent_property_names_ 的属性时,部分会变为临时的。
采用分层存储策略的蓝牙配置缓存系统,通过持久化/临时化的二元分类和LRU淘汰机制,在内存效率与数据持久性之间取得平衡。
关键架构设计
①三元存储结构
-
通用配置段 (
information_sections_
)-
存储与具体设备无关的全局配置
-
使用
ListMap
保证有序存储 -
始终持久化到磁盘
-
-
持久化设备段 (
persistent_devices_
)-
存储已配对设备的配置信息
-
当包含
persistent_property_names_
定义的属性时自动持久化 -
使用
ListMap
维护插入顺序
-
-
临时设备段 (
temporary_devices_
)-
存储未配对设备的临时配置
-
采用
LruCache
实现,当容量超过初始化阈值时自动淘汰最久未使用的条目 -
不写入磁盘
-
②持久化判定机制
-
通过构造函数传入的
persistent_property_names
集合定义持久化属性 -
当设备配置段包含任意持久化属性时:
-
该段升级为持久化状态
-
所有属性(包括非持久化属性)将被写入磁盘
-
-
当所有持久化属性被移除时:
-
该段降级为临时状态
-
可能被LRU机制淘汰
-
③线程安全实现
-
使用
std::recursive_mutex
保护所有访问操作 -
支持递归加锁,避免死锁风险
-
所有public方法均通过mutex保护,保证多线程环境下的数据一致性
时序图
总结
①核心流程:系统启动时,通过遍历NVRAM中存储的已配对设备信息,提取HID属性(如子类、应用ID、描述符等),校验设备绑定状态后,将有效信息注册到蓝牙HID主机模块(BTA_HH)。采用7步链式处理(设备遍历→属性校验→描述符构建→主机注册),通过btif_config
系列接口实现跨模块数据透传,确保HID设备信息的完整性加载
②架构创新:
-
三元存储结构:分离全局配置/持久设备/临时设备数据,采用差异化的ListMap与LruCache容器
-
动态持久化:通过预定义
persistent_property_names
自动升级设备段存储等级,支持密钥触发式落盘 -
安全机制:集成数值范围校验模板(
IsNumberInNumericLimits
)、加密属性自动解密、双阶段设备查重
③生产级特性:
-
递归锁实现配置操作的原子性
-
设备描述符内存动态分配(
alloca
)避免内存泄漏 -
通过
Mutation
队列实现批量配置更新的事务性提交