一、问题现象
先遮盖P-Sensor,然后拨打电话,90%的情况下屏幕无法自动关闭背光显示。关闭Settings-》Display-》Brightness-》Auto,然后再执行以上操作则100%能够正常关闭背光显示。
Platform:MT6732
Android版本:4.4KK
BuildType:user
系统软件版本:SWA1H+UM
系统RAM:1GB
参考机行为:参考机1正常,参考机2正常
二、MTK平台Android的Sensor流程框架
整个流程框架主要分为6个部分:
1,APPLICATIONS
这里主要是指Dialer/PhoneApp,他们是用户直接操作的接口,他们使用了P-Sensor来进行亮屏和灭屏的操作(通过向PowerManagerService请求PROXIMITY_SCREEN_OFF_WAKE_LOCK实现)。
2, FRAMEWORKS(JAVA)
主要包括两部分:
一、PowerManager/PowerManagerService,其作用是提供PROXIMITY_SCREEN_OFF_WAKE_LOCK,并与SensorManager/SystemSensorManager交互。
二、SensorManager/ SystemSensorManager,其作用是提供JAVA层控制sensor的接口,并透过JNI与Native的SensorManager通信。
3,FRAMEWORKS(JNI)
这里主要是是指SensorManager JNI,其主要作用是提供接口给SensorManager/SystemSensorManager与NatvieLibs的SensorManager通信。
4,FRAMEWORKS(LIBS/NativeService)
主要包括两部分:
一、SensorManager/SensorEventQueue,其属于NativeLibs,主要作用是为SensorManager JNI提供接口,请求SensorService创建SensorEventQueue(基于Binder的IPC),从而完成SensorEvent从SensorService到SensorManager JNI的传输。
二、Sensorservice/sensordevice,其属于NativeService,主要作用是为上层提供接口createSensorEventConnection,与Sensor的HAL层进行交互,控制sensor以及获取sensorEvent。
5,HAL
这里主要是指Nusensors和Hwmsen,其主要功能是为SensorService提供接口,与Sensor的Driver层进行交互,从而达到控制Sensor和获取SensorEvent的目的。
这里主要包括两大部分:
一、hwmsen_dev/StandardInputDevice,这部分是在具体的SensorDriver的上面又抽象出的一层,其主要功能是集中处理不同类型的sensor,包括lightsensor,proximitysensor等。
二、PROXIMITY/LIGHT(stk3x1x-new)等,这部分是指具体的SensorDriver,其主要功能是与具体的Sensor交互,包括控制、获取数据并上报等。这里有一点需要说明的是,Sensor分两种:一种是interrupt sensor,一种是polling sensor,他们的区别在于interrupt sensor是直接挂接在特定的中断上的,一旦sensor有数据就会触发中断处理(我们的PROXIMITYsensor就属于interrupt sensor),polling sensor是被动的提供数据,抽象出的hwmsen_dev会按照一定频率定时的去获取它的数据(我们的LIGHTsensor就属于polling sensor)。
三、问题分析
1、初步分析
根据问题在遮住p-sensor的情况下拨打电话无法灭屏的表面现象,我们首先考虑的是p-sensor硬件有没有产生数据并报给Driver,为了确认这一点我们首先在p-sensor的Driver中添加log:
然后执行操作,打出的log如下:
以上log中value 0x0,代表p-sensor的接近,0x1代表p-sensor的远离,所以说明硬件已经将p-sensor的数据上报到了SensorDriver中,SensorDriver又将数据上报到了driver抽象层hwmsen_dev/StandardInputDevice中,接下我们就要看driver抽象层是否将p-sensor的数据正确上报到了HAL。Nusensor.cpp中的关键代码如下:
以上部分代码是HAL中轮询所有sensor并获取event,其中就包括p-sensor,另外这里有一个很关键的data type,就是SENSOR_TYPE_META_DATA,下面会具体说明它的作用,同时说明一下这里的轮询的实现代码是通过读取StandardInputDevice的节点("/dev/input/event%d", num)来实现的。
在轮询完所有的sensor之后,如果还有空间没有用完就继续poll在sensor的data_fd上去继续获取event以填充完一次获取,然后返回给上层的sensorservice。使用同样的方法再这些代码流中添加log,以获取运行时的数据状态,发现p-sensor的数据同样正确的获取到了,这里就不再赘述。
接下来继续分析sensorservice中的数据流向,看是否正确上报到了SensorManager/SensorEventQueue中,sensorservice的关键代码如下:
首先,从代码中我们看到sensorservice继承于Thread,所以其本身是一个Thread并拥有一个闭合循环的threadloop,不断的从sensor的HAL中读取数据,通过添加log信息,发现在以后代码中p-sensor的数据依然被正确的获取到。
其次,读取完数据之后它会向当前所有连接到sensorservice的client发送sensorEvent,在以上代码中加上发送之前的log打印出p-sensor的数据依然存在。
然后,是具体的发送到client之前的处理代码,我们继续再其中添加log,发现在处理之前p-sensor的数据都是存在的,具体代码如下:
最后,是最终将处理完的数据发送到client的代码,我们在发送之前添加log,最终发现打印出的log中p-sensor的数据已经不存在了,具体代码如下:
2、继续分析
根据以上分析我们发现在被sendEvents处理之前,p-sensor的数据还存在,处理之后在发送之前p-sensor的数据已经被过滤掉,我们可以初步将问题的关键定位在处理过程中。
通过阅读和分析其处理过程的代码,发现了一个关键条件,就是如果sensor的数据想要被最终发送,必须满足mSensorInfo[index].mFirstFlushPending == false的条件,而这个条件满足的前提是当前这个SensorEventConnection必须先接收到SENSOR_TYPE_META_DATA,将mSensorInfo[index].mFirstFlushPending置为false,然后再接收到的具体sensor数据才能被最终发送出去。
根据初步分析的过程中添加的log,我们发现SENSOR_TYPE_META_DATA在sensor的数据流中是存在,但是却是在具体的sensor数据之后,从而导致具体的sensor数据被忽略(这里指是p-sensor的靠近数据)。
通过分析代码我们发现SENSOR_TYPE_META_DATA是sensor被enable之后发出的第一个first flush event,应当在具体的sensor数据之前,enable的关键代码如下:
首先batch,然后setFirstFlushPending为true并flush,在alto4.5TMO中这些操作就会为BatchSensor产生SENSOR_TYPE_META_DATA奠定基础。
最终会走到activate,将sensor真正enable,enable之后sensor会马上产生中断并上报数据,这里p-sensor的数据产生的地方是来自于Hwmsen(在nusensor的sensorlist中,Hwmsen是在第一位的,也就是说在做轮询数据的时候它会被第一个处理)。
这里需要说明的是Soul4NA和Yaris3.5AT&T为什么没有这个问题,原因就在于他们不支持batch,所以在执行batch之后会返回error,不会执行到setFirstFlushPending为true并flush的这个代码分支,而且mFirstFlushPending默认是false,具体代码如下:
从BatchSensor中获取SENSOR_TYPE_META_DATA的具体代码如下:
从log中我们发现在HAL返回数据给sensorservice时,SENSOR_TYPE_META_DATA已经被放在了具体的sensor数据之后,也就是说在sensorservice执行poll获取sensor数据的时候先获取到了具体的sensor数据,后获取到的SENSOR_TYPE_META_DATA。
3、深度分析
带着上面的问题,先获取到了sensor的数据,后获取到的SENSOR_TYPE_META_DATA,这是不正常的。对比关闭AUTO调节背光之后的正常log,我们发现一个关键现象,就是在打开AUTO调节背光的情况下,LIGHT sensor已经在工作,90%的情况下执行enable会阻塞sensorservice被系统调度,也就是执行的poll的thread不会被调度,直观的现象就是看到log中enable执行完才会调度sensorservice的poll的thread去获取事件,在这种情况下问题是必现的,另外10%的情况就是在enable执行的过程中batch刚刚执行完,满足产生SENSOR_TYPE_META_DATA的时候会先发生调度,这样sensorservice的poll的thread就先获取到了SENSOR_TYPE_META_DATA,这种情况下就没有此问题,屏幕可以正常熄灭。
根据这个关键现象我们又深入分析了enable的代码,然后再结合LIGHT sensor开和关的情况下,我们发现Driver中的执行流程存在一个条件差异:
一、100%可以正常熄灭屏幕的情况:
关闭AUTO调节背光,也就是关闭LIGHT sensor的情况下,在hwmsen_get_interrupt_data函数中obj->dc->polling_running的值为0,所以p-sensor上报数据时不会走hwmsen_work_func,具体代码如下:
在enable的IOCTL还没有执行完,并且没有其他活动的sensor时obj->dc->polling_running的值就会为0,enable的IOCTL执行完之后就会将obj->dc->polling_running的值置为1,同时开启polling的timer,按照一定的频率去polling sensor的数据
二、90%不能熄灭屏幕的情况以及10%可以熄灭屏幕的情况:
打开AUTO调节背光,也就是LIGHT sensor打开的情况下,在hwmsen_get_interrupt_data函数中obj->dc->polling_running的值为1,p-sensor上报数据时就会走hwmsen_work_func,具体代码如下:
在hwmsen_work_func中就会循环遍历所有sensor的driver,同时会区分interrupt sensor和polling sensor,然后获取它们的数据并上报。
1、90%不能熄灭的情况
由于p-sensor是interrupt sensor,所以这些调用都是在中断服务程序中处理的,由于正常情况下中断服务程序是不会被打断和抢占的,所以CPU会被其hold住直到中断服务器程序处理完毕并返回。如果在执行完enable中的batch和flush之后,系统没有发生调度并调度到sensorservice并先获取到SENSOR_TYPE_META_DATA,那么就会被activate的IOCTL触发p-sensor的数据中断,并将p-sensor的数据先上报,从而导致sensorservice被这个上报过程阻塞,最终影响到sensorservice获取数据的正常流程。
2、10%可以熄灭的情况
在执行完enable中的batch和flush之后,系统发生了调度并调度到sensorservice并先获取到SENSOR_TYPE_META_DATA,然后activate的IOCTL再触发p-sensor的数据中断,再将p-sensor的数据上报,这时就不会影响sensorservice获取数据的正常流程。
4、根本原因
在无法保证系统调度的情况下,我们发现问题的根本原因在于p-sensor的中断服务程序在LIGHT sensor打开时(obj->dc->polling_running的值为1)没有分上下段执行,而是将所有处理都放在了中断服务程序里面,从而影响了sensorservice的正常执行及数据流的正常顺序。
四、解决方案
通过以上分析,我们可以知道造成最终问题的原因是中断服务程序在LIGHT sensor打开时(obj->dc->polling_running的值为1)没有分上下段执行。
通过详细分析当前的代码逻辑、结构以及测试,我们给出以下改动和影响尽可能小的解决方案:
1、在Sensor的抽象Driver中(hwmsen_dev),将interrupt sensor(即p-sensor)的中断服务程序调用的函数:hwmsen_get_interrupt_data中的中断下半部处理的代码移除,只执行中断的上半部分处理,将关键数据和状态保存,即将以下代码移除:
中断的下半部分的操作放在固定频率的timer中执行,因为代码原来的逻辑就是在enable sensor的时候开启timer,去完成interrupt sensor的work,具体代码如下:
五、结论及后续动作
Sensor的抽象Driver中(hwmsen_dev)的中断服务程序不分上下段执行的问题在Yaris3.5AT&T以及SOUL4NA中都是存在的,但是由于没有BatchSensor的SENSOR_TYPE_META_DATA的影响,所有并没有出现这个问题。因此在以后的MTK的平台上我们都要检查是否存在此问题,以提前避免,Qualcomm平台也会同时关注。
#analyzed by vincent.song from SWD2 Framework team.
#vincent.song@tcl.com
#201501071718