Android源码分析:传感器系统

Sensors in Android

  

总述

  

如下图,应用程序开发者使用几个sensor的几个API类进行应用程序的开发。Java的部分的API使用C/C++来实现,也就是调用到JNI层。左侧运行于应用程序的进程空间,右侧运行于system server进程空间。双方通过ISensorEventConnection/SensorChannel进行通讯。SensorService负责与Sensors的硬件适配层HAL进行通讯,后者与驱动和硬件进行交互。

  

Java API

  

Java层的API类有SensorManager,利用它才可以使用系统的各种感应器(sensor)。sensor的采样值、精确度、时间戳以及信息是自哪个感应器等信息封装在Java类SensorEvent中。Java类Sensor代表一个感应器,包含感应器的各种信息,它的成员数据与本地Sensor类以及HAL层的sensor_t对应(见后述章节)。作为父类的SensorEventListener是一个监听器接口,应用开发者编写它的一个子类可以实现对SensorEvent的监听并做出相应反应。

  

在获取sensor service创建SensorManager时,会创建一个线程去轮询(poll,调用sensors_data_poll)去取sensor的数据,然后以发送消息的形式将SensorEvent发送给ListenerDelegate中的Handler,由handler在新一轮的线程循环中调用对应的sensorListener进行处理。

  

 

  

JNI与native层

  

JNI层位于frameworks/base/core/jni/下面,主要就是一个文件android_hardware_SensorManager.cpp。它使用的类如Sensor、SensorChannel、SensorEventQueue、、ISensorEventConnection和ISensorServer则放在libgui.so中,见目录frameworks/base/libs/gui。

  

 

  

Java层在轮询之前,必须调用sensors_create_queue创建(见SensorThreadRunnable的open函数)一个本地的SensorEventQueue队列,这个C++对象的指针被转换为int型后保存为SensorManager的静态成员变量sQueue。当轮询时,将该队列传递给JNI层的sensors_data_poll,用于从该队列中读取Event数据(具体数据类型是ASensorEvent)。

  

本地SensorEventQueue类主要借助于两个类进行工作。一是封装了管道的SensorChannel类,event的读取和写入都是针对封装的管道进行的;二是libutils库中的Looper类,Looper类实现了在调用者线程中对文件描述符的轮询(内部使用的epoll),甚至可以注册回调函数,当有文件描述符对应的文件有数据到达时使用回调函数进行处理。这样,队列类SensorEventQueue使用Looper监听着管道对应的描述符,当有数据达到时,就可以读取,没有使用回调机制。整个过程是:在Java层的SensorManager的线程中不断调用sensors_data_poll查询数据,这导致其JNI层的native实现在队列上等待event事件(见队列的成员函数waitForEvent,它使用poll进行轮询),也就是说,直到有管道中有数据可用才返回。当没有发生错误返回时,表示有数据可读,然后对数据进行读取。一次读取单位为一个event。

  

下面是JNI层中的sensors_data_poll代码片段:

  

res = queue->read(&event, 1);

if (res == -EAGAIN) {

res = queue->waitForEvent();//等待有数据可读取

if (res != NO_ERROR)//检查是否发生错误

return -1;

res = queue->read(&event, 1);//没错误,进行数据读取

}

  

封装管道的SensorChannel类的对象由ISensorEventConnection接口获取。另外,对sensor的激活/去激活也是通过ISensorEventConnection调用到server侧的SensorService完成的。

  

C++类Sensor代表了一个sensor,它是HAL层sensor_t的封装,同时又为Java层的Sensor类中的数据成员变量提供数据"源",也就是说,Java中的Sensor的成员变量信息是由该C++中的Sensor类设置,后者又是根据sensor_t而获取对应的sensor信息。Java中的Sensor是应用开发的API类。在C++中的Sensor类中定义了sensor的枚举类型:

  

enum {

TYPE_ACCELEROMETER = ASENSOR_TYPE_ACCELEROMETER, //加速度

TYPE_MAGNETIC_FIELD = ASENSOR_TYPE_MAGNETIC_FIELD, //磁场

TYPE_GYROSCOPE = ASENSOR_TYPE_GYROSCOPE, //陀螺仪

TYPE_LIGHT = ASENSOR_TYPE_LIGHT, //光传感器

TYPE_PROXIMITY = ASENSOR_TYPE_PROXIMITY //距离传感器

};

  

 

  

SensorService

  

在frameworks/base/services/sensorservice/下面给出sensorService的相关实现代码,它们最终生成libsensorservice.so库文件,作为service被注册到system server后,最终运行于system_server后台进程空间。

  

Sensor service模块的核心部分是SensorService类。另外还定义了几个逻辑上的虚拟sensor:GravitySensor、LinearAccelerationSensor和RotationVectorSensor,它们的接口由抽象类SensorInterface定义,物理意义上实际传感器HardwareSensor也同样遵循该接口规范。

  

SensorInterface与四个子类继承关系图如下:

  

SensorInterface是个抽象类,定义了五个接口:

  

virtual bool process(sensors_event_t* outEvent,const sensors_event_t& event) = 0; //处理原始数据,换成上层应用希望得到的数据

  

virtual status_t activate(void* ident, bool enabled) = 0; //激活与去激活

  

virtual sttus_t setDelay(void* ident, int handle, int64_t ns) = 0;//设置报告处理频率

  

virtual Sensor getSensor() const = 0;//获取对应的sensor

  

virtual bool isVirtual() const = 0;//是否为虚拟的,即是否为逻辑(虚拟)传感器

  

GravitySensor和LinearAccelerationSensor,它们不是物理意义上的传感器,只是逻辑意义上的传感器,可称之为虚拟(virtual)传感器。它们实际上是将加速器(即gsensor)的值经过处理过滤后再上报。

  

RotationVectorSensor方向向量传感器,实际上它由加速器和磁场传感器(compass)组成,根据它们上报的值来判断是否旋转屏幕。

  

引入虚拟传感器的目的是方便上层程序的处理。在上层看来,它不需要关注设备上的传感器的某些原始数据,只需要经过加工处理后的数据,如是否旋转屏幕,它是依据虚拟的"传感器"sensorRotationVectorSensor得来的经过加工后的数据。这些虚拟传感器包含了处理原始数据的算法。算法包含在重载的process函数中。

  

HardwareSensor代表了真正的传感器,它继承自SensorInterface,实现了各个抽象接口,但其实现是借助于与位于下层的HAL层的sensor硬件模块打交道的类SensorDevice来完成的。

  

SensorDevice与HAL中的libsensors.so打交道,如获取对应的硬件module,打开sensor设备,参见其构造函数:

  

SensorDevice::SensorDevice()

: mSensorDevice(0),

mSensorModule(0)

{

status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,

(hw_module_t const**)&mSensorModule);//打开sensor硬件模块

  

LOGE_IF(err, "couldn‘t load %s module (%s)",

SENSORS_HARDWARE_MODULE_ID, strerror(-err));

  

if (mSensorModule) {

err = sensors_open(&mSensorModule->common, &mSensorDevice);//打开HAL层的poll设备

LOGE_IF(err, "couldn‘t open device for module %s (%s)",

SENSORS_HARDWARE_MODULE_ID, strerror(-err));

if (mSensorDevice) {

sensor_t const* list;

ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);//获取sensor_t列表

mActivationCount.setCapacity(count);

Info model;

for (size_t i=0 ; i<size_t(count) ; i++) {

mActivationCount.add(list[i].handle, model);

mSensorDevice->activate(mSensorDevice, list[i].handle, 0);

}

}

}

}

  

其结构图如下:

  

作为核心代码的SensorService类有三个父类:

  

BinderService<SensorService>:继承该父类使其成为一个标准的本地(native) service,将自己添加到系统的system server中去,其它感兴趣者可以使用该service。

  

BnSensorServer:意味着作为子类,SensorService是抽象类ISensorServer中定义的两个接口(getSensorList和createSensorEventConnection)的server侧的真正实现者。一个接口是用来获取系统的sensor列表,另一个则是创建一个事件连接(EventConnection),用于基于管道加上轮询方式的event传输。

  

 

  

 

  

 

  

Thread:意味着它也是一个线程类,在SensorService创建后,有个单独的线程去执行重载的threadLoop

  

这个threadLoop可以说是整个sensor的调度处理中心,让sensor相关的模块都动起来。作为一个后台线程,它是个无限循环,不断去处理

  

bool SensorService::threadLoop()

{

LOGD("nuSensorService thread starting…");

  

const size_t numEventMax = 16 * (1 + mVirtualSensorList.size());

sensors_event_t buffer[numEventMax];

sensors_event_t scratch[numEventMax];

SensorDevice& device(SensorDevice::getInstance());

const size_t vcount = mVirtualSensorList.size();

  

ssize_t count;

do {

count = device.poll(buffer, numEventMax);//轮询event数据到缓冲区

if (count<0) {

LOGE("sensor poll failed (%s)", strerror(-count));

break;

}

  

recordLastValue(buffer, count);//记录每个sensor最新的值,记入到mLastEventSeen这个KeyedVector(从sensor标识符到sensors_event_t的映射)中。

  

// handle virtual sensors

if (count && vcount) {//下面是处理虚拟sensors数据

const DefaultKeyedVector<int, SensorInterface*> virtualSensors( getActiveVirtualSensors());

  

const size_t activeVirtualSensorCount = virtualSensors.size();

  

if (activeVirtualSensorCount) {

size_t k = 0;

for (size_t i=0 ; i<size_t(count) ; i++) {

sensors_event_t const * const event = buffer;

for (size_t j=0 ; j<activeVirtualSensorCount ; j++) {

sensors_event_t out;

if (virtualSensors.valueAt(j)->process(&out, event[i])) {//处理原始数据,经过处理转换后的数据信息保存在out这个event中

buffer[count + k] = out;//将它们添加到buffer中

k++;

}

}

}

  

if (k) {

// record the last synthesized values

recordLastValue(&buffer[count], k);//同样对虚拟的sensor的event最新值添加到mLastEventSeen中

count += k;

// sort the buffer by time-stamps

sortEventBuffer(buffer, count);//按时间戳排序

}

}

}

  

// send our events to clients…

const SortedVector< wp<SensorEventConnection> > activeConnections(

getActiveConnections());

size_t numConnections = activeConnections.size();

for (size_t i=0 ; i<numConnections ; i++) {

sp<SensorEventConnection> connection(

activeConnections[i].promote());

if (connection != 0) {

connection->sendEvents(buffer, count, scratch);//发送给client端,实际是写入管道

}

}

} while (count >= 0 || Thread::exitPending());

  

LOGW("Exiting SensorService::threadLoop!");

return false;

}

  

因此,可以看出,SensorService的工作线程不断去轮询设备中是否有数据可用。当有数据可用时,将它们写入管道。对方的应用程序中的线程也不断轮询管道,当有数据时,便调用对应的listener进行处理。它们工作在不断的线程中,或使用looper,或使用handler,在不同的线程循环中进行处理,多次的异步操作构成了sensor的处理过程。

  

 

  

HAL

  

在Android HAL中只对sensors的数据结构进行了定义(见头文件hardware/libhardware/include/hardware/sensors.h),其具体实现应由芯片厂家给出。

  

在使用sensors的HAL时,首先使用HAL提供的hw_get_module函数,根据其模块ID字符串(SENSORS_HARDWARE_MODULE_ID)获取硬件模块sensors_module_t,然后借助于sensors_module_t枚举中设备中所带的所有sensors(sensor由结构体sensor_t定义)列表。

  

数据结构sensors_module_t定义了sensors硬件模块,其中的get_sensors_list函数指针用于枚举设备上的各种类型的sensor,实现由平台厂商给出。

  

同样,可以接着使用API函数sensors_open打开HAL中定义的sensors_poll_device_t类型的设备,该结构体定义三个API,用于激活/去激活sensor(见成员activate函数指针)、设置数据报告频率(见setDelay函数指针)和轮训(见poll函数指针)。同样,这三个函数也由平台厂家实现。

  

这样,我们可以使用hw_get_module函数打开硬件模块,并得到sensors列表,同时,也可以使用sensors_open打开sensors_poll_device_t类型的设备,对sensor进行激活/去激活,轮询读数和设置数据报告频率等基本操作。

  

结构体sensor_t代表了一个sensor,定义了sensor的各种属性,如:名称、厂家、版本、句柄、类型、最大值范围、解析度、功耗、数据上报频率等。其定义具体如下:

  

struct sensor_t {

/* name of this sensors */

const char* name;//sensor的名称

  

/* vendor of the hardware part */

const char* vendor;//厂家

  

/* version of the hardware part + driver. The value of this field is

* left to the implementation and doesn‘t have to be monotonically

* increasing.

*/

int version;//版本

  

/* handle that identifies this sensors. This handle is used to activate

* and deactivate this sensor. The value of the handle must be 8 bits

* in this version of the API.

*/

int handle;//句柄,用于标识是激活/去激活哪个sensor,亦即sensors_event_t中的int32_t sensor;它实际是由四个字符的ascii码值来填充

  

/* this sensor‘s type. */

int type;//sensor类型,在sensor.h中定义了多达12种类型(有的为逻辑上的sensor),并以注释的方式对它们进行了详细解释

  

/* maximaum range of this sensor‘s value in SI units */

float maxRange;//最大取值范围

  

/* smallest difference between two values reported by this sensor */

float resolution;//解析度

  

/* rough estimate of this sensor‘s power consumption in mA */

float power;//估计的功耗,单位为mA

  

/* minimum delay allowed between events in microseconds. A value of zero means that this sensor doesn‘t report events at a constant rate, but rather only when a new data is available */

int32_t minDelay;//报告读数值的events时间间隔(单位:ms),若为0,意味着不按该频率报告,而是数据到来时才报告

  

/* reserved fields, must be zero */

void* reserved[8];//保留

};

  

sensor的采样值的上报可以按照某个固定的频率进行上报,也可以当有可用的数据时再上报(minDelay设为0)。上报数据以event的形式进行,见结构体sensors_event_t,它包含了sensor的标识符、类型、数据采样时间戳以及采样数据。因为各种sensor的采样值各式各样,它更多地是用联合体union来定义,根据不同的sensor来解释返回的值,比如,当是加速器sensor或磁场sensor时,就分别取联合体中的acceleration和magnetic两个字段,它们的类型是结构体sensors_vec_t,其中又包含有union联合体。这样,Android将各种sensor统一成一种接口,依据不同的sensor分别对其标识和类型对采样值进行解释。

Android源码分析:传感器系统,,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。