隔壁部門做了一個(gè)評(píng)價(jià)器批狐,就是一個(gè)jsp頁(yè)面在安卓設(shè)備上一直運(yùn)行滨彻,安卓原生部分的很簡(jiǎn)單术徊,就是通過webview加載本刽,打了個(gè)apk。最近用戶反饋說在運(yùn)行一段時(shí)間后弧关,有時(shí)4-5個(gè)小時(shí)盅安,有時(shí)10幾個(gè)小時(shí),再次點(diǎn)擊頁(yè)面就會(huì)出現(xiàn)程序無響應(yīng)的情況世囊。于是找到我這邊給測(cè)試解決别瞭,說真的,我比較慌株憾。
a.自己提出了幾個(gè)可能的問題:
1.設(shè)備的問題(因?yàn)榧胁少?gòu)的是一些奇奇怪怪的設(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.頁(yè)面的問題。
頁(yè)面不是我寫的霎褐,沒證據(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)程的操作長(zhǎng)時(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ù)是否被正常掛起增長(zhǎng),但是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í)間片長(zhǎng)度变丧,有的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í)說難不難鲁捏,文本冗長(zhǎng)我們沒必要弄懂每一行的意思芯砸,一般的,如果是我們的應(yīng)用造成的anr,至少能夠在這個(gè)文件里看到包名com.xxx.xx的表述给梅,結(jié)合上下文分析應(yīng)該不難假丧,但我這個(gè)沒找到。
除了找應(yīng)用信息动羽,查找wating ,anr等關(guān)鍵字包帚,因?yàn)閍nr的情況一般是讓主線程做了很多耗時(shí)的操作,我這個(gè)是應(yīng)用長(zhǎng)駐的曹质,放在柜臺(tái)員前讓辦事用戶再辦完事情進(jìn)行評(píng)價(jià)的婴噩,很簡(jiǎn)答的功能擎场,原生并沒有耗時(shí)操作,jsp頁(yè)面問了問寫的人員也沒有做耗時(shí)操作几莽,這就很奇怪迅办。
苦苦閱讀這個(gè)anr日志時(shí),事情出現(xiàn)了轉(zhuǎn)機(jī)章蚣,外派員反饋另一個(gè)地區(qū)的設(shè)備是來自不同廠商的站欺,出現(xiàn)問題后廠商過來給設(shè)備進(jìn)行過處理,目前那一批設(shè)備是好的(為啥不早說)纤垂,于是聯(lián)系那邊詢問矾策,做了什么騷操作,發(fā)來了一個(gè)文件夾:
簡(jiǎn)單看了看峭沦,主要是給更新了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ò)誤琐谤。就寫到這里蟆技。