SensorDaemon服务端流程解析 Android Sensor HAL层初始化流程 Android Sensor HAL层数据获取,基于Qualcomm平台

在前面的文章中,我们分析到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架构全解析,欢迎关注。

猜你喜欢

转载自blog.csdn.net/huilin9960/article/details/80757038