Android ANR,看完不慌

隔壁部門做了一個(gè)評(píng)價(jià)器,就是一個(gè)jsp頁面在安卓設(shè)備上一直運(yùn)行,安卓原生部分的很簡單,就是通過webview加載,打了個(gè)apk。最近用戶反饋說在運(yùn)行一段時(shí)間后,有時(shí)4-5個(gè)小時(shí),有時(shí)10幾個(gè)小時(shí),再次點(diǎn)擊頁面就會(huì)出現(xiàn)程序無響應(yīng)的情況。于是找到我這邊給測(cè)試解決,說真的,我比較慌。

a.自己提出了幾個(gè)可能的問題:

1.設(shè)備的問題(因?yàn)榧胁少彽氖且恍┢嫫婀止值脑O(shè)備)。


不過從設(shè)備信息看,除了low一些,看不出啥問題。
2.webview的問題,或相關(guān)settings沒有配置。
看一一下,他們打的包是用原生的webview,我比較習(xí)慣用騰訊x5內(nèi)核的,就是這個(gè) com.tencent.smtt.sdk.WebView

        webView = new WebView(getApplicationContext());
        webView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        relativeLayout.addView(webView);

WebSettings的相關(guān)配置也是添加的

  WebSettings s = webView.getSettings();
        s.setJavaScriptEnabled(true);
        s.setJavaScriptCanOpenWindowsAutomatically(true);

        @SuppressLint("SdCardPath") String path = "/data/data/" + context.getPackageName() + "/databases/";
        s.setAppCachePath(path);
        s.setAppCacheEnabled(true);
        s.setCacheMode(WebSettings.LOAD_NO_CACHE);
        s.setSaveFormData(true);
        s.setDomStorageEnabled(true);

tWebChromeClient 及WebViewClient相關(guān)也是設(shè)置了的,看起來也沒啥問題。

3.頁面的問題。
頁面不是我寫的,沒證據(jù)不能講。

b.自己提出了幾個(gè)可能的問題

假設(shè)被推翻,出問題的時(shí)間也沒法確定,看來捷徑是走不通了,只能從抓日志下手了,這里用了友盟統(tǒng)計(jì)的sdk去幫助完成這一步,等待兩天之后,錯(cuò)誤日志收獲滿滿,還是比較興奮的。



待俺趕上前去,選取一條仔細(xì)觀瞧,不由得一身冷汗,尷尬了,看不懂。
莫慌,看不不要緊,根據(jù)指導(dǎo)原則猜猜也是有用的。

ANR 顧名思義Application Not Response ,就是程序無響應(yīng),應(yīng)用跑著跑著Duang的卡住了,無法響應(yīng)用戶的操作如觸摸事件等等

觸發(fā)原因和分類,也就是指導(dǎo)原則

觸發(fā)ANR的原因

  • 應(yīng)用進(jìn)程自身引起
    例如:
    1.主線程阻塞、掛起、死循環(huán)
    2.應(yīng)用進(jìn)程的其他線程的CPU占用率高,使得主線程無法搶占到CPU時(shí)間片
  • 其他進(jìn)程間接引起(誤傷)
    例如:
    1.當(dāng)前應(yīng)用進(jìn)程進(jìn)行進(jìn)程間通信請(qǐng)求其他進(jìn)程,其他進(jìn)程的操作長時(shí)間沒有反饋
    2.其他進(jìn)程的CPU占用率極高,使得當(dāng)前應(yīng)用進(jìn)程無法搶占到CPU時(shí)間片

ANR的分類:

  1. 應(yīng)用在5秒內(nèi)未響應(yīng)用戶的輸入事件,如按鍵或觸摸事件
  2. BroadcastReceiver未在10秒內(nèi)完成相關(guān)的處理
  3. Service的各個(gè)生命周期函數(shù)時(shí)20秒內(nèi)沒有執(zhí)行完畢
    接下來試著讀讀日志

anr traces:

generate begin time: 2020-09-10 08:40:39

[DEBUG] dump art internal: 111

[DEBUG] VMExt: 0xb4c7c000, i: 64, str: 3

[DEBUG] runtime trace: 33,20,/data/anr/traces.txt

[DEBUG] aborting: 0xb4bfde3c, 0

[DEBUG] Dump: 0x0, State: 0xb4aed931, JavaStack: 0xb4ae878d

[DEBUG] Thread spec key: 0xb4bff7fc

[DEBUG] current: 0xb4cb6500, pid: 6495

[DEBUG] List: 0xb4c6a800

[DEBUG] Each: 0xb4af3b09

[DEBUG] err: 0xb6d4ee44

[DEBUG] begin each

[DEBUG] dumping 0xb4cb6500 ...

main prio=7 tid=1 Native

  | group= sCount=0 dsCount=0 obj=0x74bcc000 self=0xb4cb6500

  | sysTid=4068 nice=-4 cgrp=default sched=0/0 handle=0xb6f0cb34

  | state=? schedstat=( 0 0 0 ) utm=0 stm=0 core=0 HZ=100

  | stack=0xbe71d000-0xbe71f000 stackSize=8MB

  | held mutexes=

  at android.view.ThreadedRenderer.nSyncAndDrawFrame(Native method)

  at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:341)

  at android.view.ViewRootImpl.draw(ViewRootImpl.java:2620)

  at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2439)

  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2072)

  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1112)

[DEBUG] runtime trace: 33,20,/data/anr/traces.txt這句告訴我們anr日志保存路徑(沒卵用)
main prio=7 tid=1 Native main 表示主線程 prio線程優(yōu)先級(jí) tid不是線程的id,它是一個(gè)在Java虛擬機(jī)中用來實(shí)現(xiàn)線程鎖的變量,隨著線程的增減,這個(gè)變量的值是可能被復(fù)用的. Native不必多說。
tid對(duì)應(yīng)值解釋說明


后面一行

group= sCount=0 dsCount=0 obj=0x74bcc000 self=0xb4cb6500

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

此后是線程的調(diào)度信息

 sysTid=4068 nice=-4 cgrp=default sched=0/0 handle=0xb6f0cb34

sysTid是Linux下的內(nèi)核線程id,nice是線程的調(diào)度優(yōu)先級(jí),sched分別標(biāo)志了線程的調(diào)度策略和優(yōu)先級(jí),cgrp是調(diào)度屬組,handle是線程的處理函數(shù)地址。

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

 stack=0xbe71d000-0xbe71f000 stackSize=8MB

看了日志文件,對(duì)于如何找出ANR的真正原因,還是一件難事,其實(shí)說難不難,文本冗長我們沒必要弄懂每一行的意思,一般的,如果是我們的應(yīng)用造成的anr,至少能夠在這個(gè)文件里看到包名com.xxx.xx的表述,結(jié)合上下文分析應(yīng)該不難,但我這個(gè)沒找到。
除了找應(yīng)用信息,查找wating ,anr等關(guān)鍵字,因?yàn)閍nr的情況一般是讓主線程做了很多耗時(shí)的操作,我這個(gè)是應(yīng)用長駐的,放在柜臺(tái)員前讓辦事用戶再辦完事情進(jìn)行評(píng)價(jià)的,很簡答的功能,原生并沒有耗時(shí)操作,jsp頁面問了問寫的人員也沒有做耗時(shí)操作,這就很奇怪。

苦苦閱讀這個(gè)anr日志時(shí),事情出現(xiàn)了轉(zhuǎn)機(jī),外派員反饋另一個(gè)地區(qū)的設(shè)備是來自不同廠商的,出現(xiàn)問題后廠商過來給設(shè)備進(jìn)行過處理,目前那一批設(shè)備是好的(為啥不早說),于是聯(lián)系那邊詢問,做了什么騷操作,發(fā)來了一個(gè)文件夾:


圖片.png

簡單看了看,主要是給更新了WebViewGoogle_arm32.apk,手機(jī)上是見過這東西的,開發(fā)者選項(xiàng)下查看`webView實(shí)現(xiàn)'就能夠看到,小米華為都有,然而我手里這臺(tái)設(shè)備在設(shè)置里搜尋一圈都沒有(什么鬼設(shè)備)



果斷把這玩意給打上去,之后在 “設(shè)置-->應(yīng)用-->Android System WebView” 看到了這個(gè)東西,不知道是否會(huì)生效。
繼續(xù)打開評(píng)價(jià)器,靜置一個(gè)晚上,看明日會(huì)不會(huì)有錯(cuò)誤。就寫到這里。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容