Android 异常问题分析

2017/02/28 09:40
阅读数 3.5K

1. Introduction

解决问题通常分为以下几个步骤:

a) 确定问题,这是个什么样的问题,有什么外在表现;

b) 分析问题,根据log里面的蛛丝马迹,定位出问题的原因;

c) 对症下药,尽量用最少的代码解决问题,并确保不会引入新的问题;

d) 验证修改,把自己的修改导入,确保自己的修改起了作用,并已经彻底解决了问题,同时观察是否引入新的问题;

此文档主要面对的是几类问题:

a) 重启;

b) 死机(定屏);

c) 开机;

d) 黑屏;

下面会介绍各个问题,但基本只会从理论上介绍如何分析,所以不要期望看了这个文档,你就能解决问题,这就像抓鱼一样,知道了如何抓鱼,不代表你能抓得到鱼;

2. 重启问题

重启问题分为两类,一类是内核重启(包含Modem重启),一类是上层重启,如何区分?

如果有震动,那么就是内核重启,反之则是上层重启;如果不记得有无震动,也可以通过开机时间来判断,设置里面可以看开机经过了多少时间,dmesg的输出也有时间标签;还可以通过ps看进程号来判断,如果zygote,servicemanager等的进程号比较小(一般100左右),那么通常是内核重启,否则就是上层重启;如果你没有看到现场,就只能通过Log来判断了,后面会说到。

2.1 上层重启

对于上层导致的重启,这个比较普遍,一般有watch dog导致的重启,需要进一步分析anr,一般是应用死锁导致的问题,很遗憾这里没有例子;还有一种常见的问题就是native crash。重启问题需要关注的就是时间点,一般在重启之前一定有异常的log,往上继续查找出现的异常,通常不远处就是系统重启的原因,并会打印出具体的栈信息。

如果是watch dog触发的重启,就需要分析anr里面的文件traces.txt,如果前面的进程名字不是system_server,通常意味着这个anr已经被覆盖了,这时候需要去dropbox里面找到对应时间的文件,里面会保留下来;如果是system_server,就搜索ServerThread,这个是主线程,里面会告诉你它阻塞在了什么地方,然后顺着它阻塞的路径,一直追,就可以找到真正触发系统阻塞的原因,通过栈信息,找到具体的文件,函数,并联系上下文,猜测出可能的路径;这里是非常需要灵感的地方,不同的情景不同的原因,基本上没有一个万能的方法,全靠分析者自己的造化。

如果是native crash引发,当发生native crash的时候,一般在tombstone目录下都能找到记录。native调用栈一般都是在tombstone或者applogcat-log中打印出来。会有类似以下的log信息出现。

pid: 2363,tid: 2756, name: rild >>> /system/bin/rild <<<

signal 11(SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000

检查发生错误的类型,比如SIGSEGV、SIGBUS、SIGPIPE等,这里是SIGSEGV表示地址错误,那就检查访问地址。

这里有一个上层导致的重启例子:

pid: 2363,tid: 2756, name: rild >>> /system/bin/rild <<<

signal 11(SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000

r0 00000000r1 00000000 r2 1e7c32c2 r3 00000000

r4 b6d65565r5 b6d561a4 r6 00000000 r7 00000000

r8 b6d6be1cr9 b6b25cf8 sl b6d58e17 fp b6d6c1e8

ip b6d6beecsp b6b25a08 lr b6d3be41 pc b6f79140 cpsr 600f0030

d0676f6c522d657352 d1 6464615f79617749

d272207473756a204c d3 756e2074726f705f

d4002d00650074006c d5 007000750067006c

d6002e00730075006c d7 006b002e006f0063

d80000000000000000 d9 0000000000000000

d100000000000000000 d11 0000000000000000

d120000000000000000 d13 0000000000000000

d140000000000000000 d15 0000000000000000

d164150c82e3d2f1aa0 d17 0000000000000000

d18 41b7ccaa7c000000d19 0000000000000000

d200000000000000000 d21 0000000000000000

d220000000000000000 d23 0000000000000000

d240000000000000000 d25 0000000000000000

d260000000000000000 d27 0000000000000000

d280000000000000000 d29 0000000000000000

d30 0000000000000000d31 0000000000000000

scr 00000010

backtrace:

#00 pc00023140 /system/lib/libc.so (strlen+83)

#01 pc00015e3d /system/lib/libbalong-ril.so

#02 pc0001a1a3 /system/lib/libbalong-ril.so

#03 pc0001a903 /system/lib/libbalong-ril.so (on_data_call_list_changed+42)

#04 pc0002dffd /system/lib/libbalong-ril.so

#05 pc0000d410 /system/lib/libc.so (__thread_entry+72)

#06 pc0000d5a8 /system/lib/libc.so (pthread_create+240)

#07 pc00001014 [heap]

2.2 Modem重启

关键log: sys rebootreason: Software EXCE CP

出现内核重启问题,首先应该看看是不是Modem重启,在目前发现的重启问题来看,大部分是Modem导致的,当然随着版本的稳定,现在也比较少了。

相关问题log:

06-0915:29:00.746 <6>[17425.253448] [1198.0, rdr_init_thread] rdr:sys rebootreason: Software EXCE CP

06-0915:29:00.748 <6>[17425.271850] [1198.0, rdr_init_thread] rdr:we shouldsave file to emmc before reboot!

06-0915:29:01.774 <6>[17426.294281] [1198.1, rdr_init_thread] save resetlog:rdr:system reboot reason: Software EXCE CP

06-0915:29:11.739 <6>[17436.260955] [1198.2, rdr_init_thread] we need rebootnow ...

06-09 15:29:14.645<6>[17439.164001] [1198.3, rdr_init_thread] sysreboot reason: SoftwareEXCE AP, tick: 20140609072914_17857.690150, systemError para: ModId=0x82000006,Arg1=5, Arg2=0

06-0915:29:14.648 <6>[17439.169677] [1198.3, rdr_init_thread] rdr:we shouldsave file to emmc before reboot!

06-0915:29:15.599 <6>[17440.122100] [1198.0, rdr_init_thread] save resetlog:sysreboot reason: Software EXCE AP, tick: 20140609072914_17857.690150

2.3 内核重启

关键log:sysreboot reason: Software EXCE AP

导致内核重启的原因主要是以下两种:

1、代码异常直接主动panic、被动panic(一般出现了踩了内存、非法指针等致命错误)

2、硬件狗复位

内核检测到异常,直接调用BUG函数触发panic,这里的BUG函数是一个宏定义,最终会调用panic函数打印出调用栈,同时导致手机重启。在kmseg中能看到oops字串和backtrace调用栈,另外会生成dontpanic/APANIC_CONSOLE和dontpanic/APANIC_THREAD两个文件,前者能看出引起重启的时刻每个核的调用栈,后者能看出重启时刻所有线程的调用栈信息。

panic信息位于apanic_console的末段,首先的找到panic信息的有关描述。通过分析堆栈信息可以找到问题的根因。

如果是因为指针异常一般会有以下log信息:

Unable tohandle kernel NULL pointer dereference at virtual address 00000000

踩内存log一般如下:

Unable tohandle kernel paging request at virtual address 656d616e

踩内存问题一般很难定位,需要往前追溯看看有没有异常的log,警告也需要重点关注。例如:字符串操作不当,引起的内存越界问题。

3. 开机问题

这个问题的现象就是机器一直在开机界面,有两种情况,一是静态LOGO;一种是动态LOGO。

3.1 静态的LOGO的情景

1、硬件故障,基本adb都无法连接上,需要硬件同事帮忙分析。

主要可能出现的硬件故障有:

CPU(包括L1,L2 cache)、DDR、 EMMC、 BUS 、PMU(电源管理)…

2、内核(或BOOT)故障,不能连接adb,需要连接串口分析。

3、zygote反复重启引起的问题,导致systemserver没有起来。

4、如果不是以上问题,就需要分析内核日志。

3.2 停在动态的LOGO界面

一般是因为开机时因为各种异常导致系统应用层面出现崩溃,一般还是可以正常使用adb shell的。

1、如果动画界面,是否卡死Systemserver。

2、反复播放动画,是否Systemserver反复重启。

3、关注内核死锁问题。关注dmesg_sysrq.txt文件,文件的尾部都有SYSRQ信息,会打印出当前的D进程状态,可以逐个查看是否有死锁的情况。

4. 死机(定屏)问题

如何判断一个问题是否是一个死机问题?

对于Android平台,从现象上说,就是屏幕以及按键没有任何反应,给此设备打电话,也不会有任何反应,但是对于分析者来说,是插入USB线没有反应,也就是Windows的设备管理器,不会因为插USB线而出来新的设备(如果屏幕按键无反应,但出现了新的设备,那这个是后面要说的白屏问题)

需要收集哪些现场?

对于这类问题,我们当前的策略通常是需要抓取串口log,也就是说,如果出现这种情况的时候,没有连接串口,基本上是无能为力的(Google默认提供了一种机制叫做last_kmsg,似乎是可以在重启的时候把上次crash的kernel log写到/proc/last_kmsg里面去),如果连接了串口,通过判断串口是否有输出,可以定位出内核到底死了没有,如果是kernel死,会打印出kernel crash的栈信息以及寄存器信息,可以根据栈信息,定位出是什么模块导致的;

简单点说,如果是对于死机问题,我们需要抓取串口log。

如何分析:

如果一定要有秘籍的话,那么就是认真观察死之前的遗言!

通常都会有栈信息出来,根据栈信息就可以看到是那个函数引起的,所以相对来说好定位,当然也出现过出事的函数只是替罪羊,真正的罪魁祸首在幕后的情况,但是,打印的信息都会做出一定的暗示,透过现象看本质,不轻易下结论。

给出一些判断建议:

1、连接不了adb,也没有按键中断,只能连接jtag调试了;

2、连接不了adb,有按键中断,连接串口、按键触发panic;

3、可以连接adb,触发SYSRQ,检查是否内核异常卡死,OOM(分析卡死原因、内存是否真的少了)。

5、getevent是否上报,找出不上报原因;

6、InputDispatch出现异常,队列爆了,无法正常分发事件;

7、界面无刷新,分析surfacefinger、LCD驱动(显示异常定位)。

5. 黑屏问题

黑屏问题,很好确认,屏变黑了,拨电话没反应,并且维持这个状态很长一段时间,如果插入USB没有反应,那么它就是一个死机问题,请看死机部分;如果有反应,那么它就是我们这里说的黑屏问题了;

正常情况下,都应该是系统重启,所以它的情报搜集以及分析过程和上面说的重启是一样的!(但是,有种黑屏的现象是触屏,按键都无法响应,但是打电话还有反应,是我们说的点不亮的问题,这个问题通常是在睡眠或者唤醒的时候被阻塞住了,它的分析,比较复杂,需要在内核里的睡眠唤醒的核心加大量的信息来定位,通常是suspend的线程被阻塞了,导致后面的late_resume函数,也就是点亮lcd的动作一直没有被触发执行,因为它们是放在同一个work queue suspend_work_queue来做的,需要去检查为什么前面的suspend被阻塞了,当然,如果你对内核非常的熟悉,也能从串口或者dmesg信息里面看出蛛丝马迹,然后做对应的测试,这里就不讨论了)。

6. 总结

1、当我们被测试部的同事急急忙忙的叫去看现场的时候,通常并不知道这是个什么样的现象,所以要尽量抓取足够多的信息。尤其是需要知道出现问题的时间点。

2、根据现场,初步判断是死机,重启,白屏中的哪种?

3、根据第二步的判断,如果是内核死机,则重点查看dmesg信息;如果是上层死机,重点查看tombstone,bugreport,logcat,anr;如果是内核重启,重点查看dmesg信息;如果是上层重启,重点查看logcat,anr

4、然后就根据面的介绍,逐个分析,如果还无法定位的话,就需要添加自己的打印信息

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部