文章目录[隐藏]
前言
换工作在即,也有了难得的一段空闲时间做下总结。接下来计划分别介绍下Android的Sensor/Touch/Camera/Binder的Software架构,如果还有时间就总结下kernel。
Sensor属于Android相对简单的一个模块,但麻雀虽小,五脏俱全,以此来作为切入点对理解整个Android系统有很大帮助。必须要说的是,Android系统的整体架构并不适用于所有模块,每个模块都有各自的特殊性,请不要一开始就把某些介绍当作公式。
1、Sensor架构试用范围
很多模块都可以称为Sensor,Touch是一种Sensor,Camera也可以理解为一种Sensor。但这里介绍的Sensor架构并不适用于Touch和Camera,所使用的主要包含下面几类Sensor。
Category |
Components |
Motion Sensors |
Accelerameter/ Gravity/ Gyroscope/ Rotation Vector/… |
Environmental Sensors |
ALS/ Pressure/… |
Position Sensors |
Orientation/ Mag/… |
这几类器件有几个相似的特点,产生的数据量少,实时性较强,构造相对简单。
2、整体架构
首先从整体上,Sensor的架构可以用下图来解释。
有些分法把SensorService归为Framework的一部分,但这里为了凸显出Service的重要性单独分为一层。
Sensor的整体逻辑非常清晰,一个控制流(蓝色向下箭头),一个数据流(红色向上箭头)。控制主要包括开关Sensor,设置Sensor的采样频率,数据流则是数据从驱动到应用的整个过程。
3、初始化
系统初始化过程中,SensorService和HAL层(硬件抽象层)会进行初始化操作。SensorService连接着Framework和HAL,它采用动态链接加载HAL层模块(HAL层以so共享文件的形式存在)。
//动态链接的匹配 hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&mSensorModule); //Service |
struct sensors_module_t my_hal = { common: { … id: SENSORS_HARDWARE_MODULE_ID, … }, get_sensors_list: …, }; //HAL |
一句话概括该过程的目的就是,经过动态链接,Service可以调用HAL层的函数,方便将控制传递至HAL层,也可以从HAL获取数据。完成该动作后,Service调用my_hal内的open函数。HAL可以在open动作中完成初始化,如检测系统中存在的Sensor,保存每个Sensor的信息,维护一个所有的Sensor的列表。
HAL初始化后,Service即可调用get_sensors_list获取系统所支持的所有Sensor。某些物理Sensor组合后,可以虚拟出其他Sensor,Service也会针对虚拟Sensor做处理,这部分暂不介绍。
一句话总结,与HAL建立联系(动态链接),HAL初始化(open),获取Sensor信息(get_sensors_list)。
4、控制流
控制,一是开关,二是频率,Android默认支持四种采样频率。
名称 |
频率 |
SENSOR_DELAY_FASTEST |
器件的最大采样频率 |
SENSOR_DELAY_GAME |
50HZ |
SENSOR_DELAY_UI |
30HZ |
SENSOR_DELAY_NORMAL |
5HZ |
除了这四种频率以外,用户也可以指定一个特定频率。控制的流程如下。
控制从APP注册监听器开始,熟悉面向对象程序设计的童鞋应该可以猜得到这是一个观察者设计模式,实际上也确实如此。注册监听器的直接操作就是enable和setDelay两个操作(unregisterListener则对应disable操作),Service与APP并不是执行在同一个进程内的,Framework传递来的控制需要通过进程通信传递至Service,使用的就是Binder(Binder几乎贯穿了Android系统的各个模块,后面介绍)。Service是唯一的,APP可以有无限个,Service为它们服务。这样设计的原因显而易见——保证单一控制:硬件是唯一的(比如某一个加速度Sensor),对它的控制也应该是唯一的,不应该由各APP单独控制。比如enable操作,如果已经有APP打开了设备,那么只需要将引用计数增加1即可,并不会真正的触发驱动的操作;disable操作,如果引用计数大于1,说明当前除了该APP,还有其他使用者,那么也不会触发驱动的操作。
Service与HAL层属于同一个进程,Service调用HAL层的函数,HAL找到对应的文件节点,根据不同的目的写入不同的值来触发驱动的操作。驱动根据得到的指令,读写设定好的寄存器控制流就得到了最终的落实。
一句话总结,应用开启控制流,层层传递,最终读写寄存器。
5、数据流
数据由硬件产生,最终被应用使用,流程如下图。
驱动负责收集数据(中断或者轮询模式),通过input子系统(也有部分厂商选择使用IIO)上报数据。HAL层使用poll监控input节点,数据到来后poll返回,然后读取数据。Service部分有一个线程,该线程可以理解为一个循环,不断地poll HAL层的数据。收到数据后,Service会做一些处理(比如计算虚拟Sensor的数据),之后则通过socket将数据发送至APP进程。APP收到数据后,遍历当前已经注册的listener,通知它们,观察者模式完成。
与控制流相同,数据流依然是一个Service对应多个APP,Service会将数据发送到多个APP。
说到这里,有个地方可以优化下。目前Service收到数据后,会通知所有的已经注册了listener的APP,这个过程并不是没有代价的,除了正常的执行代码外,还涉及了进程通信。如果给APP添加一个感兴趣的Sensor类型的列表(bitmap也可),只有列表内的Sensor的数据到来才会通知该APP进程,会高效的多。
6、各层次介绍
形象一点讲,整个Sensor的软件架构就像是水泵抽水灌溉。Service扮演电机的角色,它不断的产生抽水的动力,并将水输送至目的地(APP),驱动扮演泵的角色,它负责完成抽水的必要准备并抽水,HAL则很像是连接电机和泵的管道。
driver可以逻辑上分为三部分,如下图。一部分支持它本身的功能,i2c读写,中断或者轮询处理。第二部分为sysfs文件节点,接受HAL层传递下来的操作,通过i2c读写完成任务。第三部分为input子系统(注意,该处为Linux内核的input子系统,并不是Android的input系统),负责数据上报。
一句话,driver的任务就是正常工作,完成控制操作,产生数据。
HAL层的作用一是屏蔽硬件差异,二是传递控制和数据。
SensorService本身就是一个线程(Thread为其父类),不出意外它循环地执行threadLoop(Android的机制),该函数一方面负责poll数据,一方面得到数据后处理,发送。
到了Framework,问题就简单了,简单的函数调用(最多涉及到jni)。
本文仅阐释了整个框架,并未罗列出详细的代码,希望给出一个全局的介绍。
博客得来终觉浅,只因码上才能见真知。若有任何疑问或者希望下一篇博客的内容介绍哪部分请直接留言或发邮件至邮箱(我的用户名@onesixthree邮箱)。