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); 封装管道的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 {
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() LOGE_IF(err, “couldn’t load %s module (%s)”, if (mSensorModule) { 其结构图如下: 作为核心代码的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() const size_t numEventMax = 16 * (1 + mVirtualSensorList.size()); ssize_t count; recordLastValue(buffer, count);//记录每个sensor最新的值,记入到mLastEventSeen这个KeyedVector(从sensor标识符到sensors_event_t的映射)中。 // handle virtual sensors const size_t activeVirtualSensorCount = virtualSensors.size(); if (activeVirtualSensorCount) { if (k) { // send our events to clients… LOGW(“Exiting SensorService::threadLoop!”); 因此,可以看出,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 { /* vendor of the hardware part */ /* version of the hardware part + driver. The value of this field is /* handle that identifies this sensors. This handle is used to activate /* this sensor’s type. */ /* maximaum range of this sensor’s value in SI units */ /* smallest difference between two values reported by this sensor */ /* rough estimate of this sensor’s power consumption in 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 */ /* reserved fields, must be zero */ sensor的采样值的上报可以按照某个固定的频率进行上报,也可以当有可用的数据时再上报(minDelay设为0)。上报数据以event的形式进行,见结构体sensors_event_t,它包含了sensor的标识符、类型、数据采样时间戳以及采样数据。因为各种sensor的采样值各式各样,它更多地是用联合体union来定义,根据不同的sensor来解释返回的值,比如,当是加速器sensor或磁场sensor时,就分别取联合体中的acceleration和magnetic两个字段,它们的类型是结构体sensors_vec_t,其中又包含有union联合体。这样,Android将各种sensor统一成一种接口,依据不同的sensor分别对其标识和类型对采样值进行解释。
本文链接地址: http://www./?p=953 原创文章,版权?红狼博客所有, 转载随意,但请注明出处。 相关文章: |
|
来自: dwlinux_gs > 《重力感应专题》