Android 异常问题分析
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、然后就根據面的介紹,逐個分析,如果還無法定位的話,就需要添加自己的打印信息。
?
總結
以上是生活随笔為你收集整理的Android 异常问题分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HiJson,一个json格式化查看工具
- 下一篇: android java 调试快捷键_最