对SensorService类的作用的理解:

SensorService是android的sensor方面相关核心的类,其实是android系统SystemServer中的一个,是在android系统运行SystemServer时会自动运行起来,其实就是创建了一个线程,用来专门处理sensor相关的数据从hal到app(client)的传输以及对sensor的控制等功能。

下面对SensorService类的架构分析。

SensorService的作用主要是沟通app和底层hal的桥梁。我的理解是这样的。大概的连接图如下:

如上图,SensorService与HAL和client的沟通通过的是抽离出来的SensorDevice和SensorEventConnection两个类,sensordevice是hal与sensorservice之间,SensorEventConection是client和sensorservice之间。

所以Sensorservice类相当于控制中心,负责调度管理contrl SensorEventConnection和sensordevice的工作,真正具体的怎么实现交由这两个具体实现。那么其实SensorEventConnetion和sensordevice是sensorservice与上下层之间沟通的interface。

这样的架构功能划分很清楚,以及各个模块之间的独立性很好,也很方便将来对于部分模块的修改与代码维护。

下面具体的来看看:

Sensorservice必须实体化一些上面的interface的具体对象,所以sensorservice定义一些容器来存储相关的对象。

1.    数据容器存放所有sensor相关对象

Vector<Sensor> mSensorList; //sensor对象容器//handle与与之对应的sensor对象指针的map容器//SensorInterface内封装的sensorDefaultKeyedVector<int,SensorInterface*> mSensorMap;Vector<SensorInterface *>mVirtualSensorList;//记录与sensorservcie连接的sensor对象容器DefaultKeyedVector<int,SensorRecord*> mActiveSensors;//记录与sensorservcie连接的virtual sensor对象容器DefaultKeyedVector<int,SensorInterface*> mActiveVirtualSensors;//记录client与sensorservice连接的SensorEventConnectionSortedVector< wp<SensorEventConnection>> mActiveConnections;

2.所有sensor对象的获取方式

前面说过SensorService与hal层的沟通通过SensorDevice,因此获取sensor对象 就必须实例化一个sensordevice对象。在sensorservice的onFirstref函数中:

 voidSensorService::onFirstRef(){LOGD("nuSensorService starting...");SensorDevice& dev(SensorDevice::getInstance());   if (dev.initCheck() == NO_ERROR) {sensor_t const* list;ssize_t count = dev.getSensorList(&list);if (count > 0) {ssize_t orientationIndex = -1;bool hasGyro = false;uint32_t virtualSensorsNeeds =(1<<SENSOR_TYPE_GRAVITY) |(1<<SENSOR_TYPE_LINEAR_ACCELERATION) |(1<<SENSOR_TYPE_ROTATION_VECTOR);mLastEventSeen.setCapacity(count);for (ssize_t i=0 ; i<count ; i++) {registerSensor( newHardwareSensor(list[i]) );switch (list[i].type) {caseSENSOR_TYPE_ORIENTATION:orientationIndex = i;break;case SENSOR_TYPE_GYROSCOPE:hasGyro = true;break;}}// build the sensor list returned to usersmUserSensorList = mSensorList;if (hasGyro && (virtualSensorsNeeds &(1<<SENSOR_TYPE_ROTATION_VECTOR))) {if(orientationIndex >= 0) {                 mUserSensorList.removeItemsAt(orientationIndex);}}run("SensorService",PRIORITY_URGENT_DISPLAY);mInitCheck = NO_ERROR;}}} 

首先调用SensorDevice&dev(SensorDevice::getInstance());得到一个dev对象,调用dev的方法getSensorList(&list);获取sensor所有对象给list。然后调用registerSensor函数将所有sensor对象加入到sensor容器中,如下:

for (ssize_t i=0 ; i<count ; i++) {

registerSensor( new HardwareSensor(list[i]));

看看registerSensor的具体内容:

voidSensorService::registerSensor(SensorInterface* s)

{

sensors_event_t event;

memset(&event, 0, sizeof(event));

constSensor sensor(s->getSensor());

// add to the sensor list (returned to clients)

mSensorList.add(sensor);

// add to our handle->SensorInterfacemapping

mSensorMap.add(sensor.getHandle(), s);

// create an entry in the mLastEventSeenarray

mLastEventSeen.add(sensor.getHandle(),event);

}

可以看到是将所有sensor对象获取逐一添加到容器中。

这里面registerSesnor函数传入的参数不是直接传的sensor对象,

而是传的Sensorinterface,然后函数内部再通过Sensorinterface的getsensor对象获取sensor。一下是整个sensors获取的架构图:

我对上面sensors的获取架构的理解:

其实sensorService从hal层获取sensors还是通过Sensordevice,但是中间经过一个SensorInterface,这个其实就是对Sensor的一个处理,参看SensorInterface.cpp的源码中Hardware类就可以知道,

其实Hardware中只是对所有的sensor对象做了一个简单处理,比如获取handler,name等,然后将SensorInterface和Sensor分别都存入两个容器中,而且两个容器中的sensor和sensorInterface其实是一一对应上的。构建SensorInterface,主要是便于后面对Sensor的各种简单的处理,通过调用SensorInterface的一些统一封装好的函数。便于对sensor的统一处理,比如说在registerSensor中通过gethandler获取到handler,这就是便于日后handler与sensor的匹配。

3.    数据event的处理

SensorService类继承Thread类,其中在onFirestRef函数中最后run一个线程,这个线程专门是用来管理从hal层获取sensor_event_t的。在threadLoop()函数中:

bool SensorService::threadLoop(){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);if (count<0) {LOGE("sensor poll failed(%s)", strerror(-count));break;}recordLastValue(buffer, count);// handle virtual sensorsif (count && vcount) {sensors_event_t const * constevent = buffer;const DefaultKeyedVector<int,SensorInterface*> virtualSensors(getActiveVirtualSensors());const size_t activeVirtualSensorCount = virtualSensors.size();if (activeVirtualSensorCount){size_t k = 0;SensorFusion&fusion(SensorFusion::getInstance());if (fusion.isEnabled()) {for (size_t i=0 ;i<size_t(count) ; i++) {fusion.process(event[i]);}}for (size_t i=0 ; i<size_t(count) ; i++) {for (size_t j=0 ;j<activeVirtualSensorCount ; j++) {sensors_event_t out;if (virtualSensors.valueAt(j)->process(&out, event[i])) {buffer[count + k] = out;k++;}               }}if (k) {// record the last synthesized valuesrecordLastValue(&buffer[count], k);count += k;// sort the buffer by time-stampssortEventBuffer(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);}}}while (count >= 0 || Thread::exitPending());LOGW("Exiting SensorService::threadLoop!");return false;}

SensorDevice&device(SensorDevice::getInstance());同样实例化一个SensorDevice device,然后调用device的poll方法如下,

count = device.poll(buffer, numEventMax);来获取从hal的event,将event放入临时buffer中。中间通过fusion类的一些处理函数处理,通过对fusion类的源码分析,它主要做的是对从hal层传递过来的数据做些过滤和检查处理,然后调用 sortEventBuffer(buffer, count);将所有有效sensor_event_t按time-stamps排序好准备发给client。那么这个是如何发送给client,当然就是前面说的SensorEventConnection模块。看看代码:

//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);

}

}

可以看到首先是获取到所有与sensorservice有效连接的client对应的ensorEventConnection,然后通过调用sendEvents将所有buffer中的events发给client。架构图如下:

整个data相关event传递的架构是很完美也很清晰的我感觉。

整个过程就好像是一个寄邮件的过程,而sensorservice就相当于中间的快递公司,而sensordevice和sensorEventConnetcion就好比是收邮件和派送邮件的两个快递员,快递公司sensorService不管发送两个快递员sensordevice和sensorEventConnetcion具体收和送的具体实现细节,只是发个命令让他们接和送。

这样的架构很清晰,分工很明确,这样也很好的屏蔽封装了sensorservice和client之间通信传递数据的具体细节,这样安全性和维护性更好,功能模块之间独立性比较好,不互相影响。

可以看看sensorEventConnection的源码:

class SensorEventConnection : publicBnSensorEventConnection {

virtual ~SensorEventConnection();

virtual void onFirstRef();

virtual sp<SensorChannel> getSensorChannel() const;

virtual status_t enableDisable(int handle, bool enabled);

virtual status_t setEventRate(int handle, nsecs_t ns);

sp<SensorService> const mService;

sp<SensorChannel> const mChannel;

mutable Mutex mConnectionLock;

// protected by SensorService::mLock

SortedVector<int> mSensorInfo;

public:

SensorEventConnection(const sp<SensorService>& service);

status_t sendEvents(sensors_event_t const* buffer, size_t count,

sensors_event_t* scratch = NULL);

bool hasSensor(int32_t handle) const;

bool hasAnySensor() const;

bool addSensor(int32_t handle);

bool removeSensor(int32_t handle);

};

SensorEvenConnection内部其实主要是定义有与之对应的SensorChanel和SensorService,而sensorChanel则是sensorEventConnection和client之间的沟通桥梁,sensorservice先将event传给sensorEventConnection,再由sensorEventConnection通过SensorChanel给client,具体可以看看sendEvents方法源码,其中有这么一句:

ssize_t size =mChannel->write(scratch,count*sizeof(sensors_event_t));

可以看到原来SensorChannel是调用它的write将event传给client的。通过查看sensorchannel的源码,我发现sensorchannel是通过管道将event给client。

4.    sensor的控制

从sensorEventConnection的enabledisable()方法可以看到它其实是调用sensorservice的enable和disable函数,而sensorservice函数则是调用sensor的active等sensor的开关函数。

5.    类sensorRecord

先看看类sensorrecord的定义:

class SensorRecord {

SortedVector<wp<SensorEventConnection> > mConnections;

public:

SensorRecord(constsp<SensorEventConnection>& connection);

bool addConnection(const sp<SensorEventConnection>&connection);

bool removeConnection(constwp<SensorEventConnection>& connection);

size_tgetNumConnections() const { return mConnections.size(); }

};

从它的定义中可以看出来它主要负责的是sensorService对SensorEveentConnection容器list记录维护与控制,即对connections的增删等。

Sensorservice将这个功能块也独立出来,以一个独立的累得方式来处理所有connection的list记录。这是一种很好的方式。将所有关于connections的操作集中起来,将方法的一种归类。

6.关于Virtual sensor

在SebsorService中,你会看到几个虚拟sensor,GravitySensor,LinearAccelerationSensor,RotationVectorSensor,所谓虚拟sensor就是不是物理上真实存在的,像accsensor那样硬件实实在在存在的,而是逻辑上有的,就是通过实实在在存在的sensor加上一些逻辑上运算得到的sensor。

对于它们的处理sensorService其实是视为和其它物理sensor一样处理,不过和其它物理上真实存在的sensor不同的是它的数据获取不是通过硬件从外界获取,而是在现有这些物理传感器的得到的数据上进行一些处理从而得到自己的数据。

所以在SensorService.cpp同一层目录下,andorid分别为山歌虚拟sensor写了自己的class,让他们都继承sensorInterface类,分别实现自己的process函数,这个函数内部其实就是对物理传感器获取到的数据做的逻辑上的处理,得到自己的数据。这可以看源码就知道。看其中一个的的源码:

bool LinearAccelerationSensor::process(sensors_event_t*outEvent,

constsensors_event_t& event)

{

bool result =mGravitySensor.process(outEvent, event);

if (result) {

if(event.type == SENSOR_TYPE_ACCELEROMETER) {

mData[0] = event.acceleration.x;

mData[1] = event.acceleration.y;

mData[2] = event.acceleration.z;

}

outEvent->data[0] = mData[0] -outEvent->data[0];

outEvent->data[1] = mData[1] -outEvent->data[1];

outEvent->data[2] = mData[2] -outEvent->data[2];

outEvent->sensor = '_lin';

outEvent->type =SENSOR_TYPE_LINEAR_ACCELERATION;

}

return result;

}

可以看到 LinearAccelerationSensor的data是在mData 减去acc sensor的x,y,z。在sensorservice的threadloop函数中可以看到都调用了process函数处理了数据。

for (size_t j=0 ;j<activeVirtualSensorCount ; j++) {

sensors_event_t out;

if(virtualSensors.valueAt(j)->process(&out, event[i])) {

buffer[count+ k] = out;

k++;

}

}

在sensorservice的onFirstRef函数中,

利用函数registerVirtualSensor函数分别将三个虚拟sensor添加到sensorservice的 mActiveVirtualSensors和mActiveSensors等容器中,便于后面发给client。

7.    总体架构总结

最后从整体上对sensorservice的架构做出总结。

SensorService architechure’ note相关推荐

  1. Android Senor Framework (三)SensorService启动

    SystemServer 启动SensorService Zygote启动之后,调用SystemServer的main方法(调用run方法)启动系统服务: 代码路径: ./frameworks/bas ...

  2. Paddle Release Note

    Paddle Release Note 重要更新 飞桨paddle框架2.0.0版本有如下重要更新: • 编程范式:默认开启动态图模式进行模型开发和训练,通过动转静的方式进行模型部署和训练加速.如果需 ...

  3. 机器学习与高维信息检索 - Note 7 - 核主成分分析(Kernel Principal Component Analysis,K-PCA)

    Note 7 - 核主成分分析(Kernel Principal Component Analysis) 核主成分分析 Note 7 - 核主成分分析(Kernel Principal Compone ...

  4. 机器学习与高维信息检索 - Note 6 - 核, 核方法与核函数(Kernels and the Kernel Trick)

    Note 6 核, 核方法与核函数 到目前为止,我们所讨论的机器学习算法的成功都依赖于对输入数据分布的假设.例如,PCA的效果越好,数据围绕线性子空间分布.或者在线性判别分析中,我们假设类的高斯分布, ...

  5. ADPRL - 近似动态规划和强化学习 - Note 10 - 蒙特卡洛法和时序差分学习及其实例 (Monte Carlo and Temporal Difference)

    Note 10 蒙特卡洛法和时序差分学习 Monte Carlo and Temporal Difference 蒙特卡洛法和时序差分学习 Note 10 蒙特卡洛法和时序差分学习 Monte Car ...

  6. 机器学习与高维信息检索 - Note 5 - (深度)前馈神经网络((Deep) Feedforward Neural Networks)及基于CVXOPT的相关实例

    Note 5 - (深度)前馈神经网络((Deep) Feedforward Neural Networks)及相关实例 5.1 FNN的定义和动机 粗略地说,前馈神经网络(FNN)是一种特殊的函数类 ...

  7. ADPRL - 近似动态规划和强化学习 - Note 8 - 近似策略迭代 (Approximate Policy Iteration)

    Note 8 近似策略迭代 Approximate Policy Iteration 近似策略迭代 Note 8 近似策略迭代 Approximate Policy Iteration 8.1 通用框 ...

  8. 机器学习与高维信息检索 - Note 4 - 主成分分析及其现代解释(Principal Component Analysis, PCA)及相关实例

    主成分分析及其现代解释 4. 主成分分析及其现代解释 Principal Component Analysis and Its Modern Interpretations 4.1 几何学解释 The ...

  9. ADPRL - 近似动态规划和强化学习 - Note 7 - Approximate Dynamic Programming

    Note 7 - 近似动态规划 Approximate Dynamic Programming 7. 近似动态规划 (Approximate Dynamic Programming) 7.1 近似架构 ...

最新文章

  1. CSS实现跨浏览器兼容性的盒阴影效果
  2. 浅谈 PHP 神盾的解密过程
  3. 美团2015校招哈尔滨站笔试题--第二题
  4. XFire WebService demo
  5. Vue.extend
  6. 驱动精灵2007_畅玩Steam的Win10游戏掌机发布! |莱莎2新战斗动画,肉腿致命驱动~...
  7. vs 无法解析变量$_C语言新手常见错误(Vs使用,语法...),绝对直击痛点
  8. java jsf_将Java 8日期时间API与JSF和Java EE 7结合使用
  9. 工作338:pc重置筛选条件
  10. 硬盘快速格式化和格式化的区别
  11. 经典计算机实现量子逻辑门,量子计算机:对量子逻辑门的探讨
  12. 物联网卡得持续增长对企业带来怎样的挑战
  13. 目标检测工具安装使用--labelImg
  14. 世界杯:裁判看了视频后判罚更重?
  15. window自带字体
  16. 联通机顶盒显示网络服务器超时,中国联通机顶盒验证失败一开启就这样该怎么办...
  17. 手机如何使用USSD命令设置呼叫转移
  18. 机器学习(埋坑)—— 概念学习(Concept Learning)
  19. [深度学习概念]·CNN网络架构演进:从LeNet到DenseNet(代码实现基于Keras)
  20. go语言能开发什么?go语言开发案例

热门文章

  1. 荐书 | 2021年1季度我读过的十本好书!
  2. MySQL数据库单词
  3. 转:盖子法则:领导力的边界
  4. 网站性能优化实战——从12.67s到1.06s的故事
  5. 零基础转行IT,是学Java、C++、Linux和Web前端哪个好?
  6. DALI标准协议分享
  7. ArcGIS如何使用菜单栏的快捷键
  8. FlieBeat Kafka Clickhouse 替代ELK 系列一
  9. 根据url,本地文件下载
  10. 【艾特淘】店铺直播玩法全攻略,快速提升流量转化