在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中不让其配对
绝大部分都是用等号表示的string=value对, 也有使用{}与逗号区分的一串数据, 例如COD.
配置文件的解析位于bte_config.c中, 其含有下面这些函数:
▼ functions device_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.
新闻热点
疑难解答