温控daemon(二)启动参数解析、device初始化

这样我们主要开始将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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值