BUG实例分析一:死机

来自个人维基
跳转至: 导航搜索

目录

一、现象

手机睡眠后按power键无法正常唤醒,具体表现如下:

现象一:无法点亮屏幕,按任意键无响应;

现象二:可以点亮屏幕,但触屏、按键无响应,电话也无法呼入,但插入usb偶尔可以更新状态栏时间


二、初步判断

从log上看,有两个案例log是有明显异常,在不停地打印同一条log,由于这些log是在有触屏事件时会出现的(包括但不限于),因此初步判断是input(如按键、触屏)事件出现异常,导致系统的input机制拥挤阻塞,但由于input及powerManager很多log屏蔽,无法作出进一步有效判断,故这里提供一个增加了大量log的image,请协助测试一下,力争抓到log(如能发掘必现规律就更好了)。


三、解决思路

一方面,由于input消息流程中大部分log是关闭的,因此仅从产品上抓取的log消息不足以定位问题点,因此决定发一版包含input所有log并在关键函数加入了不少log的软件给品质部测试(同时也鼓励内部试用机用户烧写这个软件),并且要求品质部一旦发现此问题立马将现场保留,以便我们进行adb分析。

另一方面,之前今天有过一台出现此问题的机器,在不停地打印按键的 "repeatCount=xxx",并且这个数值一直在递增,因此我们也做了第二手准备:即如果短期内无法重现这个问题,那则在打印 "repeatCount"这个地方进行判断,当 "repeatCount"大于某个值时则认为出现了异常,这样则重启手机。如此一来,至少问题会得到恢复,而不至于一直处理“死机”状态而不得不拔电池。这是为了不影响发货不得已的临时解决方案。


四、终得真机分析

几天过去,品质部同事重现了此问题!

adb Go!!!

1、adb logcat,按键,inputDispatcher中的 notifyKey有无log产生?——无

2、adb shell getevent,按键,是否能接收到按键消息?——是

==>驱动ok,问题发生在了framework

3、动态卸载、添加event2 ——无论卸载还是添加,均不成功

==>怀疑 inputReader所在的 Thread阻塞

4、查看anr ——InputReader处于 WAIT状态,栈直指 interceptKeyBeforeQueueing中所调用的某一个函数,而这个函数调用了ContentResolver中的parse操作

==>这就是卡的地方?!


五、验证

又在上述关键的地方加了些log,发个了软件(品质的同事辛苦了!),幸运的是这次不到一天便出现了三台问题机器,其中有一台的log显示:

 7824 07-14 15:53:03.688 D/InputDispatcher(  278): before call interceptKeyBeforeQueueing, 2816
 7825 07-14 15:53:03.688 W/WindowManager(  278): interceptKeyBeforeQueueing start
 7888 07-14 15:53:03.694 W/WindowManager(  278): interceptKeyBeforeQueueing end
 7891 07-14 15:53:03.694 D/InputDispatcher(  278): after call interceptKeyBeforeQueueing, 2818
 7917 07-14 15:53:03.697 D/InputDispatcher(  278): before call interceptKeyBeforeQueueing, 2816
 7918 07-14 15:53:03.697 W/WindowManager(  278): interceptKeyBeforeQueueing start
 7923 07-14 15:53:03.699 W/WindowManager(  278): interceptKeyBeforeQueueing end
 7926 07-14 15:53:03.699 D/InputDispatcher(  278): after call interceptKeyBeforeQueueing, 2818
22072 07-14 15:57:54.647 D/InputDispatcher(  278): before call interceptKeyBeforeQueueing, 2816
22073 07-14 15:57:54.647 W/WindowManager(  278): interceptKeyBeforeQueueing start
22135 07-14 15:57:54.652 W/WindowManager(  278): interceptKeyBeforeQueueing end
22141 07-14 15:57:54.654 D/InputDispatcher(  278): after call interceptKeyBeforeQueueing, 2818
22186 07-14 15:57:54.887 D/InputDispatcher(  278): before call interceptKeyBeforeQueueing, 2816
22187 07-14 15:57:54.887 W/WindowManager(  278): interceptKeyBeforeQueueing start
22192 07-14 15:57:54.888 W/WindowManager(  278): interceptKeyBeforeQueueing end
22195 07-14 15:57:54.888 D/InputDispatcher(  278): after call interceptKeyBeforeQueueing, 2818
40764 07-14 16:01:19.988 D/InputDispatcher(  278): before call interceptKeyBeforeQueueing, 2816
40765 07-14 16:01:19.988 W/WindowManager(  278): interceptKeyBeforeQueueing start
40767 07-14 16:01:19.989 W/WindowManager(  278): interceptKeyBeforeQueueing end
40770 07-14 16:01:19.989 D/InputDispatcher(  278): after call interceptKeyBeforeQueueing, 2818
40799 07-14 16:01:20.404 D/InputDispatcher(  278): before call interceptKeyBeforeQueueing, 2816
40800 07-14 16:01:20.404 W/WindowManager(  278): interceptKeyBeforeQueueing start

完美地验证了之前的猜测!


六、后续规避

这个问题的原因主要是在关键的路径(所有input事件都要调用的函数)上,增加了比较复杂的、有风险的ContentResolver操作,而一旦操作超时则导致整个系统的input系统瘫痪,用户无法操作,手机也无法自动恢复,只有拔电池了。

所以在后续framework的修改时,一定要考虑到所作更改的影响,在这些地方的更改也尽量要使用简单的逻辑、可靠数据操作方式进行,同时也要兼顾到性能方面的影响,如这里的更改就会导致每个input事件都要去操作ContentResolver,且不论是否可靠,单从性能上讲也不太可取。