隔壁部門做了一個(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的分類:
- 應(yīng)用在5秒內(nèi)未響應(yīng)用戶的輸入事件,如按鍵或觸摸事件
- BroadcastReceiver未在10秒內(nèi)完成相關(guān)的處理
- 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è)文件夾:

簡單看了看,主要是給更新了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ò)誤。就寫到這里。