既上一篇博客继续分析main函数,上一篇博客我们分析了devices_init device的初始化,这篇博客先是分析保持KTM工作,后面主要分析sensor的初始化,。
1. 保持KTM工作
我们先来看如下,先是创建了一个kernel的client,然后因为有kernel 的device,所以会调用device_clnt_request函数
kernel_dev = devices_manager_reg_clnt("kernel");//创建一个kernel device的client if (kernel_dev == NULL) { msg("%s Failed to create kernel device handle\n", __func__); } else { req.value = 1;//有kernel device device_clnt_request(kernel_dev, &req); }
上一篇博客我们分析过device_clnt_reques函数,这里传进来的device的type不一样我们再来分析下。kernel的device的type是DEVICE_GENERIC_TYPE,所以调用了devices_manager_set_lvl函数
int device_clnt_request(device_clnt_handle clnt, union device_request *req) { struct devices_manager_dev *dev_mgr = NULL; struct device_clnt *client = clnt; int ret_val = 0; if ((client == NULL) || (req == NULL)) { msg("%s: Invalid args.\n", __func__); return -(EINVAL); } ret_val = validate_clnt(client);//验证client,就是遍历device的list看每个device的client有没有这个client if (ret_val != 0) return ret_val; dev_mgr = client->dev_mgr; switch (dev_mgr->dev_info.dev_type) { case DEVICE_GENERIC_TYPE://kernel的device的type为这个 ret_val = devices_manager_set_lvl(dev_mgr, client, req->value); break; case DEVICE_OP_VALUE_TYPE: ret_val = devices_manager_set_op_value(dev_mgr, client, req->value); break; case DEVICE_DIRECT_ACTION_TYPE: ret_val = devices_manager_set_direct_action(dev_mgr, client, req); break; default: dbgmsg("%s: Unhandled dev_type %d", __func__, dev_mgr->dev_info.dev_type); break; } return ret_val; }
devices_manager_set_lvl函数设置了client的request.value的值,然后调用了update_dev_state来更新device的state。
static int devices_manager_set_lvl(struct devices_manager_dev *dev_mgr, struct device_clnt *client, int lvl) { lvl = MIN(lvl, (int)(dev_mgr->dev_info.num_of_levels - 1)); lvl = MAX(lvl, (int)(dev_mgr->dev_info.min_lvl)); pthread_mutex_lock(&clnt_mtx); client->request.value = lvl; client->request_active = 1; pthread_mutex_unlock(&clnt_mtx); dbgmsg("%s: DEV %s, lvl %d\n", __func__, dev_mgr->dev_info.name, lvl); update_dev_state(dev_mgr); return dev_mgr->active_req.value;; }
update_dev_state函数上一篇博客已经分析过了,这里我们再来看下这里主要是遍历所有的client找到其最大值然后调用device的action函数。
static int update_dev_state(struct devices_manager_dev *dev_mgr) { union device_request req; struct device_clnt *client = dev_mgr->client_list; if ((dev_mgr->dev_info.dev_type != DEVICE_GENERIC_TYPE) && (dev_mgr->dev_info.dev_type != DEVICE_OP_VALUE_TYPE)) return -(EFAULT); pthread_mutex_lock(&clnt_mtx); if (dev_mgr->dev_info.dev_type == DEVICE_GENERIC_TYPE) {//kernel的type为这个分支 /* Start from min level to find the highest existing client request */ req.value = dev_mgr->dev_info.min_lvl;//device的min_lvl作为初始值 /* Walk client list to find highest mitigation level */ while (client != NULL) { if (client->request_active) req.value = MAX(req.value, client->request.value);//遍历所有的client的req.value取其最大值 client = client->next_clnt; } } else if (dev_mgr->dev_info.dev_type == DEVICE_OP_VALUE_TYPE) { /* Start from max allowable value find lowest request */ req.value = dev_mgr->dev_info.max_dev_op_value; /* Walk client list to find highest mitigation level */ while (client != NULL) { if (client->request_active) req.value = MIN(req.value, client->request.value); client = client->next_clnt; } } if (dev_mgr->active_req.value != req.value) { dev_mgr->active_req.value = req.value; if (dev_mgr->action) dev_mgr->action(dev_mgr);//调用device的action函数 /* Notify clients */ client = dev_mgr->client_list; while (client != NULL) {//如果client有回调,就调用回调 if (client->cb_func != NULL) client->cb_func(client, &req, client->cb_usr_data); client = client->next_clnt; } } pthread_mutex_unlock(&clnt_mtx); return 0; }而kernel的action最后调用了kernel_mitigation_request函数
static int kernel_mitigation_action(struct devices_manager_dev *dev_mgr) { return kernel_mitigation_request(dev_mgr->active_req.value); }
kernel_mitigation_request函数现在的request传入的是1,因此不做操作就是继续保持kernel的KTM工作,而当我们的thermal-engine完全工作后(初始化完成),最后会重新走到这,那时request为0,就会write /sys/module/msm_thermal/parameters/enabled节点为N,接管KTM的工作。
int kernel_mitigation_request(int request) { int ret = -1; pthread_mutex_lock(&kernel_disable_mtx); if (request == 0) { /* Disable kernel thermal module and take over */ write_to_file("/sys/module/msm_thermal/parameters/enabled", "N" , strlen("N") + 1); dbgmsg("KERNEL mitigation disabled\n"); } else dbgmsg("KERNEL request to keep mitigation enabled\n"); pthread_mutex_unlock(&kernel_disable_mtx); return ret; }
2. sensor初始化
这节我们开始分析sensor的初始化,main函数调用了sensors_init函数,这个minimum_mode一般为0,我们的代码在Sensors.c中,这个可以从Android.mk查看。
int sensors_init(int minimum_mode) { int ret_val = 0; min_mode = minimum_mode; if (!min_mode) modem_ts_qmi_init();//这里和modem通信的qmi我们后续分析 init_sensor_alias(); parse_thermal_zones(); /* BCL */ if (add_tgt_sensors_set(bcl_sensors, ARRAY_SIZE(bcl_sensors)) != 0) { msg("%s: Error adding BCL TS\n", __func__); ret_val = -(EFAULT); } return ret_val; }
2.1 读取每个sensor的信息
我们来看下init_sensor_alias函数,先从节点/sys/module/msm_thermal/sensor_info读取节点信息,然后保存sensor信息到sensors数组中,这个sensors的类型是msm_sensor_info。
static void init_sensor_alias(void) { char buf[MAX_SENSOR_INFO_LEN]; char *psensor_info = NULL, *psave1 = NULL; if (read_line_from_file(SENSOR_INFO_SYSFS, buf,//读取/sys/module/msm_thermal/sensor_info节点信息 MAX_SENSOR_INFO_LEN) <= 0) return; psensor_info = strtok_r(buf, " ", &psave1); while (psensor_info != NULL && sensor_cnt < MAX_NUM_SENSORS) { char *psensor = NULL; char *psave2 = NULL; psensor = strtok_r(psensor_info, ":", &psave2); if ((psensor == NULL) || strlcpy(sensors[sensor_cnt].type,//type psensor, MAX_SENSOR_NAME_LEN) >= MAX_SENSOR_NAME_LEN) goto next_sensor; psensor = strtok_r(NULL, ":", &psave2); if ((psensor == NULL) || strlcpy(sensors[sensor_cnt].name,//name psensor, MAX_SENSOR_NAME_LEN) >= MAX_SENSOR_NAME_LEN) goto next_sensor; if (psensor[strlen(psensor) + 1] != ':') { psensor = strtok_r(NULL, ":", &psave2); if ((psensor == NULL) || strlcpy(sensors[sensor_cnt].alias, psensor,//alias MAX_SENSOR_NAME_LEN) >= MAX_SENSOR_NAME_LEN) goto next_sensor; } psensor = strtok_r(NULL, ":", &psave2); if (psensor == NULL) goto next_sensor; sensors[sensor_cnt].scaling_factor = (int)strtol( psensor, NULL, 10); if (sensors[sensor_cnt].scaling_factor <= 0)//scaling_factor sensors[sensor_cnt].scaling_factor = 1; sensor_cnt++; next_sensor: psensor_info = strtok_r(NULL, " ", &psave1); } dbgmsg("%s: sensor_cnt:%d\n", __func__, sensor_cnt); }
我们来先看下节点/sys/module/msm_thermal/sensor_info节点读取到的信息。以冒号为分割第一个是sensor的type,第二个是sensor的name,第三个是alias,第四个是scaling_factor。
tsens:tsens_tz_sensor0:pop_mem:1 tsens:tsens_tz_sensor1::1 tsens:tsens_tz_sensor2::1 tsens:tsens_tz_sensor3:cpu0-cpu2:1 tsens:tsens_tz_sensor4:cpu1-cpu3:1 adc:pa_therm0::1 adc:case_therm::1 alarm:pm8909_tz::1000 adc:xo_therm::1 adc:xo_therm_buf::1
2.2 创建sensor
创建sensor有两种方法,一种读取sys/devices/vitual/thermal下的设备创建,另一种可以直接做一个sensor_info的数组,直接遍历数组创建sensor。
2.2.1 读取thermal节点创建sensor
再来看看parse_thermal_zones函数,这个函数主要看/sys/devices/virtual/thermal下面每个目录下的type 是否和我们前面保存的sensors数组中的sensor的name一样,不一样我们直接跳过。一样的话,我们在根据这个sensor的type调用不同的函数。
static void parse_thermal_zones(void) { DIR *tdir = NULL; struct dirent *tdirent = NULL; char name[MAX_PATH] = {0}; char cwd[MAX_PATH] = {0}; int cnt = 0, ret = 0; if (!getcwd(cwd, sizeof(cwd))) return; if (sensor_cnt <= 0) return init_user_space_sensors(); ret = chdir(THERMAL_SYSFS); /* Change dir to read the entries. Doesnt work otherwise */ tdir = opendir(THERMAL_SYSFS);//sys/devices/virtual/thermal目录 if (!tdir || ret) { msg("%s: Unable to open %s\n", __func__, THERMAL_SYSFS); return; } while ((tdirent = readdir(tdir))) { char buf[MAX_PATH]; DIR *tzdir = NULL; tzdir = opendir(tdirent->d_name); if (!tzdir) continue; snprintf(name, MAX_PATH, SENSOR_TZ_TYPE, tdirent->d_name);//sys/devices/virtual/thermal目录下个各个子目录下的type值 dbgmsg("%s: Opening %s\n", __func__, name); ret = read_line_from_file(name, buf, sizeof(buf)); if (ret <= 0) continue; buf[strlen(buf) -1] = '\0'; for (cnt = 0; cnt < sensor_cnt; cnt++) { if (strncmp(buf, sensors[cnt].name,//每一个type值和sensors数组中sensor的那么做对比,不同直接continue MAX_SENSOR_NAME_LEN)) continue; if (!strncmp(sensors[cnt].type, TSENS_TYPE,//类型不同调用不同的函数 strlen(TSENS_TYPE)) || !strncmp(sensors[cnt].type, LLM_TYPE, strlen(LLM_TYPE))) { add_tgt_tsens_sensors(sensors[cnt].name, &sensors[cnt]); dbgmsg( "%s: Added sensor: %s to %s sensor list\n", __func__, buf, sensors[cnt].type); } else if (!strncmp(sensors[cnt].type, ALARM_TYPE, strlen(ALARM_TYPE)) || (!strncmp(sensors[cnt].type, ADC_TYPE, strlen(ADC_TYPE)))) { add_tgt_gen_sensors(sensors[cnt].name, &sensors[cnt]); dbgmsg( "%s: Added sensor: %s to %s sensor list\n", __func__, buf, sensors[cnt].type); } } closedir(tzdir); } closedir(tdir); ret = chdir(cwd); /* Restore current working dir */ }
我们先来看下sys/devices/virtual/thermal目录下的各个目录
然后再来看各个目录下type的值。
我们接着看上面根据sensor的type不同调用了不同的函数。 如果是tsens和llm的type调用add_tgt_tsens_sensors函数
static int add_tgt_tsens_sensors(char *sensor_name, struct msm_sensor_info *sens_info) { int ret_val = 0; struct sensor_info *sensor; sensor = malloc(sizeof(struct sensor_info));//创建sensor if (sensor == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor, 0, sizeof(struct sensor_info)); sensor->name = malloc(MAX_SENSOR_NAME_LEN); if (sensor->name == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor->name, 0, MAX_SENSOR_NAME_LEN); strlcpy(sensor->name, sensor_name, MAX_SENSOR_NAME_LEN); sensor->setup = tsens_sensors_setup;//获取到sensor的fd,就是各个zone下面的temp文件 sensor->shutdown = tsens_sensors_shutdown;//close fd sensor->get_temperature = tsens_sensor_get_temperature;//获取温度的方法,从fd读取 sensor->get_trip_temperature = NULL; sensor->interrupt_wait = tsens_sensor_interrupt_wait; sensor->update_thresholds = tsens_sensor_update_thresholds; sensor->tzn = 0; sensor->data = NULL; sensor->interrupt_enable = 1; sensor->scaling_factor = sens_info->scaling_factor; pthread_mutex_init(&(sensor->read_mtx), NULL); add_tgt_sensor(sensor);//新建一个sensors_mgr_sensor_info对象 error_handler: if (ret_val) { if (sensor) { if (sensor->name) free(sensor->name); free(sensor); } } return ret_val; }
add_tgt_sensor函数就是新建一个sensors_mgr_sensor_info对象,并且将sensor_info中的name alias,方法都复制过来。
static int add_tgt_sensor(struct sensor_info *sensor) { int ret_val = 0; struct sensors_mgr_sensor_info *sensor_mgr = NULL; dbgmsg("%s: Add sensor:%s to sensor list\n", __func__, sensor->name); sensor_mgr = malloc(sizeof(struct sensors_mgr_sensor_info)); if (sensor_mgr == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor_mgr, 0, sizeof(struct sensors_mgr_sensor_info)); sensor_mgr->name = sensor->name; sensor_mgr->alias = find_alias(sensor->name); if (sensor->setup(sensor) == 0) {//会在这里调用sensor中的setup获取sensor的fd msg("%s: %s sensor setup failed failed.\n", __func__, sensor->name); ret_val = -(EFAULT); goto error_handler; } sensor_mgr->data = (void*) sensor; sensor->sensor_mgr = sensor_mgr; sensor_mgr->get_temperature = generic_read; sensor_mgr->shutdown = generic_shutdown; if (sensor->interrupt_wait) sensor_mgr->wait = generic_wait; if (sensor->update_thresholds) sensor_mgr->update_thresholds = generic_update_thresholds; if (sensor->get_trip_temperature) sensor_mgr->get_trip_temperature = generic_trip_temp_read; sensors_manager_add_sensor(sensor_mgr);//将这个sensor放入sensor_list中 error_handler: if (ret_val) { if (sensor_mgr) free(sensor_mgr); } return ret_val; }
如果是sensor的type是alarm和adc的话调用add_tgt_gen_sensors函数,这个函数和上面的函数类似,最后也是调用add_tgt_sensor函数创建sensors_mgr_sensor_info对象最后加入sensor_list中
static int add_tgt_gen_sensors(char *sensor_name, struct msm_sensor_info *sens_info) { int ret_val = 0; struct sensor_info *sensor; sensor = malloc(sizeof(struct sensor_info)); if (sensor == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor, 0, sizeof(struct sensor_info)); sensor->name = malloc(MAX_SENSOR_NAME_LEN); if (sensor->name == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor->name, 0, MAX_SENSOR_NAME_LEN); strlcpy(sensor->name, sensor_name, MAX_SENSOR_NAME_LEN); sensor->setup = thermal_sensor_setup; sensor->shutdown = thermal_sensor_shutdown; sensor->get_temperature = thermal_sensor_get_temperature; sensor->get_trip_temperature = NULL; sensor->update_thresholds = NULL; sensor->scaling_factor = sens_info->scaling_factor; if (!strncmp(sens_info->type, ALARM_TYPE, strlen(ALARM_TYPE))) { sensor->interrupt_enable = 1; sensor->interrupt_wait = thermal_sensor_interrupt_wait; } else if (!strncmp(sens_info->type, USERSPACE_TYPE, strlen(USERSPACE_TYPE))) { sensor->interrupt_enable = 1; sensor->interrupt_wait = thermal_sensor_interrupt_wait; sensor->update_thresholds = thermal_sensor_update_thresholds; sensor->get_trip_temperature = thermal_sensor_get_trip_temp; sensor->scaling_factor = 1000; } else { sensor->interrupt_enable = 0; sensor->interrupt_wait = NULL; } pthread_mutex_init(&(sensor->read_mtx), NULL); sensor->tzn = 0; sensor->data = NULL; add_tgt_sensor(sensor); error_handler: if (ret_val) { if (sensor) { if (sensor->name) free(sensor->name); free(sensor); } } return ret_val; }
我们再来重新看下add_tgt_sensor函数,注意我们传进来的参数sensor类型是sensor_info,而这里我们新建的sensor_mgr是sensors_mgr_sensor_info
static int add_tgt_sensor(struct sensor_info *sensor) { int ret_val = 0; struct sensors_mgr_sensor_info *sensor_mgr = NULL; dbgmsg("%s: Add sensor:%s to sensor list\n", __func__, sensor->name); sensor_mgr = malloc(sizeof(struct sensors_mgr_sensor_info)); if (sensor_mgr == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor_mgr, 0, sizeof(struct sensors_mgr_sensor_info)); sensor_mgr->name = sensor->name;//name直接使用 sensor_mgr->alias = find_alias(sensor->name);//从sensors数组中找 if (sensor->setup(sensor) == 0) {//调用sensor的setup函数 msg("%s: %s sensor setup failed failed.\n", __func__, sensor->name); ret_val = -(EFAULT); goto error_handler; } sensor_mgr->data = (void*) sensor;//将sensor放入sensor_mgr的data sensor->sensor_mgr = sensor_mgr; sensor_mgr->get_temperature = generic_read;//sensor_mgr的函数都是最后通过其data(sensor的各个函数执行) sensor_mgr->shutdown = generic_shutdown; if (sensor->interrupt_wait) sensor_mgr->wait = generic_wait; if (sensor->update_thresholds) sensor_mgr->update_thresholds = generic_update_thresholds; if (sensor->get_trip_temperature) sensor_mgr->get_trip_temperature = generic_trip_temp_read; sensors_manager_add_sensor(sensor_mgr); error_handler: if (ret_val) { if (sensor_mgr) free(sensor_mgr); } return ret_val; }
我们举个读取温度的为例,最终就是通过sensor_mgr的data,就是sensor的get_temperature函数执行。
static int generic_read(struct sensors_mgr_sensor_info *sensor_mgr) { struct sensor_info *sensor = (struct sensor_info *)sensor_mgr->data; return sensor->get_temperature(sensor); }
我们再来看sensors_manager_add_sensor函数,将sensor_mgr放入sensor_list列表中。然后创建了一个线程执行sensor_monitor函数,sensor_mgr作为参数传入sensor_monitor函数。
int sensors_manager_add_sensor(struct sensors_mgr_sensor_info *sensor_mgr) { if (sensor_mgr == NULL) { msg("%s: Invalid argument\n", __func__); return -(EINVAL); } dbgmsg("%s: add sensor %s\n", __func__, sensor_mgr->name); if (!sensor_mgr->default_polling_interval) sensor_mgr->default_polling_interval = SENSOR_DEFAULT_POLLING_INTERVAL; /* Just add new device to begining of list */ sensor_mgr->next_sensor = sensor_list; sensor_list = sensor_mgr; sensor_cnt++; if (sensor_mgr->alias) alias_cnt++; pthread_mutex_init(&(sensor_mgr->req_wait_mutex), NULL); pthread_cond_init(&(sensor_mgr->req_wait_cond), NULL); pthread_create(&(sensor_mgr->monitor_thread), NULL, sensor_monitor, sensor_mgr); return 0; }
2.2.2 sensor监控函数
下面我们就来看下sensor_monitor函数,这个函数在没创建一个sensor最后放入sensor_list的时候开启一个线程对该sensor进行监控。
static void *sensor_monitor(void *vsensor_mgr) { struct sensors_mgr_sensor_info *sensor_mgr = vsensor_mgr; while (sensor_mgr->thread_shutdown != 1) {//这个只有在sensor被remove的时候才会退出 /* Wait here until there is actually a request to process */ if (!sensor_mgr->req_active) { dbgmsg("%s: %s Wait for client request.\n", __func__, sensor_mgr->name); pthread_mutex_lock(&(sensor_mgr->req_wait_mutex)); while (!sensor_mgr->req_active) {//只有当sensor_mgr的req_active为1该线程才会继续 pthread_cond_wait(&(sensor_mgr->req_wait_cond), &(sensor_mgr->req_wait_mutex)); } pthread_mutex_unlock(&(sensor_mgr->req_wait_mutex)); } dbgmsg("%s: %s Sensor wait.\n", __func__, sensor_mgr->name); sensor_wait(sensor_mgr);//线程等待相关 if (sensor_mgr->get_trip_temperature) sensor_mgr->last_reading = sensor_mgr->get_trip_temperature(sensor_mgr); else sensor_mgr->last_reading =//获取温度保存在last_reading中 sensor_mgr->get_temperature(sensor_mgr); dbgmsg("%s: %s Reading %d .\n", __func__, sensor_mgr->name, sensor_mgr->last_reading); .......//log notify_clnts(sensor_mgr);//调用notify_clnts通知各个client } return NULL; }
我们先来看下sensor_wait就是
static void sensor_wait(struct sensors_mgr_sensor_info *sensor_mgr) { if (sensor_mgr->wait) sensor_mgr->wait(sensor_mgr); else { uint32_t polling_interval = (sensor_mgr->active_thresh.polling_interval_valid)? (sensor_mgr->active_thresh.polling_interval): (sensor_mgr->default_polling_interval); dbgmsg("%s: %s Wait start. %dms\n", __func__, sensor_mgr->name, polling_interval); usleep(polling_interval*1000); dbgmsg("%s: %s Wait done.\n", __func__, sensor_mgr->name); } }
每一个sensor_mgr的wait函数,最后都是调用的sensor_info的interrupt_wait函数,我们来看下如下的,都是利用condition来等待。
void thermal_sensor_interrupt_wait(struct sensor_info *sensor) { struct thermal_sensor_data *sensor_data; if (NULL == sensor || NULL == sensor->data) { msg("%s: unexpected NULL", __func__); return; } sensor_data = (struct thermal_sensor_data *) sensor->data; if (sensor->interrupt_enable) { /* Wait for sensor threshold condition */ pthread_mutex_lock(&(sensor_data->thermal_sensor_mutex)); while (!sensor_data->threshold_reached) { pthread_cond_wait(&(sensor_data->thermal_sensor_condition), &(sensor_data->thermal_sensor_mutex)); } sensor_data->threshold_reached = 0; pthread_mutex_unlock(&(sensor_data->thermal_sensor_mutex)); } }
我们再来看下notify_clnts函数,先是遍历了client的request.thresh然后调用回调,后面还调用了update_active_thresh函数最后会调用sensor_info的update_thresholds,我们后续再分析。
static int notify_clnts(struct sensors_mgr_sensor_info *sensor_mgr) { struct sensor_client_type *client = NULL; enum sensor_notify_event_type thresh_event; if (sensor_mgr == NULL) return -(EINVAL); client = sensor_mgr->client_list; THERM_MUTEX_LOCK(&ts_clnt_mtx); while (client != NULL) { if (client->request_active) { struct thresholds_req_t *thresh = &client->request.thresh;//遍历client的request.thresh /* Notify clients of thresh crossings */ thresh_event = SENSOR_NOTIFY_NORMAL_THRESH_EVENT; if (thresh->high_valid && (sensor_mgr->last_reading >= thresh->high)) { thresh_event = SENSOR_NOTIFY_HIGH_THRESH_EVENT; } else if (thresh->low_valid && (sensor_mgr->last_reading <= thresh->low)) { thresh_event = SENSOR_NOTIFY_LOW_THRESH_EVENT; } if (thresh_event != SENSOR_NOTIFY_NORMAL_THRESH_EVENT) { client->request_active = 0; client->request.notify_cb_func(client,//调用request的回调函数 thresh_event, sensor_mgr->last_reading, client->request.notify_cb_data); } } client = client->next_clnt; } THERM_MUTEX_UNLOCK(&ts_clnt_mtx); update_active_thresh(sensor_mgr); return 0; }
2.2.3 读取sensor_info数组创建sensor
最后我们再来看看,bcl sensor的创建。这里和前面alarm adc tsens类型的sensor创建不一样,前面我们通过读取节点信息等等一步步最后得到sensor_info后再调用的add_tgt_sensor函数创建最后色sensor。这里直接调用了add_tgt_sensors_set函数。
int sensors_init(int minimum_mode) { ...... /* BCL */ if (add_tgt_sensors_set(bcl_sensors, ARRAY_SIZE(bcl_sensors)) != 0) { msg("%s: Error adding BCL TS\n", __func__); ret_val = -(EFAULT); } return ret_val; }
我们来看下add_tgt_sensors_set函数,这里就是遍历传进来的bcl_sensors的list,这个已经是sensor_info类型的数组了,然后我们遍历这个数组,依次调用add_tgt_sensor创建sensor。
int add_tgt_sensors_set(struct sensor_info *sensor_arr, int arr_size) { int idx = 0; int ret_val = 0; for (idx = 0; idx < arr_size; idx++) { if (add_tgt_sensor(&sensor_arr[idx]) != 0) { msg("%s: Error adding %s\n", __func__, sensor_arr[idx].name); ret_val = -(EFAULT); break; } } return ret_val; }
我们来看下bcl_sensors数组,目前只有一个sensor,就是sensor_info的结构体。
static struct sensor_info bcl_sensors[] = { { .name = "bcl", .setup = bcl_setup, .shutdown = bcl_shutdown, .get_temperature = bcl_get_iavail, .interrupt_wait = bcl_interrupt_wait, .update_thresholds = bcl_update_thresholds, .tzn = 0, .data = NULL, .get_trip_temperature = NULL, .interrupt_enable = 1, } };
这样sensor的各个函数都分析了,下面我们从sensor监控温度的流程上进一步分析。
3. sensor监控温度的流程
上面我们只是分析了一些函数,没有从流程上分析sensor是如何监控温度以及和各个算法联系起来的。
之前分析过add_tgt_tsens_sensors函数,这个函数的sensor主要是监控cpu、gpu的温度。我们再来看下这个函数。在add_tgt_sensor函数中我们会调用每个sensor的setup方法,每个sensor的setup方法我们要注意,然后我么还需要注意tsens_sensor_interrupt_wait和tsens_sensor_update_thresholds函数。
static int add_tgt_tsens_sensors(char *sensor_name, struct msm_sensor_info *sens_info) { int ret_val = 0; struct sensor_info *sensor; sensor = malloc(sizeof(struct sensor_info)); if (sensor == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor, 0, sizeof(struct sensor_info)); sensor->name = malloc(MAX_SENSOR_NAME_LEN); if (sensor->name == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor->name, 0, MAX_SENSOR_NAME_LEN); strlcpy(sensor->name, sensor_name, MAX_SENSOR_NAME_LEN); sensor->setup = tsens_sensors_setup; sensor->shutdown = tsens_sensors_shutdown; sensor->get_temperature = tsens_sensor_get_temperature; sensor->get_trip_temperature = NULL; sensor->interrupt_wait = tsens_sensor_interrupt_wait;//有自己的wait函数 sensor->update_thresholds = tsens_sensor_update_thresholds;//更新sensor的thresholds的low和high sensor->tzn = 0; sensor->data = NULL; sensor->interrupt_enable = 1;//允许中断 sensor->scaling_factor = sens_info->scaling_factor; pthread_mutex_init(&(sensor->read_mtx), NULL); add_tgt_sensor(sensor); error_handler: if (ret_val) { if (sensor) { if (sensor->name) free(sensor->name); free(sensor); } } return ret_val; }
我们先来看下sensor_monitor函数,先需要sensor的req_active为1,代表这个时候sensor的client有申请(这个在后面的算法会提到),这个时候我们再调用sensor_wait,这个函数会去等待
static void *sensor_monitor(void *vsensor_mgr) { struct sensors_mgr_sensor_info *sensor_mgr = vsensor_mgr; while (sensor_mgr->thread_shutdown != 1) { /* Wait here until there is actually a request to process */ if (!sensor_mgr->req_active) { dbgmsg("%s: %s Wait for client request.\n", __func__, sensor_mgr->name); pthread_mutex_lock(&(sensor_mgr->req_wait_mutex)); while (!sensor_mgr->req_active) { pthread_cond_wait(&(sensor_mgr->req_wait_cond), &(sensor_mgr->req_wait_mutex)); } pthread_mutex_unlock(&(sensor_mgr->req_wait_mutex)); } dbgmsg("%s: %s Sensor wait.\n", __func__, sensor_mgr->name); sensor_wait(sensor_mgr); if (sensor_mgr->get_trip_temperature) sensor_mgr->last_reading = sensor_mgr->get_trip_temperature(sensor_mgr); else sensor_mgr->last_reading = sensor_mgr->get_temperature(sensor_mgr); dbgmsg("%s: %s Reading %d .\n", __func__, sensor_mgr->name, sensor_mgr->last_reading); if (!strncmp(sensor_mgr->name, "bcl", 3)) { thermalmsg(LOG_LVL_DBG, (LOG_LOGCAT | LOG_LOCAL_SOCKET), "%s:%s:%d mA\n", SENSORS, sensor_mgr->name, sensor_mgr->last_reading); } else if (!strncmp(sensor_mgr->name, "bcm", 3)) { thermalmsg(LOG_LVL_DBG, (LOG_LOGCAT | LOG_LOCAL_SOCKET), "%s:%s:%d mPercent\n", SENSORS, sensor_mgr->name, sensor_mgr->last_reading); } else { thermalmsg(LOG_LVL_DBG, (LOG_LOGCAT | LOG_LOCAL_SOCKET), "%s:%s:%d mC\n", SENSORS, sensor_mgr->name, sensor_mgr->last_reading); } notify_clnts(sensor_mgr); } return NULL; }我们来看这个sensor_wait函数,sensor有wait函数就去调用wait函数。没有就用usleep来替代,这个时候polling_interval就是每个配置算法中的采样率。
static void sensor_wait(struct sensors_mgr_sensor_info *sensor_mgr) { if (sensor_mgr->wait) sensor_mgr->wait(sensor_mgr); else { uint32_t polling_interval = (sensor_mgr->active_thresh.polling_interval_valid)? (sensor_mgr->active_thresh.polling_interval): (sensor_mgr->default_polling_interval); dbgmsg("%s: %s Wait start. %dms\n", __func__, sensor_mgr->name, polling_interval); usleep(polling_interval*1000); dbgmsg("%s: %s Wait done.\n", __func__, sensor_mgr->name); } }
我们再来看上面的sensor的wait函数,这个函数先看这个sensor是否允许中断,如果允许然后一直等待condition,直到某个地方broadcast这个condition。下一步我们就要看哪个地方broadcast这个condition。
void tsens_sensor_interrupt_wait(struct sensor_info *sensor) { struct tsens_data *tsens; if (NULL == sensor || NULL == sensor->data) { msg("%s: unexpected NULL", __func__); return; } if (sensor->interrupt_enable) { tsens = (struct tsens_data *) sensor->data; /* Wait for sensor threshold condition */ pthread_mutex_lock(&(tsens->tsens_mutex)); while (!tsens->threshold_reached) { pthread_cond_wait(&(tsens->tsens_condition), &(tsens->tsens_mutex)); } tsens->threshold_reached = 0; pthread_mutex_unlock(&(tsens->tsens_mutex)); } }我们来看前面的tsens_sensors_setup函数,最后会建一个thread来执行tsens_uevent函数。
int tsens_sensors_setup(struct sensor_info *sensor) { int fd = -1; int sensor_count = 0; char name[MAX_PATH] = {0}; int tzn = 0; struct tsens_data *tsens = NULL; tzn = get_tzn(sensor->name); if (tzn < 0) { msg("No thermal zone device found in the kernel for sensor %s\n", sensor->name); return sensor_count; } sensor->tzn = tzn; snprintf(name, MAX_PATH, TZ_TEMP, sensor->tzn); fd = open(name, O_RDONLY); if (fd < 0) { msg("%s: Error opening %s\n", __func__, TZ_TEMP); return sensor_count; } /* Allocate TSENS data */ tsens = (struct tsens_data *) malloc(sizeof(struct tsens_data)); if (NULL == tsens) { msg("%s: malloc failed", __func__); close(fd); return sensor_count; } memset(tsens, 0, sizeof(struct tsens_data)); sensor->data = (void *) tsens; sensor_count++; pthread_mutex_init(&(tsens->tsens_mutex), NULL); pthread_cond_init(&(tsens->tsens_condition), NULL); tsens->sensor_shutdown = 0; tsens->threshold_reached = 0; tsens->sensor = sensor; sensor->fd = fd; init_tsens_trip_type(tsens); if (sensor->interrupt_enable) { pthread_create(&(tsens->tsens_thread), NULL, tsens_uevent, sensor); } return sensor_count; }我们来分析下这个函数,这个函数就是去读每个sensor的/sys/devices/virtual/thermal/thermal_zone%d/type节点了,然后使用poll,看看是否有事件可以读取,然后再去将上面提到的condition去broadcast,这样sensor_wait的等待就结束了。那么这个节点什么时候会有事件呢,稍后我们会提到一个update threshold这个,这个最后就是往sensor驱动下一个threshold的low和high,只要sensor驱动读取的数据大于high或者小于low,就会触发/sys/devices/virtual/thermal/thermal_zone%d/type节点了,就会有数据上来,这个时候sensor_wait就结束等待了。
static void *tsens_uevent(void *data) { int err = 0; struct sensor_info *sensor = (struct sensor_info *)data; struct pollfd fds; int fd; char uevent[MAX_PATH] = {0}; char buf[MAX_PATH] = {0}; struct tsens_data *tsens = NULL; if (NULL == sensor || NULL == sensor->data) { msg("%s: unexpected NULL", __func__); return NULL; } tsens = (struct tsens_data *) sensor->data; /* Looking for tsens uevent */ snprintf(uevent, MAX_PATH, TZ_TYPE, sensor->tzn); fd = open(uevent, O_RDONLY); if (fd < 0) { msg("Unable to open %s to receive notifications.\n", uevent); return NULL; }; while (!tsens->sensor_shutdown) { fds.fd = fd; fds.events = POLLERR|POLLPRI; fds.revents = 0; err = poll(&fds, 1, -1); if (err == -1) { msg("Error in uevent poll.\n"); break; } err = read(fd, buf, sizeof(buf)); if (err < 0) msg("sysfs[%s] read error:%d\n", uevent, errno); lseek(fd, 0, SEEK_SET); dbgmsg("%s: %s", __func__, buf); /* notify the waiting threads */ pthread_mutex_lock(&(tsens->tsens_mutex)); tsens->threshold_reached = 1;//sensor的threshold被触发 pthread_cond_broadcast(&(tsens->tsens_condition));//broadcast condition pthread_mutex_unlock(&(tsens->tsens_mutex)); } close(fd); return NULL; }
我们再来看函数,就会去遍历每一个client,如果当前的温度超过了该client thresh的high或者low就会调用该client的回调(其实就去处理该配置算法的流程了),最后还会调用update_active_thresh函数来更新sensor的thresh值。
static int notify_clnts(struct sensors_mgr_sensor_info *sensor_mgr) { struct sensor_client_type *client = NULL; enum sensor_notify_event_type thresh_event; if (sensor_mgr == NULL) return -(EINVAL); client = sensor_mgr->client_list; THERM_MUTEX_LOCK(&ts_clnt_mtx); while (client != NULL) { if (client->request_active) { struct thresholds_req_t *thresh = &client->request.thresh; /* Notify clients of thresh crossings */ thresh_event = SENSOR_NOTIFY_NORMAL_THRESH_EVENT; if (thresh->high_valid && (sensor_mgr->last_reading >= thresh->high)) { thresh_event = SENSOR_NOTIFY_HIGH_THRESH_EVENT; } else if (thresh->low_valid && (sensor_mgr->last_reading <= thresh->low)) { thresh_event = SENSOR_NOTIFY_LOW_THRESH_EVENT; } if (thresh_event != SENSOR_NOTIFY_NORMAL_THRESH_EVENT) { client->request_active = 0; client->request.notify_cb_func(client,//调用各个client的回调 thresh_event, sensor_mgr->last_reading, client->request.notify_cb_data); } } client = client->next_clnt; } THERM_MUTEX_UNLOCK(&ts_clnt_mtx); update_active_thresh(sensor_mgr); return 0; }
我们来看下update_active_thresh函数,其实就是遍历各个client获取thresh.high thresh.low然后比较保存在sensor中,然后调用sensor的update_thresholds函数。这函数在各个算法初始化的时候都会去调用,用来设置各个client thresh的low、high然后设置到sensor中(比如ss算法中会去调用sensors_manager_set_thresh_lvl函数设置client的thresh,最后还是调用update_active_thresh函数来更新sensor中的值)
static int update_active_thresh(struct sensors_mgr_sensor_info *sensor_mgr) { struct sensor_client_type *client = NULL; struct sensor_thresh_req *active = NULL; uint8_t active_req = 0; if (sensor_mgr == NULL) return -(EINVAL); active = &sensor_mgr->active_thresh; memset(active, 0, sizeof(struct sensor_thresh_req)); active->thresh.low = INT32_MIN; active->thresh.high = INT32_MAX; active->polling_interval = UINT32_MAX; client = sensor_mgr->client_list; THERM_MUTEX_LOCK(&ts_clnt_mtx); while (client != NULL) { if (!client->request_active) { client = client->next_clnt; continue; } struct sensor_thresh_req *thresh = &client->request; if (thresh->thresh.descending_threshold) active->thresh.descending_threshold = 1; /* Find active high */ if (thresh->thresh.high_valid) { active->thresh.high_valid = 1; active->thresh.high = MIN(active->thresh.high, thresh->thresh.high); } /* Find active low */ if (thresh->thresh.low_valid) { active->thresh.low_valid = 1; active->thresh.low = MAX(active->thresh.low, thresh->thresh.low); } /* Find min polling interval */ if (thresh->polling_interval_valid) { active->polling_interval_valid = 1; active->polling_interval = MIN(active->polling_interval, thresh->polling_interval); } active_req = 1; client = client->next_clnt; } if ((active->thresh.high > active->thresh.low) &&//当high大于low 并且high_valid或者low_valid才需要更新sensor的threshold (active->thresh.high_valid || active->thresh.low_valid)) { /* We can take advantage of interrupt */ sensor_mgr->active_thresh_valid = 1; } else { sensor_mgr->active_thresh_valid = 0; } /* Room for optimization if thresholds didn't change. */ if (sensor_mgr->active_thresh_valid && sensor_mgr->update_thresholds) { sensor_mgr->update_thresholds(sensor_mgr);//更新sensor的threshold } if (!sensor_mgr->req_active && active_req) { /* Advertise there is now an active request available */ pthread_mutex_lock(&(sensor_mgr->req_wait_mutex)); sensor_mgr->req_active = 1; pthread_cond_broadcast(&(sensor_mgr->req_wait_cond)); pthread_mutex_unlock(&(sensor_mgr->req_wait_mutex)); } else { sensor_mgr->req_active = active_req; } THERM_MUTEX_UNLOCK(&ts_clnt_mtx); return 0; }
我们再来看上面这个sensor的update_thresholds函数
void tsens_sensor_update_thresholds(struct sensor_info *sensor, struct thresholds_req_t *thresh) { struct tsens_data *tsens; if (NULL == thresh || NULL == sensor || NULL == sensor->data) { msg("%s: unexpected NULL", __func__); return; } tsens = (struct tsens_data *) sensor->data; /* Convert thresholds to Celsius for TSENS*/ thresh->high = RCONV(thresh->high); thresh->low = RCONV(thresh->low); set_thresholds(tsens, thresh); }
主要还是看set_thresholds函数,这个函数主要会去设置 /sys/devices/virtual/thermal/thermal_zone%d/trip_point_%d_temp,其中一个是threshold的low,另一个是threshold的high,设置完之后还需要对/sys/devices/virtual/thermal/thermal_zone%d/trip_point_%d_type节点设置enabled或者disabled(注意这个里的enabled和disabled只是对sensor驱动下一次中断而言)。这样当sensor检测到温度大于high或者小于low,这个时候/sys/devices/virtual/thermal/thermal_zone%d/type节点就会有事件了,sensor_wait就不会去wait了,这样就可以调用各个client的回调来开启各个配置算法的流程。
static void set_thresholds(struct tsens_data *tsens, struct thresholds_req_t *thresh) { char minname[MAX_PATH]= {0}; char maxname[MAX_PATH]= {0}; char buf[LVL_BUF_MAX] = {0}; int ret = 0; int mintemp = 0; if (NULL == tsens) { msg("%s: unexpected NULL", __func__); return; } snprintf(minname, MAX_PATH, TSENS_TZ_TRIP_TEMP, tsens->sensor->tzn, tsens->trip_min); snprintf(maxname, MAX_PATH, TSENS_TZ_TRIP_TEMP, tsens->sensor->tzn, tsens->trip_max); /* Set thresholds in legal order */ if (read_line_from_file(minname, buf, sizeof(buf)) > 0) { mintemp = atoi(buf); } if (thresh->high >= (mintemp / tsens->sensor->scaling_factor)) { /* set high threshold first */ if (thresh->high_valid) { dbgmsg("Setting up TSENS thresholds high: %d\n", thresh->high); snprintf(buf, LVL_BUF_MAX, "%d", thresh->high * tsens->sensor->scaling_factor); ret = write_to_file(maxname, buf, strlen(buf)); if (ret <= 0) msg("TSENS threshold high failed to set %d\n", thresh->high); } enable_threshold(tsens, tsens->trip_max, thresh->high_valid); if (thresh->low_valid) { dbgmsg("Setting up TSENS thresholds low: %d\n", thresh->low); snprintf(buf, LVL_BUF_MAX, "%d", thresh->low * tsens->sensor->scaling_factor); ret = write_to_file(minname, buf, strlen(buf)); if (ret <= 0) msg("TSENS threshold low failed to set %d\n", thresh->low); } enable_threshold(tsens, tsens->trip_min, thresh->low_valid); } else { if (thresh->low_valid) { dbgmsg("Setting up TSENS thresholds low: %d\n", thresh->low); snprintf(buf, LVL_BUF_MAX, "%d", thresh->low * tsens->sensor->scaling_factor); ret = write_to_file(minname, buf, strlen(buf)); if (ret <= 0) msg("TSENS threshold low failed to set %d\n", thresh->low); } enable_threshold(tsens, tsens->trip_min, thresh->low_valid); if (thresh->high_valid) { dbgmsg("Setting up TSENS thresholds high: %d\n", thresh->high); snprintf(buf, LVL_BUF_MAX, "%d", thresh->high * tsens->sensor->scaling_factor); ret = write_to_file(maxname, buf, strlen(buf)); if (ret <= 0) msg("TSENS threshold high failed to set %d\n", thresh->high); } enable_threshold(tsens, tsens->trip_max, thresh->high_valid); } }
上面我们基本分析了sensor监控温度的流程,上面我们分析的是tsens的sensor,下面我们再来看看下面sensor。有区分sensor的类型来做处理,有没有update_thresholds函数。有没有interrupt_wait函数的,如果没有interrupt_wait就是用usleep函数来达到wait的目的,wait的interval就是用算法配置中的采样率。
static int add_tgt_gen_sensors(char *sensor_name, struct msm_sensor_info *sens_info) { int ret_val = 0; struct sensor_info *sensor; sensor = malloc(sizeof(struct sensor_info)); if (sensor == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor, 0, sizeof(struct sensor_info)); sensor->name = malloc(MAX_SENSOR_NAME_LEN); if (sensor->name == NULL) { msg("%s: malloc failed.\n", __func__); ret_val = -(ENOMEM); goto error_handler; } memset(sensor->name, 0, MAX_SENSOR_NAME_LEN); strlcpy(sensor->name, sensor_name, MAX_SENSOR_NAME_LEN); sensor->setup = thermal_sensor_setup; sensor->shutdown = thermal_sensor_shutdown; sensor->get_temperature = thermal_sensor_get_temperature; sensor->get_trip_temperature = NULL; sensor->update_thresholds = NULL; sensor->scaling_factor = sens_info->scaling_factor; if (!strncmp(sens_info->type, ALARM_TYPE, strlen(ALARM_TYPE))) { sensor->interrupt_enable = 1; sensor->interrupt_wait = thermal_sensor_interrupt_wait;//alarm类型sensor有wait函数,但是没有threshold } else if (!strncmp(sens_info->type, USERSPACE_TYPE, strlen(USERSPACE_TYPE))) { sensor->interrupt_enable = 1; sensor->interrupt_wait = thermal_sensor_interrupt_wait; sensor->update_thresholds = thermal_sensor_update_thresholds; sensor->get_trip_temperature = thermal_sensor_get_trip_temp; sensor->scaling_factor = 1000; } else { sensor->interrupt_enable = 0;//这个interrupt不允许 sensor->interrupt_wait = NULL; } pthread_mutex_init(&(sensor->read_mtx), NULL); sensor->tzn = 0; sensor->data = NULL; add_tgt_sensor(sensor); error_handler: if (ret_val) { if (sensor) { if (sensor->name) free(sensor->name); free(sensor); } } return ret_val; }这样sensor监控温度,sensor_monitor函数wait如何唤醒,以及如何启动配置算法的流程,都分析清楚了。