这样我们主要开始将thermal-engine的流程。
1. thermal-engine启动
先从启动开始说起,在init.target.rc中定义了thermal-engine为一个service,并且属于main class,随main服务一起启动。
service thermal-engine /system/vendor/bin/thermal-engine
class main
user root
socket thermal-send-client stream 0666 system system
socket thermal-recv-client stream 0660 system system
socket thermal-recv-passive-client stream 0666 system system
socket thermal-send-rule stream 0660 system system
group root
2. 启动参数&configfile
我们先从thermal-engine的主函数开始分析,main函数在Thermal.c中。这里我们主要分下parse_commandline函数(解析启动参数),以及配置文件。
int main(int argc, char **argv)
{
device_clnt_handle kernel_dev;
union device_request req;
info("Thermal daemon started\n");
setpriority(PRIO_PROCESS, getpid(), -20);//设置程序的优先级为最高
if (!parse_commandline(argc, argv)) {//解析启动参数
print_help();
return 0;
}
if (thermal_set_limits_priv_debug_lvl(debug_output))
info("Invalid debug level for limits priv");
/* Get target default config file if no config is requested
through command line */
if (!config_file) {//配置文件相关
if ((config_file = get_target_default_thermal_config_file()))
info("Using target config file '%s'\n", config_file);
else
info("No target config file, falling back to '%s'\n",
CONFIG_FILE_DEFAULT);
}
我们先从parse_commandline函数分析启动参数。下面各个参数的意义可以看注释,配置文件的话就是thermal-engine的温度策略很多都是thermal-engine中写死的,比如现在涉及的平台8909,我们也可以从配置文件中读取;soc_id主要就是用来区分平台然后用来取不同的温控策略。而debug模式可以先stop thermal-engine然后在thermal-engine -d &就可以开启debug模式
int parse_commandline(int argc, char *const argv[])
{
int c;
struct option long_options[] = {
{"config-file", 1, 0, 'c'},
{"debug", 0, 0, 'd'},
{"soc_id", 1, 0, 's'},
{"norestorebrightness", 0, 0, 'r'},
{"output-conf", 0, 0, 'o'},
{"dump-bcl", 2, 0, 'i'},
{"help", 0, 0, 'h'},
{"trace", 0, 0, 't'},
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "c:i::s:droht", long_options, NULL)) != EOF) {
switch (c) {
case 'c'://设置配置文件
info("Using config file '%s'\n", optarg);
config_file = optarg;
break;
case 'i'://设置sensor bcl的dump文件
info("dump BCL ibat/imax to a file\n");
dump_bcl = 1;
dump_bcl_file = optarg;
break;
case 'd'://开启debug模式,主要就是debug级别的log会打印
info("Debug output enabled\n");
debug_output = LOG_LVL_DBG;
break;
case 's'://soc_id本来可以通过平台节点获取,也可以通过参数输入
info("Target SOC_ID specified as '%s'\n", optarg);
soc_id = atoi(optarg);
break;
case 'r':
info("Enable restore brightness feature\n");
enable_restore_brightness = 1;
break;
case 'o'://打印thermal-engine的配置信息
info("Output conf file to stdout and quit\n");
output_conf = 1;
break;
case 't'://打开tracelog
info("tracing enabled\n");
trace_fd = open(TRACE_MARKER, O_WRONLY);
break;
case 'h':
default:
return 0;
}
}
/* Too many/unrecognized argument(s) */
if (optind < argc) {
msg("Too many arguments\n");
return 0;
}
return 1;
}
下面这一段主要是当我们没有在启动参数中设置配置文件的话,我们会给一个默认的配置文件,或者为空的话进入else。
if (!config_file) {
if ((config_file = get_target_default_thermal_config_file()))
info("Using target config file '%s'\n", config_file);
else
info("No target config file, falling back to '%s'\n",
CONFIG_FILE_DEFAULT);
}
我们来看下get_target_default_thermal_config_file函数,先获取msm_id,获取了msm_id之后再通过thermal_config_table找到对应的config_file,而我们平台的msm_id是THERM_MSM_8909(是通过soc_id找到的),再从thermal_config_table中到这个msm_id对应的config_file为NULL。因此我们最后用的是#define CONFIG_FILE_DEFAULT "/system/etc/thermal-engine.conf"这个路径。
char *get_target_default_thermal_config_file(void)
{
static char config_file_path[MAX_CONFIG_PATH] = {0};
static uint8_t config_init;
if (!config_init) {//是否已经配置过config
int idx;
char *config = NULL;
enum therm_msm_id msm_id = therm_get_msm_id();
for (idx = 0; idx < ARRAY_SIZE(thermal_config_table); idx++) {
if (msm_id == thermal_config_table[idx].msm_id) {
config = thermal_config_table[idx].config_file;
break;
}
}
if (config) {
snprintf(config_file_path, MAX_CONFIG_PATH, "%s%s",
DEFAULT_CONFIG_PATH, config);
}
config_init = 1;
}
if (config_file_path[0] == 0)
return NULL;
else
return config_file_path;
}
我们来如何获取平台的msm_id,是先获取soc_id,然后通过msm_soc_table来获取msm_id,而soc_id是通过#define SYSFS_PLATFORMID "/sys/devices/soc0/soc_id"或者#define SYSFS_PLATFORMID_DEPRECATED "/sys/devices/system/soc/soc0/id"这两个路径获取的,看我们的平台是第一个路径是245,然后知道soc_id再通过msm_soc_table这个表格找到msm_id
enum therm_msm_id therm_get_msm_id(void)
{
static enum therm_msm_id msm_id;
static uint8_t msm_id_init;
if (!msm_id_init) {
int idx;
char buf[MAX_SOC_INFO_NAME_LEN];
if (soc_id < 0) {
get_soc_info(buf, SYSFS_PLATFORMID, SYSFS_PLATFORMID_DEPRECATED);
soc_id = atoi(buf);
}
for (idx = 0; idx < ARRAY_SIZE(msm_soc_table); idx++) {
if (soc_id == msm_soc_table[idx].soc_id) {
msm_id = msm_soc_table[idx].msm_id;
break;
}
}
if (!msm_id)
msg("Unknown target identified with soc id %d\n", soc_id);
msm_id_init = 1;
}
return msm_id;
}
通过soc_id找到msm_id
static struct therm_msm_soc_type msm_soc_table[] = {
{THERM_MSM_8960, 87},
......
{THERM_MSM_8909, 245},
下面这段代码主要就是thermal-engine -o的时候输出thermal-engine的各个配置包括monitor ss pid等算法也包括config_file中的算法
if (output_conf) {
devices_manager_init();
devices_init(minimum_mode);
sensors_manager_init();
sensors_init(minimum_mode);
init_settings(&thermal_settings);
pid_init_data(&thermal_settings);
thermal_monitor_init_data(&thermal_settings);
speaker_cal_init_data(&thermal_settings);
ss_init_data(&thermal_settings);
tb_init_data(&thermal_settings);
virtual_sensors_init_data(&thermal_settings);
virtual_sensors_init(&thermal_settings, config_file);
# ifdef ENABLE_OLD_PARSER
load_config(&thermal_settings, config_file);
# else
load_config(&thermal_settings, config_file, LOAD_ALL_FLAG);
# endif
print_settings(&thermal_settings);
return 0;
}
上面是程序的一些配置文件,参数解析。下面开始主要的代码分析。
3. device的初始化
这节我们来分析device的初始化,主要是下面代码
devices_manager_init();//空内容
devices_init(minimum_mode);//这个mode的值一般为0,只有当加密时为1
target_algo_init();//只有个别芯片有用,先不分析
/* Vote to keep kernel mitigation enabled until init is done */
kernel_dev = devices_manager_reg_clnt("kernel");
if (kernel_dev == NULL) {
msg("%s Failed to create kernel device handle\n", __func__);
} else {
req.value = 1;
device_clnt_request(kernel_dev, &req);//这里只是keep KTM
}
下面我们先来分析devices_init, 就是一个一个device初始化。
int devices_init(int minimum_mode)
{
int ret_val = 0;
min_mode = minimum_mode;
gpufreq_init();
cpufreq_init();
clusterfreq_init();
thermal_ioctl_init();
if (!min_mode)
qmi_communication_init();
ret_val = tmd_init_cpu_devs();
if (ret_val)
msg("%s: Init CPU TMD failed %d\n", __func__, ret_val);
ret_val = tmd_init_cluster_devs();
if (ret_val)
msg("%s: Init cluster TMD failed %d\n", __func__, ret_val);
ret_val = tmd_init_voltage_devs();//主要是cpu电压,后续分析
if (ret_val)
msg("%s: Init voltage TMD failed %d\n", __func__, ret_val);
ret_val = tmd_init_gpu_devs();
if (ret_val)
msg("%s: Init GPU TMD failed %d\n", __func__, ret_val);
ret_val = init_generic_devs();
if (ret_val)
msg("%s: Init generic TMDs failed %d\n", __func__, ret_val);
/* Functions to execute post devices added to device manager */
hotplug_init();
vdd_dig_sw_mode_init();
vdd_rstr_init();
opt_curr_req_init();
profile_switch_init();
cpr_band_init();
lcd_device_init();
bat