关闭

Sensor框架理解

341人阅读 评论(0) 收藏 举报
分类:


在这个系列的文章我们只是为了讲清楚Sensor框架的设计和工作原理基于4.0,4.0以下的代码有所区别,尤其是2.2以下根本就没有Binder架构,不讲驱动,也不讲具体的某一个应用该怎么处理Sensor的数据。

一、整体的架构:

从这个图来看Sensor的架构还是非常的清淅,

黄色部分表示硬件,它要挂在I2C总线上

红色部分表示驱动,把驱动注册到Kernel的Input Subsystem上,然后通过Event Device把Sensor数据传到HAL层,准确说是HAL从Event读

绿色部分表示动态库,它封装了整个Sensor的IPC机制,如SensorManager是客户端,SensorService是服务端,而HAL部分是封装了服务端对Kernel的直接访问

蓝色部分就是我们的Framework和Application了,JNI负责访问Sensor的客户端,而Application就是具体的应用程序,用来接收Sensor返回的数据,并处理实现对应的UI效果,如屏幕旋转,打电话时灭屏,自动调接背光(这三个功能的具体实现会在以后分析)

相关代码:

从HAL到Framework:

Framework部分:

frameworks/base/core/java/android/hardware/SensorManager.java
frameworks/base/core/jni/android_hardware_sensorManager.cpp

下面的代码会生成到:libgui.so
frameworks/base/libs/gui/SensorManager.cpp
frameworks/base/libs/gui/SensorEventQueue.cpp
frameworks/base/libs/gui/SensorChannel.cpp
frameworks/base/libs/gui/Sensor.cpp

下面的代码会生成:libsensorservice.so
frameworks/base/services/sensorservice/SensorService.cpp
frameworks/base/services/sensorservice/SensorDevice.cpp

HAL部分:这部分代码最终会生成 sensor.default.so 到/system/lib/hw/

hardware/libhardware/include/hardware/Sensors.h

device/qcom/msm7627a/libsensors/Sensors.cpp

device/qcom/msm7627a/libsensors/SensorBase.h
device/qcom/msm7627a/libsensors/AccSensor.cpp
device/qcom/msm7627a/libsensors/ProximitySensor.cpp
device/qcom/msm7627a/libsensors/LightSensor.cpp
device/qcom/msm7627a/libsensors/TmdSensor.cpp
device/qcom/msm7627a/libsensors/MagnetoSensor.cpp
device/qcom/msm7627a/libsensors/GyroSensor.cpp

device/qcom/msm7627a/libsensors/InputEventRead.h

device/qcom/msm7627a/libsensors/InputEventRead.cpp

Drivers:

P-Sensor:

device/qcom/msm7627a/libsensors/Tmd2771.h

kernel/drivers/misc/Tmd2771.c

(从这个代码路径大家可以看出我用来分析的代码是高通7627a平台的,

和Google原生代码没什么差别,而MTK的代码差别就大了,从HAL层开始完全不一样。)

我们还是列一下Android一般有哪些Sensor吧!

AccelerometerSensor

MagneticSensor

OrientationSensor

ProximitySensor

LightSensor

Gyro

这是我们最常见手机上有的Sensor,不过一般低端手机是没有Gyro的,而A Sensor用的并不是三轴的而是两轴。


二、应用举例:

[java] view plain copy
  1. SensorManager sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);  
  2. Sensor accSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);  
  3. sensorManager.registerListener(this, accSensor, SensorManager.SENSOR_DELAY_NORMAL);  
  4. sensorManager.unregisterListener(this, accSensor);  
  5. //然后在当前Activity中实现以下的两个函数  
  6. public void onSensorChanged(SensorEvent event)   
  7. public void onAccuracyChanged(Sensor sensor, int accuracy)  

三、SensorService

服务程序启动,它是由SystemManager启动起来的:

frameworks/base/cmds/system_server/library/system_init.cpp

[cpp] view plain copy
  1. property_get("system_init.startsensorservice", propBuf, "1");  
  2. if (strcmp(propBuf, "1") == 0) {  
  3.     // Start the sensor service  
  4.     SensorService::instantiate();  
  5. }  
整个C/S通信的架构图:


需要特别说明的是,BpSensorServer并没有在系统中被用到,如果你从ISensorServer.cpp中把它删除也不会对Sensor的工作有任何影响。

它的工作被SensorManager.cpp所取代,ServiceManager直接获取上面System_init文件中添加的SensorService对像。

四、创建SensorManager


1. new SensorManager

它有两个地方去创建这个Sensor client Object,一个就是ContextImpl,另一个就是PowerManagerService中,contextImpl大家都明白是为了应用程序很方便的获取Service,PowerManager中为什么要创建这个对象我们后面再分析。

2.natvieClassInit

它在SensorManager(JAVA)的构造函数中被调用,作用就是创建一个Sensor.java类的实例对象。

3.sensors_module_init()

它也是在SensorManager(JAVA)的构造函数中被调用的,它的作用就是初始华SensorManager(cpp)。

[cpp] view plain copy
  1. static jint  
  2. sensors_module_init(JNIEnv *env, jclass clazz)  
  3. {  
  4.     SensorManager::getInstance();  
  5.     return 0;  
  6. }  
通过getInstance()就可以知道它是一个单件类,实例的创建由其父类Singleton<SensorManager>,

SensorManager只需要在实现文件调用以下的代码:

ANDROID_SINGLETON_STATIC_INSTANCE(SensorManager)

接着是SensorManager(cpp)的构造函数也没有做什么就是通过ServiceManager获取了SensorService的实例对象。

4. onFirstRef的实例

其实SensorService在添加实例到ServiceManager的时候就已经实例化过后了,因为在Binder.c中就会保存对它的引用,而RefBase的意思就是用来管理对像的引用,所以它会在对象第一次被引用的时候就调用onFirstRef。

接下来我们看看SensorService::onFirstRef里面做了哪些工作。

5. 创建SensorDevice

SensorDevice的构造函数:

[cpp] view plain copy
  1. status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,  
  2.         (hw_module_t const**)&mSensorModule);  
这句话的意思是JNI加载HAL的库文件,并创建SensorModle的对象,Sensor的库文件通常是sensor.default.so

上图接下来是sensors_open,这个函数并没有在SensorDevice中实现,而是调用的HAL层的函数,相关代码路径已在上面列出。

[cpp] view plain copy
  1. static int open_sensors(const struct hw_module_t* module, const char* id,  
  2.                         struct hw_device_t** device)  
  3. {  
  4.         int status = -EINVAL;  
  5.     LOGE("%s %d => %s", __FILE__, __LINE__, __func__);  
  6.         sensors_poll_context_t *dev = new sensors_poll_context_t();  
  7.   
  8.         memset(&dev->device, 0, sizeof(sensors_poll_device_t));  
  9.   
  10.         dev->device.common.tag = HARDWARE_DEVICE_TAG;  
  11.         dev->device.common.version  = 0;  
  12.         dev->device.common.module   = const_cast<hw_module_t*>(module);  
  13.         dev->device.common.close    = poll__close;  
  14.         dev->device.activate        = poll__activate;  
  15.         dev->device.setDelay        = poll__setDelay;  
  16.         dev->device.poll            = poll__poll;  
  17.   
  18.         *device = &dev->device.common;  
  19.         status = 0;  
  20.   
  21.         return status;  
  22. }  
我们看new sensors_poll_device_t();

[cpp] view plain copy
  1. sensors_poll_context_t::sensors_poll_context_t()  
  2. {  
  3. #ifdef TMD27713_SENSOR  
  4.     mSensors[tmd] = new TmdSensor();  
  5.     mPollFds[tmd].fd = mSensors[tmd]->getFd();  
  6.     mPollFds[tmd].events = POLLIN;  
  7.     mPollFds[tmd].revents = 0;    
  8. #else  
  9.     mSensors[light] = new LightSensor();  
  10.     mPollFds[light].fd = mSensors[light]->getFd();  
  11.     mPollFds[light].events = POLLIN;  
  12. #endif    
  13.     mSensors[acc] = new AccSensor();  
  14.     mPollFds[acc].fd = mSensors[acc]->getFd();  
  15.     mPollFds[acc].events = POLLIN;  
  16.     mPollFds[acc].revents = 0;  
  17.   
  18.     mSensors[mag] = new MagnetoSensor((AccSensor*)mSensors[acc]);  
  19.     mPollFds[mag].fd = mSensors[mag]->getFd();  
  20.     mPollFds[mag].events = POLLIN;  
  21.     mPollFds[mag].revents = 0;  
  22.   
  23.     int wakeFds[2];  
  24.     int result = pipe(wakeFds);  
  25.     fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);  
  26.     fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);  
  27.     mWritePipeFd = wakeFds[1];  
  28.   
  29.     mPollFds[wake].fd = wakeFds[0];  
  30.     mPollFds[wake].events = POLLIN;  
  31.     mPollFds[wake].revents = 0;  
  32. }  
这部分代码就创建HAL和Kernel Event通信的类,还有Sensor数据读写管道的创建。
返回open_sensors再看剩下的代码,就是创建sensors_poll_device_t对象并把sensor控制的相关函数指针赋值给它。

6. SensorDevice 调用get_sensors_list

这个方法还是调用到了HAL中,而HAL中的这个函数也就是返回以下数组:

[cpp] view plain copy
  1. /* The SENSORS Module */  
  2. static const struct sensor_t sSensorList[] = {  
  3.         { "ST 3-axis Accelerometer",  
  4.           "STMicroelectronics",  
  5.           1, SENSORS_ACCELERATION_HANDLE,  
  6.           SENSOR_TYPE_ACCELEROMETER, RANGE_A, CONVERT_A, 0.23f, 20000, { } },  
  7.         { "ST 3-axis Magnetic field sensor",  
  8.           "STMicroelectronics",  
  9.           1, SENSORS_MAGNETIC_FIELD_HANDLE,  
  10.           SENSOR_TYPE_MAGNETIC_FIELD, 2000.0f, CONVERT_M, 6.8f, 16667, { } },  
  11.         { "iNemo Orientation sensor",  
  12.           "STMicroelectronics",  
  13.           1, SENSORS_ORIENTATION_HANDLE,  
  14.           SENSOR_TYPE_ORIENTATION, 360.0f, CONVERT_O, 7.8f, 16667, { } },  
  15. };  
我们需要特别关组的是第4,5个参数,第4参数Handle是对kernel而言的,如激活,读写event,代码中的说明:

    /* 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. 
     */

而第五个参数是相对于上层代码而言。
7. mSensorDevice->activate

在获取到Sensor列表以后,我们就去激活每一个Sensor:

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

[cpp] view plain copy
  1. int sensors_poll_context_t::activate(int handle, int enabled) {  
  2.     int index = handleToDriver(handle);  
  3.     if (index < 0) return index;  
  4.     LOGE("sensor.cpp:index = %d\t handle= %d\t en=%d",index,handle,enabled);//by zhangfeng  
  5.     int err =  mSensors[index]->enable(handle, enabled);  
  6.     if (enabled && !err) {  
  7.         const char wakeMessage(WAKE_MESSAGE);  
  8.         int result = write(mWritePipeFd, &wakeMessage, 1);  
  9.         LOGE_IF(result<0, "error sending wake message (%s)", strerror(errno));  
  10.     }  
  11.     return err;  
  12. }  
这儿要介绍一下handleToDriver

[cpp] view plain copy
  1.   int handleToDriver(int handle) const {  
  2.       switch (handle) {  
  3.           case ID_A:  
  4.               return acc;  
  5.           case ID_M:  
  6.           case ID_O:  
  7.               return mag;  
  8. #ifdef TMD27713_SENSOR  
  9.      case ID_P:  
  10.      case ID_L:  
  11.         return tmd;  
  12. #else  
  13.     case ID_P:  
  14.         return proximity;  
  15.     case ID_L:  
  16.         return light;  
  17. #endif  
  18.     case ID_GY:  
  19.         return gyro;  
  20.       }  
  21.       return -EINVAL;  
  22.   }  
传进来的就是我们上面说的第4个参数Handle,返回的是对应的和kernel交互的类的数组下标(Sensors[acc])下标。

从上面的sensors_poll_context_t()中sensors[]的定义我们可以找到Sensors[acc]对应的值为AccSensor。

mSensors[index]->enable(handle,enabled)目的就是打开这个Sensor,里面如何打开的?linux上面不是一切兼为文件吗?就是打开对应的驱动文件嘛,所以里面的东西我们就不看了,HAL我们只分析到Sensors.cpp。

8. 扩展Sensor list

好SensorDevice里面的初始化代码走完了,回到SensorService。

[cpp] view plain copy
  1. void SensorService::onFirstRef()  
  2. {  
  3.     LOGD("nuSensorService starting...");  
  4.   
  5.     SensorDevice& dev(SensorDevice::getInstance());  
  6. ....  
  7.             if (hasGyro) {  
  8.                 // Always instantiate Android's virtual sensors. Since they are  
  9.                 // instantiated behind sensors from the HAL, they won't  
  10.                 // interfere with applications, unless they looks specifically  
  11.                 // for them (by name).  
  12.   
  13.                 registerVirtualSensor( new RotationVectorSensor() );  
  14.                 registerVirtualSensor( new GravitySensor(list, count) );  
  15.                 registerVirtualSensor( new LinearAccelerationSensor(list, count) );  
  16.   
  17.                 // these are optional  
  18.                 registerVirtualSensor( new OrientationSensor() );  
  19.                 registerVirtualSensor( new CorrectedGyroSensor(list, count) );  
  20.   
  21.                 // virtual debugging sensors...  
  22.                 char value[PROPERTY_VALUE_MAX];  
  23.                 property_get("debug.sensors", value, "0");  
  24.                 if (atoi(value)) {  
  25.                     registerVirtualSensor( new GyroDriftSensor() );  
  26.                 }  
  27.             }  
[cpp] view plain copy
  1. ......  
[cpp] view plain copy
  1. run("SensorService", PRIORITY_URGENT_DISPLAY);  
省去了很多的代码,从上面的代码可以看出如果有Gyro在Sensor List中,那么它就会注册RotationVector,Gravity,LinearAcceleration,Orientation,CorrectedGyro这些虚拟Sensor。

这些Sensor又是如何与Kernel通信的呢,我们在第七节会来分析。

最后这个run方法不得不介绍,其实SensorService是继承了Thread,而线程函数就是threadLoop,这个threadLoop在干什么呢?我们也放到第七节来讲吧!

好SensorService的初始化工作也看完了。

9、返回到SensorManager(Java)

首先它也会获取Sensor列表。

然后创建SensorEventPool和SensorThread,但这儿还没有用到,在第六节会用到。

五、获取Sensor

[cpp] view plain copy
  1. public Sensor getDefaultSensor(int type) {  
  2.     // TODO: need to be smarter, for now, just return the 1st sensor  
  3.     List<Sensor> l = getSensorList(type);  
  4.     return l.isEmpty() ? null : l.get(0);  
  5. }  
这个很简单就不用解释了。

六、注册SensorLisenter


1. new ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) 

这儿要特别说明一下,在这个构造函数中会创建一个Handler,它会在获取到Sensor数据的时候被调用。

[cpp] view plain copy
  1. mHandler = new Handler(looper) {  
  2.                 @Override  
  3.                 public void handleMessage(Message msg) {  
  4.                     final SensorEvent t = (SensorEvent)msg.obj;  
  5.                     final int handle = t.sensor.getHandle();  
  6.   
  7.                     switch (t.sensor.getType()) {  
  8.                         // Only report accuracy for sensors that support it.  
  9.                         case Sensor.TYPE_MAGNETIC_FIELD:  
  10.                         case Sensor.TYPE_ORIENTATION:  
  11.                             // call onAccuracyChanged() only if the value changes  
  12.                             final int accuracy = mSensorAccuracies.get(handle);  
  13.                             if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {  
  14.                                 mSensorAccuracies.put(handle, t.accuracy);  
  15.                                 mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);  
  16.                             }  
  17.                             break;  
  18.                         default:  
  19.                             // For other sensors, just report the accuracy once  
  20.                             if (mFirstEvent.get(handle) == false) {  
  21.                                 mFirstEvent.put(handle, true);  
  22.                                 mSensorEventListener.onAccuracyChanged(  
  23.                                         t.sensor, SENSOR_STATUS_ACCURACY_HIGH);  
  24.                             }  
  25.                             break;  
  26.                     }  
  27.   
  28.                     mSensorEventListener.onSensorChanged(t);  
  29.                     sPool.returnToPool(t);  
  30.                 }  
  31.             };  
2. sensors_create_queue


要注意一下SensorEventConnection的构造

[cpp] view plain copy
  1. SensorService::SensorEventConnection::SensorEventConnection(  
  2.         const sp<SensorService>& service)  
  3.     : mService(service), mChannel(new SensorChannel())  
  4. {  
  5. }  
SensorChannel构造://这部分还没有搞懂,这个管道的具体功能,接着往下分析希望能搞明白

[cpp] view plain copy
  1. SensorChannel::SensorChannel()  
  2.     : mSendFd(-1), mReceiveFd(-1)  
  3. {  
  4.     int fds[2];  
  5.     if (pipe(fds) == 0) {  
  6.         mReceiveFd = fds[0];  
  7.         mSendFd = fds[1];  
  8.         fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);  
  9.         fcntl(mSendFd, F_SETFL, O_NONBLOCK);  
  10.     }  
  11. }  
3. sensors_data_poll



七、Sensor的数据处理流程


八、校准

初始化校准

它都是把校准数据写在一些文件里的,qcom 7627a的路径是:

/persist/GsensorCalibrationData

/persist/MsensorCalibrationData

/persist/PSensorCalibrateData

然后在Hal中对应的Sensor的构造函数中去读数据,如P-sensor对应的TmdSensor

[cpp] view plain copy
  1. ioctl(dev_fd, TAOS_IOCTL_ALS_CALIBRATE, 0);  
  2. if((fp = fopen(PSENSOR_CALIBRATED_DATA_FILE, "r+"))!= NULL)  
  3. {  
  4.     fscanf(fp,"%d %d\n",&TaosProxCalibateData[0],&TaosProxCalibateData[1]);  
  5.     fclose( fp );  
  6.     if((TaosProxCalibateData[0] > 0) && (TaosProxCalibateData[1] < 1023) && (TaosProxCalibateData[0] < TaosProxCalibateData[1]))  
  7.         ioctl(dev_fd,TAOS_IOCTL_SET_PROX_CALIBRATE_DATA,&TaosProxCalibateData);  
  8.     else   
  9.         ioctl(dev_fd, TAOS_IOCTL_PROX_CALIBRATE, 0);  
  10. }  
  11. else  
  12. {  
  13.     ioctl(dev_fd, TAOS_IOCTL_PROX_CALIBRATE, 0);  
  14. }  
发ioctl到Tmd驱动程序中去,其实这个功能比较的简单,从TaosProxcalibateData的定义可以看出就是传一个大值和一个小值。
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:318566次
    • 积分:6730
    • 等级:
    • 排名:第3474名
    • 原创:216篇
    • 转载:1078篇
    • 译文:0篇
    • 评论:39条
    博客专栏
    文章分类
    最新评论