打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
红狼博客 ? 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的采样值、精确度、时间戳以及信息是自哪个感应器等信息封装在JavaSensorEvent中。JavaSensor代表一个感应器,包含感应器的各种信息,它的成员数据与本地Sensor类以及HAL层的sensor_t对应(见后述章节)。作为父类的SensorEventListener是一个监听器接口,应用开发者编写它的一个子类可以实现对SensorEvent的监听并做出相应反应。

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

 

JNInative

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

 

Java层在轮询之前,必须调用sensors_create_queue创建(见SensorThreadRunnableopen函数)一个本地的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,它是HALsensor_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类。另外还定义了几个逻辑上的虚拟sensorGravitySensorLinearAccelerationSensorRotationVectorSensor,它们的接口由抽象类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;//是否为虚拟的,即是否为逻辑(虚拟)传感器

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

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

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

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

SensorDeviceHAL中的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>:继承该父类使其成为一个标准的本地(nativeservice,将自己添加到系统的system server中去,其它感兴趣者可以使用该service

BnSensorServer:意味着作为子类,SensorService是抽象类ISensorServer中定义的两个接口(getSensorListcreateSensorEventConnection)的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);//
同样对虚拟的sensorevent最新值添加到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),其具体实现应由芯片厂家给出。

在使用sensorsHAL时,首先使用HAL提供的hw_get_module函数,根据其模块ID字符串(SENSORS_HARDWARE_MODULE_ID)获取硬件模块sensors_module_t,然后借助于sensors_module_t枚举中设备中所带的所有sensorssensor由结构体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时,就分别取联合体中的accelerationmagnetic两个字段,它们的类型是结构体sensors_vec_t,其中又包含有union联合体。这样,Android将各种sensor统一成一种接口,依据不同的sensor分别对其标识和类型对采样值进行解释。

 

本文链接地址: http://www.redwolf-blog.com/?p=953

原创文章,版权?红狼博客所有, 转载随意,但请注明出处。

    分享到:

相关文章:

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
深入理解Android Sensor系统 (4.0)
Android之传感器系统(Gsensor)
阅读android有关sensor的源码总结
Android Sensor软件架构分析
如何在Android应用程序中使用传感器(OpenIntents开源组织SensorSimulator项目)
gsensor即时数据的apk && 用gsensor来判断手机的静和动 && 手机摇一摇 &&气压计的测试应用
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服