Android 异常问题分析
1. Introduction
解決問題通常分為以下幾個(gè)步驟:
a) 確定問題,這是個(gè)什么樣的問題,有什么外在表現(xiàn);
b) 分析問題,根據(jù)log里面的蛛絲馬跡,定位出問題的原因;
c) 對(duì)癥下藥,盡量用最少的代碼解決問題,并確保不會(huì)引入新的問題;
d) 驗(yàn)證修改,把自己的修改導(dǎo)入,確保自己的修改起了作用,并已經(jīng)徹底解決了問題,同時(shí)觀察是否引入新的問題;
此文檔主要面對(duì)的是幾類問題:
a) 重啟;
b) 死機(jī)(定屏);
c) 開機(jī);
d) 黑屏;
下面會(huì)介紹各個(gè)問題,但基本只會(huì)從理論上介紹如何分析,所以不要期望看了這個(gè)文檔,你就能解決問題,這就像抓魚一樣,知道了如何抓魚,不代表你能抓得到魚;
2. 重啟問題
重啟問題分為兩類,一類是內(nèi)核重啟(包含Modem重啟),一類是上層重啟,如何區(qū)分?
如果有震動(dòng),那么就是內(nèi)核重啟,反之則是上層重啟;如果不記得有無震動(dòng),也可以通過開機(jī)時(shí)間來判斷,設(shè)置里面可以看開機(jī)經(jīng)過了多少時(shí)間,dmesg的輸出也有時(shí)間標(biāo)簽;還可以通過ps看進(jìn)程號(hào)來判斷,如果zygote,servicemanager等的進(jìn)程號(hào)比較小(一般100左右),那么通常是內(nèi)核重啟,否則就是上層重啟;如果你沒有看到現(xiàn)場(chǎng),就只能通過Log來判斷了,后面會(huì)說到。
2.1 上層重啟
對(duì)于上層導(dǎo)致的重啟,這個(gè)比較普遍,一般有watch dog導(dǎo)致的重啟,需要進(jìn)一步分析anr,一般是應(yīng)用死鎖導(dǎo)致的問題,很遺憾這里沒有例子;還有一種常見的問題就是native crash。重啟問題需要關(guān)注的就是時(shí)間點(diǎn),一般在重啟之前一定有異常的log,往上繼續(xù)查找出現(xiàn)的異常,通常不遠(yuǎn)處就是系統(tǒng)重啟的原因,并會(huì)打印出具體的棧信息。
如果是watch dog觸發(fā)的重啟,就需要分析anr里面的文件traces.txt,如果前面的進(jìn)程名字不是system_server,通常意味著這個(gè)anr已經(jīng)被覆蓋了,這時(shí)候需要去dropbox里面找到對(duì)應(yīng)時(shí)間的文件,里面會(huì)保留下來;如果是system_server,就搜索ServerThread,這個(gè)是主線程,里面會(huì)告訴你它阻塞在了什么地方,然后順著它阻塞的路徑,一直追,就可以找到真正觸發(fā)系統(tǒng)阻塞的原因,通過棧信息,找到具體的文件,函數(shù),并聯(lián)系上下文,猜測(cè)出可能的路徑;這里是非常需要靈感的地方,不同的情景不同的原因,基本上沒有一個(gè)萬能的方法,全靠分析者自己的造化。
如果是native crash引發(fā),當(dāng)發(fā)生native crash的時(shí)候,一般在tombstone目錄下都能找到記錄。native調(diào)用棧一般都是在tombstone或者applogcat-log中打印出來。會(huì)有類似以下的log信息出現(xiàn)。
pid: 2363,tid: 2756, name: rild >>> /system/bin/rild <<<
signal 11(SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000
檢查發(fā)生錯(cuò)誤的類型,比如SIGSEGV、SIGBUS、SIGPIPE等,這里是SIGSEGV表示地址錯(cuò)誤,那就檢查訪問地址。
這里有一個(gè)上層導(dǎo)致的重啟例子:
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重啟
關(guān)鍵log: sys rebootreason: Software EXCE CP
出現(xiàn)內(nèi)核重啟問題,首先應(yīng)該看看是不是Modem重啟,在目前發(fā)現(xiàn)的重啟問題來看,大部分是Modem導(dǎo)致的,當(dāng)然隨著版本的穩(wěn)定,現(xiàn)在也比較少了。
相關(guān)問題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 內(nèi)核重啟
關(guān)鍵log:sysreboot reason: Software EXCE AP
導(dǎo)致內(nèi)核重啟的原因主要是以下兩種:
1、代碼異常直接主動(dòng)panic、被動(dòng)panic(一般出現(xiàn)了踩了內(nèi)存、非法指針等致命錯(cuò)誤)
2、硬件狗復(fù)位
內(nèi)核檢測(cè)到異常,直接調(diào)用BUG函數(shù)觸發(fā)panic,這里的BUG函數(shù)是一個(gè)宏定義,最終會(huì)調(diào)用panic函數(shù)打印出調(diào)用棧,同時(shí)導(dǎo)致手機(jī)重啟。在kmseg中能看到oops字串和backtrace調(diào)用棧,另外會(huì)生成dontpanic/APANIC_CONSOLE和dontpanic/APANIC_THREAD兩個(gè)文件,前者能看出引起重啟的時(shí)刻每個(gè)核的調(diào)用棧,后者能看出重啟時(shí)刻所有線程的調(diào)用棧信息。
panic信息位于apanic_console的末段,首先的找到panic信息的有關(guān)描述。通過分析堆棧信息可以找到問題的根因。
如果是因?yàn)橹羔槷惓R话銜?huì)有以下log信息:
Unable tohandle kernel NULL pointer dereference at virtual address 00000000
踩內(nèi)存log一般如下:
Unable tohandle kernel paging request at virtual address 656d616e
踩內(nèi)存問題一般很難定位,需要往前追溯看看有沒有異常的log,警告也需要重點(diǎn)關(guān)注。例如:字符串操作不當(dāng),引起的內(nèi)存越界問題。
3. 開機(jī)問題
這個(gè)問題的現(xiàn)象就是機(jī)器一直在開機(jī)界面,有兩種情況,一是靜態(tài)LOGO;一種是動(dòng)態(tài)LOGO。
3.1 靜態(tài)的LOGO的情景
1、硬件故障,基本adb都無法連接上,需要硬件同事幫忙分析。
主要可能出現(xiàn)的硬件故障有:
CPU(包括L1,L2 cache)、DDR、 EMMC、 BUS 、PMU(電源管理)…
2、內(nèi)核(或BOOT)故障,不能連接adb,需要連接串口分析。
3、zygote反復(fù)重啟引起的問題,導(dǎo)致systemserver沒有起來。
4、如果不是以上問題,就需要分析內(nèi)核日志。
3.2 停在動(dòng)態(tài)的LOGO界面
一般是因?yàn)殚_機(jī)時(shí)因?yàn)楦鞣N異常導(dǎo)致系統(tǒng)應(yīng)用層面出現(xiàn)崩潰,一般還是可以正常使用adb shell的。
1、如果動(dòng)畫界面,是否卡死Systemserver。
2、反復(fù)播放動(dòng)畫,是否Systemserver反復(fù)重啟。
3、關(guān)注內(nèi)核死鎖問題。關(guān)注dmesg_sysrq.txt文件,文件的尾部都有SYSRQ信息,會(huì)打印出當(dāng)前的D進(jìn)程狀態(tài),可以逐個(gè)查看是否有死鎖的情況。
4. 死機(jī)(定屏)問題
如何判斷一個(gè)問題是否是一個(gè)死機(jī)問題?
對(duì)于Android平臺(tái),從現(xiàn)象上說,就是屏幕以及按鍵沒有任何反應(yīng),給此設(shè)備打電話,也不會(huì)有任何反應(yīng),但是對(duì)于分析者來說,是插入USB線沒有反應(yīng),也就是Windows的設(shè)備管理器,不會(huì)因?yàn)椴?/span>USB線而出來新的設(shè)備(如果屏幕按鍵無反應(yīng),但出現(xiàn)了新的設(shè)備,那這個(gè)是后面要說的白屏問題)
需要收集哪些現(xiàn)場(chǎng)?
對(duì)于這類問題,我們當(dāng)前的策略通常是需要抓取串口log,也就是說,如果出現(xiàn)這種情況的時(shí)候,沒有連接串口,基本上是無能為力的(Google默認(rèn)提供了一種機(jī)制叫做last_kmsg,似乎是可以在重啟的時(shí)候把上次crash的kernel log寫到/proc/last_kmsg里面去),如果連接了串口,通過判斷串口是否有輸出,可以定位出內(nèi)核到底死了沒有,如果是kernel死,會(huì)打印出kernel crash的棧信息以及寄存器信息,可以根據(jù)棧信息,定位出是什么模塊導(dǎo)致的;
簡單點(diǎn)說,如果是對(duì)于死機(jī)問題,我們需要抓取串口log。
如何分析:
如果一定要有秘籍的話,那么就是認(rèn)真觀察死之前的遺言!
通常都會(huì)有棧信息出來,根據(jù)棧信息就可以看到是那個(gè)函數(shù)引起的,所以相對(duì)來說好定位,當(dāng)然也出現(xiàn)過出事的函數(shù)只是替罪羊,真正的罪魁禍?zhǔn)自谀缓蟮那闆r,但是,打印的信息都會(huì)做出一定的暗示,透過現(xiàn)象看本質(zhì),不輕易下結(jié)論。
給出一些判斷建議:
1、連接不了adb,也沒有按鍵中斷,只能連接jtag調(diào)試了;
2、連接不了adb,有按鍵中斷,連接串口、按鍵觸發(fā)panic;
3、可以連接adb,觸發(fā)SYSRQ,檢查是否內(nèi)核異常卡死,OOM(分析卡死原因、內(nèi)存是否真的少了)。
5、getevent是否上報(bào),找出不上報(bào)原因;
6、InputDispatch出現(xiàn)異常,隊(duì)列爆了,無法正常分發(fā)事件;
7、界面無刷新,分析surfacefinger、LCD驅(qū)動(dòng)(顯示異常定位)。
5. 黑屏問題
黑屏問題,很好確認(rèn),屏變黑了,撥電話沒反應(yīng),并且維持這個(gè)狀態(tài)很長一段時(shí)間,如果插入USB沒有反應(yīng),那么它就是一個(gè)死機(jī)問題,請(qǐng)看死機(jī)部分;如果有反應(yīng),那么它就是我們這里說的黑屏問題了;
正常情況下,都應(yīng)該是系統(tǒng)重啟,所以它的情報(bào)搜集以及分析過程和上面說的重啟是一樣的!(但是,有種黑屏的現(xiàn)象是觸屏,按鍵都無法響應(yīng),但是打電話還有反應(yīng),是我們說的點(diǎn)不亮的問題,這個(gè)問題通常是在睡眠或者喚醒的時(shí)候被阻塞住了,它的分析,比較復(fù)雜,需要在內(nèi)核里的睡眠喚醒的核心加大量的信息來定位,通常是suspend的線程被阻塞了,導(dǎo)致后面的late_resume函數(shù),也就是點(diǎn)亮lcd的動(dòng)作一直沒有被觸發(fā)執(zhí)行,因?yàn)樗鼈兪欠旁谕粋€(gè)work queue suspend_work_queue來做的,需要去檢查為什么前面的suspend被阻塞了,當(dāng)然,如果你對(duì)內(nèi)核非常的熟悉,也能從串口或者dmesg信息里面看出蛛絲馬跡,然后做對(duì)應(yīng)的測(cè)試,這里就不討論了)。
6. 總結(jié)
1、當(dāng)我們被測(cè)試部的同事急急忙忙的叫去看現(xiàn)場(chǎng)的時(shí)候,通常并不知道這是個(gè)什么樣的現(xiàn)象,所以要盡量抓取足夠多的信息。尤其是需要知道出現(xiàn)問題的時(shí)間點(diǎn)。
2、根據(jù)現(xiàn)場(chǎng),初步判斷是死機(jī),重啟,白屏中的哪種?
3、根據(jù)第二步的判斷,如果是內(nèi)核死機(jī),則重點(diǎn)查看dmesg信息;如果是上層死機(jī),重點(diǎn)查看tombstone,bugreport,logcat,anr;如果是內(nèi)核重啟,重點(diǎn)查看dmesg信息;如果是上層重啟,重點(diǎn)查看logcat,anr
4、然后就根據(jù)面的介紹,逐個(gè)分析,如果還無法定位的話,就需要添加自己的打印信息。
?
總結(jié)
以上是生活随笔為你收集整理的Android 异常问题分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HiJson,一个json格式化查看工具
- 下一篇: Obsidian模板指北