Android Sensor 代码流程简介
如今的传感器被越来越多用到设备开发当中,今天我们就来讲解下Qualcomm DragonBoard 410c的sensor架构,本篇主要基于Android5.1.1 来介绍sensor的Framework ,JNI,HAL以及lib,基于mma7660.c驱动的源码分析。
我们先来分析SystemSensorManager源码。
1.SystemSensorManager构造函数
public SystemSensorManager(Context context,Looper mainLooper) {
mMainLooper = mainLooper;
mTargetSdkLevel =context.getApplicationInfo().targetSdkVersion;
synchronized(sSensorModuleLock) {
if (!sSensorModuleInitialized) {
sSensorModuleInitialized =true;
nativeClassInit();
// initialize the sensor list
final ArrayList
int i = 0;
do {
Sensor sensor = newSensor();
i = nativeGetNextSensor(sensor,i);
if (i>=0) {
//Log.d(TAG,"found sensor: " + sensor.getName() +
// ", handle=" +sensor.getHandle());
fullList.add(sensor);
sHandleToSensor.append(sensor.getHandle(),sensor);
}
} while (i>0);
}
}
}
构造函数接收Context和looper参数。理解这两个参数很重要,后面在讲到传感器数据读取时就是利用主线程的looper来读取数据(这和Android5.0之前创建线程读取数据不同)。
构造函数先保留Context和looper私有变量。然后查看SystemSensorManager对象是否被初始化过,如果已经初始化了则什么也不做,反之,初始化JNI,获取传感器列表,并形成传感器handler和sensor的映射关系。
2.注册监听器
protected booleanregisterListenerImpl(SensorEventListener listener, Sensor sensor,
int delayUs, Handler handler, intmaxBatchReportLatencyUs, int reservedFlags) {
if (listener == null || sensor == null){
Log.e(TAG, "sensor or listeneris null");
return false;
}
// Trigger Sensors should use therequestTriggerSensor call.
if (sensor.getReportingMode() ==Sensor.REPORTING_MODE_ONE_SHOT) {
Log.e(TAG, "Trigger Sensorsshould use the requestTriggerSensor.");
return false;
}
if (maxBatchReportLatencyUs < 0 ||delayUs < 0) {
Log.e(TAG, "maxBatchReportLatencyUsand delayUs should be non-negative");
return false;
}
// Invariants to preserve:
// - one Looper per SensorEventListener
// - one Looper per SensorEventQueue
// We map SensorEventListener to aSensorEventQueue, which holds the looper
synchronized (mSensorListeners) {
SensorEventQueue queue =mSensorListeners.get(listener);
if (queue == null) {
Looper looper = (handler !=null) ? handler.getLooper() : mMainLooper;
queue = newSensorEventQueue(listener, looper, this);
if (!queue.addSensor(sensor,delayUs, maxBatchReportLatencyUs, reservedFlags)) {
queue.dispose();
return false;
}
mSensorListeners.put(listener,queue);
return true;
} else {
return queue.addSensor(sensor,delayUs, maxBatchReportLatencyUs, reservedFlags);
}
}
}
监听数据的思想如下:
讲监听器Listener包装到SensorEventQueue事件队列中。SensorEventQueue这个事件队列在获取传感器数据后会调用Listener。其中主要的数据获取逻辑包装在SensorEventQueue中。
3. SensorEventQueue分析
SensorEventQueue类继承自BaseEventQueue。
a. SensorEventQueue构造函数
public SensorEventQueue(SensorEventListener listener, Looper looper,
SystemSensorManager manager) {
super(looper, manager);
mListener = listener;
}
构造函数传入的三个参数为listener,looper和manager。从构造函数中,looper和manager传递给父构造函数。Listener有SensorEventQueue维护。
当传感器数据到来时,会调用
protectedabstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
long timestamp);
SensorEventQueue在dispatchSensorEvent函数中调用listener。
b. BaseEventQueue构造函数
BaseEventQueue(Looper looper,SystemSensorManager manager) {
nSensorEventQueue= nativeInitBaseEventQueue(this, looper.getQueue(), mScratch);
mCloseGuard.open("dispose");
mManager =manager;
}
Looper参数主要是用来在JNI中读取传感器的值。
JNI文件的源码为android_hardware_SensorManager.cpp中。整个文件的核心在于Receiver类。该类负责从sensor服务端获取数据,并回调1.3.1中的dispatchSensorEvent函数分发数据。
这里主要讲
nativeInitSensorEventQueue函数和Receive类。nativeInitSensorEventQueue负责与服务端建立连接管道,后者用于读取管道中的值和数据分发。
static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz,jobject eventQ, jobject msgQ, jfloatArray scratch) {
SensorManager&mgr(SensorManager::getInstance());
sp
sp
if (messageQueue == NULL){
jniThrowRuntimeException(env, "MessageQueue is notinitialized.");
return 0;
}
sp
receiver->incStrong((void*)nativeInitSensorEventQueue);
returnjlong(receiver.get());
}
该函数主要是调用Sensormanager创建一个事件队列。然后利用事件队列和消息队列构造出Receiver。
类Receiver。
Class Reveiver : public LooperCallback。
重要的成员和方法为
mSensorQueue :数据通道的队列
mMessageQueue :looper的消息队列
mReceiverObject:被Framework层引用
mScratch:数据容器
virtual void onFirstRef(){
LooperCallback::onFirstRef();
mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
}
在引用时调用,将数据通道队列中的数据上报文件描述符添加到looper的epool模型中。
virtual int handleEvent(int fd, int events, void* data)。当looper中的epool模型监测到onFirstRef中添加的文件描述符有事件发生时,被调用。该函数的实现主要是从数据通道中读取传感器事件,回调dispatchSensorEvent函数像应用注册的监听器发送数据。
Android 5.1.1HAL层的设计和Android5.0之前的设计思想相同,实现的原理相同。基本思想为:
Sensorserver.cpp文件中维护与SensorEventQueue对应的SensorEventConnection链表。一个SensroEventQueue对用一个SensorEventConnection。同时Sensorserver.cpp创建一个线程去读取传感器的数据,然后向这个SensorEventConnection链表进行分发(向Connection的文件描述符写入),在JNI的looper线程中这个写入动作会被epool模型监测到,JNI就可以去读取connection中的数值。
因为Android中任何cpp类继承与RefBase类,因此在引用的时候调用onFirstRef。SensorService类在系统启动时初始化,主要初始化程序在onFirstRef中
onRirstRef函数中主要执行以下几个任务。
1.引用SensorDevice类获取sensor列表。
2.将获取到的sensor列表注册到本地列表
3.检查是否有虚拟sensor,如果有,注册到本地列表。
4.调用run()函数来执行threadlooper。
下面分析threadlooper函数
Threadoppe函数主要执行下面的工作:
1.调用SensorDevice类的poll来获取传感器数据
2.传感器融合逻辑
3.扫面connection链表,将传感器数据分达到connection链表中。
SensorDevice类。
SensorDevice类负责与lib库交互,主要是为sensorserver类提供统一的接口。
SensorDevice构造函数
该函数实现了两个功能:
1 获取sensormodule
2 打开sensordevice
3 获取sensor列表并保存在本地
高通的lib库在文档
80-NT275-1_A_MSM8916_8939_8909_Native_Sensors_Overview.pdf描述的非常清楚。与Androoid原生代码的区别在于高通提供了一个NativeSensorManager类
1.该类可以用来定制厂商的融合逻辑。
2.方便的读取内核中sysfs文件系统中的sensor信息(主要方法就是扫面固定目录下的所有目录和目录下所有文件的属性,然后将扫描结果保存在本地)。
以上就是sensor在框架层中的代码结构了。kernel层的驱动由各个厂商实现了,我们只需集成到我们的系统当中即可。