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分别对其标识和类型对采样值进行解释。
posted on 2014-04-12 16:28 To Do List 阅读(584) 评论(0) 编辑 收藏 举报