Android全面解析ANR日志

不論從事安卓應(yīng)用開發(fā)片橡,還是安卓系統(tǒng)研發(fā)妈经,應(yīng)該都遇到應(yīng)用無響應(yīng)(簡稱ANR)問題,當(dāng)應(yīng)用程序一段時(shí)間無法及時(shí)響應(yīng)捧书,則會彈出ANR對話框吹泡,讓用戶選擇繼續(xù)等待,還是強(qiáng)制關(guān)閉经瓷。本文將帶你全面解析Android之ANR日志

一爆哑、概述

解決ANR一直是Android 開發(fā)者需要掌握的重要技巧,一般從三個(gè)方面著手舆吮。

開發(fā)階段:通過工具檢查各個(gè)方法的耗時(shí)揭朝,卡頓情況,發(fā)現(xiàn)一處修改一處歪泳。
線上階段:這個(gè)階段主要依靠監(jiān)控工具發(fā)現(xiàn)ANR并上報(bào)萝勤,比如matrix。
分析階段:如果線上用戶發(fā)生ANR呐伞,并且你獲取了一份日志敌卓,這就涉及了本文要分享的內(nèi)容——ANR日志分析技巧。

二伶氢、ANR產(chǎn)生機(jī)制

網(wǎng)上通俗的一段面試答題

ANR——應(yīng)用無響應(yīng)趟径,Activity是5秒,BroadCastReceiver是10秒癣防,Service是20秒蜗巧。

這句話說的很籠統(tǒng),要想深入分析定位ANR蕾盯,需要知道更多知識點(diǎn)幕屹,一般來說,ANR按產(chǎn)生機(jī)制,分為4類:

2.1 輸入事件超時(shí)(5s)

InputEvent Timeout

a.InputDispatcher發(fā)送key事件給 對應(yīng)的進(jìn)程的 Focused Window 望拖,對應(yīng)的window不存在渺尘、處于暫停態(tài)、或通道(input channel)占滿说敏、通道未注冊鸥跟、通道異常、或5s內(nèi)沒有處理完一個(gè)事件盔沫,就會發(fā)生ANR

b.InputDispatcher發(fā)送MotionEvent事件有個(gè)例外之處:當(dāng)對應(yīng)Touched Window的 input waitQueue中有超過0.5s的事件医咨,inputDispatcher會暫停該事件,并等待5s架诞,如果仍舊沒有收到window的‘finish'事件拟淮,則觸發(fā)ANR

c.下一個(gè)事件到達(dá),發(fā)現(xiàn)有一個(gè)超時(shí)事件才會觸發(fā)ANR

2.2 廣播類型超時(shí)(前臺15s侈贷,后臺60s)

BroadcastReceiver Timeout

a.靜態(tài)注冊的廣播和有序廣播會ANR惩歉,動態(tài)注冊的非有序廣播并不會ANR
b.廣播發(fā)送時(shí)等脂,會判斷該進(jìn)程是否存在俏蛮,不存在則創(chuàng)建,創(chuàng)建進(jìn)程的耗時(shí)也算在超時(shí)時(shí)間里
c.只有當(dāng)進(jìn)程存在前臺顯示的Activity才會彈出ANR對話框上遥,否則會直接殺掉當(dāng)前進(jìn)程
d.當(dāng)onReceive執(zhí)行超過閾值(前臺15s搏屑,后臺60s),將產(chǎn)生ANR
e.如何發(fā)送前臺廣播:Intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)

2.3 服務(wù)超時(shí)(前臺20s粉楚,后臺200s)

Service Timeout

a.Service的以下方法都會觸發(fā)ANR:onCreate(),onStartCommand(), onStart(), onBind(), onRebind(), onTaskRemoved(), onUnbind(),onDestroy().
b.前臺Service超時(shí)時(shí)間為20s辣恋,后臺Service超時(shí)時(shí)間為200s
c.如何區(qū)分前臺、后臺執(zhí)行————當(dāng)前APP處于用戶態(tài)模软,此時(shí)執(zhí)行的Service則為前臺執(zhí)行伟骨。
d.用戶態(tài):有前臺activity、有前臺廣播在執(zhí)行燃异、有foreground service執(zhí)行

2.4 ContentProvider 類型

a.ContentProvider創(chuàng)建發(fā)布超時(shí)并不會ANR
b.使用ContentProviderclient來訪問ContentProverder可以自主選擇觸發(fā)ANR携狭,超時(shí)時(shí)間自己定client.setDetectNotResponding(PROVIDER_ANR_TIMEOUT);

ps:Activity生命周期超時(shí)會不會ANR?——經(jīng)測試并不會回俐。

override fun onCreate(savedInstanceState: Bundle?) {
    Thread.sleep(60000)
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
}

三逛腿、導(dǎo)致ANR的原因

很多開發(fā)者認(rèn)為,那就是耗時(shí)操作導(dǎo)致ANR仅颇,全部是app應(yīng)用層的問題单默。實(shí)際上,線上環(huán)境大部分ANR由系統(tǒng)原因?qū)е隆?/p>

3.1 應(yīng)用層導(dǎo)致ANR(耗時(shí)操作)

1.函數(shù)阻塞:如死循環(huán)忘瓦、主線程IO搁廓、處理大數(shù)據(jù)
2.鎖出錯(cuò):主線程等待子線程的鎖
3.內(nèi)存緊張:系統(tǒng)分配給一個(gè)應(yīng)用的內(nèi)存是有上限的,長期處于內(nèi)存緊張,會導(dǎo)致頻繁內(nèi)存交換境蜕,進(jìn)而導(dǎo)致應(yīng)用的一些操作超時(shí)
3.2 系統(tǒng)導(dǎo)致ANR
1.CPU被搶占:一般來說线欲,前臺在玩游戲,可能會導(dǎo)致你的后臺廣播被搶占CPU
2.系統(tǒng)服務(wù)無法及時(shí)響應(yīng):比如獲取系統(tǒng)聯(lián)系人等汽摹,系統(tǒng)的服務(wù)都是Binder機(jī)制李丰,服務(wù)能力也是有限的,有可能系統(tǒng)服務(wù)長時(shí)間不響應(yīng)導(dǎo)致ANR
3.其他應(yīng)用占用的大量內(nèi)存

四逼泣、分析日志

發(fā)生ANR的時(shí)候趴泌,系統(tǒng)會產(chǎn)生一份anr日志文件(手機(jī)的/data/anr 目錄下,文件名稱可能各廠商不一樣拉庶,業(yè)內(nèi)大多稱呼為trace文件)嗜憔,內(nèi)含如下幾項(xiàng)重要信息。

4.1 CPU 負(fù)載

Load: 2.62 / 2.55 / 2.25

CPU usage from 0ms to 1987ms later (2020-03-10 08:31:55.169 to 2020-03-10 08:32:17.156):

  41% 2080/system_server: 28% user + 12% kernel / faults: 76445 minor 180 major

  26% 9378/com.xiaomi.store: 20% user + 6.8% kernel / faults: 68408 minor 68 major

........省略N行.....

66% TOTAL: 20% user + 15% kernel + 28% iowait + 0.7% irq + 0.7% softirq

如上所示:

第一行:1氏仗、5吉捶、15 分鐘內(nèi)正在使用和等待使用CPU 的活動進(jìn)程的平均數(shù)
第二行:表明負(fù)載信息抓取在ANR發(fā)生之后的0~1987ms。同時(shí)也指明了ANR的時(shí)間點(diǎn):2020-03-10 08:31:55.169
中間部分:各個(gè)進(jìn)程占用的CPU的詳細(xì)情況
最后一行:各個(gè)進(jìn)程合計(jì)占用的CPU信息皆尔。

名詞解釋:
1.user:用戶態(tài),kernel:內(nèi)核態(tài)
2.faults:內(nèi)存缺頁呐舔,minor——輕微的,major——重度慷蠕,需要從磁盤拿數(shù)據(jù)
3.iowait:IO使用(等待)占比
4.irq:硬中斷珊拼,softirq:軟中斷

注意:
iowait占比很高,意味著有很大可能流炕,是io耗時(shí)導(dǎo)致ANR澎现,具體進(jìn)一步查看有沒有進(jìn)程faults major比較多。
單進(jìn)程CPU的負(fù)載并不是以100%為上限每辟,而是有幾個(gè)核剑辫,就有百分之幾百,如4核上限為400%渠欺。

4.2 內(nèi)存信息

Total number of allocations 476778  進(jìn)程創(chuàng)建到現(xiàn)在一共創(chuàng)建了多少對象
Total bytes allocated 52MB 進(jìn)程創(chuàng)建到現(xiàn)在一共申請了多少內(nèi)存
Total bytes freed 52MB   進(jìn)程創(chuàng)建到現(xiàn)在一共釋放了多少內(nèi)存
Free memory 777KB    不擴(kuò)展堆的情況下可用的內(nèi)存
Free memory until GC 777KB  GC前的可用內(nèi)存
Free memory until OOME 383MB  OOM之前的可用內(nèi)存
Total memory 當(dāng)前總內(nèi)存(已用+可用)
Max memory 384MB  進(jìn)程最多能申請的內(nèi)存

從含義可以得出結(jié)論:Free memory until OOME的值很小的時(shí)候妹蔽,已經(jīng)處于內(nèi)存緊張狀態(tài)。應(yīng)用可能是占用了過多內(nèi)存峻堰。

另外讹开,除了trace文件中有內(nèi)存信息,普通的eventlog日志中捐名,也有內(nèi)存信息(不一定打拥┩颉)

04-02 22:00:08.195  1531  1544 I am_meminfo: [350937088,41086976,492830720,427937792,291887104]

以上四個(gè)值分別指的是:
Cached
Free,
Zram,
Kernel,Native
Cached+Free的內(nèi)存代表著當(dāng)前整個(gè)手機(jī)的可用內(nèi)存,如果值很小镶蹋,意味著處于內(nèi)存緊張狀態(tài)成艘。一般低內(nèi)存的判定閾值為:4G 內(nèi)存手機(jī)以下閥值:350MB赏半,以上閥值則為:450MB

ps:如果ANR時(shí)間點(diǎn)前后,日志里有打印onTrimMemory淆两,也可以作為內(nèi)存緊張的一個(gè)參考判斷

4.3 堆棧消息

堆棧信息是最重要的一個(gè)信息断箫,展示了ANR發(fā)生的進(jìn)程當(dāng)前所有線程的狀態(tài)。

suspend all histogram:  Sum: 2.834s 99% C.I. 5.738us-7145.919us Avg: 607.155us Max: 41543us

DALVIK THREADS (248):

"main" prio=5 tid=1 Native
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x74b17080 self=0x7bb7a14c00
  | sysTid=2080 nice=-2 cgrp=default sched=0/0 handle=0x7c3e82b548
  | state=S schedstat=( 757205342094 583547320723 2145008 ) utm=52002 stm=23718 core=5 HZ=100
  | stack=0x7fdc995000-0x7fdc997000 stackSize=8MB
  | held mutexes=
  kernel: __switch_to+0xb0/0xbc
  kernel: SyS_epoll_wait+0x288/0x364
  kernel: SyS_epoll_pwait+0xb0/0x124
  kernel: cpu_switch_to+0x38c/0x2258
  native: #00 pc 000000000007cd8c  /system/lib64/libc.so (__epoll_pwait+8)
  native: #01 pc 0000000000014d48  /system/lib64/libutils.so (android::Looper::pollInner(int)+148)
  native: #02 pc 0000000000014c18  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+60)
  native: #03 pc 0000000000127474  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)

  at android.os.MessageQueue.nativePollOnce(Native method)
  at android.os.MessageQueue.next(MessageQueue.java:330)
  at android.os.Looper.loop(Looper.java:169)
  at com.android.server.SystemServer.run(SystemServer.java:508)
  at com.android.server.SystemServer.main(SystemServer.java:340)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:536)秋冰、
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:856)

  ........省略N行.....

  "OkHttp ConnectionPool" daemon prio=5 tid=251 TimedWaiting
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x13daea90 self=0x7bad32b400
  | sysTid=29998 nice=0 cgrp=default sched=0/0 handle=0x7b7d2614f0
  | state=S schedstat=( 951407 137448 11 ) utm=0 stm=0 core=3 HZ=100
  | stack=0x7b7d15e000-0x7b7d160000 stackSize=1041KB
  | held mutexes=
  at java.lang.Object.wait(Native method)
  - waiting on <0x05e5732e> (a com.android.okhttp.ConnectionPool)
  at com.android.okhttp.ConnectionPool$1.run(ConnectionPool.java:103)
  - locked <0x05e5732e> (a com.android.okhttp.ConnectionPool)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
  at java.lang.Thread.run(Thread.java:764)

上日志所示仲义,本文截圖了兩個(gè)線程信息,一個(gè)是主線程main剑勾,它的狀態(tài)是native埃撵。

另一個(gè)是OkHttp ConnectionPool,它的狀態(tài)是TimeWaiting虽另。眾所周知暂刘,教科書上說線程狀態(tài)有5種:新建、就緒捂刺、執(zhí)行谣拣、阻塞、死亡族展。而Java中的線程狀態(tài)有6種森缠,6種狀態(tài)都定義在:java.lang.Thread.State中


image.png

問題來了,上述main線程的native是什么狀態(tài)苛谷,哪來的辅鲸?其實(shí)trace文件中的狀態(tài)是是CPP代碼中定義的狀態(tài)格郁,下面是一張對應(yīng)關(guān)系表腹殿。


image.png

由此可知,main函數(shù)的native狀態(tài)是正在執(zhí)行JNI函數(shù)例书。堆棧信息是我們分析ANR的第一個(gè)重要的信息锣尉,一般來說:main線程處于BLOCK、WAITING决采、TIMEWAITING狀態(tài)自沧,那基本上是函數(shù)阻塞導(dǎo)致ANR;如果main線程無異常树瞭,則應(yīng)該排查CPU負(fù)載和內(nèi)存環(huán)境拇厢。

五、典型案例分析

5.1 主線程無卡頓晒喷,處于正常狀態(tài)堆棧

"main" prio=5 tid=1 Native
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x74b38080 self=0x7ad9014c00
  | sysTid=23081 nice=0 cgrp=default sched=0/0 handle=0x7b5fdc5548
  | state=S schedstat=( 284838633 166738594 505 ) utm=21 stm=7 core=1 HZ=100
  | stack=0x7fc95da000-0x7fc95dc000 stackSize=8MB
  | held mutexes=
  kernel: __switch_to+0xb0/0xbc
  kernel: SyS_epoll_wait+0x288/0x364
  kernel: SyS_epoll_pwait+0xb0/0x124
  kernel: cpu_switch_to+0x38c/0x2258
  native: #00 pc 000000000007cd8c  /system/lib64/libc.so (__epoll_pwait+8)
  native: #01 pc 0000000000014d48  /system/lib64/libutils.so (android::Looper::pollInner(int)+148)
  native: #02 pc 0000000000014c18  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+60)
  native: #03 pc 00000000001275f4  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
  at android.os.MessageQueue.nativePollOnce(Native method)
  at android.os.MessageQueue.next(MessageQueue.java:330)
  at android.os.Looper.loop(Looper.java:169)
  at android.app.ActivityThread.main(ActivityThread.java:7073)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:536)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)

上述主線程堆棧就是一個(gè)很正常的空閑堆棧孝偎,表明主線程正在等待新的消息。

如果ANR日志里主線程是這樣一個(gè)狀態(tài)凉敲,那可能有兩個(gè)原因:

該ANR是CPU搶占或內(nèi)存緊張等其他因素引起
這份ANR日志抓取的時(shí)候衣盾,主線程已經(jīng)恢復(fù)正常
遇到這種空閑堆棧寺旺,可以按照第3節(jié)的方法去分析CPU、內(nèi)存的情況势决。其次可以關(guān)注抓取日志的時(shí)間和ANR發(fā)生的時(shí)間是否相隔過久阻塑,時(shí)間過久這個(gè)堆棧就沒有分析意義了。

5.2 主線程執(zhí)行耗時(shí)操作

"main" prio=5 tid=1 Runnable
  | group="main" sCount=0 dsCount=0 flags=0 obj=0x72deb848 self=0x7748c10800
  | sysTid=8968 nice=-10 cgrp=default sched=0/0 handle=0x77cfa75ed0
  | state=R schedstat=( 24783612979 48520902 756 ) utm=2473 stm=5 core=5 HZ=100
  | stack=0x7fce68b000-0x7fce68d000 stackSize=8192KB
  | held mutexes= "mutator lock"(shared held)
  at com.example.test.MainActivity$onCreate$2.onClick(MainActivity.kt:20)——關(guān)鍵行9础3旅А!
  at android.view.View.performClick(View.java:7187)
  at android.view.View.performClickInternal(View.java:7164)
  at android.view.View.access$3500(View.java:813)
  at android.view.View$PerformClick.run(View.java:27640)
  at android.os.Handler.handleCallback(Handler.java:883)
  at android.os.Handler.dispatchMessage(Handler.java:100)
  at android.os.Looper.loop(Looper.java:230)
  at android.app.ActivityThread.main(ActivityThread.java:7725)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:526)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)

上述日志表明虽抄,主線程正處于執(zhí)行狀態(tài)传透,看堆棧信息可知不是處于空閑狀態(tài),發(fā)生ANR是因?yàn)橐惶巆lick監(jiān)聽函數(shù)里執(zhí)行了耗時(shí)操作极颓。

5.3 主線程被鎖阻塞(搜索關(guān)鍵詞held by)


  | group="main" sCount=1 dsCount=0 flags=1 obj=0x72deb848 self=0x7748c10800

  | sysTid=22838 nice=-10 cgrp=default sched=0/0 handle=0x77cfa75ed0

  | state=S schedstat=( 390366023 28399376 279 ) utm=34 stm=5 core=1 HZ=100

  | stack=0x7fce68b000-0x7fce68d000 stackSize=8192KB

  | held mutexes=

  at com.example.test.MainActivity$onCreate$1.onClick(MainActivity.kt:15)

  - waiting to lock <0x01aed1da> (a java.lang.Object) held by thread 3 ——————關(guān)鍵行V煅巍!菠隆!

  at android.view.View.performClick(View.java:7187)

  at android.view.View.performClickInternal(View.java:7164)

  at android.view.View.access$3500(View.java:813)

  at android.view.View$PerformClick.run(View.java:27640)

  at android.os.Handler.handleCallback(Handler.java:883)

  at android.os.Handler.dispatchMessage(Handler.java:100)

  at android.os.Looper.loop(Looper.java:230)

  at android.app.ActivityThread.main(ActivityThread.java:7725)

  at java.lang.reflect.Method.invoke(Native method)

  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:526)

  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)

  ........省略N行.....

  "WQW TEST" prio=5 tid=3 TimeWating

  | group="main" sCount=1 dsCount=0 flags=1 obj=0x12c44230 self=0x772f0ec000

  | sysTid=22938 nice=0 cgrp=default sched=0/0 handle=0x77391fbd50

  | state=S schedstat=( 274896 0 1 ) utm=0 stm=0 core=1 HZ=100

  | stack=0x77390f9000-0x77390fb000 stackSize=1039KB

  | held mutexes=

  at java.lang.Thread.sleep(Native method)

  - sleeping on <0x043831a6> (a java.lang.Object)

  at java.lang.Thread.sleep(Thread.java:440)

  - locked <0x043831a6> (a java.lang.Object)

  at java.lang.Thread.sleep(Thread.java:356)

  at com.example.test.MainActivity$onCreate$2$thread$1.run(MainActivity.kt:22)

  - locked <0x01aed1da> (a java.lang.Object)————————————————————關(guān)鍵行1铡!骇径!

  at java.lang.Thread.run(Thread.java:919)

這是一個(gè)典型的主線程被鎖阻塞的例子躯肌;

waiting to lock <0x01aed1da> (a java.lang.Object) held by thread 3

其中等待的鎖是<0x01aed1da>,這個(gè)鎖的持有者是線程 3破衔。進(jìn)一步搜索 “tid=3” 找到線程3清女, 發(fā)現(xiàn)它正在TimeWating。

那么ANR的原因找到了:線程3持有了一把鎖晰筛,并且自身長時(shí)間不釋放嫡丙,主線程等待這把鎖發(fā)生超時(shí)。在線上環(huán)境中读第,常見因鎖而ANR的場景是SharePreference寫入曙博。

5.4 CPU被搶占

CPU usage from 0ms to 10625ms later (2020-03-09 14:38:31.633 to 2020-03-09 14:38:42.257):

  543% 2045/com.alibaba.android.rimet: 54% user + 89% kernel / faults: 4608 minor 1 major ————關(guān)鍵行!A鳌父泳!

  99% 674/android.hardware.camera.provider@2.4-service: 81% user + 18% kernel / faults: 403 minor

  24% 32589/com.wang.test: 22% user + 1.4% kernel / faults: 7432 minor 1 major

  ........省略N行.....

如上日志,第二行是釘釘?shù)倪M(jìn)程吴汪,占據(jù)CPU高達(dá)543%惠窄,搶占了大部分CPU資源,因而導(dǎo)致發(fā)生ANR漾橙。

5.5內(nèi)存緊張導(dǎo)致ANR

如果有一份日志杆融,CPU和堆棧都很正常(不貼出來了),仍舊發(fā)生ANR近刘,考慮是內(nèi)存緊張擒贸。

從CPU第一行信息可以發(fā)現(xiàn)臀晃,ANR的時(shí)間點(diǎn)是

2020-10-31 22:38:58.468—CPU usage from 0ms to 21752ms later (2020-10-31 22:38:58.468 to 2020-10-31 22:39:20.220)

接著去系統(tǒng)日志里搜索am_meminfo, 這個(gè)沒有搜索到介劫。再次搜索onTrimMemory徽惋,果然發(fā)現(xiàn)了很多條記錄;

10-31 22:37:19.749 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0

10-31 22:37:33.458 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0

10-31 22:38:00.153 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0

10-31 22:38:58.731 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0

10-31 22:39:02.816 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0

可以看出座韵,在發(fā)生ANR的時(shí)間點(diǎn)前后险绘,內(nèi)存都處于緊張狀態(tài),level等級是80誉碴,查看Android API 文檔宦棺;

/**
    * Level for {@link #onTrimMemory(int)}: the process is nearing the end
    * of the background LRU list, and if more memory isn't found soon it will
    * be killed.
    */
   static final int TRIM_MEMORY_COMPLETE = 80;

可知80這個(gè)等級是很嚴(yán)重的,應(yīng)用馬上就要被殺死黔帕,被殺死的這個(gè)應(yīng)用從名字可以看出來是桌面代咸,連桌面都快要被殺死,那普通應(yīng)用能好到哪里去呢成黄?

一般來說呐芥,發(fā)生內(nèi)存緊張,會導(dǎo)致多個(gè)應(yīng)用發(fā)生ANR奋岁,所以在日志中如果發(fā)現(xiàn)有多個(gè)應(yīng)用一起ANR了思瘟,可以初步判定,此ANR與你的應(yīng)用無關(guān)闻伶。

5.6 系統(tǒng)服務(wù)超時(shí)導(dǎo)致ANR

系統(tǒng)服務(wù)超時(shí)一般會包含BinderProxy.transactNative關(guān)鍵字滨攻,請看如下日志:

"main" prio=5 tid=1 Native

  | group="main" sCount=1 dsCount=0 flags=1 obj=0x727851e8 self=0x78d7060e00

  | sysTid=4894 nice=0 cgrp=default sched=0/0 handle=0x795cc1e9a8

  | state=S schedstat=( 8292806752 1621087524 7167 ) utm=707 stm=122 core=5 HZ=100

  | stack=0x7febb64000-0x7febb66000 stackSize=8MB

  | held mutexes=

  kernel: __switch_to+0x90/0xc4

  kernel: binder_thread_read+0xbd8/0x144c

  kernel: binder_ioctl_write_read.constprop.58+0x20c/0x348

  kernel: binder_ioctl+0x5d4/0x88c

  kernel: do_vfs_ioctl+0xb8/0xb1c

  kernel: SyS_ioctl+0x84/0x98

  kernel: cpu_switch_to+0x34c/0x22c0

  native: #00 pc 000000000007a2ac  /system/lib64/libc.so (__ioctl+4)

  native: #01 pc 00000000000276ec  /system/lib64/libc.so (ioctl+132)

  native: #02 pc 00000000000557d4  /system/lib64/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+252)

  native: #03 pc 0000000000056494  /system/lib64/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+60)

  native: #04 pc 00000000000562d0  /system/lib64/libbinder.so (android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+216)

  native: #05 pc 000000000004ce1c  /system/lib64/libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+72)

  native: #06 pc 00000000001281c8  /system/lib64/libandroid_runtime.so (???)

  native: #07 pc 0000000000947ed4  /system/framework/arm64/boot-framework.oat (Java_android_os_BinderProxy_transactNative__ILandroid_os_Parcel_2Landroid_os_Parcel_2I+196)

  at android.os.BinderProxy.transactNative(Native method) ————————————————關(guān)鍵行!@逗病光绕!

  at android.os.BinderProxy.transact(Binder.java:804)

  at android.net.IConnectivityManager$Stub$Proxy.getActiveNetworkInfo(IConnectivityManager.java:1204)—關(guān)鍵行!

  at android.net.ConnectivityManager.getActiveNetworkInfo(ConnectivityManager.java:800)

  at com.xiaomi.NetworkUtils.getNetworkInfo(NetworkUtils.java:2)

  at com.xiaomi.frameworkbase.utils.NetworkUtils.getNetWorkType(NetworkUtils.java:1)

  at com.xiaomi.frameworkbase.utils.NetworkUtils.isWifiConnected(NetworkUtils.java:1)

從堆楒浚可以看出獲取網(wǎng)絡(luò)信息發(fā)生了ANR:getActiveNetworkInfo奇钞。

系統(tǒng)的服務(wù)都是Binder機(jī)制(16個(gè)線程),服務(wù)能力也是有限的漂坏,有可能系統(tǒng)服務(wù)長時(shí)間不響應(yīng)導(dǎo)致ANR。如果其他應(yīng)用占用了所有Binder線程媒至,那么當(dāng)前應(yīng)用只能等待顶别。

可進(jìn)一步搜索:blockUntilThreadAvailable關(guān)鍵字:

at android.os.Binder.blockUntilThreadAvailable(Native method)

如果有發(fā)現(xiàn)某個(gè)線程的堆棧,包含此字樣拒啰,可進(jìn)一步看其堆棧驯绎,確定是調(diào)用了什么系統(tǒng)服務(wù)。此類ANR也是屬于系統(tǒng)環(huán)境的問題谋旦,如果某類型機(jī)器上頻繁發(fā)生此問題剩失,應(yīng)用層可以考慮規(guī)避策略屈尼。

以上就是全面解析Android之ANR日志的詳細(xì)內(nèi)容,更多關(guān)于Android ANR日志的資料請關(guān)注腳本之家其它相關(guān)文章拴孤!

參考:
https://www.dianjilingqu.com/615880.html
https://www.yii666.com/blog/66647.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脾歧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子演熟,更是在濱河造成了極大的恐慌鞭执,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芒粹,死亡現(xiàn)場離奇詭異兄纺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)化漆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門估脆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人座云,你說我怎么就攤上這事旁蔼。” “怎么了疙教?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵棺聊,是天一觀的道長。 經(jīng)常有香客問我贞谓,道長限佩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任裸弦,我火速辦了婚禮祟同,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘理疙。我一直安慰自己晕城,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布窖贤。 她就那樣靜靜地躺著砖顷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赃梧。 梳的紋絲不亂的頭發(fā)上滤蝠,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音授嘀,去河邊找鬼物咳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蹄皱,可吹牛的內(nèi)容都是我干的览闰。 我是一名探鬼主播芯肤,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼压鉴!你這毒婦竟也來了崖咨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤晴弃,失蹤者是張志新(化名)和其女友劉穎掩幢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體上鞠,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡际邻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了芍阎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片世曾。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖谴咸,靈堂內(nèi)的尸體忽然破棺而出轮听,到底是詐尸還是另有隱情,我是刑警寧澤岭佳,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布血巍,位于F島的核電站,受9級特大地震影響珊随,放射性物質(zhì)發(fā)生泄漏述寡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一叶洞、第九天 我趴在偏房一處隱蔽的房頂上張望鲫凶。 院中可真熱鬧,春花似錦衩辟、人聲如沸螟炫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昼钻。三九已至,卻和暖如春财饥,著一層夾襖步出監(jiān)牢的瞬間换吧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工钥星, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人满着。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓谦炒,卻偏偏與公主長得像贯莺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子宁改,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

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