gps.conf是gps的配置文件,这里面经常使用到的DEBUG_LEVEL配置项是gps HAL层logcat的开关,弄清楚这个配置项的解析流程一样对全部gps.conf的解析有很大的帮助,这里来走1下flow。
hardware/qcom/gps/loc_api/libloc_api_50001/gps.c
const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
{
return get_gps_interface();
}
在前面open_gps里面有提到过,gps__get_gps_interface()是在那里绑定的,以下:
static int open_gps(const struct hw_module_t* module, char const* name,
struct hw_device_t** device)
{
struct gps_device_t *dev = (struct gps_device_t *) malloc(sizeof(struct gps_device_t));
if(dev == NULL)
return -1;
memset(dev, 0, sizeof(*dev));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (struct hw_module_t*)module;
dev->get_gps_interface = gps__get_gps_interface;
*device = (struct hw_device_t*)dev;
return 0;
}
所以需要查到get_gps_interface在哪里调用的,以下:
frameworks/base/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
int err;
hw_module_t* module;
...
if (err == 0) {
hw_device_t* device;
err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
if (err == 0) {
gps_device_t* gps_device = (gps_device_t *)device;
sGpsInterface = gps_device->get_gps_interface(gps_device);
}
}
...
}
所以接下来看下get_gps_interface()定义,以下:
hardware/qcom/gps/loc_api/libloc_api_50001/loc.cpp
extern "C" const GpsInterface* get_gps_interface()
{
unsigned int target = TARGET_DEFAULT;
loc_eng_read_config();
...
}
hardware/qcom/gps/loc_api/libloc_api_50001/loc_eng.cpp
int loc_eng_read_config(void)
{
ENTRY_LOG_CALLFLOW();
if(configAlreadyRead == false)
{
//gps config信息只用read1次
// Initialize our defaults before reading of configuration file overwrites them.
//初始化1些参数
loc_default_parameters();
// We only want to parse the conf file once. This is a good place to ensure that.
// In fact one day the conf file should go into context.
//暂时先只关注GPS_CONF_FILE,也就是/etc/gps.conf
UTIL_READ_CONF(GPS_CONF_FILE, gps_conf_table);
UTIL_READ_CONF(SAP_CONF_FILE, sap_conf_table);
configAlreadyRead = true;
} else {
LOC_LOGV("GPS Config file has already been read
");
}
EXIT_LOG(%d, 0);
return 0;
}
看下UTIL_READ_CONF的定义:
hardware/qcom/gps/utils/loc_cfg.h
#define UTIL_READ_CONF(filename, config_table)
loc_read_conf((filename), (config_table), sizeof(config_table) / sizeof(config_table[0]))
这里面传入两个参数,1个是const char* conf_file_name,这里的值是”/etc/gps.conf”,另外一个是1个gps_conf_table,有必要看下这个table的类型:
hardware/qcom/gps/loc_api/libloc_api_50001/loc_eng.cpp
static loc_param_s_type gps_conf_table[] =
{
{"GPS_LOCK", &gps_conf.GPS_LOCK, NULL, 'n'},
{"SUPL_VER", &gps_conf.SUPL_VER, NULL, 'n'},
{"LPP_PROFILE", &gps_conf.LPP_PROFILE, NULL, 'n'},
{"A_GLONASS_POS_PROTOCOL_SELECT", &gps_conf.A_GLONASS_POS_PROTOCOL_SELECT, NULL, 'n'},
{"AGPS_CERT_WRITABLE_MASK", &gps_conf.AGPS_CERT_WRITABLE_MASK, NULL, 'n'},
{"SUPL_MODE", &gps_conf.SUPL_MODE, NULL, 'n'},
{"INTERMEDIATE_POS", &gps_conf.INTERMEDIATE_POS, NULL, 'n'},
{"ACCURACY_THRES", &gps_conf.ACCURACY_THRES, NULL, 'n'},
{"NMEA_PROVIDER", &gps_conf.NMEA_PROVIDER, NULL, 'n'},
{"CAPABILITIES", &gps_conf.CAPABILITIES, NULL, 'n'},
{"USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", &gps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL, NULL, 'n'},
};
数组的每一个单项的类型是loc_param_s_type,这个单项的定义以下:
hardware/qcom/gps/utils/loc_cfg.h
typedef struct
{
char param_name[LOC_MAX_PARAM_NAME];
void *param_ptr;
uint8_t *param_set; /* was this value set by config file? */
char param_type; /* 'n' for number,
's' for string,
'f' for float */
} loc_param_s_type;
table项的第2个参数用到了gps_conf变量,而gps_conf是loc_gps_cfg_s_type类型的,定义以下:
hardware/qcom/gps/loc_api/libloc_api_50001/loc_eng.h
typedef struct loc_gps_cfg_s
{
uint32_t INTERMEDIATE_POS;
uint32_t ACCURACY_THRES;
uint32_t SUPL_VER;
uint32_t SUPL_MODE;
uint32_t CAPABILITIES;
uint32_t LPP_PROFILE;
uint32_t XTRA_VERSION_CHECK;
char XTRA_SERVER_1[MAX_XTRA_SERVER_URL_LENGTH];
char XTRA_SERVER_2[MAX_XTRA_SERVER_URL_LENGTH];
char XTRA_SERVER_3[MAX_XTRA_SERVER_URL_LENGTH];
uint32_t USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL;
uint32_t NMEA_PROVIDER;
uint32_t GPS_LOCK;
uint32_t A_GLONASS_POS_PROTOCOL_SELECT;
uint32_t AGPS_CERT_WRITABLE_MASK;
} loc_gps_cfg_s_type;
hardware/qcom/gps/utils/loc_cfg.cpp
void loc_read_conf(const char* conf_file_name, loc_param_s_type* config_table,
uint32_t table_length)
{
FILE *conf_fp = NULL;
char *lasts;
loc_param_v_type config_value;
uint32_t i;
//打开/etc/gps.conf,拿到fp,这个是读取conf的第1步
if((conf_fp = fopen(conf_file_name, "r")) != NULL)
{
LOC_LOGD("%s: using %s", __FUNCTION__, conf_file_name);
if(table_length && config_table) {
//table_length和config_table前面有定义,肯定是走这里啦,这里面是填充config_table的
loc_read_conf_r(conf_fp, config_table, table_length);
//走过1边以后,conf_fp的文件指针已知道文件尾部了,rewind1下conf_fp又到了文件头部
rewind(conf_fp);
}
//这里是是读DEBUG_LEVEL的地方,重点跟进1下
loc_read_conf_r(conf_fp, loc_param_table, loc_param_num);
fclose(conf_fp);
}
/* Initialize logging mechanism with parsed data */
loc_logger_init(DEBUG_LEVEL, TIMESTAMP);
}
先看下loc_param_table的定义和初始化:
/* Parameter data */
static uint8_t DEBUG_LEVEL = 0xff;
static uint8_t TIMESTAMP = 0;
/* Parameter spec table */
static loc_param_s_type loc_param_table[] =
{
{"DEBUG_LEVEL", &DEBUG_LEVEL, NULL, 'n'},
{"TIMESTAMP", &TIMESTAMP, NULL, 'n'},
};
int loc_param_num = sizeof(loc_param_table) / sizeof(loc_param_s_type);
在来看下loc_read_conf_r的具体实现:
int loc_read_conf_r(FILE *conf_fp, loc_param_s_type* config_table, uint32_t table_length)
{
//conf_fp rewind到文件头部了,config_table的定义和初始化前面也做了,table_length就是loc_param_num,这里值是2
int ret=0;
unsigned int num_params=table_length;
if(conf_fp == NULL) {
LOC_LOGE("%s:%d]: ERROR: File pointer is NULL
", __func__, __LINE__);
ret = -1;
goto err;
}
/* Clear all validity bits */
//param_set全部初始化为NULL,表明这些值还没有被conf file设置
for(uint32_t i = 0; NULL != config_table && i < table_length; i++)
{
if(NULL != config_table[i].param_set)
{
*(config_table[i].param_set) = 0;
}
}
char input_buf[LOC_MAX_PARAM_LINE]; /* declare a char array */
LOC_LOGD("%s:%d]: num_params: %d
", __func__, __LINE__, num_params);
while(num_params)
{
//弄了半天,fp是有了但是1直没有读conf,这个fgets马上跟进
if(!fgets(input_buf, LOC_MAX_PARAM_LINE, conf_fp)) {
//逐行来解析,如果读到文件尾就结束
LOC_LOGD("%s:%d]: fgets returned NULL
", __func__, __LINE__);
break;
}
//根据读取的行,解析出里面的内容填充到config_table中,如果config_table填充终了(就是说table里面的DEBUG_LEVEL和TIMESTAMP都填充完),这个循环一样结束
num_params -= loc_fill_conf_item(input_buf, config_table, table_length);
}
err:
return ret;
}
在loc_fill_conf_item之前,有1个类型需要关注1下:
typedef struct loc_param_v_type
{
char* param_name;
char* param_str_value;
int param_int_value;
double param_double_value;
}loc_param_v_type;
这个是用来存储从conf里面读出来的内容的,param_name用来存储conf的key的,param_str_value是用来存储value的字符串形态,param_int_value是用来存储value的int形态,param_double_value是用来存储value的double形态
int loc_fill_conf_item(char* input_buf,
loc_param_s_type* config_table, uint32_t table_length)
{
int ret = 0;
if (input_buf && config_table) {
char *lasts;
//定义和初始化1个loc_param_v_type,用来存储fgets读出来的这行conf
loc_param_v_type config_value;
memset(&config_value, 0, sizeof(config_value));
/* Separate variable and value */
把这行conf用strtok_r分离出key,直接存储到param_name中
config_value.param_name = strtok_r(input_buf, "=", &lasts);
/* skip lines that do not contain "=" */
if (config_value.param_name) {
//第2次用strtok_r分离出value来,但是目前暂时不知道value的类型
config_value.param_str_value = strtok_r(NULL, "=", &lasts);
/* skip lines that do not contain two operands */
if (config_value.param_str_value) {
/* Trim leading and trailing spaces */
//对key和value做1下处理,清除里面的无用空格
loc_util_trim_space(config_value.param_name);
loc_util_trim_space(config_value.param_str_value);
/* Parse numerical value */
if ((strlen(config_value.param_str_value) >=3) &&
(config_value.param_str_value[0] == '0') &&
(tolower(config_value.param_str_value[1]) == 'x'))
{
//如果value的前两个字符是0x,那末认为value是int类型
/* hex */
config_value.param_int_value = (int) strtol(&config_value.param_str_value[2],
(char**) NULL, 16);
}
else {
//否则int和double类型都存储1次
config_value.param_double_value = (double) atof(config_value.param_str_value); /* float */
config_value.param_int_value = atoi(config_value.param_str_value); /* dec */
}
//前面的动作是把fgets拿到的行填充到loc_param_v_type struct里面去,接下来要把这个struct填充到config_table里面去
//针对DEBUG_LEVEL这个conf项,这里填充的结果以下:
//param_name: DEBUG_LEVEL
//param_str_value: 5
//param_int_value: 5
//param_double_value: 5 (由于没有0x开头,所以double也被填充了)
for(uint32_t i = 0; NULL != config_table && i < table_length; i++)
{
//table_length是2,前面有说到,也就是说把fgets拿到的行在config_table里面逐行的匹配
if(!loc_set_config_entry(&config_table[i], &config_value)) {
ret += 1;
}
}
}
}
}
return ret;
}
看下是config_table里面的DEBUG_LEVEL是怎样被赋值的:
int loc_set_config_entry(loc_param_s_type* config_entry, loc_param_v_type* config_value)
{
//loc_param_s_type在前面有定义过
int ret=-1;
if(NULL == config_entry || NULL == config_value)
{
LOC_LOGE("%s: INVALID config entry or parameter", __FUNCTION__);
return ret;
}
//填充好的config_value的param_name(前面有分析的结果是DEBUG_LEVEL)跟config_table的param_name(由因而逐行匹配,第1个就是DEBUG_LEVEL)做匹配
if (strcmp(config_entry->param_name, config_value->param_name) == 0 &&
config_entry->param_ptr)
{
//如果匹配成功,且param_ptr的值不是NULL则继续分析
switch (config_entry->param_type)
{
//config_table的定义和初始化前面有给出,param_type的值都是'n'
case 's':
if (strcmp(config_value->param_str_value, "NULL") == 0)
{
*((char*)config_entry->param_ptr) = ' ';
}
else {
strlcpy((char*) config_entry->param_ptr,
config_value->param_str_value,
LOC_MAX_PARAM_STRING + 1);
}
/* Log INI values */
LOC_LOGD("%s: PARAM %s = %s", __FUNCTION__,
config_entry->param_name, (char*)config_entry->param_ptr);
if(NULL != config_entry->param_set)
{
*(config_entry->param_set) = 1;
}
ret = 0;
break;
case 'n':
//config_value的param_int_value赋值给config_entry的param_ptr,这里的值是5,这模样DEBUG_LEVEL的值就被改成了conf中的值了(也就是5)
*((int *)config_entry->param_ptr) = config_value->param_int_value;
/* Log INI values */
LOC_LOGD("%s: PARAM %s = %d", __FUNCTION__,
config_entry->param_name, config_value->param_int_value);
if(NULL != config_entry->param_set)
{
//param_set置1,说明该config_entry被conf修改过
*(config_entry->param_set) = 1;
}
ret = 0;
break;
case 'f':
*((double *)config_entry->param_ptr) = config_value->param_double_value;
/* Log INI values */
LOC_LOGD("%s: PARAM %s = %f", __FUNCTION__,
config_entry->param_name, config_value->param_double_value);
if(NULL != config_entry->param_set)
{
*(config_entry->param_set) = 1;
}
ret = 0;
break;
default:
LOC_LOGE("%s: PARAM %s parameter type must be n, f, or s",
__FUNCTION__, config_entry->param_name);
}
}
return ret;
}
DEBUG_LEVEL已写入,那末接下来看下DEBUG_LEVEL是怎样使能的:
void loc_logger_init(unsigned long debug, unsigned long timestamp)
{
//这个函数主要是把传入的参数填充到loc_logger里面
loc_logger.DEBUG_LEVEL = debug;
#ifdef TARGET_BUILD_VARIANT_USER
// force user builds to 2 or less
if (loc_logger.DEBUG_LEVEL > 2) {
loc_logger.DEBUG_LEVEL = 2;
}
#endif
loc_logger.TIMESTAMP = timestamp;
}
loc_logger是loc_logger_s类型的,看下具体的定义:
hardware/qcom/gps/utils/log_util.h
typedef struct loc_logger_s
{
unsigned long DEBUG_LEVEL;
unsigned long TIMESTAMP;
} loc_logger_s_type;
到目前为止,我们拿到了填充好的loc_logger变量,有必要看下log是如何打印的了:
看下LOC_LOGE:
#define LOC_LOGE(...)
IF_LOC_LOGE { ALOGE("E/" __VA_ARGS__); }
else if (loc_logger.DEBUG_LEVEL == 0xff) { ALOGE("E/" __VA_ARGS__); }
转换以后的代码以下:
if ((loc_logger.DEBUG_LEVEL >= 1) && (loc_logger.DEBUG_LEVEL <= 5)){
ALOGE("E/" __VA_ARGS__);
} else if (loc_logger.DEBUG_LEVEL == 0xff) {
ALOGE("E/" __VA_ARGS__);
}
gps.conf默许的DEBUG_LEVEL是3,也就是说这个会调用ALOGE(“E/” VA_ARGS);,也就是说LOC_LOGE在默许情况下是可以打印的
对照看下LOC_LOGV:
#define LOC_LOGV(...)
IF_LOC_LOGV { ALOGE("V/" __VA_ARGS__); }
else if (loc_logger.DEBUG_LEVEL == 0xff) { ALOGV("V/" __VA_ARGS__); }
转换以后的代码以下:
if ((loc_logger.DEBUG_LEVEL >= 5) && (loc_logger.DEBUG_LEVEL <= 5)){
ALOGE("E/" __VA_ARGS__);
} else if (loc_logger.DEBUG_LEVEL == 0xff) {
ALOGE("E/" __VA_ARGS__);
}
如果DEBUG_LEVEL是3,则LOC_LOGV是没法打印的,必须要改成5才行
如果gps.conf中没有DEBUG_LEVEL的配置项,那末loc_logger.DEBUG_LEVEL会使用默许的0xff,那末所有信息也是可以打印的
下一篇 设计模式――简单工厂模式