Sensor整体架构:

整体架构说明:
- 黄色部分表示硬件,它要挂在I2C总线上
- 红色部分表示驱动,驱动注册到Kernel的Input Subsystem上,然后通过Event Device把Sensor数据传到HAL层,准确说是HAL从Event读
- 绿色部分表示动态库,它封装了整个Sensor的IPC机制,如SensorManager是客户端,SensorService是服务端,而HAL部分是封装了服务端对Kernel的直接访问
- 蓝色部分就是我们的Framework和Application了,JNI负责访问Sensor的客户端,而Application就是具体的应用程序,用来接收Sensor返回的数据,并处理实现对应的UI效果,如屏幕旋转,打电话时灭屏,自动调接背光(这三个功能的具体实现会在以后分析)
Sensor总体调用关系图
- 本节主要解读Android的Framework层框架。
- Sensor 框架分为三个层次,客户度、服务端、HAL层,服务端负责从HAL读取数据,并将数据写到管道中,客户端通过管道读取服务端数据。

客户端主要类
SensorManager.java
:从android4.1开始,把SensorManager定义为一个抽象类,定义了一些主要的方法,该类主要是应用层直接使用的类,提供给应用层的接口SystemSensorManager.java
:继承于SensorManager,客户端消息处理的实体,应用程序通过获取其实例,并注册监听接口,获取sensor数据。sensorEventListener
接口:用于注册监听的接口sensorThread
:是SystemSensorManager的一个内部类,开启一个新线程负责读取读取sensor数据,当注册了sensorEventListener接口的时候才会启动线程android_hardware_SensorManager.cpp
:负责与java层通信的JNI接口SensorManager.cpp
:sensor在Native层的客户端,负责与服务端SensorService.cpp的通信SenorEventQueue.cpp
:消息队列
服务端主要类
SensorService.cpp
:服务端数据处理中心SensorEventConnection
:从BnSensorEventConnection继承来,实现接口ISensorEventConnection的一些方法,ISensorEventConnection在SensorEventQueue会保存一个指针,指向调用服务接口创建的SensorEventConnection对象Bittube.cpp
:在这个类中创建了管道,用于服务端与客户端读写数据SensorDevice
:负责与HAL读取数据
HAL层
Sensor.h
是google为Sensor定义的Hal接口,单独提出去
客户端读取数据
调用时序图

apk注册监听器
- Activity实现了SensorEventListener接口。在onCreate方法中,获取SystemSensorManager,并获取到加速传感器的Sensor;在onResume方法中调用SystemSensorManager,registerListenerImpl注册监听器;当Sensor数据有改变的时候将会回调onSensorChanged方法。
1 | SensorManager mSensorManager = |
初始化SystemSensorManager
系统开机启动的时候,会创建SystemSensorManager的实例,在其构造函数中,主要做了四件事情:
- 初始化JNI:调用JNI函数nativeClassInit()进行初始化
- 初始化Sensor列表:调用JNI函数sensors_module_init,对Sensor模块进行初始化。创建了native层SensorManager的实例。
- 获取Sensor列表:调用JNI函数sensors_module_get_next_sensor()获取Sensor,并存在sHandleToSensor列表中
- 构造SensorThread类:构造线程的类函数,并没有启动线程,当有应用注册的时候才会启动线程
1 | public SystemSensorManager(Context context,Looper mainLooper) { |
启动SensorThread线程读取消息队列中数据
- 当有应用程序调用registerListenerImpl()方法注册监听的时候,会调用SensorThread.startLoacked()启动线程。线程只会启动一次,并调用enableSensorLocked()接口对指定的sensor使能,并设置采样时间。 SensorThreadRunnable实现了Runnable接口,在SensorThread类中被启动。
1 | protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, |
- 在open函数中调用JNI函数sensors_create_queue()来创建消息队列,然后调用SensorManager. createEventQueue()创建。在startLocked函数中启动新的线程后,做了一个while的等待while (mSensorsReady == false),只有当mSensorsReady等于true的时候,才会执行enableSensorLocked()函数对sensor使能。而mSensorsReady变量,是在open()调用创建消息队列成功之后才会true,所以认为,三个功能调用顺序是如下:
- 调用open函数创建消息队列
- 调用enableSensorLocked()函数对sensor使能
- 调用sensors_data_poll从消息队列中读取数据,而且是在while (true)循环里一直读取
1 | boolean startLocked() { |
服务端实现
调用时序图

启动SensorService服务
- 在SystemServer进程中的main函数中,通过JNI调用,调用到
com_android_server_SystemServer.cpp
的android_server_SystemServer_init1()
方法,该方法又调用system_init.cpp中的system_init()
,在这里创建了SensorService的实例。
1 | extern "C" status_t system_init() |
SensorService初始化
- SensorService创建完之后,将会调用SensorService::onFirstRef()方法,在该方法中完成初始化工作。首先获取SensorDevice实例,在其构造函数中,完成了对Sensor模块HAL的初始化:
1 | SensorDevice::SensorDevice() |
这里主要做了三个工作:
- 调用HAL层的hw_get_modele()方法,加载Sensor模块so文件
- 调用sensor.h的sensors_open方法打开设备
- 调用sensors_poll_device_t->activate()对Sensor模块使能
再看看SensorService::onFirstRef()方法:
1 | void SensorService::onFirstRef() |
在这个方法中,主要做了4件事情:
- 创建SensorDevice实例
- 获取Sensor列表
- 调用SensorDevice.getSensorList(),获取Sensor模块所有传感器列表
- 为每个传感器注册监听器
registerSensor(new HardwareSensor(list[i]))
;
1 | void SensorService::registerSensor(SensorInterface* s) |
- HardwareSensor实现了SensorInterface接口。启动线程读取数据,调用run方法启动新线程,将调用SensorService::threadLoop()方法。
在新的线程中读取HAL层数据
- SensorService实现了Thread类,当在onFirstRef中调用run方法后,将在新的线程中调用
SensorService::threadLoop()
方法。在while循环中一直读取HAL层数据,再调用SensorEventConnection->sendEvents
将数据写到管道中。
1 | bool SensorService::threadLoop() |
客户端与服务端通信
数据传送
- 客户端与服务端通信的状态图:

- 客户端服务端线程,在图中可以看到有两个线程:
- 一个是服务端的一个线程,这个线程负责源源不断的从HAL读取数据。
- 另一个是客户端的一个线程,客户端线程负责从消息队列中读数据。
- 创建消息队列,客户端可以创建多个消息队列,一个消息队列对应有一个与服务器通信的连接接口
- 创建连接接口,服务端与客户端沟通的桥梁,服务端读取到HAL层数据后,会扫面有多少个与客户端连接的接口,然后往每个接口的管道中写数据
- 创建管道,每一个连接接口都有对应的一个管道。
- 上面是设计者设计数据传送的原理,但是目前Android上面的数据传送不能完全按照上面的理解。因为在实际使用中,消息队列只会创建一个,也就是说客户端与服务端之间的通信只有一个连接接口,只有一个管道传数据。那么数据的形式是怎么从HAL层传到JAVA层的呢?其实数据是以一个结构体sensors_event_t的形式从HAL层传到JNI层。看看HAL的sensors_event_t结构体:
1 | typedef struct sensors_event_t { |
- 在JNI层有一个ASensorEvent结构体与sensors_event_t向对应,frameworks/native/include/android/sensor.h:
1 | typedef struct ASensorEvent { |
交互调用时序图

- 经过前面的介绍,现在知道了客户端实现的方式及服务端的实现,但是没有具体讲到它们是如何进行通信的,现在看看客户端与服务端之间的通信。
- 主要涉及的是进程间通信,有IBind和管道通信。
- 客户端通过IBind通信获取到服务端的远程调用,然后通过管道进行sensor数据的传输。
服务端
- native层实现了sensor服务的核心实现,Sensor服务的主要流程的实现在sensorservice类中,下面重点分析下这个类的流程。
1 | class SensorService : |
- 看看sensorService继承的类:继承BinderService
这个模板类添加到系统服务,用于Ibinder进程间通信。
1 | template<typename SERVICE> |
在前面的介绍中,SensorService服务的实例是在System_init.cpp中调用SensorService::instantiate()创建的,即调用了上面的instantiate()方法,接着调用了publish(),在该方法中,我们看到了new SensorService的实例,并且调用了defaultServiceManager::addService()将Sensor服务添加到了系统服务管理中,客户端可以通过defaultServiceManager:getService()获取到Sensor服务的实例。
继承BnSensorServer这个是sensor服务抽象接口类提供给客户端调用:
1 | class Sensor; |
- ISensorServer接口提供了两个抽象方法给客户端调用,关键在于createSensorEventConnection()方法,该在服务端被实现,在客户端被调用,并返回一个SensorEventConnection的实例,创建连接,客户端拿到SensorEventConnection实例之后,可以对sensor进行通信操作,仅仅作为通信的接口而已,它并没有用来传送Sensor数据,因为Sensor数据量比较大,IBind实现比较困难。真正实现Sensor数据传送的是管道,在创建SensorEventConnection实例中,创建了BitTube对象,里面创建了管道,用于客户端与服务端的通信。
客户端
- 时序图:

- 客户端主要在SensorManager.cpp中创建消息队列:
1 | class ISensorEventConnection; |
- SensorEventQueue类作为消息队列,作用非常重要,在创建其实例的时候,传入了SensorEventConnection的实例,SensorEventConnection继承于ISensorEventConnection。SensorEventConnection其实是客户端调用SensorService的createSensorEventConnection()方法创建的,它是客户端与服务端沟通的桥梁,通过这个桥梁,可以完成一下任务:
- 获取管道的句柄
- 往管道读写数据
- 通知服务端对Sensor使能
流程解析
客户端获取SensorService服务实例
- 客户端初始化的时候,即SystemSensorManager的构造函数中,通过JNI调用,创建native层SensorManager的实例,然后调用SensorManager::assertStateLocked()方法做一些初始化的动作。
1 | status_t SensorManager::assertStateLocked() const { |
- 前面我们讲到过,SensorService的创建的时候调用了defaultServiceManager:getService()将服务添加到了系统服务管理中。现在我们又调用defaultServiceManager::geService()获取到SensorService服务的实例。在通过IBind通信,就可以获取到Sensor列表,所以在客户端初始化的时候,做了两件事情:
- 获取SensorService实例引用
- 获取Sensor传感器列表
注册SensorLisenter
- 时序图:

new ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler)
在这个构造函数中会创建一个Handler,它会在获取到Sensor数据的时候被调用。
1 | mHandler = new Handler(looper) { |
创建消息队列
- 时序图:

当客户端第一次注册监听器的时候,就需要创建一个消息队列,也就是说,android在目前的实现中,只创建了一个消息队列,一个消息队列中有一个管道,用于服务端与客户断传送Sensor数据。
在SensorManager.cpp中的createEventQueue方法创建消息队列:
1 | sp<SensorEventQueue> SensorManager::createEventQueue() |
- 客户端与服务器创建一个
SensorEventConnection
连接接口,而一个消息队列中包含一个连接接口。创建连接接口:
1 | sp<ISensorEventConnection> SensorService::createSensorEventConnection() |
- 关键在于BitTube,在构造函数中创建了管道:
1 | BitTube::BitTube() |
- 其中:fds[0]就是对应的mReceiveFd,是管道的读端,sensor数据的读取端,对应的是客户端进程访问的。fds[1]就是对应mSendFd,是管道的写端,sensor数据写入端,是sensor的服务进程访问的一端。通过pipe(fds)创建管道,通过fcntl来设置操作管道的方式,设置通道两端的操作方式为O_NONBLOCK ,非阻塞IO方式,read或write调用返回-1和EAGAIN错误。总结下消息队列,客户端第一次注册监听器的时候,就需要创建一个消息队列,客户端创了SensorThread线程从消息队列里面读取数据。SensorEventQueue中有一个SensorEventConnection实例的引用,SensorEventConnection中有一个BitTube实例的引用。
使能Sensor
- 客户端创建了连接接口SensorEventConnection后,可以调用其方法使能Sensor传感器:
1 | status_t SensorService::SensorEventConnection::enableDisable( |
- handle对应着Sensor传感器的句柄
服务端往管道写数据
1 | bool SensorService::threadLoop() |
前面介绍过,在SensorService中,创建了一个线程不断从HAL层读取Sensor数据,就是在threadLoop方法中。
关键在与下面了一个for循环,其实是扫描有多少个客户端连接接口,然后就往没每个连接的管道中写数据
1 | status_t SensorService::SensorEventConnection::sendEvents( |
- 调用该连接接口的BitTube::write(),到此,服务端就完成了往管道的写端写入数据:
1 | ssize_t BitTube::write(void const* vaddr, size_t size) |
客户端读管道数据
- 时序图:

1 | ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents) |
- 调用到了BitTube::read():
1 | static ssize_t recvObjects(const sp<BitTube>& tube, |