Android BlueDroid分析: 配置文件(bt_stack.conf bt_vendor.conf )的加载与分析

2024-03-04 12:18

本文主要是介绍Android BlueDroid分析: 配置文件(bt_stack.conf bt_vendor.conf )的加载与分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

说明

在Android BlueDroid启动,即stack启动的时候,回去加载好几个配置文件, 然后BlueDroid Stack根据这几个配置文件会进行调整, 例如Device ID(did), Log相关的Trace Level, COD(即Class of Device), BT snoop log相关配置等等.下面结合代码和配置文件一起来说明分析.

配置文件说明

配置文件分为运行时动态加载和编译的时候直接解析使用的.主要有下面三个, 冒号后面是简要的作用说明.

编译完成后,这些配置文件都是位于: /system/etc/bluetooth/

如果是编译之前,那么是在device相关的vendor board中, 或者是默认的stack里面自带的文件.


 bt_stack.conf: 对stack进行配置, 包括不同的stack里面的log level, bt snoop的控制

 bt_did.conf : 记录和配置BLE Controller的信息, 例如VendorID可能是QualComm也可以是Broadcom等等.

 auto_pair_devlist.conf: 将某些slave/peripheral加入到BlackList中不让其配对

config格式

绝大部分都是用等号表示的string=value对, 也有使用{}与逗号区分的一串数据, 例如COD.

代码分析

配置文件的解析位于bte_config.c中, 其含有下面这些函数:

▼ functionsdevice_name_cfg(char *p_conf_name, char *p_conf_value)device_class_cfg(char *p_conf_name, char *p_conf_value)logging_cfg_onoff(char *p_conf_name, char *p_conf_value)logging_set_filepath(char *p_conf_name, char *p_conf_value)trace_cfg_onoff(char *p_conf_name, char *p_conf_value)bte_load_conf(const char *p_path)-bte_parse_did_conf(const char *p_path, UINT32 num, tKEY_VALUE_PAIRS *conf_pairs, UINT32 conf_pairs_num)bte_load_did_conf(const char *p_path)

其中有trace log level解析相关的函数, 对于不同的文件解析使用的函数不同, 例如did使用did相关函数, 而bt_stack.conf使用bte_load_conf来解析.

而代码的实现也比较简单, 使用最多的函数就是strtok, 即对token的解析(可以参考C++程序设计原理与实践). 

解析完成后进行赋值完事.

那么对于did都有哪些assignment item:

/*******************************************************************************
**
** Function        bte_load_did_conf
**
** Description     Set local Device ID records, reading from configuration files
**
** Returns         None
**
*******************************************************************************/void bte_load_did_conf (const char *p_path)
{tBTA_DI_RECORD rec;UINT32 rec_num, i, j;for (i=1; i<=BTA_DI_NUM_MAX; i++) {for (j=0; j<CONF_DID_MAX; j++) {*did_conf_pairs[j].value = 0;}if (bte_parse_did_conf(p_path, i, did_conf_pairs, CONF_DID_MAX)) {memset(&rec, 0, sizeof(rec));if (*did_conf_pairs[CONF_DID_RECORD_NUM].value) {rec_num = (UINT32)(strtoul(did_conf_pairs[CONF_DID_RECORD_NUM].value, NULL, 0)-1);} else {debug("[%d] Unknown %s", (unsigned int)i, did_conf_pairs[CONF_DID_RECORD_NUM].key);continue;}if (*did_conf_pairs[CONF_DID_VENDOR_ID].value) {rec.vendor = (UINT16)strtoul(did_conf_pairs[CONF_DID_VENDOR_ID].value, NULL, 0);} else {rec.vendor = LMP_COMPID_BROADCOM;}if (*did_conf_pairs[CONF_DID_VENDOR_ID_SOURCE].value) {rec.vendor_id_source = (UINT16)strtoul(did_conf_pairs[CONF_DID_VENDOR_ID_SOURCE].value, NULL, 0);} else {rec.vendor_id_source = DI_VENDOR_ID_SOURCE_BTSIG;}if ((*did_conf_pairs[CONF_DID].value == 0) ||(rec_num >= BTA_DI_NUM_MAX) ||(!((rec.vendor_id_source >= DI_VENDOR_ID_SOURCE_BTSIG) &&(rec.vendor_id_source <= DI_VENDOR_ID_SOURCE_USBIF))) ||(rec.vendor == DI_VENDOR_ID_DEFAULT)) {error("DID record #%u not set", (unsigned int)i);for (j=0; j<CONF_DID_MAX; j++) {error("%s:%s", did_conf_pairs[j].key, did_conf_pairs[j].value);}continue;}rec.product = (UINT16)strtoul(did_conf_pairs[CONF_DID_PRODUCT_ID].value, NULL, 0);rec.version = (UINT16)strtoul(did_conf_pairs[CONF_DID_VERSION].value, NULL, 0);strncpy(rec.client_executable_url,did_conf_pairs[CONF_DID_CLIENT_EXECUTABLE_URL].value,SDP_MAX_ATTR_LEN);strncpy(rec.service_description,did_conf_pairs[CONF_DID_SERVICE_DESCRIPTION].value,SDP_MAX_ATTR_LEN);strncpy(rec.documentation_url,did_conf_pairs[CONF_DID_DOCUMENTATION_URL].value,SDP_MAX_ATTR_LEN);for (j=0; j<strlen(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value); j++) {did_conf_pairs[CONF_DID_PRIMARY_RECORD].value[j] =tolower(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value[j]);}if ((!strcmp(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value, "true")) ||(!strcmp(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value, "1"))) {rec.primary_record = TRUE;} else {rec.primary_record = FALSE;}info("[%u] primary_record=%d vendor_id=0x%04X vendor_id_source=0x%04X product_id=0x%04X version=0x%04X",(unsigned int)rec_num+1, rec.primary_record, rec.vendor,rec.vendor_id_source, rec.product, rec.version);if (*rec.client_executable_url) {info(" client_executable_url=%s", rec.client_executable_url);}if (*rec.service_description) {info(" service_description=%s", rec.service_description);}if (*rec.documentation_url) {info(" documentation_url=%s", rec.documentation_url);}if (BTA_DmSetLocalDiRecord(&rec, &rec_num) != BTA_SUCCESS) {error("SetLocalDiInfo failed for #%u!", (unsigned int)i);}}}
}

上面的代码看起来有一片,但是根据数组的下表宏,可以很清晰的知道只有这么几个:

▼ __anon3* : enum[enumerators]-CONF_DID-CONF_DID_RECORD_NUM-CONF_DID_PRIMARY_RECORD-CONF_DID_VENDOR_ID-CONF_DID_VENDOR_ID_SOURCE-CONF_DID_PRODUCT_ID-CONF_DID_VERSION-CONF_DID_CLIENT_EXECUTABLE_URL-CONF_DID_SERVICE_DESCRIPTION-CONF_DID_DOCUMENTATION_URL

对应的意义如下:

static tKEY_VALUE_PAIRS did_conf_pairs[CONF_DID_MAX] = {{ "[DID]",               "" },{ "recordNumber",        "" },{ "primaryRecord",       "" },{ "vendorId",            "" },{ "vendorIdSource",      "" },{ "productId",           "" },{ "version",             "" },{ "clientExecutableURL", "" },{ "serviceDescription",  "" },{ "documentationURL",    "" },
};

对于bt_stack.conf的解析分为两类, 一类是Trace Log Level, 还有就是其他的,具体见下面代码中的注释, 下面就是所有的可用被用来配置的string:

static const conf_entry_t conf_table[] = {/*{"Name", device_name_cfg},{"Class", device_class_cfg},*/{"BtSnoopLogOutput", logging_cfg_onoff},{"BtSnoopFileName", logging_set_filepath},{"TraceConf", trace_cfg_onoff},{(const char *) NULL, NULL}
};
解析的代码如下:

void bte_load_conf(const char *p_path)
{FILE    *p_file;char    *p_name;char    *p_value;conf_entry_t    *p_entry;char    line[CONF_MAX_LINE_LEN+1]; /* add 1 for \0 char */BOOLEAN name_matched;ALOGI("Attempt to load stack conf from %s", p_path);if ((p_file = fopen(p_path, "r")) != NULL){/* read line by line */while (fgets(line, CONF_MAX_LINE_LEN+1, p_file) != NULL){if (line[0] == CONF_COMMENT)continue;p_name = strtok(line, CONF_DELIMITERS);if (NULL == p_name){continue;}p_value = strtok(NULL, CONF_VALUES_DELIMITERS);if (NULL == p_value){ALOGW("bte_load_conf: missing value for name: %s", p_name);continue;}name_matched = FALSE;p_entry = (conf_entry_t *)conf_table;while (p_entry->conf_entry != NULL){if (strcmp(p_entry->conf_entry, (const char *)p_name) == 0)//判断是否是前面list中的{name_matched = TRUE;if (p_entry->p_action != NULL)p_entry->p_action(p_name, p_value);break;}p_entry++;}if ((name_matched == FALSE) && (trace_conf_enabled == TRUE)) //判断是否是TraceLevel{/* Check if this is a TRC config item */bte_trace_conf(p_name, p_value);}}fclose(p_file);}else{ALOGI( "bte_load_conf file >%s< not found", p_path);}
}

总结

实际上,除了上面三个conf文件, 我们还会看到一个额外的bt_vendor.conf, 在某些设备上面, 这个配置文件是给libbt-vendor.so中用的,用来配置串口与firmware. 

这篇关于Android BlueDroid分析: 配置文件(bt_stack.conf bt_vendor.conf )的加载与分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/773143

相关文章

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

Olingo分析和实践之EDM 辅助序列化器详解(最佳实践)

《Olingo分析和实践之EDM辅助序列化器详解(最佳实践)》EDM辅助序列化器是ApacheOlingoOData框架中无需完整EDM模型的智能序列化工具,通过运行时类型推断实现灵活数据转换,适用... 目录概念与定义什么是 EDM 辅助序列化器?核心概念设计目标核心特点1. EDM 信息可选2. 智能类

Olingo分析和实践之OData框架核心组件初始化(关键步骤)

《Olingo分析和实践之OData框架核心组件初始化(关键步骤)》ODataSpringBootService通过初始化OData实例和服务元数据,构建框架核心能力与数据模型结构,实现序列化、URI... 目录概述第一步:OData实例创建1.1 OData.newInstance() 详细分析1.1.1

Olingo分析和实践之ODataImpl详细分析(重要方法详解)

《Olingo分析和实践之ODataImpl详细分析(重要方法详解)》ODataImpl.java是ApacheOlingoOData框架的核心工厂类,负责创建序列化器、反序列化器和处理器等组件,... 目录概述主要职责类结构与继承关系核心功能分析1. 序列化器管理2. 反序列化器管理3. 处理器管理重要方

从入门到精通详解LangChain加载HTML内容的全攻略

《从入门到精通详解LangChain加载HTML内容的全攻略》这篇文章主要为大家详细介绍了如何用LangChain优雅地处理HTML内容,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录引言:当大语言模型遇见html一、HTML加载器为什么需要专门的HTML加载器核心加载器对比表二

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种