温控daemon(五)socket监控

这篇博客我们主要分析thermal-engine的socket监控,包括应用client的注册回调,以及client发送thermal消息都是通过socket。在thermal-engine启动分析的时候我们看到其创建了4个socket。

1. socket初始化

我们从main函数的thermal_server_init函数分析,这个函数其实流程很简单,对创建的4个socket,thermal-engine是server端,要bind listen,最后创建了一个thead进行各个socket的收发工作。这个thread的函数是

int thermal_server_init(void)
{
	...
#ifdef ANDROID
	sockfd_server_send = android_get_control_socket(
				THERMAL_SEND_SOCKET_NAME);
	if (sockfd_server_send > -1) {
		sockfd_server_recv = android_get_control_socket(
					THERMAL_RECV_SOCKET_NAME);
		if (sockfd_server_recv < 0)
			goto error;

		sockfd_server_recv_passive = android_get_control_socket(
					THERMAL_RECV_PASSIVE_SOCKET_NAME);
		if (sockfd_server_recv_passive < 0)
			goto error;
		sockfd_server_rule = android_get_control_socket(
					THERMAL_SEND_RULE_SOCKET_NAME);
		if (sockfd_server_rule < 0)
			goto error;
	}
#endif
	if (sockfd_server_send > -1)
		goto end_file_socket_create;
	sockfd_server_send = socket(AF_LOCAL, SOCK_STREAM, 0);
	...

	sockfd_server_recv = socket(AF_LOCAL, SOCK_STREAM, 0);
	...

	sockfd_server_recv_passive = socket(AF_LOCAL, SOCK_STREAM, 0);
	...

	sockfd_server_rule = socket(AF_LOCAL, SOCK_STREAM, 0);
	...

	memset(&server_addr_send, 0, sizeof(struct sockaddr_un));
	snprintf(server_addr_send.sun_path, UNIX_PATH_MAX, THERMAL_SEND_CLIENT_SOCKET);
	server_addr_send.sun_family = AF_LOCAL;

	memset(&server_addr_recv, 0, sizeof(struct sockaddr_un));
	snprintf(server_addr_recv.sun_path, UNIX_PATH_MAX, THERMAL_RECV_CLIENT_SOCKET);
	server_addr_recv.sun_family = AF_LOCAL;

	memset(&server_addr_recv_passive, 0, sizeof(struct sockaddr_un));
	snprintf(server_addr_recv_passive.sun_path, UNIX_PATH_MAX, THERMAL_RECV_PASSIVE_CLIENT_SOCKET);
	server_addr_recv_passive.sun_family = AF_LOCAL;

	memset(&server_addr_rule, 0, sizeof(struct sockaddr_un));
	snprintf(server_addr_rule.sun_path, UNIX_PATH_MAX, THERMAL_SEND_RULE_SOCKET);
	server_addr_rule.sun_family = AF_LOCAL;

	/* Delete existing socket file if necessary */
	unlink(server_addr_send.sun_path);
	unlink(server_addr_recv.sun_path);
	unlink(server_addr_recv_passive.sun_path);
	unlink(server_addr_rule.sun_path);

	rc = bind(sockfd_server_send,(struct sockaddr  const *)&server_addr_send, sizeof(struct sockaddr_un));
	...
	rc = bind(sockfd_server_recv,(struct sockaddr  const *)&server_addr_recv, sizeof(struct sockaddr_un));
	...

	rc = bind(sockfd_server_recv_passive,(struct sockaddr  const *)&server_addr_recv_passive, sizeof(struct sockaddr_un));
	if (rc != 0) {
		msg("Thermal-Server: Recv passive socket: bind error - %s", strerror(errno));
		goto error;
	}

	rc = bind(sockfd_server_rule,(struct sockaddr  const *)&server_addr_rule, sizeof(struct sockaddr_un));
	...

	/* Allow any client to connect to send socket.
	   Allow any client to connect to passive receive socket.
	   Only root group clients can connect recieve socket. */
	chmod(server_addr_send.sun_path, 0666);
	chmod(server_addr_recv.sun_path, 0660);
	chmod(server_addr_recv_passive.sun_path, 0666);
	chmod(server_addr_rule.sun_path, 0666);

end_file_socket_create:
	sockfd_server_log = socket(AF_LOCAL, SOCK_STREAM, 0);
	if (sockfd_server_log < 0)
		goto error;

	memset(&server_log, 0, sizeof(struct sockaddr_un));
	snprintf(server_log.sun_path, UNIX_PATH_MAX, " %s",
			UI_LOCALSOCKET_NAME);
	server_log.sun_family = AF_LOCAL;

	/* abstract namespace socket starts with NULL char */
	server_log.sun_path[0] = '\0';
	rc = bind(sockfd_server_log,
			(struct sockaddr  const *)&server_log,
			(int)(sizeof(sa_family_t) + 1
			+ strlen(UI_LOCALSOCKET_NAME)));
    ...
	rc = listen(sockfd_server_send, NUM_LISTEN_QUEUE);
	...

	rc = listen(sockfd_server_recv, NUM_LISTEN_QUEUE);
	...

	rc = listen(sockfd_server_recv_passive, NUM_LISTEN_QUEUE);
	...

	rc = listen(sockfd_server_log, NUM_LISTEN_QUEUE);
	...

	rc = listen(sockfd_server_rule, NUM_LISTEN_QUEUE);
	...

	rc = pthread_create(&listen_client_fd_thread, NULL, do_listen_client_fd, NULL);
	......

	ret = 0;
	return ret;
error:
	......
	return ret;
}

2. 各个socket监听

do_listen_client_fd函数,这里我们主要讲一下两个socket一个是sockfd_server_send这个主要是client用来注册回调,另一个是sockfd_server_recv时client给thermal-engine发送消息的。我们先分析这个函数,后面我们再从client端进行分析。

static void *do_listen_client_fd(void *data)
{
	int fd;
	uint8_t i;
	int nread;
	int result;
	socklen_t client_len;
	int client_fd = -1;
	struct sockaddr_un client_addr;
	fd_set t_readfds,testfds;

	FD_ZERO(&t_readfds);
	FD_SET(sockfd_server_send, &t_readfds);
	FD_SET(sockfd_server_recv, &t_readfds);
	FD_SET(sockfd_server_recv_passive, &t_readfds);
	FD_SET(sockfd_server_log, &t_readfds);
	FD_SET(sockfd_server_rule, &t_readfds);

	for (i = 0; i < NUM_LISTEN_QUEUE; i++) {
		thermal_send_fds[i] = -1;
	}

	while(server_socket_exit != 1) {
		testfds = t_readfds;
		result = select(FD_SETSIZE, &testfds, (fd_set *)0,//使用select
			       (fd_set *)0, (struct timeval *) 0);
		if (result < 1) {
			msg("Thermal-Server: %s select error", __func__);
			break;
		}

		for (fd = 0; fd < FD_SETSIZE; fd++) {
			if (FD_ISSET(fd,&testfds)) {
				if (fd == sockfd_server_send) {
					client_len = sizeof(struct sockaddr_un);
					client_fd = accept(sockfd_server_send,//client的fd
						          (struct sockaddr *)&client_addr,
						           &client_len);
					if (client_fd < 0)
						continue;
					FD_SET(client_fd, &t_readfds);//将client的fd放入select
					info("Thermal-Server: Adding thermal event listener on fd %d\n", client_fd);
					for (i = 0; i < NUM_LISTEN_QUEUE && thermal_send_fds[i] != -1; i++)
							continue;
						if (i < NUM_LISTEN_QUEUE)
							thermal_send_fds[i] = client_fd;//将client的fd放入thermal_send_fds数组中
					notify_client_on_register(client_fd);//client注册回调

				} else if (fd == sockfd_server_recv ||
					   fd == sockfd_server_recv_passive) {
					client_len = sizeof(struct sockaddr_un);
					client_fd = accept(fd,
						          (struct sockaddr *)&client_addr,
						           &client_len);
					if (client_fd < 0)
						continue;
					thermal_recv_data_from_client(client_fd, fd);//从client收消息
					close(client_fd);
				} else if (fd == sockfd_server_log || fd == sockfd_server_rule) {
					client_len = sizeof(struct sockaddr_un);
					client_fd = accept(fd,
						           (struct sockaddr *)&client_addr,
							    &client_len);
					if (client_fd < 0)
						continue;
					FD_SET(client_fd, &t_readfds);
					info("Thermal-Server: Adding thermal log/rule listener on fd %d\n", client_fd);
					if (fd == sockfd_server_log)
						add_local_socket_fd(SOCKET_RPT_LOG, client_fd);
					else
						add_local_socket_fd(SOCKET_RPT_RULE, client_fd);
				} else {
					ioctl(fd, FIONREAD, &nread);//client的fd没有数据直接清除该client的fd
					if (nread == 0) {
						close(fd);
						FD_CLR(fd, &t_readfds);
						info("Thermal-Server: removing client on fd %d\n", fd);
						for (i = 0; i < NUM_LISTEN_QUEUE && thermal_send_fds[i] != fd; i++)
							continue;
						if (i < NUM_LISTEN_QUEUE)
							thermal_send_fds[i] = -1;
						else
							remove_local_socket_fd(fd);
					}
				}
			}
		}
	}
	for (i = 0; i < NUM_LISTEN_QUEUE; i++) {
		if (thermal_send_fds[i] > -1)
			close(thermal_send_fds[i]);
	}
	return NULL;
}

3. client注册回调

3.1 thermal-engine发送数据

这里notify_client_on_register函数直接遍历了notify_clients给这个client发thermal_msg,这里是client第一次connect之后,thermal-engine给client回的消息,这个时候req_data还是0(初始化的值)

static void notify_client_on_register(int client_fd)
{
	ssize_t rc;
	int i;
	struct thermal_msg_data thermal_msg;

	pthread_mutex_lock(&soc_client_mutex);

	for (i = 0; i < ARRAY_SIZE(notify_clients); i++) {
		if (notify_clients[i].device_type == MITIGATION_DEVICE) {

			memset(&thermal_msg, 0, sizeof(struct thermal_msg_data));
			strlcpy(thermal_msg.client_name, notify_clients[i].name, CLIENT_NAME_MAX);
			thermal_msg.req_data = notify_clients[i].cur_level;

			rc = send_to_fd(client_fd, (unsigned char *)&thermal_msg,
				sizeof(struct thermal_msg_data));
			if (rc <= 0)
				msg("Thermal-Server: Unable to send "
				    "event to fd %d", client_fd);
		}
	}

	pthread_mutex_unlock(&soc_client_mutex);
}

我们再来看下notify_clients,这里在这个数组里的client才可以注册,而这里在client刚注册的时候我们只给MITIGATION_DEVICE类型的client发了消息。

static struct notify_client notify_clients[] =
{
	{
		.name      = "camera",
		.cur_level = 0,
		.device_type = MITIGATION_DEVICE,
	},
	{
		.name      = "camcorder",
		.cur_level = 0,
		.device_type = MITIGATION_DEVICE,
	},
	{
		.name      = "spkr",
		.cur_level = 0,
		.device_type = NON_MITIGATION_DEVICE,
	},
	{
		.name      = CONFIG_QUERY_CLIENT,
		.cur_level = 0,
		.device_type = NON_MITIGATION_DEVICE,
	},
};

3.2 client注册回调

我们再来看看client是如何通信的,client的进程需要引入Thermal_client.h的头文件,并且调用thermal_client_register_callback函数才能注册thermal的回调函数,我们来看下这个函数。

int thermal_client_register_callback(char *client_name, int (*callback)(int, void *, void *), void *data)
{
	int rc = 0;
	int ret = 0;
	uint8_t i;
	uint32_t client_cb_handle;

	if (NULL == client_name ||
	    NULL == callback) {
		msg("Thermal-Lib-Client:%s: unexpected NULL client registraion "
		    "failed ", __func__);
		return ret;
	}

	/* Check for client is supported  or not*///这里是检测进来的client是否在notify_clients中
	for (i = 0; i < ARRAY_SIZE(notify_clients); i++) {
		if (0 == strncmp(notify_clients[i].name, client_name, CLIENT_NAME_MAX))
			break;
	}

	if (i >= ARRAY_SIZE(notify_clients)) {
		msg("Thermal-Lib-Client:%s is not in supported thermal client list", client_name);
		return ret;
	}

	/* synchronize register and unregister calls */
	pthread_mutex_lock(&clnt_reg_mtx);

	if (thermal_client_shutdown != 0)
		thermal_client_shutdown = 0;

	pthread_mutex_lock(&clnt_list_mtx);
	client_cb_handle = add_to_list(client_name, callback, data);//新建一个thermal_cdata数据结构,将回调保存起来
	if (client_cb_handle == 0) {
		msg("Thermal-Lib-Client: %s: Client Registration failed", __func__);
		pthread_mutex_unlock(&clnt_list_mtx);
		goto error_handler;
	}
	pthread_mutex_unlock(&clnt_list_mtx);

	if (first_client == 1) {
		rc = pthread_create(&thermal_client_recv_thread, NULL, do_listen, NULL);//创建线程调用do_listen函数
		if (rc != 0) {
			msg("Thermal-Lib-Client: Unable to create pthread to "
			    "listen thermal events for %s", client_name);
			pthread_mutex_lock(&clnt_list_mtx);
			remove_from_list(client_cb_handle);
			pthread_mutex_unlock(&clnt_list_mtx);
			goto error_handler;
		}
		first_client = 0;
	}

	info("Thermal-Lib-Client: Registraion successful "
	     "for %s with handle:%d", client_name, client_cb_handle);
	ret = (int)client_cb_handle;
error_handler:
	pthread_mutex_unlock(&clnt_reg_mtx);
	return ret;
}

我们来看下add_to_list函数,新建了一个thermal_cdata,然后将client的name和回调保存起来。

unsigned int add_to_list(char *name,  void *callback, void *data)
{
	uint32_t ret = 0;
	uint32_t i;
	struct thermal_cdata *newclient = NULL;

	if (NULL == name ||
	     NULL == callback)
		return ret;

	for (i = 1; i < CLIENT_HANDLE_MAX; i++) {
		if (!CLIENT_HANDLE_COND(i))
			break;
	}
	if (i >= CLIENT_HANDLE_MAX)
		return ret;

	client_cb_handle |= (1U << i);

	newclient = (struct thermal_cdata *) malloc(sizeof(struct thermal_cdata));
	if (NULL == newclient) {
		return ret;
	}
	memset(newclient, 0, sizeof(struct thermal_cdata));

	newclient->client_cb_handle = i;
	newclient->client_name = name;
	newclient->callback = callback;
	newclient->user_data = data;
	newclient->data_reserved = NULL;
	newclient->next = NULL;

	if (list_head == NULL) {
		list_head = newclient;
	} else {
		newclient->next = list_head;
		list_head = newclient;
	}
	ret = newclient->client_cb_handle;
	return ret;
}

3.3 client接受数据

我们再来看do_listen函数,这个函数回去connect thermal-engine这个时候thermal-engine就有client的sockfd了,之后thermal-engine就会发来数据,这里再通过select之后再接受数据,然后调用回调函数。

static void *do_listen(void *data)
{
	ssize_t rc;
	uint32_t i;
	int count;
	int (*callback)(int, void *, void *);
	struct thermal_cdata *callback_node;
	static struct sockaddr_un client_addr;
	struct thermal_msg_data thermal_msg;
	int sockfd_client_recv = -1;
	fd_set readfds, testfds;

	while (thermal_client_shutdown != 1) {

		if (pipe_fds[0] < 0 && pipe(pipe_fds)) {//创建了一个管道,主要用来注销回调用
			msg("Thermal-Client-Lib: Pipe error. Re-trying after 5sec\n");
			sleep(5);
			continue;
		}

		sockfd_client_recv = socket(AF_LOCAL, SOCK_STREAM, 0);
		if (sockfd_client_recv < 0) {
			sleep(5);
			continue;
		}

		memset(&client_addr, 0, sizeof(struct sockaddr_un));
		snprintf(client_addr.sun_path, UNIX_PATH_MAX, THERMAL_SEND_CLIENT_SOCKET);//thermal_send_client的socket
		client_addr.sun_family = AF_LOCAL;

		rc = connect(sockfd_client_recv, (struct sockaddr *)&client_addr,//connect之后thermal-engine就可以获取client的fd了
				     (socklen_t)(sizeof(sa_family_t) + strlen(THERMAL_SEND_CLIENT_SOCKET)));
		if (rc != 0) {
			close(sockfd_client_recv);
			sleep(5);
			continue;
		}

		FD_ZERO(&readfds);
		FD_SET(sockfd_client_recv, &readfds);
		FD_SET(pipe_fds[0], &readfds);
		while (thermal_client_shutdown != 1) {

			testfds = readfds;
			rc = select(FD_SETSIZE, &testfds, (fd_set *)0,
				           (fd_set *)0, (struct timeval *)0);
			if (rc < 1)
				continue;

                        if (FD_ISSET(pipe_fds[0], &testfds))//注销通过管道的一端直接退出该循环了
				break;

			memset(&thermal_msg, 0, sizeof(struct thermal_msg_data));
			rc = recv_from_fd(sockfd_client_recv, (unsigned char *)&thermal_msg,//获取数据
				sizeof(struct thermal_msg_data));
			if (rc <= 0) {
				msg("Thermal-Lib-Client:%s: recv failed", __func__);
				break;
			}

			if (rc != sizeof(struct thermal_msg_data))
				continue;

			for (i = 0; i < CLIENT_NAME_MAX; i++) {
				if (thermal_msg.client_name[i] == '\0')
					break;
			}
			if (i >= CLIENT_NAME_MAX)
				thermal_msg.client_name[CLIENT_NAME_MAX - 1] = '\0';

			info("Thermal-Lib-Client: Client received msg %s %d",
					thermal_msg.client_name, thermal_msg.req_data);

			/* Check for client is supported  or not*/
			for (i = 0; i < ARRAY_SIZE(notify_clients); i++) {//看看thermal-engine发来的client的name是否在该数组中
				if (0 == strncmp(notify_clients[i].name, thermal_msg.client_name, CLIENT_NAME_MAX))
					break;
			}

			if (i >= ARRAY_SIZE(notify_clients)) {
				msg("Thermal-Lib-Client:%s is not in supported "
				    "thermal client list", thermal_msg.client_name);
				continue;
			} else if (thermal_msg.req_data < notify_clients[i].min_req_data ||
				   thermal_msg.req_data > notify_clients[i].max_req_data) {
				msg("Thermal-Lib-Client:%s: invalid level %d "
				    "unexpected", __func__, thermal_msg.req_data);
				continue;
			}

			pthread_mutex_lock(&clnt_list_mtx);
			callback_node = list_head;//从前面我们保存的thermal_cdata的list
			count = 0;
			for (; callback_node != NULL; callback_node = callback_node->next) {

				callback_node = get_callback_node_from_list(callback_node, thermal_msg.client_name);
				if (callback_node) {//从thermal_cdata的list中获取client_name对的thermal_cdata
					count++;
					callback = callback_node->callback;
					if (callback)//调用回调
						callback(thermal_msg.req_data, callback_node->user_data,
									    callback_node->data_reserved);
				} else {
					if (count == 0)
						msg("Thermal-Lib-Client: No Callback "
						    "registered for %s", thermal_msg.client_name);
					break;
				}
			}
			pthread_mutex_unlock(&clnt_list_mtx);
		}
		close(sockfd_client_recv);
		FD_CLR(sockfd_client_recv, &readfds);
		FD_CLR(pipe_fds[0], &readfds);
	}
	close(pipe_fds[0]);
	close(pipe_fds[1]);
	pipe_fds[0] = -1;
	pipe_fds[1] = -1;

	return NULL;
}

client的一端也有自己的notify_clients数组,client和thermal-engine都会检查下client的name是否是该数组的。

static struct notify_client notify_clients[] = {
	{
		.name = "camera",
		.min_req_data = 0,
		.max_req_data = MAX_CAMERA_MITIGATION_LEVEL,
	},
	{
		.name = "camcorder",
		.min_req_data = 0,
		.max_req_data = MAX_CAMCORDER_MITIGATION_LEVEL,
	},
	{
		.name = "spkr",
		.min_req_data = -30,
		.max_req_data = 150,
	},
	{
		.name = CONFIG_QUERY_CLIENT,
		.min_req_data = 0,
		.max_req_data = LEVEL_MAX,
	}
};

我再来看下注销回调就是往管道的一端写下。

void thermal_client_unregister_callback(int client_cb_handle)
{
	int ret = 0;

	pthread_mutex_lock(&clnt_reg_mtx);

	pthread_mutex_lock(&clnt_list_mtx);
	ret = remove_from_list((unsigned int)client_cb_handle);
	pthread_mutex_unlock(&clnt_list_mtx);
	if (ret < 0) {
		msg("Thermal-Lib-Client: thermal client unregister callback error");
	} else {
		if (list_head == NULL) {
			thermal_client_shutdown = 1;
			ret = write(pipe_fds[1], "exit", 5);
			if (ret < 0)
				msg("pipe write error:%d\n", errno);
			pthread_join(thermal_client_recv_thread, NULL);
			first_client = 1;
		}
		info("Thermal-Lib-Client: Unregisteration is successfull for "
		     "handle:%d", client_cb_handle);
	}
	pthread_mutex_unlock(&clnt_reg_mtx);
}

4. thermal-engine接受客户端数据

4.1 thermal-engine接受数据

前面说到当fd是sockfd_server_recv或者sockfd_server_recv_passive时,就是客户端那边给thermal-engine发来数据。而接受数据的函数是thermal_recv_data_from_client,从客户端发来的数据放入client_msg.然后也要检测client的name是否在req_clients数组中,然后会根据client的name不同做不同处理。最后也会调用server端注册的回调。

static int thermal_recv_data_from_client(int client_fd, int socket_fd)
{
	ssize_t rc;
	uint32_t i;
	int ret = -EINVAL;
	int count = 0;
	int (*callback)(int, void *, void *);
	struct thermal_cdata *callback_node;
	struct thermal_msg_data client_msg;

	if ((client_fd == -1) || (socket_fd == -1))
		return ret;

	memset(&client_msg, 0, sizeof(struct thermal_msg_data));
	rc = recv_from_fd(client_fd, (unsigned char *)&client_msg,//client的数据放入client_msg
		sizeof(struct thermal_msg_data));
	if (rc <= 0) {
		msg("Thermal-Server: %s: recv failed", __func__);
		return ret;
	}

	if (rc != sizeof(struct thermal_msg_data))
		return ret;

	for (i = 0; i < CLIENT_NAME_MAX; i++) {
		if (client_msg.client_name[i] == '\0')
			break;
	}
	if (i >= CLIENT_NAME_MAX)
		client_msg.client_name[CLIENT_NAME_MAX - 1] = '\0';
	info("Thermal-Server: Thermal received "
	     "msg from  %s\n", client_msg.client_name);

	/* Check for client is supported or not*/
	for (i = 0; i < ARRAY_SIZE(req_clients); i++) {//client的name是否在req_clients数组中
		if (0 == strncmp(req_clients[i].name, client_msg.client_name,
				 CLIENT_NAME_MAX) &&
		    *(req_clients[i].fd) == socket_fd)
			break;
	}

	if (i >= ARRAY_SIZE(req_clients)) {
		msg("Thermal-Server:%s is not in supported "
		    "thermal client list", client_msg.client_name);
		return ret;
	}

	if (0 == strncmp(client_msg.client_name, CONFIG_QUERY_CLIENT, CLIENT_NAME_MAX)) {//根据client的name做不同处理
		thermal_config_query_recv(client_msg, client_fd);
		return 0;
	} else if (0 == strncmp(client_msg.client_name, CONFIG_SET_CLIENT, CLIENT_NAME_MAX)) {
		thermal_config_update_recv(client_msg, client_fd);
		return 0;
	}

	for (callback_node = list_head; callback_node != NULL; callback_node = callback_node->next) {//调用回调

		callback_node = get_callback_node_from_list(callback_node, client_msg.client_name);
		if (callback_node) {
			count++;
			callback = callback_node->callback;
			if (callback)
				callback(client_msg.req_data, callback_node->user_data, callback_node->data_reserved);
		} else {
			if (count == 0)
				msg("Thermal-Server: No clients are "
				    "connected for %s", client_msg.client_name);
			break;
		}
	}
	ret = 0;
	return ret;
}

我们单独来看下面这段代码,CONFIG_QUERY_CLIENT对应的是thermal_config_query_recv函数处理。而CONFIG_SET_CLIENT对应的是thermal_config_update_recv处理。

	if (0 == strncmp(client_msg.client_name, CONFIG_QUERY_CLIENT, CLIENT_NAME_MAX)) {
		thermal_config_query_recv(client_msg, client_fd);
		return 0;
	} else if (0 == strncmp(client_msg.client_name, CONFIG_SET_CLIENT, CLIENT_NAME_MAX)) {
		thermal_config_update_recv(client_msg, client_fd);
		return 0;
	}

thermal_config_query_recv函数,只要是调用回调,然后重新发送数据给client。

static int thermal_config_query_recv(struct thermal_msg_data client_msg,
				      int client_fd)
{
	int count = 0;
	int (*callback)(int, void *, void *);
	struct thermal_cdata *callback_node;
	struct thermal_msg_data thermal_msg;
	int num_cfg_req_per_algo = 1;
	int num_configs = 0;

	if (client_fd < 0 ||
	    0 != strcmp(client_msg.client_name, CONFIG_QUERY_CLIENT))
		return -1;

	config_query_client_fd = client_fd;

	/* Get num of requested config file and send it to client as a first
	   packet(msg_type = ALGO_IDX_MAX and req_data = num_configs) */
	for (callback_node = list_head; callback_node != NULL;) {
		callback_node = get_callback_node_from_list(callback_node,//根据client_name得到回调和前面在client的代码类似
						client_msg.client_name);
		if (callback_node) {
			callback = callback_node->callback;
			if (callback)
				num_configs = num_configs + \//累计调用回调得到num_configs
					callback(client_msg.msg_type,
						 callback_node->user_data,
						 (int *)&num_cfg_req_per_algo);
			callback_node = callback_node->next;
		}
	}

	info("Thermal-Server: total num of config queried %d\n", num_configs);
	memset(&thermal_msg, 0, sizeof(struct thermal_msg_data));
	thermal_msg.msg_type = ALGO_IDX_MAX;
	thermal_msg.req_data = num_configs;
	strlcpy(thermal_msg.client_name, CONFIG_QUERY_CLIENT, CLIENT_NAME_MAX);
	thermal_server_config_info_to_client(&thermal_msg);//把这数据重新发给client

	for (callback_node = list_head; callback_node != NULL;) {
		callback_node = get_callback_node_from_list(callback_node,
							client_msg.client_name);
		if (callback_node) {
			count++;
			callback = callback_node->callback;
			if (callback)
				callback(client_msg.msg_type,
				         callback_node->user_data, NULL);//最后一个参数为NULL,重新调用回调
			callback_node = callback_node->next;
		} else {
			if (count == 0)
				msg("Thermal-Server: No clients are "
				    "connected for %s", client_msg.client_name);
		}
	}

	/* End of packet algo_type ALGO_IDX_MAX and req_data = 0 */
	memset(&thermal_msg, 0, sizeof(struct thermal_msg_data));
	thermal_msg.msg_type = ALGO_IDX_MAX;
	thermal_msg.req_data = 0;//这个值为0重新发给client
	strlcpy(thermal_msg.client_name, CONFIG_QUERY_CLIENT, CLIENT_NAME_MAX);
	thermal_server_config_info_to_client(&thermal_msg);//给client发数据还是要看client的name是否在notify_clients数组中

	config_query_client_fd = -1;
	return 0;
}

thermal_config_update_recv函数也是从client获取数据,然后调用回调,但是最后不会给client再发数据了。

4.2 thermal-engine注册回调

我们再来看下thermal-engine都是怎么注册回调的。

4.2.1 Monitor注册回调

先看Monitor的注册回调,是在Thermal_monitor.c的sensor_monitor函数中

	thermal_server_register_client_req_handler(CONFIG_QUERY_CLIENT, config_query_notify, NULL);
	thermal_server_register_client_req_handler(CONFIG_SET_CLIENT, config_set_notify, NULL);

4.2.2 SS注册回调

ss注册回调是在Ss_algorithm.c的algo_monitor函数中

	thermal_server_register_client_req_handler(CONFIG_QUERY_CLIENT, config_query_notify, NULL);
	thermal_server_register_client_req_handler(CONFIG_SET_CLIENT, config_parameter_set_notify, NULL);

4.2.3 pid注册回调

pid算法注册回调是在Pid_algorithm.c的pid_algo_monitor函数中

        thermal_server_register_client_req_handler(CONFIG_QUERY_CLIENT, config_query_notify, NULL);
	thermal_server_register_client_req_handler(CONFIG_SET_CLIENT, config_parameter_set_notify, NULL);

这几个回调其实差不多,CONFIG_QUERY_CLIENT就是获取了config,然后发送给client、另一个就是设置config。我们主要来看下thermal_server_register_client_req_handler函数。这个函数也需要检测下client的name是否在req_clients数组中,然后再调用add_to_list和client注册回调类似。

int thermal_server_register_client_req_handler(char *client_name, int (*callback)(int, void *, void *), void *data)
{
	int i;
	uint32_t client_cb_handle;

	if (NULL == client_name ||
	    NULL == callback) {
		msg("Thermal-Server: %s: unexpected NULL client registraion failed ", __func__);
		return 0;
	}

	/* Check for client is supported  or not*/
	for (i = 0; i < ARRAY_SIZE(req_clients); i++) {
		if (0 == strncmp(req_clients[i].name, client_name, CLIENT_NAME_MAX))
			break;
	}

	if (i >= ARRAY_SIZE(req_clients)) {
		msg("Thermal-Server: %s is not in supported thermal client list", client_name);
		return 0;
	}

	client_cb_handle = add_to_list(client_name, callback, data);
	if (client_cb_handle == 0) {
		msg("Thermal-Server: %s: Client Registration failed", __func__);
		return 0;
	}

	return (int)client_cb_handle;
}

add_to_list函数就和client是一样的了,新建一个thermal_cdata数据。然后用list_head保存起来。

unsigned int add_to_list(char *name,  void *callback, void *data)
{
	uint32_t ret = 0;
	uint32_t i;
	struct thermal_cdata *newclient = NULL;

	if (NULL == name ||
	     NULL == callback)
		return ret;

	for (i = 1; i < CLIENT_HANDLE_MAX; i++) {
		if (!CLIENT_HANDLE_COND(i))
			break;
	}
	if (i >= CLIENT_HANDLE_MAX)
		return ret;

	client_cb_handle |= (1U << i);

	newclient = (struct thermal_cdata *) malloc(sizeof(struct thermal_cdata));
	if (NULL == newclient) {
		return ret;
	}
	memset(newclient, 0, sizeof(struct thermal_cdata));

	newclient->client_cb_handle = i;
	newclient->client_name = name;
	newclient->callback = callback;//回调
	newclient->user_data = data;//数据
	newclient->data_reserved = NULL;
	newclient->next = NULL;

	if (list_head == NULL) {
		list_head = newclient;
	} else {
		newclient->next = list_head;
		list_head = newclient;
	}
	ret = newclient->client_cb_handle;
	return ret;
}

 

4.3 client发送数据给thermal-engine

 

我们再来看下client端发给来数据的代码在Thermal_client.c中,这个函数主要是获取Thermal-engine特定算法的配置,保存在configs中。

int thermal_client_config_query(char *algo_type,
				struct config_instance **configs)
{
	uint32_t idx = 0;
	ssize_t rc = 0;
	struct thermal_msg_data query_msg;  /* sending data */
	struct thermal_msg_data thermal_msg; /* recieving data */
	struct sockaddr_un client_addr;
	struct config_instance *config_local = NULL;
	int sockfd_client = -1;
	char algo_name[MAX_ALGO_NAME];
	enum algo_type algo = UNKNOWN_ALGO_TYPE;
	uint32_t num_configs = 0;
	struct timeval tv;

	if (NULL == algo_type) {
		msg("Thermal-Lib-Client:%s: unexpected NULL", __func__);
		return 0;
	}

	/* Get algo type enum if it is supported */
	algo = check_for_algo_type(UNKNOWN_ALGO_TYPE, algo_type);
	if (algo == UNKNOWN_ALGO_TYPE)
		return 0;

	memset(&query_msg, 0, sizeof(struct thermal_msg_data));
	query_msg.msg_type = algo;
	query_msg.req_data = 0;
	strlcpy(query_msg.client_name, CONFIG_QUERY_CLIENT, CLIENT_NAME_MAX);//client的name,这个是询问配置

	sockfd_client = connect_to_socket(query_msg.client_name, &client_addr);//连接到thermal-engine获取socket的fd
	if (sockfd_client < 0) {
		msg("Thermal-Lib-Client:%s: could not connect to socket\n",
		    __func__);
		return 0;
	}

	tv.tv_sec = RECV_TIMEOUT_SEC;
	tv.tv_usec = 0;
	setsockopt(sockfd_client, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
			sizeof(struct timeval));
	/* Send client info to thermal server */
	rc = send_to_fd(sockfd_client, (unsigned char *)&query_msg,//通过socket发给thermal-engine
		sizeof(struct thermal_msg_data));
	if (rc <= 0) {
		msg("Thermal-Lib-Client: "
		    "Unable to send request data to fd %d", sockfd_client);
		close(sockfd_client);
		return 0;
	}
	info("Thermal-Lib-Client: Client config query request sent %s  %d\n",
	      query_msg.client_name, query_msg.msg_type);

	/* Recv configs one by one from thermal */
	while (1) {
		rc = recv_and_extract_packet(sockfd_client, &config_local,//接受thermal-engine的配置信息,最后将配置信息放在configs中
					     &thermal_msg, &num_configs);
		if (rc < 0) {
			if (idx == num_configs)
				break;
			else
				goto error_handler;
		} else if (rc == 0) {
			continue;
		}

		/* check idx is within limit */
		if (idx >= num_configs)
			goto error_handler;

		/* validate config data with client request */
		if ((query_msg.msg_type != ALGO_IDX_MAX) &&
		    (thermal_msg.msg_type != query_msg.msg_type))
			goto error_handler;

		/* Get algo_name if it is supported */
		algo = check_for_algo_type(thermal_msg.msg_type, algo_name);
		if (algo == UNKNOWN_ALGO_TYPE)
			goto error_handler;

		if (config_local == NULL)
			goto error_handler;

		/* allocate memory and save config fields */
		config_local[idx].cfg_desc =
		(char *)malloc(sizeof(char) * MAX_ALGO_DESC);
		if (config_local[idx].cfg_desc == NULL) {
			msg("%s: malloc failed for config_desc", __func__);
			goto error_handler;
		}
		strlcpy(config_local[idx].cfg_desc, thermal_msg.config.config_desc,
			MAX_ALGO_DESC);

		config_local[idx].algo_type =
		(char *)malloc(sizeof(char) * MAX_ALGO_NAME);
		if (config_local[idx].algo_type == NULL) {
			msg("%s: malloc failed for algo_type", __func__);
			goto error_handler;
		}
		strlcpy(config_local[idx].algo_type, algo_name,
		        MAX_ALGO_NAME);

		/* fields_mask is valid during only set request */
		config_local[idx].fields_mask = UNKNOWN_FIELD;

		switch(thermal_msg.msg_type) {
			case MONITOR_ALGO_TYPE:
				if (add_settings_to_client_config(&config_local[idx],
						&thermal_msg, monitor_fields,
						ARRAY_SIZE(monitor_fields))) {
					msg("Thermal-Lib-Client:%s: config data is invalid\n",
					     __func__);
					goto error_handler;
				}
				idx++;
				break;
			case SS_ALGO_TYPE:
			case TB_ALGO_TYPE:
			case PID_ALGO_TYPE:
				if (add_settings_to_client_config(&config_local[idx],
						&thermal_msg, pid_ss_tb_fields,
						ARRAY_SIZE(pid_ss_tb_fields))) {
					msg("Thermal-Lib-Client:%s: config data is invalid\n",
					     __func__);
					goto error_handler;
				}
				idx++;
				break;
			default:
				msg("Thermal-Lib-Client:Unknown algo type\n");
				goto error_handler;
		}
	}

	*configs = config_local;
	close(sockfd_client);
	return (int)idx;

我们再来看connect_to_socket函数client是如何连接到thermal-engine的,同样client的name需要在req_clients数组中,然后再去获取数组中对应的socket的path,再去connect获取socket的fd。

static int connect_to_socket(char *client_name, struct sockaddr_un *client_addr)
{
	uint8_t i;
	int rc;
	int sockfd_client = -1;

	if (client_name == NULL)
		return -1;

	/* Get socket file to connect using client_name */
	for (i = 0; i < ARRAY_SIZE(req_clients); i++) {//检查client的name是否在req_clients中
		if (0 == strcmp(req_clients[i].name, client_name))
			break;
	}

	if (i >= ARRAY_SIZE(req_clients)) {
		msg("Thermal-Lib-Client:%s is not in supported "
		    "thermal client list", client_name);
		return -1;
	}

	sockfd_client = socket(AF_LOCAL, SOCK_STREAM, 0);
	if (sockfd_client < 0)
		return -1;

	memset(client_addr, 0, sizeof(struct sockaddr_un));
	strlcpy(client_addr->sun_path, req_clients[i].send_sock_path,
	        UNIX_PATH_MAX);
	client_addr->sun_family = AF_LOCAL;
	rc = connect(sockfd_client, (struct sockaddr *)client_addr,
		     (socklen_t)(sizeof(sa_family_t) + strlen(req_clients[i].send_sock_path)));
	if (rc != 0) {
		close(sockfd_client);
		return -1;
	}

	return sockfd_client;
}

我们来看下req_clients中每一个client都保存着socket的path。

static struct req_client req_clients[] = {
	{
		.name = "spkr",
		.send_sock_path = THERMAL_RECV_PASSIVE_CLIENT_SOCKET,
	},
	{
		.name = "override",
		.send_sock_path = THERMAL_RECV_CLIENT_SOCKET,
	},
	{
		.name = CONFIG_SET_CLIENT,
		.send_sock_path = THERMAL_RECV_CLIENT_SOCKET,
	},
	{
		.name = CONFIG_QUERY_CLIENT,
		.send_sock_path = THERMAL_RECV_CLIENT_SOCKET,
	},
};

而thermal_client_config_set函数是设置config到thermal-engine中去,过程类似只是我们不需要从thermal-engine中接受数据了。

 

你可能感兴趣的:(android,thermal)