我是靠谱客的博主 忐忑绿茶,最近开发中收集的这篇文章主要介绍Qcom_Sensor(三)--- 之 Android Sensor HAL层初始化流程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Qcom_Sensor(三)--- 之 Android Sensor HAL层初始化流程

    • 一、Sensor HAL打开/初始化过程
    • 二、sensor1 API详解
      • 2.1 、SensorsContext() --> sensor1_init() 调用流程
    • 三、获取sensor列表getSensorList
    • 四、addSensor具体过程
    • 五、添加其他的sensor
    • 六、updateSensorList更新设备列表


前面我们分析到了sensor通过hw_get_module以及sensors_open_1去load HAL层的库以及打开我们的sensor设备,
今天我们的文章就来分析这两部分的流程。

一、Sensor HAL打开/初始化过程

进入我们的hal模块,sensors_open,
该方法实现在vendor/qcom/proprietary/sensors/dsps/libhalsensors/src/sensors_hal.cpp中,

其方法体如下:

static int sensors_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device)
{
    UNREFERENCED_PARAMETER(id);
    int ret = -EINVAL;
    SensorsContext *dev = SensorsContext::getInstance();
 
    memset(&dev->device, 0, sizeof(sensors_poll_device_1_t));
 
    dev->device.common.tag       = HARDWARE_DEVICE_TAG;
    dev->device.common.version   = SENSORS_DEVICE_API_VERSION_1_3;
    dev->device.common.module    = const_cast<hw_module_t*>(module);
    dev->device.common.close     = sensors_close;
    dev->device.activate         = sensors_activate;
    dev->device.setDelay         = sensors_set_delay;
    dev->device.poll             = sensors_poll;
    dev->device.batch            = sensors_batch;
    dev->device.flush            = sensors_flush;
 
    *device = &dev->device.common;
    ret = 0;
    return ret;
}

从方法体中,将hw_module_t结构体进行方法填充,其中最主要的一个是获取SensorContext的单例对象,我们重点关注这个SensorContext对象。

SensorsContext::SensorsContext()
    : active_sensors(0),
      is_accel_available(false),
      is_gyro_available(false),
      is_mag_available(false),
      is_prox_available(false),
      smgr_version(0)
{
    int i;
    int err;
 
    /* Enable logging */
    enableLogging();
    HAL_LOG_INFO("%s", __FUNCTION__);
 
    /* Release wakelock if it is NOT due to any reason */
    release_wake_lock( SENSORS_WAKE_LOCK );
 
    /* Init sensor1 before every sensor1 connection */
    sensor1_init();
 
    /* get the data_cb form the Utility class*/
    data_cb = Utility::getDataCb();
    /* smgr_sensor1_cb is used by the SMGR sensor1 connection */
    smgr_sensor1_cb = SMGRSensor::getSMGRSensor1Cb();
    /* sensor_info_sensor1_cb is used by the getting the SMGR sensor list */
    sensor_info_sensor1_cb = new hal_sensor1_cb_t;
    memset(sensor_info_sensor1_cb, 0, sizeof(*sensor_info_sensor1_cb));
    sensor_info_sensor1_cb->is_resp_arrived = false;
    sensor_info_sensor1_cb->error = false;
 
    /* Init the mSensors */
    for( i = 0; i < MAX_NUM_SENSORS; i++ ) {
        mSensors[i] = NULL;
    }
 
    /* open the general SMGR sensors sensor1 connection */
    err = sensor1_open(&smgr_sensor1_cb->sensor1_handle, &SMGRSensor_sensor1_cb, (intptr_t)this);
    if(SENSOR1_SUCCESS != err) {
        HAL_LOG_ERROR("sensor1 open failed!");
        return;
    }
    /* open the sensor_info SMGR sensors sensor1 connection */
    err = sensor1_open(&sensor_info_sensor1_cb->sensor1_handle, &context_sensor1_cb, (intptr_t)this);
    if(SENSOR1_SUCCESS != err) {
        HAL_LOG_ERROR("sensor1 open failed!");
        return;
    }
 
    /* Check the NV3801 for Magnetic sensor source */
    checkMagCalSource();
 
    /* Init the mutex and cond */
    pthread_mutex_init(&active_mutex, NULL);
    pthread_mutex_init(&(sensor_info_sensor1_cb->cb_mutex), NULL);
    pthread_cond_init(&(sensor_info_sensor1_cb->cb_cond), NULL);
 
    /* Time Service */
    time_service = TimeSyncService::getTimeSyncService();
 
    char wu_sensor[PROPERTY_VALUE_MAX] = "false";
    property_get( HAL_PROP_WU_SENSORS, wu_sensor, "true" );
    if (!strncmp("true", wu_sensor, 4)) {
        HAL_LOG_DEBUG("%s: Wake Up Sensors are enabled!", __FUNCTION__);
    } else {
        HAL_LOG_DEBUG("%s: Wake Up sensors disabled!", __FUNCTION__);
    }
 
    err = sendSMGRVersionReq();
    if (err) {
        HAL_LOG_ERROR("%s: SMGR version request failed!", __FUNCTION__);
    }
 
    err = getSensorList();
    if (err) {
        HAL_LOG_ERROR("%s: get sensor list failed!", __FUNCTION__);
    }
 
    for (i=0; i < ARRAY_SIZE(g_sensor_list_order); i++) {
        int handle = g_sensor_list_order[i];
        /* Skip SMGR sensors as they are added above - in getSensorList */
        if (handle < SAM_HANDLE_BASE)
            continue;
        /* Skip wake up sensors if they aren't enabled */
        if (!strncmp("false", wu_sensor, 5) &&
            ((handle < SAM_HANDLE_BASE && handle >= WU_HANDLE_BASE) ||
             (handle < TXN_ID_BASE && handle >= WU_SAM_HANDLE_BASE)))
            continue;
 
        if (is_accel_available  ||
            handle == HANDLE_PROXIMITY ||
            handle == HANDLE_PROXIMITY_NON_WAKE_UP ||
            handle == HANDLE_SPEED_PULSE) {
            addSensor(handle);
        }
    }
 
    err = updateSensorList();
    if (err) {
        HAL_LOG_ERROR("%s: update sensor list failed!", __FUNCTION__);
    }
 
    /* Close the sensor_info_sensor1_cb sensor1 connection and clean the data */
    sensor1_close(sensor_info_sensor1_cb->sensor1_handle);
    pthread_mutex_destroy(&sensor_info_sensor1_cb->cb_mutex);
    pthread_cond_destroy(&sensor_info_sensor1_cb->cb_cond);
    delete sensor_info_sensor1_cb;
 
    /* Enable latency check */
    Latency::latencyCheckMeasure();
}

进入SensorContext构造方法中,先将几个属性设置,
比如当前存活的sensors数量,将加速度,陀螺仪,磁力等支持情况默认设置为false,
后面根据实际的sensor情况在更新这些值。

其主要的工作如下:

  1. 根据系统property属性打开log开关(提示:可以将persist.debug.sensors.hal属性置为1,将会在开机log中抓取到sensor hal层的log)
  2. 调用sensor1_init初始化
  3. 打开SMGR(SensorManager) 连接,传入SMGRSensor_sensor1_cb以及context_sensor1_cb用于接收请求回传的数据
  4. 通过getSensorList获取sensor列表,添加完成通过addSensor去添加已经预定义好的sensor
  5. updateSensorList去更新/填充sensor结构体

接下来我们跟进sensor1_init分析。

二、sensor1 API详解

sensor1_init是qualcomm sensor结构中sensor1的标准接口,其API接口包括如下:
也可参考高通管方文档《80_N1617_2_A_SENSORS_CORE_CLIENT_API_FRAMEWORK.pdf》 Charp3

sensor1_init是qualcomm sensor结构中sensor1的标准接口,其API接口包括如下:

sensor1_error_e sensor1_init( void );

API说明:
初始化sensor framework层,该方法应该再一个线程中处理,且只会调用一次。

sensor1_error_e sensor1_open( sensor1_handle_s **hndl, sensor1_notify_data_cb_t data_cbf, intptr_t cb_data );

API说明:
注册一个外部client端socket到sensor framework,它会返回一个client端的handle句柄,这个句柄在后面会用于与sensor framework通信。
另外,他还注册了一个callback,当有可用的数据达到时,会携带数据并回调该接口。
receive的数据有两种,一种是通过request请求得到的回应reponse,一种是indication,即底层主动上报的数据。

sensor1_error_e sensor1_close( sensor1_handle_s *hndl );

API说明:
注销之前open注册的client,并且释放分配的handle句柄。

sensor1_error_e sensor1_write( sensor1_handle_s     *hndl, sensor1_msg_header_s *msg_hdr, void                 *msg_ptr );

API说明:
向sensor framewok层写入一个request msg,这个消息最终会被QMI IDL封装成C类型的用于传输。
其中的msg_ptr需要使用sensor1_alloc_msg_buf分配内存后方可使用,
如果client端发送成功,随后由sensor framework释放内存,
如果发送失败需要由client主动释放(或者重传)。

sensor1_error_e sensor1_writable( sensor1_handle_s  *hndl,
                  sensor1_write_cb_t cbf,
                  intptr_t           cb_data,
                  uint32_t           service_number );

API说明:
向sensor framework注册一个callback,
当framework中有可用的buffer空间来处理sensor1_write的请求时,callback将会被回调通知lient端。

注意:同时只有一个回调被注册进去,如果重复调用,将会产生覆盖,且一次后失效。
sensor1_error_e sensor1_alloc_msg_buf(sensor1_handle_s *hndl,
                      uint16_t          size,
                      void            **buffer );
 
sensor1_error_e sensor1_free_msg_buf(sensor1_handle_s *hndl,
                     void             *msg_buf );

API说明:
sensor framework层分配/释放一段内存供客户端封装消息使用。

2.1 、SensorsContext() --> sensor1_init() 调用流程

接着看sensor1_init方法,前面说过,该API用于初始化hal层sensor framework,且只会call一次。

sensor1_error_e sensor1_init( void )
{
  LOG_DEBUG("%s", __func__);
  pthread_once( &init_ctl, sensor1_init_once );
  return SENSOR1_SUCCESS;
}

通过线程去调用sensor1_init_once进行sensor framework(后文如无特殊声明,这里的framework指的是hal层)。

void sensor1_init_once( void )
{
  struct timespec     ts;
  int                 seed,
                      error,
                      debug_prop_len,
                      i;
  pthread_mutexattr_t mutex_attr;
  pthread_attr_t      thread_attr;
  char                debug_prop[PROP_VALUE_MAX];
 
  debug_prop_len = __system_property_get( LIBSENSOR1_DEBUG_PROP_NAME, debug_prop );
  if( debug_prop_len == 1 ) {
    switch( debug_prop[0] ) {
      case '0':
        g_log_level = LOG_LEVEL_DISABLED;
        break;
      case '1':
        g_log_level = LOG_LEVEL_ALL;
        break;
      case 'v':
      case 'V':
        g_log_level = LOG_LEVEL_VERBOSE;
        break;
      case 'd':
      case 'D':
        g_log_level = LOG_LEVEL_DEBUG;
        break;
      case 'i':
      case 'I':
        g_log_level = LOG_LEVEL_INFO;
        break;
      case 'w':
      case 'W':
        g_log_level = LOG_LEVEL_WARN;
        break;
      case 'e':
      case 'E':
        g_log_level = LOG_LEVEL_ERROR;
        break;
      default:
        break;
    }
    ALOGI("%s: Setting log level to %d", __FUNCTION__, g_log_level);
  } else if( debug_prop_len > 1 ) {
    LOG_ERROR("%s: invalid value for %s: %s. Enabling all logs", __FUNCTION__,
              LIBSENSOR1_DEBUG_PROP_NAME, debug_prop );
    g_log_level = LOG_LEVEL_ALL;
  }
 
  LOG_DEBUG("%s", __func__);
 
#if defined(SNS_LA_SIM)
  ssc_present = true;
#else
  struct stat         stat_buf;
  // Check device driver for A-family
  ssc_present |= (-1 != stat("/dev/msm_dsps",&stat_buf));
  // Check device driver for B-family
  ssc_present |= (-1 != stat("/dev/sensors",&stat_buf));
#endif
 
  clock_gettime( CLOCK_REALTIME, &ts );
  seed = (int)ts.tv_nsec;
  seed += (int)ts.tv_sec;
  seed += getpid();
  srandom( seed );
 
  if( 0 != sem_init( &open_sem, 0, 0 ) ) {
    LOG_ERROR("%s error initializing semaphore %i", __func__, errno );
  }
 
  memset( libsensor_cli_data,
          0,
          sizeof(libsensor_client_data_s) * MAX_CLIENTS );
 
  error = pthread_mutexattr_init( &mutex_attr );
  error |= pthread_mutexattr_settype( &mutex_attr, PTHREAD_MUTEX_ERRORCHECK );
  if( error != 0 ) {
    LOG_ERROR("%s error initializing mutex attribs %d", __func__, error );
  }
 
  error = pthread_mutex_init( &libsensor_cli_data_mutex, &mutex_attr );
  if( error != 0 ) {
    LOG_ERROR("%s error %d initializing mutex", __func__, error );
  }
 
  pthread_mutexattr_destroy(&mutex_attr);
 
  error = pipe2( wakeup_pipe, O_NONBLOCK );
  if( error != 0 ) {
    LOG_ERROR("%s error %d creating wakeup pipe: %s", __func__, errno, strerror(errno) );
  }
 
  inotify_fd = inotify_init();
  if( inotify_fd == -1 ) {
    LOG_ERROR("%s error %d creating inotify listener: %s", __func__, errno, strerror(errno) );
  }
 
  pthread_mutexattr_init( &mutex_attr );
  pthread_mutexattr_settype( &mutex_attr, PTHREAD_MUTEX_RECURSIVE );
  for( i = 0; i < MAX_CLIENTS; i++ )
  {
    pthread_cond_init( &libsensor_cli_data[i].cb_q_cond, NULL );
    pthread_mutex_init( &libsensor_cli_data[i].data_cbf_mutex, &mutex_attr );
    pthread_mutex_init( &libsensor_cli_data[i].cb_q_mutex, NULL );
 
    libsensor_cli_data[i].is_valid = false;
    libsensor_cli_data[i].ctl_socket = -1;
  }
  pthread_mutexattr_destroy(&mutex_attr);
 
  if( 0 != ( error = pthread_attr_init( &thread_attr ) ) ) {
    LOG_ERROR( "%s pthread_attr_init failure %i", __func__, error );
  } else {
    if( 0 != ( error = pthread_attr_setdetachstate( &thread_attr, PTHREAD_CREATE_DETACHED ) ) ) {
      LOG_ERROR( "%s pthread_attr_setdetachstate failure %i", __func__, error );
    } else {
      error = pthread_create( &listener_thread_id, &thread_attr,
                              libsensor_rx_thread, NULL );
    }
    if( error != 0 ) {
      LOG_ERROR("%s error %d initializing thread", __func__, error );
    }
    pthread_attr_destroy( &thread_attr );
  }
}

首先也是通过property去控制libsensor1的log,最后构建了libsensor_rx_thread用于接收来自底层的数据。

我们追踪下libsensor_rx_thread方法。

static void* libsensor_rx_thread( void *thread_data )
{
  UNREFERENCED_PARAMETER(thread_data);
  uint32_t err;
  struct pollfd pollfd[MAX_ACTIVE_CLIENTS+2];
  int num_fds = 0;
  int i;
 
  num_fds = libsensor_cli_db_to_pollfd( pollfd, MAX_ACTIVE_CLIENTS+2, POLLIN|POLLPRI );
  while( true )
  {
    if( libsensor_cli_db_changed() ) {
      num_fds = libsensor_cli_db_to_pollfd( pollfd, MAX_ACTIVE_CLIENTS+2,POLLIN|POLLPRI );
    }
 
    /* Note that the wakeup FD and the inotify FD are
     * additional FDs at the end of the list after all of the clients */
#ifdef LOG_NDDEBUG
    for( i = 0; i < num_fds; i++ ) {
      LOG_DEBUG("%s: waiting on fd %d", __func__, pollfd[i].fd);
    }
#endif /* LOG_NDDEBUG */
 
    poll( pollfd, num_fds, -1 );
 
#ifdef LOG_NDDEBUG
    if( pollfd[num_fds-2].revents != 0 ) {
      LOG_DEBUG("%s: waking on wakeup pipe %d", __func__, pollfd[num_fds-2].fd);
    }
#endif /* LOG_NDDEBUG */
 
    for( i = 0; i < num_fds-2; i ++ ) {
      if( pollfd[i].revents & (POLLIN|POLLPRI) ) {
        LOG_DEBUG("%s: waking on fd %d", __func__, pollfd[i].fd);
        err = libsensor_read_socket( pollfd[i].fd );
 
        if( SENSOR1_SUCCESS != err && SENSOR1_EBUFFER != err ) {
          libsensor_del_client( pollfd[i].fd );
          i = 0;
        }
 
        pollfd[i].revents &= ~(POLLIN|POLLPRI);
      }
    }
 
    if( pollfd[num_fds-1].revents != 0 ) {
      char buf[500];
      struct inotify_event *evt = (struct inotify_event *)buf;
      read(pollfd[num_fds-1].fd, evt, 500);
      LOG_DEBUG("%s: inotify: wd %d mask 0x%x name %s", __func__,
           evt->wd, evt->mask, (evt->len > 0) ? evt->name:"<empty>");
      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, SENSOR_CTL_FILENAME, evt->len)))) {
        inotify_rm_watch( inotify_fd, evt->wd );
        libsensor_notify_waiting_clients();
      }
    }
  }
 
  LOG_INFO( "%s: thread exiting", __func__ );
  return NULL;
}

这里可以看到,相当于创建了一个读线程,通过poll方法不停的在读消息,读到消息后,会将消息封装,然后唤醒另外一个线程,这个线程是谁我们后面会揭晓答案。

在回过头来看,SensorContext的构造函数。

    /* open the general SMGR sensors sensor1 connection */
    err = sensor1_open(&smgr_sensor1_cb->sensor1_handle, &SMGRSensor_sensor1_cb, (intptr_t)this);
    if(SENSOR1_SUCCESS != err) {
        HAL_LOG_ERROR("sensor1 open failed!");
        return;
    }
    /* open the sensor_info SMGR sensors sensor1 connection */
    err = sensor1_open(&sensor_info_sensor1_cb->sensor1_handle, &context_sensor1_cb, (intptr_t)this);

这几行代码用于向sensor framework层注册client,且获得handle句柄,传入callback方法,用于接口write request msg后得到底层数据的回调。
sensor1_open在调用sensors1_init完成后,接着创建了一个socket:

sensor1_open( sensor1_handle_s **hndl, sensor1_notify_data_cb_t data_cbf, intptr_t cb_data )
{
  int sockfd;
 
  /* Call sensor1_init() here, in case the client failed to do it */
  sensor1_init();
 
  if ( (sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1)
  {
    LOG_ERROR("%s: Error in socket() %s", __func__, strerror(errno));
    return SENSOR1_ENOMEM;
  }
 
  /* connect socket to server */
  if( -1 == connect(sockfd, (struct sockaddr *)&address, len) ) {
    retries = 0;
    eacces_retries = 0;
    while( (errno == ENOENT || errno == ECONNREFUSED || errno == EACCES) &&
           (retries < OPEN_RETRIES && eacces_retries < OPEN_EACCES_RETRIES)    )
    {
      connect(sockfd, (struct sockaddr *)&address, len);
    }
  }
 
  if( -1 ==  bind( sockfd, (struct sockaddr*)&address, sizeof(address) ) ) {
    LOG_ERROR("%s: Error in bind() errno=%d %s",__func__, errno, strerror(errno));
    close( sockfd );
    return SENSOR1_EFAILED;
  }
 
  new_cli.ctl_socket  = sockfd;
 
  if( libsensor_add_client( &new_cli, false ) >= MAX_CLIENTS ) {
    LOG_ERROR( "%s: Unable to add new client (%i)", __func__, new_cli.ctl_socket );
    close( sockfd );
    return SENSOR1_ENOMEM;
  }

前面API说明中也有讲到,Sensor1_open方法会创建一条客户端链接,用于链接至sensor framework(server端的socket)。

上面读线程(libsensor_rx_thread中创建的libsensor_read_socket)读到的消息就是从server端发送过来的。

static int libsensor_add_client( libsensor_client_data_s const *cli_data, bool is_wait_clnt )
{
  int i,
  rv = MAX_CLIENTS,
  error,
  min_idx = is_wait_clnt ? MAX_ACTIVE_CLIENTS : 0,
  max_idx = is_wait_clnt ? MAX_CLIENTS : MAX_ACTIVE_CLIENTS;
  pthread_attr_t thread_attr;
 
  pthread_mutex_lock( &libsensor_cli_data_mutex );
  for( i = min_idx; i < max_idx; i++ ) {
    if( !libsensor_cli_data[i].is_valid && -1 == libsensor_cli_data[i].ctl_socket ) {
      LOG_VERBOSE( "%s Adding client index %i (%i)", __func__, i, cli_data->ctl_socket );
 
      libsensor_cli_data[i].cb_data = cli_data->cb_data;
      libsensor_cli_data[i].data_cbf = cli_data->data_cbf;
      libsensor_cli_data[i].ctl_socket = cli_data->ctl_socket;
      libsensor_cli_data[i].is_valid = true;
      libsensor_cli_data[i].cb_q_head = NULL;
      libsensor_cli_data[i].cb_q_tail = NULL;
 
      // Initialize and start callback thread
      if( 0 != ( error = pthread_attr_init( &thread_attr ) ) ) {
        LOG_ERROR( "%s pthread_attr_init failure %i", __func__, error );
      } else {
        if( 0 != ( error = pthread_attr_setdetachstate( &thread_attr, PTHREAD_CREATE_DETACHED ) ) ) {
          LOG_ERROR( "%s pthread_attr_setdetachstate failure %i", __func__, error );
        } else {
          error = pthread_create( &libsensor_cli_data[i].cb_thread, &thread_attr, libsensor_cb_thread, &libsensor_cli_data[i] );
          if( 0 != error ) {
            LOG_ERROR( "%s error %d initializing thread", __func__, error );
          }
        }
      }
      pthread_attr_destroy( &thread_attr );
 
      rv = i;
      break;
    }
  }
  pthread_mutex_unlock( &libsensor_cli_data_mutex );
  WAKEUP_RX_THREAD();
  return rv;
}

libsensor_add_client方法中又创建了一个callback回调线程,当有消息达到时,该线程唤醒,执行libsensor_cb_thread回调。我们看看这个回调的处理:

static void*
libsensor_cb_thread( void *thread_data )
{
  libsensor_client_data_s *clnt_data = (libsensor_client_data_s*)thread_data;
  sensor1_notify_data_cb_t data_cbf;
  intptr_t cb_data = clnt_data->cb_data;
  int rc = 0;
  libsensor_cb_data_s *data;
 
  pthread_mutex_lock( &clnt_data->cb_q_mutex );
  for( ;; ) {
    if( NULL == clnt_data->cb_q_head && clnt_data->is_valid ) {
      rc = pthread_cond_wait( &clnt_data->cb_q_cond, &clnt_data->cb_q_mutex );
      if( 0 != rc ) {
        LOG_ERROR( "%s: pthread_cond_wait() rc=%d", __func__, rc );
      }
    }
 
    while( NULL != (data = clnt_data->cb_q_head) ) {
      clnt_data->cb_q_head = (struct libsensor_cb_data*)data->next;
 
      // Need to release, otherwise may have deadlock in libsensor_read_socket
      pthread_mutex_unlock( &clnt_data->cb_q_mutex );
 
      // We do not want to continue using the cbf after the client has called
      // sensor1_close, but we also do not want to accidentally use a NULL cbf.
      pthread_mutex_lock( &clnt_data->data_cbf_mutex );
      data_cbf = clnt_data->data_cbf;
      pthread_mutex_unlock( &clnt_data->data_cbf_mutex );
 
      if( data_cbf ) {
        data_cbf( cb_data, &data->msg_hdr, data->msg_type, data->msg );
      }
 
      free( data );
      pthread_mutex_lock( &clnt_data->cb_q_mutex );
 
      if( !data_cbf ) {
        clnt_data->is_valid = false;
        break;
      }
    }
 
    if( !clnt_data->is_valid )
      break;
  }
  LOG_DEBUG( "%s: Exiting processing thread for socket %i", __func__, clnt_data->ctl_socket );
  libsensor_del_client_data( clnt_data->cb_q_head );
  clnt_data->cb_q_head = NULL;
  clnt_data->cb_q_tail = NULL;
  pthread_mutex_unlock( &clnt_data->cb_q_mutex );
 
  pthread_mutex_lock( &libsensor_cli_data_mutex );
  close( clnt_data->ctl_socket );
  clnt_data->ctl_socket = -1;
  pthread_mutex_unlock( &libsensor_cli_data_mutex );
 
  return NULL;
}

那么这个线程是怎样被唤醒的,当然是sensor1_init在init_once中的那个读线程(libsensor_rx_thread)嘛,
没错,就是那个线程。。。这里主要注意下面这段:

if( data_cbf ) {
        data_cbf( cb_data, &data->msg_hdr, data->msg_type, data->msg );
      }

这个方法就是call我们sensor1_open中传入的参数注册的那个回调了,即context_sensor1_cb或者SMGRSensor_sensor1_cb,
对于具体的sensor数据,当然会回调open过程注册的cb了。

总结sensor1_open就是创建一个读线程从socket服务端中读数据,读到数据后,
就回调sensor.platform.so库中的注册的cb,进而上报数据做进一步回调。

那问题来了,那个socket服务端又是怎么回事呢。。。慢慢接近真相了。。。。
这里先告诉大家,服务端就是我们的SensorDaemon守护进程了,这里暂时不做分析,请关注后续文章。

我们继续往下分析,sensor1_open完成后向sensor framework发送了第一个请求:

err = sendSMGRVersionReq();
int SensorsContext::sendSMGRVersionReq()
{
    sensor1_error_e       error;
    sensor1_msg_header_s  msg_hdr;
    sns_common_version_req_msg_v01 *smgr_version_req;
 
    HAL_LOG_INFO("%s", __FUNCTION__);
    pthread_mutex_lock(&sensor_info_sensor1_cb->cb_mutex);
    /* Send SMGR version req */
    msg_hdr.service_number = SNS_SMGR_SVC_ID_V01;
    msg_hdr.msg_id = SNS_SMGR_VERSION_REQ_V01;
    msg_hdr.msg_size = sizeof(sns_common_version_req_msg_v01);
    msg_hdr.txn_id = 0;
    error = sensor1_alloc_msg_buf(sensor_info_sensor1_cb->sensor1_handle,
                    sizeof(sns_common_version_req_msg_v01),  (void**)&smgr_version_req);
    if (SENSOR1_SUCCESS != error) {
        HAL_LOG_ERROR("%s: msg alloc failed: %d", __FUNCTION__, error );
        pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
        return -1;
    }
 
    sensor_info_sensor1_cb->error = false;
    if ((error = sensor1_write(sensor_info_sensor1_cb->sensor1_handle,
                &msg_hdr, smgr_version_req)) != SENSOR1_SUCCESS) {
        /* free the message buffer */
        sensor1_free_msg_buf(sensor_info_sensor1_cb->sensor1_handle, smgr_version_req );
        HAL_LOG_ERROR("%s: Error in sensor1_write() %s", __FUNCTION__, strerror(errno));
        sensor_info_sensor1_cb->error = true;
        pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
        return -1;
    }
 
    /* waiting for response */
    if (Utility::waitForResponse(TIME_OUT_MS,
                &sensor_info_sensor1_cb->cb_mutex,
                &sensor_info_sensor1_cb->cb_cond,
                &sensor_info_sensor1_cb->is_resp_arrived) == false) {
        HAL_LOG_ERROR("%s: SMGR version request timed out", __FUNCTION__);
        sensor_info_sensor1_cb->error = true;
        pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
        return -1;
    } else {
        HAL_LOG_VERBOSE("%s: Received SMGR version response", __FUNCTION__);
    }
    pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
    return 0;
}

通过这个方法,我们可以窥探到client端向sensor framework层发送请求时的消息封装流程了。

先填充msg_hdr,包括service number,msg_id(SNS_SMGR_VERSION_REQ_V01),txn_id等,
再通过sensor1_alloc_msg_buf向Sensor framework层分配smgr_version_req的请求buffer,
最后通过sensor1_write方法将请求的消息发送到sensor framework,
这条消息最终会通过高通独有的QMI的机制,将消息从AP测发送到modem端处理,
modem端处理完毕后会回传请求的数据在通过注册的回调来接收所请求的数据。

这里的SMGR version请求的最后,通过工具类Utility的方法waitForResponse来等待消息返回,确认消息发送情况。

由于这里调用sensor1_write时我们传入的handle为sensor_info_sensor1_cb,看到前面open过程中注册的callback了吗?
所以这里名为context_sensor1_cb的回调将会被调用。

err = sensor1_open(&sensor_info_sensor1_cb->sensor1_handle, &context_sensor1_cb, (intptr_t)this);
 
error = sensor1_write(sensor_info_sensor1_cb->sensor1_handle,&msg_hdr, smgr_version_req))

打开log开关,我们可以看到具体的消息发送流程:

06-04 19:48:04.401 I/qti_sensors_hal: sendSMGRVersionReq
06-04 19:48:04.401 I/libsensor1: libsensor_log_ctl_write_pkt: fd 55; svc 0; msg 1; txn 0; cmd WRITE_QMI
06-04 19:48:04.401 D/qti_sensors_hal: waitForResponse: timeout=1000=
……………………………………省略无关信息
06-04 19:48:04.404 D/libsensor1: libsensor_rx_thread: waking on fd 55
06-04 19:48:04.404 I/libsensor1: libsensor_log_read_pkt: fd 55; svc 0; msg 1; txn 0; type RESP; cmd WRITE_QMI
06-04 19:48:04.404 V/qti_sensors_hal: context_sensor1_cb: msg_type 1, Sn 0, msg Id 1, txn Id 0
06-04 19:48:04.405 D/qti_sensors_hal: processResp: 1
06-04 19:48:04.405 D/qti_sensors_hal: processResp: SMGR version=23
06-04 19:48:04.405 V/qti_sensors_hal: sendSMGRVersionReq: Received SMGR version response

如上log可知,SMGR的版本为23。这里读者大可不必太关注QMI消息发送流程,这个流程相当复杂,我后面会单独讲解QMI消息怎么封装,并且通过QMUX客户端和服务端消息收发,再到modem的详细流程,欢迎关注。

三、获取sensor列表getSensorList

我们接着往后走便开始获取sensor的列表了。

int SensorsContext::getSensorList()
{
    sensor1_error_e       error;
    sensor1_msg_header_s  msg_hdr;
    sns_smgr_all_sensor_info_req_msg_v01 *smgr_req;
    sns_smgr_sensor_datatype_info_s_v01* sensor_datatype = NULL;
 
    HAL_LOG_INFO("%s", __FUNCTION__);
    pthread_mutex_lock(&sensor_info_sensor1_cb->cb_mutex);
    msg_hdr.service_number = SNS_SMGR_SVC_ID_V01;
    msg_hdr.msg_id = SNS_SMGR_ALL_SENSOR_INFO_REQ_V01;
    msg_hdr.msg_size = sizeof( sns_smgr_all_sensor_info_req_msg_v01 );
    msg_hdr.txn_id = 0;
    error = sensor1_alloc_msg_buf(sensor_info_sensor1_cb->sensor1_handle,
                    sizeof(sns_smgr_all_sensor_info_req_msg_v01),
                    (void**)&smgr_req);
    if (SENSOR1_SUCCESS != error) {
        HAL_LOG_ERROR("%s: msg alloc failed: %d", __FUNCTION__, error );
        pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
        return -1;
    }
 
    sensor_info_sensor1_cb->error = false;
    if ((error = sensor1_write(sensor_info_sensor1_cb->sensor1_handle,
                &msg_hdr, smgr_req)) != SENSOR1_SUCCESS) {
        sensor1_free_msg_buf(sensor_info_sensor1_cb->sensor1_handle, smgr_req );
        HAL_LOG_ERROR("%s: Error in sensor1_write() %s", __FUNCTION__, strerror(errno));
        sensor_info_sensor1_cb->error = true;
        pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
        return -1;
    }
 
    /* waiting for response */
    if (Utility::waitForResponse(TIME_OUT_MS,
                &sensor_info_sensor1_cb->cb_mutex,
                &sensor_info_sensor1_cb->cb_cond,
                &sensor_info_sensor1_cb->is_resp_arrived) == false) {
        HAL_LOG_ERROR("%s: Request timed out", __FUNCTION__);
        sensor_info_sensor1_cb->error = true;
        pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
        return -1;
    } else {
        HAL_LOG_VERBOSE("%s: Received Response", __FUNCTION__);
    }
    pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
    return 0;
}

原理同上面的SMGR version请求,封装好消息头部,msg id为SNS_SMGR_ALL_SENSOR_INFO_REQ_V01,All sensor info, _,
在通过sensor1_write接口将消息发送到驱动层处理,最后由驱动层返回sensor info数据。

我们看这个过程的log:

06-04 19:48:04.405 I/qti_sensors_hal: getSensorList
06-04 19:48:04.405 I/libsensor1: libsensor_log_ctl_write_pkt: fd 55; svc 0; msg 5; txn 0; cmd WRITE_QMI
06-04 19:48:04.405 D/qti_sensors_hal: waitForResponse: timeout=1000
 
06-04 19:48:04.407 D/libsensor1: libsensor_rx_thread: waking on fd 55
06-04 19:48:04.407 I/libsensor1: libsensor_log_read_pkt: fd 55; svc 0; msg 5; txn 0; type RESP; cmd WRITE_QMI
06-04 19:48:04.407 D/libsensor1: libsensor_rx_thread: waiting on fd 54
06-04 19:48:04.407 D/libsensor1: libsensor_rx_thread: waiting on fd 55
06-04 19:48:04.407 D/libsensor1: libsensor_rx_thread: waiting on fd 56
06-04 19:48:04.407 V/qti_sensors_hal: context_sensor1_cb: msg_type 1, Sn 0, msg Id 5, txn Id 0
06-04 19:48:04.407 D/libsensor1: libsensor_rx_thread: waiting on fd 57
06-04 19:48:04.407 D/libsensor1: libsensor_rx_thread: waiting on fd 51
06-04 19:48:04.407 D/qti_sensors_hal: processResp: 5
06-04 19:48:04.407 D/libsensor1: libsensor_rx_thread: waiting on fd 53
06-04 19:48:04.407 D/qti_sensors_hal: processAllSensorInfoResp: SensorInfo_len: 2

可知底层返回的sensor个数为2,即两个sensor(很奇怪,这里的数据为2, 根据传感器个数打印,不可能才两个…)。

在context_sensor1_cb函数中,由于我们的msg_type为SENSOR1_MSG_TYPE_RESP,如log所示,接着会调用processResp处理。

void SensorsContext::processResp(Sensor** mSensors, sensor1_msg_header_s *msg_hdr, void *msg_ptr)
{
    HAL_LOG_DEBUG("%s: %d", __FUNCTION__,  msg_hdr->msg_id);
    switch(msg_hdr->msg_id) {
    case SNS_SMGR_VERSION_RESP_V01: {
        pthread_mutex_lock(&sensor_info_sensor1_cb->cb_mutex);
        sns_common_version_resp_msg_v01* respMsgPtr = (sns_common_version_resp_msg_v01 *)msg_ptr;
        if (respMsgPtr->resp.sns_result_t == 0) {
            smgr_version = respMsgPtr->interface_version_number;
            HAL_LOG_DEBUG("%s: SMGR version=%d", __FUNCTION__, smgr_version);
            Utility::signalResponse(false, sensor_info_sensor1_cb);
        }
        else {
            HAL_LOG_ERROR("%s: Error in getting SMGR version!", __FUNCTION__);
            Utility::signalResponse(true, sensor_info_sensor1_cb);
        }
        pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
        } break;
    case SNS_SMGR_ALL_SENSOR_INFO_RESP_V01: {
        pthread_mutex_lock(&sensor_info_sensor1_cb->cb_mutex);
        processAllSensorInfoResp(
                    (sns_smgr_all_sensor_info_resp_msg_v01*)msg_ptr);
        pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
        } break;
    case SNS_SMGR_SINGLE_SENSOR_INFO_RESP_V01: {
        pthread_mutex_lock(&sensor_info_sensor1_cb->cb_mutex);
        processSingleSensorInfoResp(mSensors, msg_hdr->txn_id,
                    (sns_smgr_single_sensor_info_resp_msg_v01*)msg_ptr);
        pthread_mutex_unlock(&sensor_info_sensor1_cb->cb_mutex);
        } break;
    }
    return;
}

msg id为SNS_SMGR_ALL_SENSOR_INFO_RESP_V01则会进入processAllSensorInfoResp分支。

void SensorsContext::processAllSensorInfoResp(sns_smgr_all_sensor_info_resp_msg_v01
                                                                *smgr_info_resp)
{
    uint32_t i;
    HAL_LOG_DEBUG("%s: SensorInfo_len: %d", __FUNCTION__,smgr_info_resp->SensorInfo_len);
 
    if (smgr_info_resp->Resp.sns_result_t != 0) {
        HAL_LOG_ERROR("%s: R: %u, E: %u", __FUNCTION__, smgr_info_resp->Resp.sns_result_t, smgr_info_resp->Resp.sns_err_t );
        Utility::signalResponse(true, sensor_info_sensor1_cb);
        return;
    }
 
    if (smgr_info_resp->SensorInfo_len > 0) {
        num_smgr_sensors = smgr_info_resp->SensorInfo_len;
        for (i = 0; i < num_smgr_sensors; i++) {
            singleSensorInfoRequest(i, smgr_info_resp->SensorInfo[i].SensorID);
        }
    } else {
        Utility::signalResponse(false, sensor_info_sensor1_cb);
    }
    return;
}

接着会根据info length(2),开始调用singleSensorInfoRequest单独对每个sensor info进行单独请求,log如下:

06-04 19:48:04.407 D/qti_sensors_hal: processAllSensorInfoResp: SensorInfo_len: 2
06-04 19:48:04.407 D/qti_sensors_hal: singleSensorInfoRequest: 0
06-04 19:48:04.407 D/qti_sensors_hal: singleSensorInfoRequest: txn_id: 0 sensor_id: 0
06-04 19:48:04.407 I/libsensor1: libsensor_log_ctl_write_pkt: fd 55; svc 0; msg 6; txn 0; cmd WRITE_QMI
06-04 19:48:04.407 D/qti_sensors_hal: singleSensorInfoRequest: 10
06-04 19:48:04.407 D/qti_sensors_hal: singleSensorInfoRequest: txn_id: 1 sensor_id: 10
06-04 19:48:04.407 I/libsensor1: libsensor_log_ctl_write_pkt: fd 55; svc 0; msg 6; txn 1; cmd WRITE_QMI

从上面的log可以看到,我们的这两个sensor handle id为0和10,查找对应的sensor handle句柄定义,我们发现这两个sensor是加速度传感器和磁力传感器:

// vendor/qcom/proprietary/sensors/dsps/libhalsensors/src/sensors_hal.h
/* sensor handle */
#define SENSORS_HANDLE_BASE             0
#define HANDLE_ACCELERATION           (SENSORS_HANDLE_BASE+0)
#define HANDLE_MAGNETIC_FIELD         (SENSORS_HANDLE_BASE+10) 

06-04 19:48:04.409 V/qti_sensors_hal: context_sensor1_cb: msg_type 1, Sn 0, msg Id 6, txn Id 0
06-04 19:48:04.409 D/qti_sensors_hal: processResp: 6
06-04 19:48:04.409 D/qti_sensors_hal: processSingleSensorInfoResp: data_type_info_len: 2
06-04 19:48:04.409 D/qti_sensors_hal: processSingleSensorInfoResp: txn: 0, ns: 2
06-04 19:48:04.409 I/qti_sensors_hal: addSensor: handle:0
06-04 19:48:04.409 I/qti_sensors_hal: SMGRSensor: Sensor()
06-04 19:48:04.410 D/qti_sensors_hal: setSensorInfo: Accel, DTy: 0
06-04 19:48:04.410 I/qti_sensors_hal: processSingleSensorInfoResp: sensor1: name: BMI160 Accelerometer, vendor: BOSCH, maxRange: 10283018, res: 78,
                     power: 180, max_freq: 200 max_buffered_samples: 10000

接着每个具体的sensor info返回时,都会调用processSingleSensorInfoResp进一步处理,这个方法很长:

void SensorsContext::processSingleSensorInfoResp(Sensor** mSensors, uint8_t txn_id,
            sns_smgr_single_sensor_info_resp_msg_v01* smgr_resp)
{
    int i;
    int handle = -1, handle_wakeup = -1;
    for (i = 0; i < (int)smgr_resp->SensorInfo.data_type_info_len; i++) {
        handle = -1, handle_wakeup = -1, error = false;
        sensor_datatype = &smgr_resp->SensorInfo.data_type_info[i];
 
        HAL_LOG_DEBUG("%s: txn: %u, ns: %u", __FUNCTION__, txn_id,
            (unsigned int)num_smgr_sensors);
 
        switch (sensor_datatype->SensorID) {
        case SNS_SMGR_ID_ACCEL_V01:
            if(SNS_SMGR_DATA_TYPE_PRIMARY_V01 == sensor_datatype->DataType) {
                handle = HANDLE_ACCELERATION;
                handle_wakeup = HANDLE_ACCELERATION_WAKE_UP;
                is_accel_available = true;
            }
            else if (SNS_SMGR_DATA_TYPE_SECONDARY_V01 == sensor_datatype->DataType) {
                /* Skip secondary data and replace with proper handle if needed */
                error = true;
            }
            break;
        case SNS_SMGR_ID_MAG_V01:
            if (SNS_SMGR_DATA_TYPE_PRIMARY_V01 == sensor_datatype->DataType) {
                handle = HANDLE_MAGNETIC_FIELD;
                handle_wakeup = HANDLE_MAGNETIC_FIELD_WAKE_UP;
                if (is_accel_available) {
                    is_mag_available = true;
                }
            }
            else if (SNS_SMGR_DATA_TYPE_SECONDARY_V01 == sensor_datatype->DataType) {
                /* Skip secondary data and replace with proper handle if needed */
                error = true;
            }
            break;
        case SNS_SMGR_ID_PROX_LIGHT_V01:
            if (SNS_SMGR_DATA_TYPE_PRIMARY_V01 == sensor_datatype->DataType) {
                handle = HANDLE_PROXIMITY;
                handle_wakeup = HANDLE_PROXIMITY_NON_WAKE_UP;
                is_prox_available = true;
            }
            else if (SNS_SMGR_DATA_TYPE_SECONDARY_V01 == sensor_datatype->DataType) {
                handle = HANDLE_LIGHT;
                handle_wakeup = HANDLE_LIGHT_WAKE_UP;
            }
            break;
        
        default:
            HAL_LOG_ERROR(" %s Unknown sensor type: %d", __FUNCTION__,
                                                    sensor_datatype->DataType);
            error = true;
            break;
        }
 
        if (handle != -1 && error == false) {
            addSensor(handle);
 
            if (mSensors[handle] != NULL) {
                /* Fill each sensor info in sub sensor classes */
                strlcpy(mSensors[handle]->getName(), sensor_datatype->SensorName,
                    SNS_MAX_SENSOR_NAME_SIZE);
                strlcpy(mSensors[handle]->getVendor(), sensor_datatype->VendorName,
                    SNS_MAX_VENDOR_NAME_SIZE);
                mSensors[handle]->setVersion(sensor_datatype->Version);
                if (sensor_datatype->MaxSampleRate <= 500 ) {
                    mSensors[handle]->setMaxFreq(sensor_datatype->MaxSampleRate);
                } else if (sensor_datatype->MaxSampleRate >= 2000) {
                    mSensors[handle]->setMaxFreq(1000.0 / sensor_datatype->MaxSampleRate);
                } else {
                    mSensors[handle]->setMaxFreq(1);
                    HAL_LOG_ERROR(" %s Invalid sample rate: %u", __FUNCTION__,
                                                sensor_datatype->MaxSampleRate);
                }
 
                /* Lower max rate if property overrides value returned from sensor */
                switch (mSensors[handle]->getType()) {
                    case SENSOR_TYPE_ACCELEROMETER:
                        property_get(HAL_PROP_MAX_ACCEL, max_rate_prop_value,
                            FREQ_ACCEL_DEF_HZ_STR);
                        break;
                    case SENSOR_TYPE_MAGNETIC_FIELD:
                    case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
                        property_get(HAL_PROP_MAX_MAG, max_rate_prop_value,
                            FREQ_MAG_DEF_HZ_STR);
                        break;
                    case SENSOR_TYPE_GYROSCOPE:
                        property_get(HAL_PROP_MAX_GYRO, max_rate_prop_value,
                            FREQ_GYRO_DEF_HZ_STR);
                        break;
                    default:
                        max_rate_prop_value[0] = 0;
                        break;
                }
                errno = 0;
                tmp_max_rate = strtol(max_rate_prop_value, &strtol_endptr, 0);
                if (0 == errno && strtol_endptr != max_rate_prop_value) {
                    mSensors[handle]->setMaxFreq(MIN(mSensors[handle]->getMaxFreq(), tmp_max_rate));
                }
                if (mSensors[handle]->getMaxFreq() >= FREQ_FASTEST_HZ) {
                    mSensors[handle]->setMaxFreq(FREQ_FASTEST_HZ);
                }
                /* check SMGR version and set min freq accordingly to support subHz */
                if (smgr_version >= SMGR_SUB_HZ_VERSION) {
                    mSensors[handle]->setMinFreq(SMGR_SUB_HZ_REPORT_RATE_MIN_HZ);
                }
                else {
                    mSensors[handle]->setMinFreq(SNS_SMGR_REPORT_RATE_MIN_HZ_V01);
                }
                mSensors[handle]->setPower((float)((float)sensor_datatype->MaxPower * UNIT_CONVERT_POWER));
                mSensors[handle]->setAttribOK(true);
 
                if (!smgr_resp->num_buffered_reports_valid ||
                    HANDLE_PROXIMITY == mSensors[handle]->getHandle()) {
                    mSensors[handle]->setMaxBufferedSamples(0);
                }
                else {
                    mSensors[handle]->setMaxBufferedSamples(smgr_resp->num_buffered_reports[i]);
                }
 
                /* check SMGR version and set Reserved FIFO accordingly */
                if (smgr_version >= SMGR_RES_FIFO_VERSION &&
                    smgr_resp->num_reserved_buffered_reports_valid) {
                    mSensors[handle]->setResBufferedSamples(smgr_resp->num_reserved_buffered_reports[i]);
                }
                else {
                    mSensors[handle]->setResBufferedSamples(0);
                }
 
                (static_cast<SMGRSensor*>(mSensors[handle]))->setSensorInfo(sensor_datatype);
 
                HAL_LOG_INFO("%s: sensor1: name: %s, vendor: %s, maxRange: %u, res: %u, 
                    power: %u, max_freq: %u max_buffered_samples: %u", __FUNCTION__,
                    sensor_datatype->SensorName, sensor_datatype->VendorName,
                    sensor_datatype->MaxRange, sensor_datatype->Resolution,
                    sensor_datatype->MaxPower, sensor_datatype->MaxSampleRate,
                    mSensors[handle]->getMaxBufferedSamples());
                HAL_LOG_DEBUG("%s: HAL: name: %s, vendor: %s, maxRange: %f, res: %f, 
                    power: %f, max_freq: %f min_freq: %f", __FUNCTION__,
                    mSensors[handle]->getName(), mSensors[handle]->getVendor(), mSensors[handle]->getMaxRange(),
                    mSensors[handle]->getResolution(), mSensors[handle]->getPower(), mSensors[handle]->getMaxFreq(),
                    mSensors[handle]->getMinFreq());
            }
        }
        else {
            HAL_LOG_ERROR("%s: either handle is -1 or error is true or mSensors[handle] is NULL!", __FUNCTION__);
        }
 
        if (handle_wakeup != -1 && error == false && !strncmp("true", wu_sensor, 4))
        {
            addSensor(handle_wakeup);
 
            if (mSensors[handle_wakeup] != NULL) {
                /* Fill each sensor info in sub sensor classes */
                strlcpy(mSensors[handle_wakeup]->getName(), sensor_datatype->SensorName,
                    SNS_MAX_SENSOR_NAME_SIZE);
                strlcpy(mSensors[handle_wakeup]->getVendor(), sensor_datatype->VendorName,
                    SNS_MAX_VENDOR_NAME_SIZE);
                mSensors[handle_wakeup]->setVersion(sensor_datatype->Version);
                if (sensor_datatype->MaxSampleRate <= 500 ) {
                    mSensors[handle_wakeup]->setMaxFreq(sensor_datatype->MaxSampleRate);
                } else if (sensor_datatype->MaxSampleRate >= 2000) {
                    mSensors[handle_wakeup]->setMaxFreq(1000.0 / sensor_datatype->MaxSampleRate);
                } else {
                    mSensors[handle_wakeup]->setMaxFreq(1);
                    HAL_LOG_ERROR(" %s Invalid sample rate: %u", __FUNCTION__,
                                                sensor_datatype->MaxSampleRate);
                }
 
                /* Lower max rate if property overrides value returned from sensor */
                switch (mSensors[handle_wakeup]->getType()) {
                    case SENSOR_TYPE_ACCELEROMETER:
                        property_get(HAL_PROP_MAX_ACCEL, max_rate_prop_value,
                            FREQ_ACCEL_DEF_HZ_STR);
                        break;
                    case SENSOR_TYPE_MAGNETIC_FIELD:
                    case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
                        property_get(HAL_PROP_MAX_MAG, max_rate_prop_value,
                            FREQ_MAG_DEF_HZ_STR);
                        break;
                    case SENSOR_TYPE_GYROSCOPE:
                        property_get(HAL_PROP_MAX_GYRO, max_rate_prop_value,
                            FREQ_GYRO_DEF_HZ_STR);
                        break;
                    default:
                        max_rate_prop_value[0] = 0;
                        break;
                }
                errno = 0;
                tmp_max_rate = strtol(max_rate_prop_value, &strtol_endptr, 0);
                if (0 == errno && strtol_endptr != max_rate_prop_value) {
                    mSensors[handle_wakeup]->setMaxFreq(MIN(mSensors[handle_wakeup]->getMaxFreq(), tmp_max_rate));
                }
                if (mSensors[handle_wakeup]->getMaxFreq() >= FREQ_FASTEST_HZ) {
                    mSensors[handle_wakeup]->setMaxFreq(FREQ_FASTEST_HZ);
                }
                /* check SMGR version and set min freq accordingly to support subHz */
                if (smgr_version >= SMGR_SUB_HZ_VERSION) {
                    mSensors[handle_wakeup]->setMinFreq(SMGR_SUB_HZ_REPORT_RATE_MIN_HZ);
                }
                else {
                    mSensors[handle_wakeup]->setMinFreq(SNS_SMGR_REPORT_RATE_MIN_HZ_V01);
                }
                mSensors[handle_wakeup]->setPower((float)((float)sensor_datatype->MaxPower * UNIT_CONVERT_POWER));
                mSensors[handle_wakeup]->setAttribOK(true);
 
                if (!smgr_resp->num_buffered_reports_valid ||
                    HANDLE_PROXIMITY_NON_WAKE_UP == mSensors[handle_wakeup]->getHandle()) {
                    mSensors[handle_wakeup]->setMaxBufferedSamples(0);
                }
                else {
                    mSensors[handle_wakeup]->setMaxBufferedSamples(smgr_resp->num_buffered_reports[i]);
                }
 
                (static_cast<SMGRSensor*>(mSensors[handle_wakeup]))->setSensorInfo(sensor_datatype);
 
                HAL_LOG_INFO("%s: sensor1: name: %s, vendor: %s, maxRange: %u, res: %u, 
                    power: %u, max_freq: %u max_buffered_samples: %u", __FUNCTION__,
                    sensor_datatype->SensorName, sensor_datatype->VendorName,
                    sensor_datatype->MaxRange, sensor_datatype->Resolution,
                    sensor_datatype->MaxPower, sensor_datatype->MaxSampleRate,
                    mSensors[handle_wakeup]->getMaxBufferedSamples());
                HAL_LOG_DEBUG("%s: HAL: name: %s, vendor: %s, maxRange: %f, res: %f, 
                    power: %f, max_freq: %f", __FUNCTION__,
                    mSensors[handle_wakeup]->getName(), mSensors[handle_wakeup]->getVendor(), mSensors[handle_wakeup]->getMaxRange(),
                    mSensors[handle_wakeup]->getResolution(), mSensors[handle_wakeup]->getPower(), mSensors[handle_wakeup]->getMaxFreq());
            }
        }
        else {
            HAL_LOG_ERROR("%s: either handle_wakeup is -1 or error is true or mSensors[handle_wakeup] is NULL!", __FUNCTION__);
        }
    }
 
    HAL_LOG_DEBUG("%s: txn: %u, ns: %u, ss_resp: %u", __FUNCTION__, txn_id,
                            (unsigned int)num_smgr_sensors, sensor_responses);
 
    if (sensor_responses == num_smgr_sensors) {
        /* All responses received */
        Utility::signalResponse(false, sensor_info_sensor1_cb);
    }
    return;
}

我们分析下主要工作:

  1. 根据传入的sensor ID来匹配对应的sensor,并设置响应的属性。
  2. 如果sensor handle句柄合法,调用addSensor构建hal层sensor 结构体。
  3. 从回调数据中获取sensor的name,vendor,version,max freq,type以及其他attribute等等,在调用setSensorInfo设置对应的attri设置sensor info。

我们下面主要查看addSensor过程。

四、addSensor具体过程

我们看看其方法体,逻辑很简单,就是根据handle,创建对应的sensor实例,在将其放到对应的mSensors数据结构中,mSensors保存着所有支持的sensor列表。通过传入handle,可以查看是否支持相应的sensor。

void SensorsContext::addSensor(int handle)
{
    char add_sensor[PROPERTY_VALUE_MAX] = "false";
 
    HAL_LOG_INFO("%s: handle:%d", __FUNCTION__, handle);
    switch(handle){
        /* SMGR sensors */
        case HANDLE_ACCELERATION:
        case HANDLE_ACCELERATION_WAKE_UP:
            mSensors[handle] = new Accelerometer(handle);
            break;
        case HANDLE_GYRO:
        case HANDLE_GYRO_WAKE_UP:
            if (is_gyro_available) {
                HAL_LOG_DEBUG("%s: GYRO enabled handle:%d",
                               __FUNCTION__, handle);
                mSensors[handle] = new Gyroscope(handle);
            } else {
                HAL_LOG_DEBUG("%s: GYRO disabled!", __FUNCTION__);
            }
            break;
         
        default:
            HAL_LOG_WARN("%s : Not supported sensor with handle %d!", __FUNCTION__, handle);
            break;
    }
}

前面提到开始获得的sensor为加速度传感器Accelerometer,我们往后跟一下。

mSensors[handle] = new Accelerometer(handle);
Accelerometer::Accelerometer(int handle):SMGRSensor(handle)
{
    trigger_mode = SENSOR_MODE_CONT;
    (handle == HANDLE_ACCELERATION_WAKE_UP)?(bWakeUp = true):(bWakeUp = false);
}
SMGRSensor::SMGRSensor(int handle):Sensor(handle), last_event()
{
    HAL_LOG_INFO("%s: Sensor(%s)", __FUNCTION__,Utility::SensorTypeToSensorString(getType()));
    time_service = TimeSyncService::getTimeSyncService();
    data_cb = Utility::getDataCb();
    memset(reg_value, 0, sizeof(reg_value));
}

从前面的log我们也可知,这个加速度sensor及其厂商之前的信息:

sensor1: name: BMI160 Accelerometer, vendor: BOSCH, maxRange: 10283018, res: 78, 
power: 180, max_freq: 200 max_buffered_samples: 10000

addSensor完成后,通过获取sensor的name,vendor,version,max freq,type以及其他attribute等等,
在调用setSensorInfo设置对应的attri设置sensor info,
基本上这个sensor的hal信息基本上就算配置完成了。

void Accelerometer::setSensorInfo(sns_smgr_sensor_datatype_info_s_v01* datatype)
{
    HAL_LOG_DEBUG("%s: Accel, DTy: %d", __FUNCTION__, datatype->DataType);
 
    setType(SENSOR_TYPE_ACCELEROMETER);
 
    if(bWakeUp == false) {
        setFlags(SENSOR_FLAG_CONTINUOUS_MODE);
    } else {
        setFlags(SENSOR_FLAG_CONTINUOUS_MODE|SENSOR_FLAG_WAKE_UP);
        strlcat(name, " -Wakeup", sizeof(name));
    }
 
    setResolution((float)((float)datatype->Resolution * UNIT_CONVERT_ACCELERATION));
    setMaxRange((float)((float)datatype->MaxRange * UNIT_CONVERT_ACCELERATION));
    setMinFreq(SNS_SMGR_REPORT_RATE_MIN_HZ_V01);
    return;
}

随后也会处理我们handle为10的磁力传感器,此时,getSensorList完毕。

五、添加其他的sensor

上面的getSensorList过程我们只得到了两个sensor,然而系统中还有多的sensor没有配置,那么是在哪里配置的呢?
跟进代码我们发现,在getSensorList完成后,有一个for循环如下:

for (i=0; i < ARRAY_SIZE(g_sensor_list_order); i++) {
        int handle = g_sensor_list_order[i];
        /* Skip SMGR sensors as they are added above - in getSensorList */
        if (handle < SAM_HANDLE_BASE)
            continue;
        /* Skip wake up sensors if they aren't enabled */
        if (!strncmp("false", wu_sensor, 5) &&
            ((handle < SAM_HANDLE_BASE && handle >= WU_HANDLE_BASE) ||
             (handle < TXN_ID_BASE && handle >= WU_SAM_HANDLE_BASE)))
            continue;
 
        if (is_accel_available  ||
            handle == HANDLE_PROXIMITY ||
            handle == HANDLE_PROXIMITY_NON_WAKE_UP ||
            handle == HANDLE_SPEED_PULSE) {
            addSensor(handle);
        }
    }

g_sensor_list_order是个什么东东?
它是定义的sensors_hal.h中全局变量,里面配置了所有当前系统可能支持的sensor列表:

const int g_sensor_list_order[] = {
    /* Physical sensors */
    HANDLE_ACCELERATION,
    HANDLE_MAGNETIC_FIELD,
    HANDLE_MAGNETIC_FIELD_UNCALIBRATED,
    HANDLE_MAGNETIC_FIELD_SAM,
    HANDLE_MAGNETIC_FIELD_UNCALIBRATED_SAM,
    HANDLE_GYRO,
    HANDLE_GYRO_UNCALIBRATED,
    HANDLE_PROXIMITY,
    HANDLE_THRESH,
    HANDLE_LIGHT,
    HANDLE_PRESSURE,
    HANDLE_RELATIVE_HUMIDITY,
    HANDLE_AMBIENT_TEMPERATURE,
    /* SMGR wake up sensors */
    HANDLE_ACCELERATION_WAKE_UP,
    HANDLE_MAGNETIC_FIELD_WAKE_UP,
    HANDLE_MAGNETIC_FIELD_UNCALIBRATED_WAKE_UP,
    HANDLE_MAGNETIC_FIELD_SAM_WAKE_UP,
    HANDLE_MAGNETIC_FIELD_UNCALIBRATED_SAM_WAKE_UP,
    HANDLE_GYRO_WAKE_UP,
    HANDLE_GYRO_UNCALIBRATED_WAKE_UP,
    HANDLE_PROXIMITY_NON_WAKE_UP,
    HANDLE_THRESH_NON_WAKE_UP,
    HANDLE_LIGHT_WAKE_UP,
    HANDLE_PRESSURE_WAKE_UP,
    HANDLE_RELATIVE_HUMIDITY_WAKE_UP,
    HANDLE_AMBIENT_TEMPERATURE_WAKE_UP,
 
    /* Android virtual sensors via SAM: */
    HANDLE_GRAVITY,
    HANDLE_LINEAR_ACCEL,
    HANDLE_ROTATION_VECTOR,
    HANDLE_SAM_STEP_DETECTOR,
    HANDLE_SAM_STEP_COUNTER,
    HANDLE_SIGNIFICANT_MOTION,
    HANDLE_GAME_ROTATION_VECTOR,
    HANDLE_GEOMAGNETIC_ROTATION_VECTOR,
    HANDLE_ORIENTATION,
    HANDLE_TILT_DETECTOR,
    HANDLE_PICK_UP_GESTURE,
    HANDLE_QHEART,
    HANDLE_WRIST_TILT,
    /* SAM wake up sensors */
    HANDLE_GRAVITY_WAKE_UP,
    HANDLE_LINEAR_ACCEL_WAKE_UP,
    HANDLE_ROTATION_VECTOR_WAKE_UP,
    HANDLE_SAM_STEP_DETECTOR_WAKE_UP,
    HANDLE_SAM_STEP_COUNTER_WAKE_UP,
    HANDLE_GAME_ROTATION_VECTOR_WAKE_UP,
    HANDLE_GEOMAGNETIC_ROTATION_VECTOR_WAKE_UP,
    HANDLE_ORIENTATION_WAKE_UP,
    HANDLE_QHEART_WAKE_UP,
 
    /* Android virtual sensors via SMGR: */
    HANDLE_SMGR_STEP_DETECTOR,
    HANDLE_SMGR_STEP_COUNT,
    HANDLE_SMGR_SMD,
    HANDLE_SMGR_GAME_RV,
    /* SMGR wake up sensors */
    HANDLE_SMGR_STEP_DETECTOR_WAKE_UP,
    HANDLE_SMGR_STEP_COUNT_WAKE_UP,
    HANDLE_SMGR_GAME_RV_WAKE_UP,
 
    /* QTI value added sensors: */
    HANDLE_GESTURE_FACE_N_SHAKE,
    HANDLE_GESTURE_BRING_TO_EAR,
    HANDLE_MOTION_ABSOLUTE,
    HANDLE_MOTION_RELATIVE,
    HANDLE_MOTION_VEHICLE,
    HANDLE_GESTURE_BASIC_GESTURES,
    HANDLE_GESTURE_TAP,
    HANDLE_GESTURE_FACING,
    HANDLE_GESTURE_TILT,
    HANDLE_GESTURE_GYRO_TAP,
    HANDLE_PEDOMETER,
    HANDLE_PAM,
    HANDLE_MOTION_ACCEL,
    HANDLE_CMC,
    HANDLE_RGB,
    HANDLE_IR_GESTURE,
    HANDLE_SAR,
    HANDLE_HALL_EFFECT,
    HANDLE_FAST_AMD,
    HANDLE_UV,
    HANDLE_THERMOPILE,
    HANDLE_CCT,
    HANDLE_IOD,
    HANDLE_DPC,
    HANDLE_MULTISHAKE,
    HANDLE_SPEED_PULSE
};

这样一来就简单了,for循环一次添加我们列表中配置的sensor,都是调addSensor方法进行处理,
可以看到我们的计步器sensor step counter以及step decetcor也在其中,其配置时的log如下:

06-04 19:48:04.420 D/qti_sensors_hal: addSensor: STEP DETECTOR enabled handle:48
06-04 19:48:04.421 I/qti_sensors_hal: sendAlgoAttribReq:sensor(android.sensor.step_detector) svc no:37 handle:48
06-04 19:48:04.423 I/qti_sensors_hal: processAlgoAttribResp:sensor(android.sensor.step_detector) Received response 0 for svc_num 37 handle 48
06-04 19:48:04.423 D/libsensor1: libsensor_rx_thread: waiting on fd 51
06-04 19:48:04.423 D/libsensor1: libsensor_rx_thread: waiting on fd 53
06-04 19:48:04.423 I/qti_sensors_hal: processAlgoAttribResp:sensor(android.sensor.step_detector) sensor1 Version:1 Power:11796 MaxFreq:65536   
                       MinFreq:18 MaxSampleFreq:3276800 MinSampleFreq:3276800 MaxBuffSamples:20208 ResBuffSamples:100
06-04 19:48:04.423 I/qti_sensors_hal: processAlgoAttribResp:sensor(android.sensor.step_detector) HAL Version:2 Power:0.179993 MaxFreq:1.000000 MinFreq:0.000275
                      MaxSampleFreq:50.000000 MinSampleFreq:50.000000 MaxBuffSamples:0.000275 ResBuffSamples:3276800.000000
06-04 19:48:04.423 D/qti_sensors_hal: sendAlgoAttribReq: Received Response: 0
06-04 19:48:04.423 I/qti_sensors_hal: addSensor: handle:49
06-04 19:48:04.423 D/qti_sensors_hal: addSensor: STEP COUNTER enabled handle:49
06-04 19:48:04.423 D/libsensor1: sensor1_init
06-04 19:48:04.423 V/libsensor1: libsensor_add_client Adding client index 7 (62)
06-04 19:48:04.423 D/libsensor1: libsensor_add_client: waking up rx thread 51 52
06-04 19:48:04.423 D/libsensor1: libsensor_rx_thread: waking on wakeup pipe 51
06-04 19:48:04.424 D/libsensor1: libsensor_rx_thread: waking on fd 62
06-04 19:48:04.424 D/libsensor1: libsensor_read_socket: socket received open success response
06-04 19:48:04.424 D/libsensor1: libsensor_rx_thread: waiting on fd 54
06-04 19:48:04.424 I/libsensor1: sensor1_open: Adding new client fd 62
06-04 19:48:04.424 I/qti_sensors_hal: SAMSensor: sensor() is_attrib_ok=1
06-04 19:48:04.424 D/libsensor1: libsensor_rx_thread: waiting on fd 55
06-04 19:48:04.424 I/qti_sensors_hal: StepCounter: handle:49
06-04 19:48:04.424 I/qti_sensors_hal: sendAlgoAttribReq:sensor(android.sensor.step_counter) svc no:37 handle:49
06-04 19:48:04.424 D/libsensor1: libsensor_rx_thread: waiting on fd 56
06-04 19:48:04.424 D/libsensor1: libsensor_rx_thread: waiting on fd 57
06-04 19:48:04.424 I/libsensor1: libsensor_log_ctl_write_pkt: fd 62; svc 37; msg 36; txn 0; cmd WRITE_QMI
06-04 19:48:04.424 D/libsensor1: libsensor_rx_thread: waiting on fd 59
06-04 19:48:04.424 D/libsensor1: libsensor_rx_thread: waiting on fd 60
06-04 19:48:04.424 D/qti_sensors_hal: waitForResponse: timeout=1000
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waking on fd 62
06-04 19:48:04.426 I/libsensor1: libsensor_log_read_pkt: fd 62; svc 37; msg 36; txn 0; type RESP; cmd WRITE_QMI
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 54
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 55
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 56
06-04 19:48:04.426 V/qti_sensors_hal: SAMSensor_sensor1_cb: msg_type 1, Sn 37, msg Id 36, txn Id 0
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 57
06-04 19:48:04.426 I/qti_sensors_hal: processResp: handle:49
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 59
06-04 19:48:04.426 D/qti_sensors_hal: processResp: Received SNS_SAM_PED_GET_ATTRIBUTES_RESP_V01
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 60
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 61
06-04 19:48:04.426 I/qti_sensors_hal: processAlgoAttribResp:sensor(android.sensor.step_counter) Received response 0 for svc_num 37 handle 49
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 62
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 51
06-04 19:48:04.426 I/qti_sensors_hal: processAlgoAttribResp:sensor(android.sensor.step_counter) sensor1 Version:1 Power:11796 MaxFreq:65536 
                                 MinFreq:18 MaxSampleFreq:3276800 MinSampleFreq:3276800 MaxBuffSamples:20208 ResBuffSamples:100
06-04 19:48:04.426 D/libsensor1: libsensor_rx_thread: waiting on fd 53
06-04 19:48:04.426 I/qti_sensors_hal: processAlgoAttribResp:sensor(android.sensor.step_counter) HAL Version:2 Power:0.179993 MaxFreq:1.000000 MinFreq:0.000275
                                MaxSampleFreq:50.000000 MinSampleFreq:50.000000 MaxBuffSamples:0.000275 ResBuffSamples:3276800.000000

StepCounter::StepCounter(int handle)
    :SAMSensor(handle),
    step_counter_running_total(0),
    step_counter_running_instance(0),
    step_counter_current_instance(0),
    step_counter_is_timer_created(false)
{
    if(getAttribOK() == true) {
        batch_support = true;
        svc_num = SNS_SAM_PED_SVC_ID_V01;
        trigger_mode = SENSOR_MODE_EVENT;
        HAL_LOG_INFO("%s: handle:%d", __FUNCTION__, handle);
        setName("Step Counter");
        setVendor("QTI");
        setType(SENSOR_TYPE_STEP_COUNTER);
 
        if(handle == HANDLE_SAM_STEP_COUNTER_WAKE_UP) {
            bWakeUp = true;
            setName("Step Counter -Wakeup");
            setFlags(SENSOR_FLAG_ON_CHANGE_MODE|SENSOR_FLAG_WAKE_UP);
        } else if(handle == HANDLE_SAM_STEP_COUNTER) {
            bWakeUp = false;
            setFlags(SENSOR_FLAG_ON_CHANGE_MODE);
        }
 
        setMaxRange(1);
        setResolution(1);
 
        /* Send Algo Attributes Request */
        sendAlgoAttribReq();
    }
}

此过程完成后,系统中的sensor基本上就已经配置完成了,因此前面的getSensorList时只返回两个,而最终所有的sensor都是在这个全局变量里配置添加的。

六、updateSensorList更新设备列表

列表已经得到,接着需要调用update更新下sensor数据结构。
在updateSensorList方法中会对一些特殊的sensor进行校验,并且再次通过setSensoeInfo设置sensor的属性值。

06-04 19:48:04.508 I/qti_sensors_hal: sensors_get_sensors_list: Number of sensors: 26
06-04 19:48:04.508 I/qti_sensors_hal: sensors_get_sensors_list
06-04 19:48:04.508 I/qti_sensors_hal: sensors_get_sensors_list: Already have the list of sensors
06-04 19:48:04.508 V/qti_sensors_hal: activate: handle is 0, en is 0
06-04 19:48:04.508 V/qti_sensors_hal: activate sensors is 0
06-04 19:48:04.508 I/qti_sensors_hal: enable: Sensor android.sensor.accelerometer is already enabled/disabled 0
06-04 19:48:04.508 V/qti_sensors_hal: activate: handle is 2, en is 0
06-04 19:48:04.508 V/qti_sensors_hal: activate sensors is 0
06-04 19:48:04.508 I/qti_sensors_hal: enable: Sensor android.sensor.gyroscope is already enabled/disabled 0
06-04 19:48:04.508 V/qti_sensors_hal: activate: handle is 8, en is 0
06-04 19:48:04.508 V/qti_sensors_hal: activate sensors is 0
06-04 19:48:04.508 I/qti_sensors_hal: enable: Sensor android.sensor.gyroscope_uncalibrated is already enabled/disabled 0
……………………省略其他sensor 

我们可以从log中看到系统中共配置了26个sensor,每一个sensor在hal层都有对应的handle匹配。

最后通过sensor1_close接口关闭sensor_info_sensor1_cb->sensor1_handle的client端。

至此,我们的hal层sensor就已经初始化完成,且已经获取到了所有支持的sensor,保存在mSensors结构体中。native层通过get_sensor_list获取sensor列表时,最终就会返回mSensors给上层。同时,底层也可以通过如下getSensor方法传入handle值来获取sensor结构体指针。

Sensor* SensorsContext::getSensor(int handle)
{
    if (mSensors[handle] != NULL) {
        return mSensors[handle];
    } else {
        HAL_LOG_DEBUG("SensorsContext::getSensor handle %d is NULL!", handle);
        return NULL;
    }
}

至此,hal层sensor初始化以及sensor列表获取就告一段落,后面会继续剖析QMI消息机制以及sensor驱动层,欢迎关注。

最后

以上就是忐忑绿茶为你收集整理的Qcom_Sensor(三)--- 之 Android Sensor HAL层初始化流程的全部内容,希望文章能够帮你解决Qcom_Sensor(三)--- 之 Android Sensor HAL层初始化流程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部