本文围绕蓝牙存储模块展开,主要解析了蓝牙存储模块(StorageModule)的初始化流程,重点围绕配置文件校验、读取、设备类型修复及加密处理展开。通过工厂重置检测、校验和验证、多源配置加载、设备类型推断修正等步骤,确保配置完整性,并结合延迟保存机制优化存储性能。
StorageModule::Start
/packages/modules/Bluetooth/system/gd/storage/storage_module.cc
void StorageModule::Start() {
// 1. 线程同步
std::lock_guard<std::recursive_mutex> lock(mutex_);
// 2. 处理工厂重置
std::string file_source;
if (os::GetSystemProperty(kFactoryResetProperty) == "true") {
LOG_INFO("%s is true, delete config files", kFactoryResetProperty.c_str());
LegacyConfigFile::FromPath(config_file_path_).Delete();
LegacyConfigFile::FromPath(config_backup_path_).Delete();
os::SetSystemProperty(kFactoryResetProperty, "false");
}
// 3. 校验配置文件的校验和
if (!is_config_checksum_pass(kConfigFileComparePass)) {
LegacyConfigFile::FromPath(config_file_path_).Delete();
}
if (!is_config_checksum_pass(kConfigBackupComparePass)) {
LegacyConfigFile::FromPath(config_backup_path_).Delete();
}
// 4. 读取配置文件
bool save_needed = false;
auto config = LegacyConfigFile::FromPath(config_file_path_).Read(temp_devices_capacity_);
if (!config || !config->HasSection(kAdapterSection)) {
LOG_WARN("cannot load config at %s, using backup at %s.", config_file_path_.c_str(), config_backup_path_.c_str());
config = LegacyConfigFile::FromPath(config_backup_path_).Read(temp_devices_capacity_);
file_source = "Backup";
// Make sure to update the file, since it wasn't read from the config_file_path_
save_needed = true;
}
if (!config || !config->HasSection(kAdapterSection)) {
LOG_WARN("cannot load backup config at %s; creating new empty ones", config_backup_path_.c_str());
config.emplace(temp_devices_capacity_, Device::kLinkKeyProperties);
file_source = "Empty";
}
// 5. 设置文件源信息
if (!file_source.empty()) {
config->SetProperty(kInfoSection, kFileSourceProperty, std::move(file_source));
}
// 6. 清理临时配对信息
// Cleanup temporary pairings if we have left guest mode
if (!is_restricted_mode_) {
config->RemoveSectionWithProperty("Restricted");
}
// 7. 设置配置文件创建时间戳
// Read or set config file creation timestamp
auto time_str = config->GetProperty(kInfoSection, kTimeCreatedProperty);
if (!time_str) {
std::stringstream ss;
auto now = std::chrono::system_clock::now();
auto now_time_t = std::chrono::system_clock::to_time_t(now);
ss << std::put_time(std::localtime(&now_time_t), kTimeCreatedFormat.c_str());
config->SetProperty(kInfoSection, kTimeCreatedProperty, ss.str());
}
// 8. 修复设备类型不一致问题
config->FixDeviceTypeInconsistencies();
// 9. 创建 impl 对象
// TODO (b/158035889) Migrate metrics module to GD
pimpl_ = std::make_unique<impl>(GetHandler(), std::move(config.value()), temp_devices_capacity_);
// 10. 延迟保存配置文件
if (save_needed) {
// Set a timer and write the new config file to disk.
SaveDelayed();
}
// 11. 设置持久化配置更改回调
pimpl_->cache_.SetPersistentConfigChangedCallback(
[this] { this->CallOn(this, &StorageModule::SaveDelayed); });
// 12. 必要时转换加密或解密密钥
if (bluetooth::os::ParameterProvider::GetBtKeystoreInterface() != nullptr) {
bluetooth::os::ParameterProvider::GetBtKeystoreInterface()->ConvertEncryptOrDecryptKeyIfNeeded();
}
}
StorageModule::Start 函数是 StorageModule 类的启动函数,主要负责初始化存储模块,包括处理工厂重置、校验配置文件的校验和、读取配置文件、清理临时配对信息、设置配置文件创建时间戳等操作,最后创建 impl 对象并在必要时延迟保存配置文件。
LegacyConfigFile::Read
/packages/modules/Bluetooth/system/gd/storage/legacy_config_file.cc
std::optional<ConfigCache> LegacyConfigFile::Read(size_t temp_devices_capacity) {
// 1. 路径检查与文件打开
ASSERT(!path_.empty());
std::ifstream config_file(path_);
if (!config_file || !config_file.is_open()) {
LOG_ERROR("unable to open file '%s', error: %s", path_.c_str(), strerror(errno));
return std::nullopt;
}
// 2. 初始化变量
[[maybe_unused]] int line_num = 0;
ConfigCache cache(temp_devices_capacity, Device::kLinkKeyProperties);
std::string line;
std::string section(ConfigCache::kDefaultSectionName);
// 3. 逐行读取文件
while (std::getline(config_file, line)) {
++line_num;
line = common::StringTrim(std::move(line)); // 去除行首尾的空白字符
if (line.empty()) {
continue;
}
if (line.front() == '\0' || line.front() == '#') {
continue;
}
// 4. 处理配置文件节
if (line.front() == '[') {
if (line.back() != ']') {
LOG_WARN("unterminated section name on line %d", line_num);
return std::nullopt;
}
// Read 'test' from '[text]', hence -2
section = line.substr(1, line.size() - 2); // 提取方括号内的节名
}
// 5. 处理键值对
else {
auto tokens = common::StringSplit(line, "=", 2);
if (tokens.size() != 2) {
LOG_WARN("no key/value separator found on line %d", line_num);
return std::nullopt;
}
tokens[0] = common::StringTrim(std::move(tokens[0]));
tokens[1] = common::StringTrim(std::move(tokens[1]));
cache.SetProperty(section, tokens[0], std::move(tokens[1]));
}
}
return cache;
}
从指定路径的配置文件中读取配置信息,并将其解析为 ConfigCache 对象。如果文件打开失败、配置文件格式错误,将返回 std::nullopt 表示读取失败;若读取和解析成功,则返回包含配置信息的 ConfigCache 对象。
ConfigCache::SetProperty
packages/modules/Bluetooth/system/gd/storage/config_cache.cc
void ConfigCache::SetProperty(std::string section, std::string property, std::string value) {
// 1. 线程同步
std::lock_guard<std::recursive_mutex> lock(mutex_);
// 2.去除 section、property 和 value 字符串中的换行符
TrimAfterNewLine(section);
TrimAfterNewLine(property);
TrimAfterNewLine(value);
ASSERT_LOG(!section.empty(), "Empty section name not allowed");
ASSERT_LOG(!property.empty(), "Empty property name not allowed");
// 3. 处理非设备节
if (!IsDeviceSection(section)) {
auto section_iter = information_sections_.find(section);
if (section_iter == information_sections_.end()) {
section_iter = information_sections_.try_emplace_back(section, common::ListMap<std::string, std::string>{}).first;
}
section_iter->second.insert_or_assign(property, std::move(value));
PersistentConfigChangedCallback();
return;
}
// 4. 处理设备节且属性为持久属性的情况
auto section_iter = persistent_devices_.find(section);
if (section_iter == persistent_devices_.end() && IsPersistentProperty(property)) {
// move paired devices or create new paired device when a link key is set
auto section_properties = temporary_devices_.extract(section);
if (section_properties) {
section_iter = persistent_devices_.try_emplace_back(section, std::move(section_properties->second)).first;
} else { //创建一个空的 common::ListMap 用于存储属性和值
section_iter = persistent_devices_.try_emplace_back(section, common::ListMap<std::string, std::string>{}).first;
}
}
// 5. 持久设备节属性的加密处理与存储
if (section_iter != persistent_devices_.end()) {
bool is_encrypted = value == kEncryptedStr;
// 值不为空、蓝牙密钥库接口可用、系统处于通用准则模式、属性在加密密钥名称列表中且值未加密
if ((!value.empty()) && os::ParameterProvider::GetBtKeystoreInterface() != nullptr &&
os::ParameterProvider::IsCommonCriteriaMode() && InEncryptKeyNameList(property) && !is_encrypted) {
// 对值进行加密
if (os::ParameterProvider::GetBtKeystoreInterface()->set_encrypt_key_or_remove_key(
section + "-" + property, value)) {
value = kEncryptedStr;
}
}
// 将属性和值插入或更新到该节的 common::ListMap 中
section_iter->second.insert_or_assign(property, std::move(value));
// 通知配置发生更改
PersistentConfigChangedCallback();
return;
}
// 6. 处理临时设备节
section_iter = temporary_devices_.find(section);
if (section_iter == temporary_devices_.end()) {
auto triple = temporary_devices_.try_emplace(section, common::ListMap<std::string, std::string>{});
section_iter = std::get<0>(triple);
}
section_iter->second.insert_or_assign(property, std::move(value));
}
在配置缓存中设置指定节(section)下的属性(property)及其对应的值(value)。根据节的类型(是否为设备节)和属性的持久性,将属性和值存储到不同的存储结构中,同时支持在特定条件下对敏感属性值进行加密处理,并在配置发生更改时调用回调函数。
ConfigCache::FixDeviceTypeInconsistencies
packages/modules/Bluetooth/system/gd/storage/config_cache.cc
bool ConfigCache::FixDeviceTypeInconsistencies() {
// 1. 线程同步
std::lock_guard<std::recursive_mutex> lock(mutex_);
bool persistent_device_changed = false;
// 2. 遍历信息部分和持久设备部分
for (auto* config_section : {&information_sections_, &persistent_devices_}) {
for (auto& elem : *config_section) {
if (FixDeviceTypeInconsistencyInSection(elem.first, elem.second)) {
persistent_device_changed = true;
}
}
}
// 3. 遍历临时设备部分
bool temp_device_changed = false;
for (auto& elem : temporary_devices_) {
if (FixDeviceTypeInconsistencyInSection(elem.first, elem.second)) {
temp_device_changed = true;
}
}
// 4. 处理持久设备部分的变更
if (persistent_device_changed) {
PersistentConfigChangedCallback();
}
return persistent_device_changed || temp_device_changed;
}
修复配置缓存中设备类型的不一致问题。遍历配置缓存中的不同部分(包括信息部分、持久设备部分和临时设备部分),针对每个部分调用 FixDeviceTypeInconsistencyInSection 函数来检查并修复设备类型的不一致。若有任何部分的设备类型发生了改变,会调用 PersistentConfigChangedCallback 函数通知配置发生了持久化变更,最后返回是否有设备类型被修改的结果。
FixDeviceTypeInconsistencyInSection
/packages/modules/Bluetooth/system/gd/storage/config_cache.cc
namespace {
bool FixDeviceTypeInconsistencyInSection(
const std::string& section_name, common::ListMap<std::string, std::string>& device_section_entries) {
// 1. 检查节名是否为有效的蓝牙地址
if (!hci::Address::IsValidAddress(section_name)) {
return false;
}
// 2. 处理设备类型为双模蓝牙(DUAL)的情况
auto device_type_iter = device_section_entries.find("DevType");
if (device_type_iter != device_section_entries.end() &&
device_type_iter->second == std::to_string(hci::DeviceType::DUAL)) {
// We might only have one of classic/LE keys for a dual device, but it is still a dual device,
// so we should not change the DevType.
return false;
}
// 3. 推断设备的实际类型
// we will ignore the existing DevType, since it is not known to be a DUAL device so
// the keys we have should be sufficient to infer the correct DevType
bool is_le = false;
bool is_classic = false;
// default
hci::DeviceType device_type = hci::DeviceType::BR_EDR;
for (const auto& entry : device_section_entries) {
if (kLePropertyNames.find(entry.first) != kLePropertyNames.end()) {
is_le = true;
}
if (kClassicPropertyNames.find(entry.first) != kClassicPropertyNames.end()) {
is_classic = true;
}
}
if (is_classic && is_le) {
device_type = hci::DeviceType::DUAL;
} else if (is_classic) {
device_type = hci::DeviceType::BR_EDR;
} else if (is_le) {
device_type = hci::DeviceType::LE;
}
// 4. 检查并更新设备类型
bool inconsistent = true; // 表示默认存在不一致
std::string device_type_str = std::to_string(device_type);
if (device_type_iter != device_section_entries.end()) {
inconsistent = device_type_str != device_type_iter->second;
if (inconsistent) {
device_type_iter->second = std::move(device_type_str);
}
} else {
device_section_entries.insert_or_assign("DevType", std::move(device_type_str));
}
return inconsistent;
}
} // namespace
修复配置节中设备类型的不一致问题。根据设备配置节中的属性信息,推断出设备的实际类型(如经典蓝牙、低功耗蓝牙或双模蓝牙),并与配置节中已有的设备类型进行比较。如果存在不一致,则更新配置节中的设备类型,最后返回是否进行了更新的标志。
ConfigCache::RemoveSectionWithProperty
packages/modules/Bluetooth/system/gd/storage/config_cache.cc
void ConfigCache::RemoveSectionWithProperty(const std::string& property) {
std::lock_guard<std::recursive_mutex> lock(mutex_);
size_t num_persistent_removed = 0;
// 遍历信息部分和持久设备部分
for (auto* config_section : {&information_sections_, &persistent_devices_}) {
for (auto it = config_section->begin(); it != config_section->end();) {
if (it->second.contains(property)) {
LOG_INFO("Removing persistent section %s with property %s", it->first.c_str(), property.c_str());
it = config_section->erase(it);
num_persistent_removed++;
continue;
}
it++;
}
}
// 遍历临时设备部分
for (auto it = temporary_devices_.begin(); it != temporary_devices_.end();) {
if (it->second.contains(property)) {
LOG_INFO("Removing temporary section %s with property %s", it->first.c_str(), property.c_str());
it = temporary_devices_.erase(it);
continue;
}
it++;
}
// 处理持久设备部分的变更
if (num_persistent_removed > 0) {
PersistentConfigChangedCallback();
}
}
从配置缓存里移除所有包含指定属性的节。遍历配置缓存的不同部分,也就是信息部分、持久设备部分以及临时设备部分,一旦发现某个节包含指定属性,就将该节移除。如果持久设备部分有节被移除,会调用 PersistentConfigChangedCallback 函数来通知配置发生了持久化变更。
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_);
// 在信息部分查找属性
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;
}
}
// 在持久设备部分查找属性
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;
}
}
// 在临时设备部分查找属性
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。
SaveDelayed
延迟保存存储模块的配置信息。安排一个延迟任务,在指定的时间后调用 SaveImmediately 函数来实际保存配置。通过这种方式,可以避免频繁地保存配置,减少对存储设备的读写操作,提高性能。
StorageModule::SaveImmediately
/packages/modules/Bluetooth/system/gd/storage/config_cache.cc
void StorageModule::SaveImmediately() {
std::lock_guard<std::recursive_mutex> lock(mutex_);
// 处理待执行的保存任务
if (pimpl_->has_pending_config_save_) {
pimpl_->config_save_alarm_.Cancel();
pimpl_->has_pending_config_save_ = false;
}
// 重命名旧的配置文件为备份文件
// 1. rename old config to backup name
if (os::FileExists(config_file_path_)) {
ASSERT(os::RenameFile(config_file_path_, config_backup_path_));
}
// 将内存中的配置信息写入主配置文件
// 2. write in-memory config to disk, if failed, backup can still be used
ASSERT(LegacyConfigFile::FromPath(config_file_path_).Write(pimpl_->cache_));
// 将内存中的配置信息写入备份文件
// 3. now write back up to disk as well
if (!LegacyConfigFile::FromPath(config_backup_path_).Write(pimpl_->cache_)) {
LOG_ERROR("Unable to write backup config file");
}
// 在特定条件下保存配置文件的校验和
// 4. save checksum if it is running in common criteria mode
if (bluetooth::os::ParameterProvider::GetBtKeystoreInterface() != nullptr &&
bluetooth::os::ParameterProvider::IsCommonCriteriaMode()) {
bluetooth::os::ParameterProvider::GetBtKeystoreInterface()->set_encrypt_key_or_remove_key(
kConfigFilePrefix, kConfigFileHash);
}
}
立即将存储模块中的配置信息保存到磁盘上。处理待执行的保存任务、对旧配置文件进行重命名、将内存中的配置信息写入主配置文件和备份文件,并且在满足特定条件时保存配置文件的校验和。
FileExists
packages/modules/Bluetooth/system/gd/os/linux_generic/files.cc
bool FileExists(const std::string& path) {
// 尝试打开文件
std::ifstream input(path, std::ios::binary | std::ios::ate);
return input.good(); // 返回文件流状态
}
input(path, std::ios::binary | std::ios::ate)
:调用 std::ifstream
的构造函数来尝试打开指定路径的文件。
path
:要打开的文件的路径。std::ios::binary
:以二进制模式打开文件,这样可以避免在读取文件时进行文本模式的转换,确保数据的原始性。std::ios::ate
:打开文件后将文件指针定位到文件末尾,ate 是 at end 的缩写。此模式在判断文件是否存在时并非必需,但它允许在后续需要时获取文件的大小。
RenameFile
/packages/modules/Bluetooth/system/gd/os/linux_generic/files.cc
bool RenameFile(const std::string& from, const std::string& to) {
if (std::rename(from.c_str(), to.c_str()) != 0) {
LOG_ERROR("unable to rename file from '%s' to '%s', error: %s", from.c_str(), to.c_str(), strerror(errno));
return false;
}
return true;
}
LegacyConfigFile::Write
/packages/modules/Bluetooth/system/gd/storage/legacy_config_file.cc
bool LegacyConfigFile::Write(const ConfigCache& cache) {
return os::WriteToFile(path_, cache.SerializeToLegacyFormat());
}
WriteToFile
packages/modules/Bluetooth/system/gd/os/linux_generic/files.cc
bool WriteToFile(const std::string& path, const std::string& data) {
ASSERT(!path.empty());
// Steps to ensure content of data gets to disk:
//
// 1) Open and write to temp file (e.g. bt_config.conf.new).
// 2) Flush the stream buffer to the temp file.
// 3) Sync the tempReadSmallFile file to disk with fsync().
// 4) Rename temp file to actual config file (e.g. bt_config.conf).
// This ensures atomic update.
// 5) Sync directory that has the conf file with fsync().
// This ensures directory entries are up-to-date.
//
// We are using traditional C type file methods because C++ std::filesystem and std::ofstream do not support:
// - Operation on directories
// - fsync() to ensure content is written to disk
// 1. 构建临时文件路径和提取目录路径
// Build temp config file based on config file (e.g. bt_config.conf.new).
const std::string temp_path = path + ".new"; // 临时文件的路径,在原文件路径后加上 .new
// Extract directory from file path (e.g. /data/misc/bluedroid).
// libc++fs is not supported in APEX yet and hence cannot use std::filesystem::path::parent_path
std::string directory_path; // 提取文件路径中的目录部分
{
// Make a temporary variable as inputs to dirname() will be modified and return value points to input char array
// temp_path_for_dir must not be destroyed until results from dirname is appended to directory_path
std::string temp_path_for_dir(path);
directory_path.append(dirname(temp_path_for_dir.data())); //获取目录路径
}
if (directory_path.empty()) {
LOG_ERROR("error extracting directory from '%s', error: %s", path.c_str(), strerror(errno));
return false;
}
// 2. 打开目录文件描述符
int dir_fd = open(directory_path.c_str(), O_RDONLY | O_DIRECTORY);
if (dir_fd < 0) {
LOG_ERROR("unable to open dir '%s', error: %s", directory_path.c_str(), strerror(errno));
return false;
}
// 3. 打开临时文件并写入数据
FILE* fp = std::fopen(temp_path.c_str(), "wt");
if (!fp) {
LOG_ERROR("unable to write to file '%s', error: %s", temp_path.c_str(), strerror(errno));
HandleError(temp_path, &dir_fd, &fp);
return false;
}
if (std::fprintf(fp, "%s", data.c_str()) < 0) {
LOG_ERROR("unable to write to file '%s', error: %s", temp_path.c_str(), strerror(errno));
HandleError(temp_path, &dir_fd, &fp);
return false;
}
// 4. 刷新缓冲区并同步到磁盘
// Flush the stream buffer to the temp file.
if (std::fflush(fp) != 0) {
LOG_ERROR("unable to write flush buffer to file '%s', error: %s", temp_path.c_str(), strerror(errno));
HandleError(temp_path, &dir_fd, &fp);
return false;
}
// Sync written temp file out to disk. fsync() is blocking until data makes it
// to disk.
if (fsync(fileno(fp)) != 0) { // 将临时文件同步到磁盘
LOG_WARN("unable to fsync file '%s', error: %s", temp_path.c_str(), strerror(errno));
// Allow fsync to fail and continue
}
// 5. 关闭文件并更改文件权限
if (std::fclose(fp) != 0) {
LOG_ERROR("unable to close file '%s', error: %s", temp_path.c_str(), strerror(errno));
HandleError(temp_path, &dir_fd, &fp);
return false;
}
fp = nullptr;
// Change the file's permissions to Read/Write by User and Group
if (chmod(temp_path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0) {
LOG_ERROR("unable to change file permissions '%s', error: %s", temp_path.c_str(), strerror(errno));
struct stat dirstat {};
if (fstat(dir_fd, &dirstat) == 0) {
LOG_ERROR("dir st_mode = 0x%02x", dirstat.st_mode);
LOG_ERROR("dir uid = %d", dirstat.st_uid);
LOG_ERROR("dir gid = %d", dirstat.st_gid);
} else {
LOG_ERROR("unable to call fstat on the directory, error: %s", strerror(errno));
}
struct stat filestat {};
if (stat(temp_path.c_str(), &filestat) == 0) {
LOG_ERROR("file st_mode = 0x%02x", filestat.st_mode);
LOG_ERROR("file uid = %d", filestat.st_uid);
LOG_ERROR("file gid = %d", filestat.st_gid);
} else {
LOG_ERROR("unable to call stat, error: %s", strerror(errno));
}
HandleError(temp_path, &dir_fd, &fp);
return false;
}
// 6. 重命名临时文件
// Rename written temp file to the actual config file.
if (std::rename(temp_path.c_str(), path.c_str()) != 0) {
LOG_ERROR("unable to commit file from '%s' to '%s', error: %s", temp_path.c_str(), path.c_str(), strerror(errno));
HandleError(temp_path, &dir_fd, &fp);
return false;
}
// 7. 同步目录并关闭目录文件描述符
// This should ensure the directory is updated as well.
if (fsync(dir_fd) != 0) {
LOG_WARN("unable to fsync dir '%s', error: %s", directory_path.c_str(), strerror(errno));
}
if (close(dir_fd) != 0) {
LOG_ERROR("unable to close dir '%s', error: %s", directory_path.c_str(), strerror(errno));
HandleError(temp_path, &dir_fd, &fp);
return false;
}
return true;
}
通过一系列步骤确保数据能安全地写入磁盘,利用临时文件和重命名操作实现原子更新,同时处理了多种可能出现的错误情况,保证了数据写入的可靠性。具体为:
把数据写入临时文件。
把流缓冲区的数据刷新到临时文件。
运用
fsync()
函数将临时文件同步到磁盘。把临时文件重命名为实际的配置文件,以此实现原子更新。
利用
fsync()
函数同步包含配置文件的目录,保证目录条目是最新的。
set_encrypt_key_or_remove_key
bool set_encrypt_key_or_remove_key(std::string prefix,
std::string decryptedString) override {
log::verbose("prefix: {}", prefix);
if (!callbacks) {
log::warn("callback isn't ready. prefix: {}", prefix);
return false;
}
// Save the value into a map.
key_map[prefix] = decryptedString;
// 在 JNI 线程中调用回调函数
do_in_jni_thread(base::BindOnce(
&bluetooth::bluetooth_keystore::BluetoothKeystoreCallbacks::
set_encrypt_key_or_remove_key,
base::Unretained(callbacks), prefix, decryptedString));
return true;
}
将一个解密后的字符串与特定前缀关联起来,并保存到一个映射中,同时通过 JNI 线程调用回调函数来进一步处理这个关联信息。用于处理密钥的加密存储或移除操作,根据传入的前缀和已解密的字符串进行相应处理。
JNI: set_encrypt_key_or_remove_key
/packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_btservice_BluetoothKeystore.cpp
void set_encrypt_key_or_remove_key(
const std::string prefixString,
const std::string decryptedString) override {
log::info("");
std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
jstring j_prefixString = sCallbackEnv->NewStringUTF(prefixString.c_str());
jstring j_decryptedString =
sCallbackEnv->NewStringUTF(decryptedString.c_str());
// 调用 Java 层的回调方法
sCallbackEnv->CallVoidMethod(mCallbacksObj,
method_setEncryptKeyOrRemoveKeyCallback,
j_prefixString, j_decryptedString);
}
将 C++ 层的 prefixString 和 decryptedString 传递到 Java 层的回调方法中。通过 JNI 环境创建对应的 Java 字符串对象,然后调用 Java 层的 setEncryptKeyOrRemoveKeyCallback 方法,完成从 C++ 到 Java 的跨语言交互。
setEncryptKeyOrRemoveKeyCallback
packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreNativeInterface.java
// Callbacks from the native stack back into the Java framework.
// All callbacks are routed via the Service which will disambiguate which
// state machine the message should be routed to.
private void setEncryptKeyOrRemoveKeyCallback(String prefixString, String decryptedString) {
final BluetoothKeystoreService service = mBluetoothKeystoreService;
if (service == null) {
Log.e(
TAG,
"setEncryptKeyOrRemoveKeyCallback: Event ignored, service not available: "
+ prefixString);
return;
}
try {
service.setEncryptKeyOrRemoveKey(prefixString, decryptedString);
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted while operating.");
} catch (IOException e) {
Log.e(TAG, "IO error while file operating.");
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "encrypt could not find the algorithm: SHA256");
}
}
从本地(Native)层回调到 Java 框架层的接口。当本地层调用 set_encrypt_key_or_remove_key 方法并通过 JNI 将信息传递到 Java 层时,会触发这个回调方法。主要功能是将接收到的 prefixString 和 decryptedString 传递给 BluetoothKeystoreService 进行进一步处理。
setEncryptKeyOrRemoveKey
packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreService.java
/**
* Sets or removes the encryption key value.
*
* <p>If the value of decryptedString matches {@link #CONFIG_FILE_HASH} then
* read the hash file and decrypt the keys and place them into {@link mPendingEncryptKey}
* otherwise cleanup all data and remove the keys.
*
* @param prefixString key to use
* @param decryptedString string to decrypt
*/
public void setEncryptKeyOrRemoveKey(String prefixString, String decryptedString)
throws InterruptedException, IOException, NoSuchAlgorithmException {
infoLog("setEncryptKeyOrRemoveKey: prefix: " + prefixString);
if (prefixString == null || decryptedString == null) {
return;
}
if (prefixString.equals(CONFIG_FILE_PREFIX)) {
if (decryptedString.isEmpty()) {
cleanupAll();
} else if (decryptedString.equals(CONFIG_FILE_HASH)) {
readHashFile(CONFIG_FILE_PATH, CONFIG_FILE_PREFIX);
mPendingEncryptKey.put(CONFIG_FILE_PREFIX);
readHashFile(CONFIG_BACKUP_PATH, CONFIG_BACKUP_PREFIX);
mPendingEncryptKey.put(CONFIG_BACKUP_PREFIX);
saveEncryptedKey();
}
return;
}
if (decryptedString.isEmpty()) {
// clear the item by prefixString.
mNameDecryptKey.remove(prefixString);
mNameEncryptKey.remove(prefixString);
} else {
mNameDecryptKey.put(prefixString, decryptedString);
mPendingEncryptKey.put(prefixString);
}
}
根据传入的 prefixString(键)和 decryptedString(待解密的字符串)来设置或移除加密密钥值。根据不同的条件进行不同的操作,例如清空数据、读取哈希文件、保存加密密钥等。
BtifConfigInterface::ConvertEncryptOrDecryptKeyIfNeeded
/packages/modules/Bluetooth/system/main/shim/config.cc
void BtifConfigInterface::ConvertEncryptOrDecryptKeyIfNeeded() {
GetStorage()->ConvertEncryptOrDecryptKeyIfNeeded();
}
StorageModule::ConvertEncryptOrDecryptKeyIfNeeded
void StorageModule::ConvertEncryptOrDecryptKeyIfNeeded() {
std::lock_guard<std::recursive_mutex> lock(mutex_);
pimpl_->cache_.ConvertEncryptOrDecryptKeyIfNeeded();
}
ConfigCache::ConvertEncryptOrDecryptKeyIfNeeded
void ConfigCache::ConvertEncryptOrDecryptKeyIfNeeded() {
std::lock_guard<std::recursive_mutex> lock(mutex_);
LOG_INFO("%s", __func__);
// 获取持久设备的节
auto persistent_sections = GetPersistentSections();
// 遍历持久设备的节
for (const auto& section : persistent_sections) {
auto section_iter = persistent_devices_.find(section);
// 遍历需要加密或解密的属性列表
for (const auto& property : kEncryptKeyNameList) {
auto property_iter = section_iter->second.find(std::string(property));
if (property_iter != section_iter->second.end()) {
// 加密操作
bool is_encrypted = property_iter->second == kEncryptedStr;
if ((!property_iter->second.empty()) && os::ParameterProvider::GetBtKeystoreInterface() != nullptr &&
os::ParameterProvider::IsCommonCriteriaMode() && !is_encrypted) {
// 对属性值进行加密
if (os::ParameterProvider::GetBtKeystoreInterface()->set_encrypt_key_or_remove_key(
section + "-" + std::string(property), property_iter->second)) {
// 表示该属性已加密
SetProperty(section, std::string(property), kEncryptedStr);
}
}
// 解密操作
if (os::ParameterProvider::GetBtKeystoreInterface() != nullptr && is_encrypted) {
// 获取解密后的字符串 value_str
std::string value_str =
os::ParameterProvider::GetBtKeystoreInterface()->get_key(section + "-" + std::string(property));
if (!os::ParameterProvider::IsCommonCriteriaMode()) {
SetProperty(section, std::string(property), value_str); // 将该属性的值更新为解密后的字符串
}
}
}
}
}
}
对配置缓存中持久设备部分的指定属性进行加密或解密操作。遍历持久设备的各个节,检查每个节中特定属性的加密状态,并根据系统配置和属性值的情况决定是否进行加密或解密,然后更新配置缓存中的属性值。
总结
初始化流程:处理工厂重置、校验配置文件,优先加载主配置,失败则使用备份或新建空配置。
配置解析:逐行读取配置文件,区分设备节与非设备节,加密敏感属性(如链接密钥),支持动态回调通知变更。
设备类型修复:通过属性特征推断设备类型(经典/低功耗/双模),自动修正配置不一致。
加密管理:在通用准则模式下,对持久化属性加密存储,支持按需解密或密钥移除。
延迟保存机制:合并频繁的配置变更操作,定时批量写入主备份文件,减少I/O开销。