ANR日志traces.txt分析

導(dǎo)致ANR的幾種情況

  • KeyDispatchTimeout(5s): 按鍵或觸摸事件在特定時間內(nèi)無法處理完成
  • BroadcastTimeout(前臺10s,后臺60s): 廣播在特定時間內(nèi)無法處理完成
  • ServiceTimeout(前臺20s,后臺200s): Service在特定的時間無法處理完成 另外還有ProviderTimeout和WatchDog等導(dǎo)致的ANR

常見的原因

    A.耗時操作,如復(fù)雜的layout,龐大的for循環(huán),IO等。
B.被Binder 對端block
C.被子線程同步鎖block
    D.Binder被占滿導(dǎo)致主線程無法和SystemServer通信
E.得不到系統(tǒng)資源(CPU/RAM/IO)
其中ABCD比較好分析,而E比較困難。

應(yīng)用ANR產(chǎn)生的時候,ActivityManagerService的appNotResponding方法就會被調(diào)用,然后在/data/anr/traces.txt文件中寫入ANR相關(guān)信息.
ANR就不作介紹了,下面只介紹如何分析ANR異常.

通常發(fā)生了ANR,ActivityManager會打印報錯信息:

E/ActivityManager: ANR in com.rui.android.poc  // ANR出現(xiàn)的進(jìn)程包名
PID: 1322  // ANR進(jìn)程ID
Reason: Broadcast of Intent { act=android.intent.action.SCREEN_ON flg=0x50000010 }//導(dǎo)致ANR的原因
Load: 4.13 / 2.52 / 1.05
CPU usage from 0ms to 12843ms later://CPU在ANR發(fā)生后的使用情況
98% 1322/com.rui.android.poc: 0.5% user + 98% kernel / faults: 1044 minor 104 major
5.6% 567/system_server: 3.4% user + 2.1% kernel / faults: 1940 minor 217 major
2.3% 766/com.android.systemui: 1.2% user + 1% kernel / faults: 251 minor 165 major
1.4% 268/kworker/0:2: 0% user + 1.4% kernel
1.2% 1690/adbd: 0.1% user + 1% kernel / faults: 2 minor 3 major
1% 756/com.android.phone: 0.6% user + 0.3% kernel / faults: 347 minor 61 major
0.9% 139/surfaceflinger: 0.3% user + 0.5% kernel / faults: 1 minor 5 major
0.2% 929/com.sprd.opm: 0.2% user + 0% kernel / faults: 279 minor 115 major
0.2% 23/kworker/u4:1: 0% user + 0.2% kernel
0.2% 368/kworker/u5:1: 0% user + 0.2% kernel
0.1% 914/com.android.modemassert: 0% user + 0% kernel / faults: 182 minor 66 major
0.1% 44/ksmd: 0% user + 0.1% kernel
0% 909/com.spreadst.validator: 0% user + 0% kernel / faults: 164 minor 39 major
0% 8/rcu_preempt: 0% user + 0% kernel
0% 43/kswapd0: 0% user + 0% kernel
0% 117/mmcqd/0: 0% user + 0% kernel
+0% 1770/kworker/0:3: 0% user + 0% kernel
+0% 1774/debuggerd: 0% user + 0% kernel
97% TOTAL: 3.7% user + 55% kernel + 38% iowait  // CUP占用情況
CPU usage from 12301ms to 12824ms later:
100% 1322/com.rui.android.poc: 0% user + 100% kernel
100% 1322/rui.android.poc: 0% user + 100% kernel
1.9% 1333/Binder_2: 0% user + 1.9% kernel
 3.8% 567/system_server: 1.9% user + 1.9% kernel
3.8% 581/ActivityManager: 1.9% user + 1.9% kernel
1.3% 139/surfaceflinger: 1.3% user + 0% kernel
1.3% 249/DispSync: 0% user + 1.3% kernel
1.5% 766/com.android.systemui: 1.5% user + 0% kernel / faults: 2 minor
1.5% 766/ndroid.systemui: 0% user + 1.5% kernel
1.6% 1770/kworker/0:3: 0% user + 1.6% kernel
100% TOTAL: 0% user + 54% kernel + 45% iowait

Log分析:

log打印了ANR的基本信息,我們可以分析CPU使用率得知ANR的簡單情況;如果CPU使用率很高,接近100%,可能是在進(jìn)行大規(guī)模的計算更可能是陷入死循環(huán);如果CUP使用率很低,說明主線程被阻塞了,并且當(dāng)IOwait很高,可能是主線程在等待I/O操作的完成.
對于ANR只是分析Log很難知道問題所在,我們還需要通過Trace文件分析stack調(diào)用情況.

traces.txt是如何生成的

當(dāng)APP(包括系統(tǒng)APP和用戶APP)進(jìn)程出現(xiàn)ANR、應(yīng)用響應(yīng)慢或WatchDog的監(jiān)視沒有得到回饋時,系統(tǒng)會dump此時的top進(jìn)程,進(jìn)程中Thread的運(yùn)行狀態(tài)就都dump到這個Trace文件中了.每次發(fā)生ANR, 這個文件都會被清空,寫入新的內(nèi)容. 如果想查看以前發(fā)生ANR的信息, 可以去查看DB文件.

DropBox中的log

traces.txt只保留最后一次發(fā)生ANR時的信息, android 2.2開始增加了DropBox功能, 保留歷史上發(fā)生的所有ANR的log.
“/data/system/dropbox”是DB指定的文件存放位置.
日志保存的最長時間, 默認(rèn)是3天.

shell@sp9820a_Rui8503:/data # cd system/dropbox/
shell@sp9820a_Rui8503:/data/system/dropbox # ls
SYSTEM_BOOT@1325376052965.txt
system_app_crash@1325376052598.txt
system_app_crash@1325376054905.txt
system_app_strictmode@1325376048453.txt.gz
system_app_strictmode@1325376053442.txt.gz
system_app_strictmode@1325376058904.txt.gz
system_server_wtf@1325376043066.txt
system_server_wtf@1325376052708.txt
system_server_wtf@1325376052842.txt
shell@sp9820a_Rui8503:/data/system/dropbox #

SystemServer在啟動時, 會創(chuàng)建并添加DROPBOX_SERVICE.

//SystemServer.java
private void startOtherServices() {
... ...
            try {
                Slog.i(TAG, "DropBox Service");
                ServiceManager.addService(Context.DROPBOX_SERVICE,
                        new DropBoxManagerService(context, new File("/data/system/dropbox")));
            } catch (Throwable e) {
                reportWtf("starting DropBoxManagerService", e);
            }
... ...
}

在traces.txt中可以看到如下信息:

//說明了發(fā)生ANR的進(jìn)程id、時間和進(jìn)程名稱。
----- pid 2023 at 2018-07-24 19:33:17 -----
Cmd line: com.rui.android.poc
//下面三行是線程的基本信息
JNI: CheckJNI is off; workarounds are off; pins=0; globals=348
DALVIK THREADS://以下是各個線程的函數(shù)堆棧信息
(mutexes: tll=0 tsl=0 tscl=0 ghl=0)

//下面一行說明了線程名稱、daemon表示守護(hù)進(jìn)程,線程的優(yōu)先級(默認(rèn)5)、線程鎖id和線程狀態(tài),
//線程名稱是啟動線程的時候手動指明的,這里的main標(biāo)識是主線程,是Android自動設(shè)定的
//一個線程名稱,如果是自己手動創(chuàng)建的線程,一般會被命名成“Thread-xx”的格式,其中xx是
//線程id,它只增不減不會被復(fù)用;注意這其中的tid不是線程的id,它是一個在Java虛擬機(jī)中用
//來實(shí)現(xiàn)線程鎖的變量,隨著線程的增減,這個變量的值是可能被復(fù)用的;
"main" prio=5 tid=1 NATIVE

//group是線程組名稱。sCount是此線程被掛起的次數(shù),dsCount是線程被調(diào)試器掛起的次數(shù),
//當(dāng)一個進(jìn)程被調(diào)試后,sCount會重置為0,調(diào)試完畢后sCount會根據(jù)是否被正常掛起增長,
//但是dsCount不會被重置為0,所以dsCount也可以用來判斷這個線程是否被調(diào)試過。obj表示
//這個線程的Java對象的地址,self表示這個線程N(yùn)ative的地址。
  | group="main" sCount=1 dsCount=0 obj=0x4164dcf0 self=0x41565628

//此后是線程的調(diào)度信息,sysTid是Linux下的內(nèi)核線程id,nice是線程的調(diào)度優(yōu)先級,
//sched分別標(biāo)志了線程的調(diào)度策略和優(yōu)先級,cgrp是調(diào)度屬組,handle是線程的處理函數(shù)地址。
  | sysTid=2023 nice=-1 sched=0/0 cgrp=apps handle=1074626900

//線程當(dāng)前上下文信息,state是調(diào)度狀態(tài);schedstat從 /proc/[pid]/task/[tid]/schedstat讀出,
//三個值分別表示線程在cpu上執(zhí)行的時間、線程的等待時間和線程執(zhí)行的時間片長度,有的
//android內(nèi)核版本不支持這項信息,得到的三個值都是0;utm是線程用戶態(tài)下使用的時間
//值(單位是jiffies);stm是內(nèi)核態(tài)下的調(diào)度時間值;core是最后執(zhí)行這個線程的cpu核的序號。
  | state=S schedstat=( 0 0 0 ) utm=49 stm=21 core=0

//線程的調(diào)用棧信息(這里可查看導(dǎo)致ANR的代碼調(diào)用流程,分析ANR最重要的信息)
  (native backtrace unavailable)
  at libcore.io.Posix.open(Native Method)
  at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
  at libcore.io.IoBridge.open(IoBridge.java:430)
  at java.io.FileInputStream.<init>(FileInputStream.java:78)
  at com.ruiven.android.Peripheral.util.kingFiles.write(kingFiles.java:58)
  at com.ruiven.android.Peripheral.util.kingFiles.write(kingFiles.java:51)
  at com.ruiven.android.Peripheral.util.kingLog.writeToFiles(kingLog.java:71)
  at com.ruiven.android.Peripheral.util.kingLog.f(kingLog.java:47)
  at com.ruiven.android.poc.receiver.ReceiverBatteryChanged.onReceive(ReceiverBatteryChanged.java:114)
  at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:767)
  at android.os.Handler.handleCallback(Handler.java:769)
  at android.os.Handler.dispatchMessage(Handler.java:97)
  at android.os.Looper.loop(Looper.java:136)
  at com.ruiven.android.Peripheral.util.Cockroach$1.run(Cockroach.java:38)
  at android.os.Handler.handleCallback(Handler.java:769)
  at android.os.Handler.dispatchMessage(Handler.java:97)
  at android.os.Looper.loop(Looper.java:136)
  at android.app.ActivityThread.main(ActivityThread.java:5375)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:515)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:976)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:792)
  at dalvik.system.NativeStart.main(Native Method)

//Binder線程是進(jìn)程的線程池中用來處理binder請求的線程
"Binder_3" prio=5 tid=23 NATIVE
  | group="main" sCount=1 dsCount=0 obj=0x41b765f8 self=0x4f213f18
  | sysTid=1347 nice=0 sched=0/0 cgrp=apps handle=1327603952
  | state=S schedstat=( 0 0 0 ) utm=0 stm=3 core=1
  #00  pc 000205d0  /system/lib/libc.so (__ioctl+8)
  #01  pc 0002d01f  /system/lib/libc.so (ioctl+14)
  #02  pc 0001e519  /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+140)
  #03  pc 0001ec67  /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+6)
  #04  pc 0001ecfd  /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+48)
  #05  pc 000236cd  /system/lib/libbinder.so
  #06  pc 0000ea19  /system/lib/libutils.so (android::Thread::_threadLoop(void*)+216)
  #07  pc 0004e769  /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+68)
  #08  pc 0000e54b  /system/lib/libutils.so
  #09  pc 0000d240  /system/lib/libc.so (__thread_entry+72)
  #10  pc 0000d3dc  /system/lib/libc.so (pthread_create+240)
  at dalvik.system.NativeStart.run(Native Method)

//JDWP線程是支持虛擬機(jī)調(diào)試的線程,daemon表示守護(hù)進(jìn)程,不需要關(guān)心
"JDWP" daemon prio=5 tid=4 VMWAIT
  | group="system" sCount=1 dsCount=0 obj=0x41a21868 self=0x4cc821b0
  | sysTid=785 nice=0 sched=0/0 cgrp=apps handle=1257589656
  | state=S schedstat=( 0 0 0 ) utm=0 stm=0 core=1
  #00  pc 00021420  /system/lib/libc.so (recvmsg+8)
  #01  pc 000668ab  /system/lib/libdvm.so
  #02  pc 00066adf  /system/lib/libdvm.so
  #03  pc 000697af  /system/lib/libdvm.so
  #04  pc 00059fdd  /system/lib/libdvm.so
  #05  pc 0000d240  /system/lib/libc.so (__thread_entry+72)
  #06  pc 0000d3dc  /system/lib/libc.so (pthread_create+240)
  at dalvik.system.NativeStart.run(Native Method)

//“Signal Catcher”負(fù)責(zé)接收和處理kernel發(fā)送的各種信號,例如SIGNAL_QUIT、SIGNAL_USR1等就是被該線程
//接收到并處理的,traces.txt 文件中的內(nèi)容就是由該線程負(fù)責(zé)輸出的,可以看到它的狀態(tài)是RUNNABLE.
"Signal Catcher" daemon prio=5 tid=3 RUNNABLE
  | group="system" sCount=0 dsCount=0 obj=0x41a21770 self=0x4af3e5e0
  | sysTid=784 nice=0 sched=0/0 cgrp=apps handle=1257677168
  | state=R schedstat=( 0 0 0 ) utm=2 stm=2 core=1
  at dalvik.system.NativeStart.run(Native Method)
----- end 2023 -----

如果ANR在native層,那么堆棧中就不會有相關(guān)調(diào)用的路徑,這種情況只能在native層添加更多的Log,一步步來查找了

NATIVE表示當(dāng)前線程的狀態(tài):

Thread狀態(tài)及其對應(yīng)的值

ThreadState (defined at “dalvik/vm/thread.h “)
THREAD_UNDEFINED = -1, /* makes enum compatible with int32_t */
THREAD_ZOMBIE = 0, /* TERMINATED */( 線程死亡,終止運(yùn)行)
THREAD_RUNNING = 1, /* RUNNABLE or running now */(線程可運(yùn)行或正在運(yùn)行)
THREAD_TIMED_WAIT = 2, /* TIMED_WAITING in Object.wait() */(執(zhí)行了帶有超時參數(shù)的wait、sleep或join函數(shù))
THREAD_MONITOR = 3, /* BLOCKED on a monitor */(線程阻塞,等待獲取對象鎖)
THREAD_WAIT = 4, /* WAITING in Object.wait() */( 執(zhí)行了無超時參數(shù)的wait函數(shù))
THREAD_INITIALIZING= 5, /* allocated, not yet running */(新建,正在初始化,為其分配資源)
THREAD_STARTING = 6, /* started, not yet on thread list */(新建,正在啟動)
THREAD_NATIVE = 7, /* off in a JNI native method */(正在執(zhí)行JNI本地函數(shù))
THREAD_VMWAIT = 8, /* waiting on a VM resource */(正在等待VM資源)
THREAD_SUSPENDED = 9, /* suspended, usually by GC or debugger */(線程暫停,通常是由于GC或debug被暫停)                       

**特別說明一下MONITOR狀態(tài)和SUSPEND狀態(tài),MONITOR狀態(tài)一般是類的同步塊或者同步方法造成的,SUSPENDED狀態(tài)在debugger的時候會出現(xiàn),可以用來區(qū)別是不是真的是用戶正常操作跑出了ANR。

mutexes(互斥)的選項簡寫對應(yīng)含義:
tll--thread list lock
tsl-- thread suspend lock
tscl-- thread suspend count lock
ghl--gc heap lock
hwl--heap worker lock
hwll--heap worker list lock
  • 通過Cmd line: packagename可以找到要分析的進(jìn)程
  • 并不是trace文件包含的應(yīng)用就一定是造成ANR的幫兇,應(yīng)用出現(xiàn)在trace文件中,只能說明出現(xiàn)ANR的時候這個應(yīng)用進(jìn)程還活著,trace文件的頂部則是觸發(fā)ANR的應(yīng)用信息。因此,如果你的應(yīng)用出現(xiàn)在了trace文件的頂部,那么很有可能是因為你的應(yīng)用造成了ANR,否則是你的應(yīng)用造成ANR的可能性不大,但是具體是不是還需要進(jìn)一步分析

參考:https://blog.csdn.net/yxz329130952/article/details/50087731

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內(nèi)容

  • 簡介 現(xiàn)在感覺自己做的工作,基本上脫離Android了就是用java寫代碼,而且可能試用期完了就會被刷,很多東西是...
    我叫王菜鳥閱讀 14,792評論 2 17
  • 一.ANR是什么 Application Not Responding,字面意思就是應(yīng)用無響應(yīng),稍加解釋就是用戶的...
    silentleaf閱讀 63,750評論 7 93
  • traces文件分析 簡單了解ANR各個應(yīng)用進(jìn)程和系統(tǒng)進(jìn)程的函數(shù)堆棧信息都輸出到了/data/anr/traces...
    youseewhat閱讀 30,225評論 0 27
  • 在實(shí)際情況中,當(dāng)Android項目的用戶量特別大時候,一些細(xì)小的問題也會被放大,ANR問題就是一個典型的例子。一些...
    Uprising閱讀 54,055評論 4 116
  • ==================================================== 一:什么...
    愛情小傻蛋閱讀 9,795評論 3 31