这篇博客我们主要分析thermal-engine的socket监控,包括应用client的注册回调,以及client发送thermal消息都是通过socket。在thermal-engine启动分析的时候我们看到其创建了4个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;
}
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.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.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中接受数据了。