在前面的文章中,我们分析到Sensor HAL层的启动以及数据获取过程,我们提到,SensorContext以及Sensor在初始化的时候会通过sensor1_open创建一个客户端的socket,这个socket会不停的从服务端读取数据,并通过注册的回调来处理得到的数据,这个服务端的socket就是我们今天分析的主角,SensorDaemon守护进程,那么SensorDaemon在Sensor架构中到底起着怎样的作用呢? 我们拭目以待。
戳下面复习:
Android Sensor HAL层初始化流程
Android Sensor HAL层数据获取,基于Qualcomm平台
SensorDaemon启动
SensorDaemon是在init阶段通过device/qcom/common/rootdir/etc/init.qcom.rc中配置启动的。
service sensors /system/bin/sensors.qcom class late_start user root group root disabled
因此我们直接跟进其main方法,相关的代码路径在vendor/qcom/proprietary/sensors/dsps/sensordaemon中,而main方法定义在文件sns_main.c中。
/*! @brief "Main" function for the sensor daemon process. Handles starting the process, initializing sockets and sensor1 API, and blocking for incoming data on sockets. @param[i] argc: Count of arguments on the command line. @param[i] argv: Array of strings contaning command line arguments. @return 0 - no error */ /*=========================================================================*/ int main( int argc, char *argv[] ) { sensor1_error_e sns_err; sns_main_data_s *srv_data; bool error = FALSE; pthread_mutexattr_t attr; if( 'd' == getopt( argc, argv, "d" ) ) { /* Put ourselves in a background daemon process */ sns_main_daemonize(); } else { printf("Use option \"-d\" to run as background process.\n"); printf("Running in foreground...\n"); } /* Start up the sensor library */ sns_err = sensor1_init(); if( SENSOR1_SUCCESS != sns_err ) { SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_APPS_MAIN, "Exiting! sensor1_init failed with %d", sns_err ); exit(6); } /* Initialize mutex */ pthread_mutexattr_init( &attr ); pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK ); pthread_mutex_init( &sns_main_data_mutex, &attr ); /* Initialize server */ srv_data = sns_main_setup(); if( NULL == srv_data ) { SNS_PRINTF_STRING_ERROR_0( SNS_DBG_MOD_APPS_MAIN, "Exiting! Can't setup server socket" ); exit(4); } /* Check to ensure sensors are enabled */ sns_main_check_enabled( srv_data ); /* Drop all root privs */ error = sns_main_drop_root(); if( error != false ) { SNS_PRINTF_STRING_ERROR_0( SNS_DBG_MOD_APPS_MAIN, "Error dropping root privs. Exiting" ); exit(5); } initialized = true; sns_monitor_adsp_restart(); utime(SENSOR_CTL_SOCKET, NULL); while( !error ) { error = sns_main_sock_handle( srv_data ); } SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_APPS_MAIN, "Exiting! Err %d", error ); return 0; }
这里首先也调用了sensor1_init来初始化sensor,由之前的博文可知,各个模块的初始化都会优先调用sensors1_init来确保其已经正常的初始化,保证功能正常运行,当然,由于SensorContext中最开始已经进行了初始化,因此这里将会什么都不做。
server的初始化时在sns_main_setup方法中完成的,我们接下来分析这个方法。
static sns_main_data_s* sns_main_setup( void ) { sns_main_data_s *srv_data; int error; srv_data = malloc( sizeof(*srv_data) ); if( NULL == srv_data ) { SNS_PRINTF_STRING_ERROR_0( SNS_DBG_MOD_APPS_MAIN, "malloc error" ); return NULL; } memset( srv_data, 0, sizeof(*srv_data) ); if( 0 != sns_main_setup_srv_sock( srv_data ) ) { free(srv_data); return NULL; } srv_data->enabled = true; srv_data->inotify_fd = inotify_init(); if( srv_data->inotify_fd == -1 ) { SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_APPS_MAIN, "inotify_init error %d", errno ); free(srv_data); return NULL; } error = pipe2( wakeup_pipe, O_NONBLOCK ); if( error != 0 ) { SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_APPS_MAIN, "pipe2 error %d", errno ); free(srv_data); return NULL; } return srv_data; }
首先通过sns_main_setup_srv_sock来创建server端的socket,通过bind,listen进行监听客户端的连接,这里的客户端就是我们的sensor1_open中创建的socket。我们回顾下:
sensor1_error_e sensor1_open( sensor1_handle_s **hndl, sensor1_notify_data_cb_t data_cbf, intptr_t cb_data ) { int sockfd; int retries, eacces_retries; int err; socklen_t len; struct sockaddr_un address; libsensor_client_data_s new_cli; struct timespec open_timeout; if( NULL == hndl ) { return SENSOR1_EBAD_PTR; } /* Call sensor1_init() here, in case the client failed to do it */ sensor1_init(); new_cli.data_cbf = data_cbf; new_cli.cb_data = cb_data; if( !ssc_present ) { LOG_WARN("%s: SSC not present", __func__); return SENSOR1_EFAILED; } if ( (sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1) { LOG_ERROR("%s: Error in socket() %s", __func__, strerror(errno)); return SENSOR1_ENOMEM; }
socket创建完成后,通过pipe方法创建了一个管道,用于唤醒及主线程退出。
/* Wakeup file descriptors, used to wake up and exit the main thread */ static int wakeup_pipe[2]; error = pipe2( wakeup_pipe, O_NONBLOCK );
接着往下,socket创建完毕后,会读取系统中的一个setting文件,来确认sensor是否使能,这个方法是sns_main_check_enabled。
static void sns_main_check_enabled( sns_main_data_s *srv_data ) { #ifdef SNS_LA_SIM srv_data->enabled = true; #else static int settings_fd = -1; char enabled; if( settings_fd == -1 ) { settings_fd = open( SENSORS_SETTINGS_DIR "/" SENSORS_SETTINGS_FILE, O_RDONLY | O_NOFOLLOW ); } if( settings_fd != -1 ) { /* File exists. */ /* Set up inotify to be notified of file changes */ inotify_add_watch( srv_data->inotify_fd, SENSORS_SETTINGS_DIR "/" SENSORS_SETTINGS_FILE, IN_CLOSE_WRITE ); /* Read value from settings file, and enable/disable as needed */ lseek( settings_fd, 0, SEEK_SET ); if( 1 == read( settings_fd, &enabled, 1 ) ) { if( enabled == '1' ) { SNS_PRINTF_STRING_HIGH_0( SNS_DBG_MOD_APPS_MAIN, "enabled=true"); srv_data->enabled = true; return; } } else { close( settings_fd ); settings_fd = -1; } } else { /* File does not exist */ SNS_PRINTF_STRING_ERROR_2( SNS_DBG_MOD_APPS_MAIN, "open error: settings file \"%s\", errno %d", (SENSORS_SETTINGS_DIR "/" SENSORS_SETTINGS_FILE), errno ); if( -1 == inotify_add_watch( srv_data->inotify_fd, SENSORS_SETTINGS_DIR, IN_CREATE ) ) { /* Error creating the watch */ SNS_PRINTF_STRING_ERROR_2( SNS_DBG_MOD_APPS_MAIN, "inotify error: settings path \"%s\", errno %d", SENSORS_SETTINGS_DIR, errno ); SNS_PRINTF_STRING_ERROR_0( SNS_DBG_MOD_APPS_MAIN, "***Sensor external clients cannot be enabled!!!***" ) } } SNS_PRINTF_STRING_ERROR_0( SNS_DBG_MOD_APPS_MAIN, "enabled=false"); srv_data->enabled = false; #endif /* SNS_LA_SIM */ }
读取的文件即如下:
/* file path for sensors settings file */ /* If file exists and contains '0', then disable external sensor clients */ #define SENSORS_SETTINGS_DIR "/persist/sensors" #define SENSORS_SETTINGS_FILE "sensors_settings"
如果在这个sensors_settings中读到1,则认为sensor是enable状态,设置SensorDaemon的成员属性srv_data->enabled值,否则sensor处于关闭状态,SensorDaemon将不会接收到达的连接。另外该方法还对文件的修改动作进行了监听,用以动态控制服务端进程的监听机制。
sns_monitor_adsp_restart方法启动了一个线程sns_handle_adsp_restart用于监听adsp端进程的重启动作,重启后会进行一些qmi客户端的初始化动作,我们暂时不关注这里。
如果之前的socket创建没有问题,那么while循环调用sns_main_sock_handle方法进对连接的客户端进行处理,当没有连接事件需要处理时,该函数会block住。
static bool sns_main_sock_handle( sns_main_data_s *data ) { fd_set read_fd; fd_set error_fd; int max_fd; sns_ctl_q_s *ctl_p; sns_ctl_q_s *prev_ctl_p; sensor1_error_e sns_err; int sel_err; bool error = true; max_fd = 0; FD_ZERO( &read_fd ); FD_ZERO( &error_fd ); FD_ADD( data->inotify_fd, &read_fd, max_fd ); FD_ADD( wakeup_pipe[0], &read_fd, max_fd ); if( data->enabled ) { /* Make sure server socket is opened */ if( data->ctl_fd == -1 ) { if( sns_main_setup_srv_sock( data ) != 0 ) { return true; } } if( data->ctl_fd >= 0 ) { FD_ADD( data->ctl_fd, &read_fd, max_fd ); } pthread_mutex_lock(&sns_main_data_mutex); prev_ctl_p = NULL; ctl_p = data->ctl_p; while (NULL != ctl_p) { /* Cleanup any disconnected clients */ if (ctl_p->sock_fd < 0) { if (prev_ctl_p != NULL) { prev_ctl_p->next = ctl_p->next; free(ctl_p); ctl_p = prev_ctl_p->next; } else { /* Handle first node in linked-list */ data->ctl_p = ctl_p->next; free(ctl_p); ctl_p = data->ctl_p; } } else { /* Add client handles to watch */ FD_ADD( ctl_p->sock_fd, &read_fd, max_fd ); prev_ctl_p = ctl_p; ctl_p = ctl_p->next; } } pthread_mutex_unlock(&sns_main_data_mutex); } else { /* Not enabled. Make sure server socket is closed */ if( data->ctl_fd >= 0 ) { unlink(SENSOR_CTL_SOCKET); close( data->ctl_fd ); } data->ctl_fd = -1; } error_fd = read_fd; max_fd++; errno = 0; RETRY_ON_EINTR(sel_err, select( max_fd, &read_fd, (fd_set *)NULL, &error_fd, (struct timeval*) NULL)); if (sel_err < 0 ) { return error; } if( FD_ISSET( wakeup_pipe[0], &read_fd ) ) { return error; } if( FD_ISSET( data->inotify_fd, &read_fd ) ) { /* Change in settings file */ char buf[500]; struct inotify_event *evt = (struct inotify_event *)buf; read(data->inotify_fd, evt, 500); if(evt->mask & IN_IGNORED) { /* Previous watch was removed. Nothing to do here */ } else if(evt->len == 0 || ( (evt->mask & IN_CREATE) && (0 == strncmp( evt->name, SENSORS_SETTINGS_FILE, evt->len)))) { inotify_rm_watch( data->inotify_fd, evt->wd ); sns_main_check_enabled( data ); } } /* Check to make sure sensors is enabled */ if( !data->enabled ) { sns_main_close_all_clients( data ); return false; } if( FD_ISSET( data->ctl_fd, &read_fd ) ) { /* incoming connection on ctl socket */ sns_err = sns_main_handle_ctl_srv_sock( data ); if( SENSOR1_ENOMEM != sns_err && SENSOR1_ENOTALLOWED != sns_err && SENSOR1_SUCCESS != sns_err ) { return true; } } prev_ctl_p = NULL; ctl_p = data->ctl_p; while( NULL != ctl_p ) { bool ctl_sock_err = false; if( (ctl_p->sock_fd >= 0) && FD_ISSET( ctl_p->sock_fd, &read_fd ) ) { /* Incoming data on a control socket */ ctl_sock_err = sns_main_handle_ctl_sock( data, &ctl_p, &prev_ctl_p ); } else { prev_ctl_p = ctl_p; ctl_p = ctl_p->next; } } error = false; return error; }
sns_main_sock_handle首先会判断之前创建的ctl_fd是否有效,如果无效,会再次调用sns_main_setup_srv_sock创建有效的服务端socket。
srv_data->ctl_p链表则存储着所有客户端的链接结构,一旦链表非空,说明有数据达到,将链表中的第一个取出来处理;
通过select轮询读端read_fd,这里加入了两个,一个是inotify_fd用于监听前面settings文件的修改,另一个是我么能通过pipe创建的唤醒读端。
如果数据达到了,则会调用sns_main_handle_ctl_srv_sock来处理。
static sensor1_error_e sns_main_handle_ctl_srv_sock( sns_main_data_s *data ) { sensor1_error_e sns_err; sns_ctl_q_s *new_ctl = malloc(sizeof(sns_ctl_q_s)); struct ucred cred; socklen_t len; int sns_ctl_unprivileged = 0; if( NULL == new_ctl ) { return SENSOR1_EFAILED; } new_ctl->next = NULL; new_ctl->privileged_user = false; new_ctl->sock_fd = accept( data->ctl_fd, NULL, NULL ); if( -1 == new_ctl->sock_fd ) { free(new_ctl); return SENSOR1_EUNKNOWN; } else { sns_main_set_non_blocking( new_ctl->sock_fd ); /* get peer credentials- uid, gid, pid */ len = sizeof(struct ucred); if (getsockopt(new_ctl->sock_fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) != -1) { SNS_PRINTF_STRING_LOW_3( SNS_DBG_MOD_APPS_MAIN, "Client PID=%d GID=%d UID=%d",(int)cred.pid,(int)cred.gid,(int)cred.uid ); if (sns_main_validate_group_access(&cred)) { new_ctl->privileged_user = true; } else { sns_ctl_q_s *ctl_p = data->ctl_p; while (NULL != ctl_p) { if (false == ctl_p->privileged_user) { sns_ctl_unprivileged++; } ctl_p = ctl_p->next; } if (sns_ctl_unprivileged > MAX_UNPRIVILEGED_CONN) { return SENSOR1_ENOTALLOWED; } } } else { SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_APPS_MAIN, "getsockopt returned error %d",errno ); close(new_ctl->sock_fd); free(new_ctl); return SENSOR1_ENOTALLOWED; } sns_err = sensor1_open( &new_ctl->sensor1_hndl, sns_main_notify_cb, (intptr_t)new_ctl ); if( SENSOR1_SUCCESS != sns_err ) { if(SENSOR1_ENOMEM == sns_err ) { sns_main_send_open_resp( new_ctl->sock_fd, SENSOR1_EWOULDBLOCK ); } close(new_ctl->sock_fd); free(new_ctl); } else { SNS_PRINTF_STRING_LOW_2( SNS_DBG_MOD_APPS_MAIN, "Incoming connection success! fd %d." "sensor1 handle 0x%"PRIxPTR, new_ctl->sock_fd, (uintptr_t)new_ctl->sensor1_hndl ); sns_main_add_ctl_cli( data, new_ctl ); sns_main_send_open_resp( new_ctl->sock_fd, SENSOR1_SUCCESS ); } } return sns_err; }
新建一个new_ctl链表,通过accept接受连接,如果连接fd有效,则设置非阻塞模式,再为这个new的fd通过sensor1_open注册一个回调方法sns_main_notify_cb,这个sensor1_open并非libsensor1中的那个,而是sensorDaemon自己的,定义在sns_acm.c中,如果open成功,则会调用sns_main_add_ctl_cli加到链表中,并且向client端发送open成功的消息。
这里创建的sns_main_notify_cb在什么情况下回回调呢?应该和之前的sensor1_open(libsensor1)一样,有个读线程来将其唤醒。
由于这里的sensor1_open调用的是sns_acm.c中的open,因此我们还是应该再这个文件里面找答案。
// vendor/qcom/proprietary/sensors/dsps/sensordaemon/apps/common/acm/src/sns_acm.c sensor1_error_e sensor1_open( sensor1_handle_s **hndl, sensor1_notify_data_cb_t notify_cb, intptr_t cb_data ) { sensor1_error_e rv; // Return value sensor1_handle_s *c_ptr; sns_log_sensor1_request_s *log_ptr; c_ptr = sns_acm_new_client_handle(); SNS_ACM_DEBUG1( LOW, "sensor1_open: allocating client %d", sns_acm_get_client_index( c_ptr ) ); if( NULL == c_ptr ) { hndl = NULL; SNS_PRINTF_STRING_ERROR_0( SNS_DBG_MOD_ACM, "sensor1_open: can't allocate client handle" ); rv = SENSOR1_ENOMEM; } else { c_ptr->notify_cb = notify_cb; c_ptr->notify_data = cb_data; *hndl = c_ptr; rv = SENSOR1_SUCCESS; } /* Generate and send log message */ sns_logpkt_malloc( SNS_LOG_SENSOR1_REQUEST, sizeof(sns_log_sensor1_request_s), (void**)(&log_ptr) ); if( NULL != log_ptr ) { sns_acm_log_api_call( SNS_LOG_SENSOR1_API_OPEN, (int32_t)rv, c_ptr, NULL, log_ptr ); } return rv; }
这里传入的notify_cb为sns_main_notify_cb,最终会赋值给类型为sensor1_handle_s的hndl句柄的notify_cb函数指针。
既然有了这个notify cb,那就一定有地方会调用它,我们在文件中发现只有一个sns_acm_handle_rx方法会调用他:
void sns_acm_handle_rx( void * msg_ptr ) { sns_smr_header_s smr_header; sensor1_msg_header_s msg_hdr; sensor1_handle_s *client_ptr; sensor1_msg_type_e msg_type; uint8_t err; sns_smr_get_hdr( &smr_header, msg_ptr ); if( sns_acm_max_clients() <= smr_header.ext_clnt_id ) { SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_ACM, "bad client ID %d\n", (int32_t)smr_header.ext_clnt_id ); sns_smr_msg_free( msg_ptr ); return; } client_ptr = sns_acm_client_handle( smr_header.ext_clnt_id ); msg_hdr.service_number = smr_header.svc_num; msg_hdr.msg_id = smr_header.msg_id; msg_hdr.txn_id = smr_header.txn_id; msg_hdr.msg_size = smr_header.body_len; sns_os_mutex_pend( sns_acm_db_mutex, 0, &err ); if( 0 == err ) { if ( smr_header.msg_type == SNS_SMR_MSG_TYPE_RESP ) { msg_type = SENSOR1_MSG_TYPE_RESP; client_ptr->outstanding_reqs--; sns_acm_peek_response( client_ptr, &msg_hdr, msg_ptr ); } else if ( smr_header.msg_type == SNS_SMR_MSG_TYPE_RESP_INT_ERR ) { msg_type = SENSOR1_MSG_TYPE_RESP_INT_ERR; client_ptr->outstanding_reqs--; sns_acm_peek_resp_error( client_ptr, &msg_hdr ); } else { msg_type = SENSOR1_MSG_TYPE_IND; } if( (SNS_ACM_CLI_STATE_OPENED == client_ptr->cli_state) && (NULL != client_ptr->notify_cb) ) { SNS_ACM_DEBUG1( LOW, "Delivering message to client %d", smr_header.ext_clnt_id ); sns_os_mutex_pend( sns_acm_log_mutex, 0, &err ); if( 0 == err ) { sns_acm_log_resp_or_ind( client_ptr, msg_type, &msg_hdr, msg_ptr ); sns_os_mutex_post( sns_acm_log_mutex ); } else { SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_ACM, "Error %d getting log mutex", (int32_t)err ); } client_ptr->notify_cb( client_ptr->notify_data, &msg_hdr, msg_type, msg_ptr ); } else { sns_smr_msg_free( msg_ptr ); } sns_os_mutex_post( sns_acm_db_mutex ); } else { SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_ACM, "Error %d getting mutex", (int32_t)err ); sns_smr_msg_free( msg_ptr ); } }
那么sns_acm_handle_rx方法又是谁驱动的呢?在/vendor/qcom/proprietary/sensors/dsps/sensordaemon/apps/common/acm/src/sns_acm_mr.c中被调用。
继续往回追,最终我们发现其逻辑如下:
main() --> /adsp_proc/xx/xx/sns_pd.c sns_init--> sns_init_once--> adsp_proc/Sensors/dsps/src/common/sns_init_dsps.c sns_acm_init--> /vendor/xxx/xx/sns_acm.c sns_os_task_create--> sns_acm_rx_thread--> sns_acm_mr_handle--> /vendor/xx/xx/sns_acm_mr.c sns_acm_handle_rx-> client_ptr->notify_cb()
看到这个流程,也许大当家会疑惑,adsp_proc是哪里的?这部分的初始化又是在做什么?其实这部分的流程涉及到adsp的启动了,代码都在modem端,这部分的内容我会在后面跟进分析,欢迎关注。
所以回到前面,SensorDaemon的open过程注册的notify_cb是上面的流程处理的,即这是modem端抛给SensorDaemon的数据,SensorDaemon在将此数据通过socekt传递到hal层,hal层再根据各个sensor自身数据结构将数据封装成sensor_event_t结构体,插入到Queue中,SensorService通过poll方法从这个Queue中读取数据,将此数据传递给对应的app。
关于adsp的部分,欢迎关注后续流程,另外,本博文已经收录到我的CSDN博客专栏:
Android Sensor架构全解析,欢迎关注。