android token机制_对Android 中的 ANR 进行详解
前言
關于ANR,以前只知道Activity、BroadCastReceiver、Service三種組件的ANR時限、一般采用哪些方式避免ANR、以及通過data/anr/traces.txt去分析ANR原因,感覺好像這就夠用了。
但是,前幾天看源碼的時候,腦海里突然跳出一個問題:
ANR是怎么判斷的5秒還是10秒?
這個問題迅速擴大為一連串問題:
ANR的時間定義在哪些文件里?
ANR是怎么計時的?
是誰在監控ANR?
所有的ANR都會彈窗嗎?
traces.txt能記錄多少內容?
ANR一定是app代碼問題導致的嗎?
前ANR機制的基本原理
任何功能都有個執行者,以及業務邏輯的實現原理,在ANR上,就是兩個問題:
1.ANR是誰做的
ANR不可能是在應用層做的,有兩個理由:
從能力上,發生ANR時,App自己已經死掉了,沒有能力處理;
從安全上,App的安全事實上是不可控的,如果有惡意App故意不處理ANR,設備就廢了。
所以,ANR的監控和處理,只能是在系統層做的。
系統層要做ANR的話,我們首先想到是在AMS,因為AMS管理著所有的組件,也只有AMS知道組件是什么時候啟動的,以便判斷是否觸發了ANR。
不過,實際上,還有Activity Service,Input Manager Service這些服務,也參與了ANR的管理。
2.ANR是怎么判斷超時時間的
這個問題,其實就是怎樣定義超時時間、什么時候開始計時、以及如何計時的問題。
ANR超時時間的定義,是在執行者,也就是系統服務那里定義的,這個容易理解。
ANR從什么時候開始計時呢,在Android中,實際上是系統服務在控制每個組件的生命周期回調,所以可以在這個邏輯入口開始計時。
至于如何計時的問題,其實Android系統里已經有一個時間相對準確的機制,就是Handler機制,可以用Handler機制發送延時消息,如果超時了,就發出ANR,如果沒有超時,就取消隊列里的延時消息,這就解決了計時的問題。
這樣看來,ANR的基本原理如下:
不過,這個機制并不完全,在判斷Activity的InputDispatching超時的情況下,是InputDispatcher發現上一個事件沒有處理完,新的事件又進來了,才會去走ANR。
各組件觸發ANR的過程
會產生ANR的,包括Activity、Service、BroadCastReceiver、ContentProvider和Application,他們各自的ANR過程都有些不同,我們先從簡單的看起。
1.BroadCastReceiver
時間定義
廣播的超時時間是定義在AMS里:
BROADCAST_FG_TIMEOUT:10s
BROADCAST_BG_TIMEOUT:60s
前/后臺廣播是在發送Intent時,在intent.addFlag里定義的。
觸發時機
當AMS處理廣播時,會調用processNextBroadcast函數,這里面會處理并行廣播和串行廣播,其中,并行廣播是單向通知,不需要等待反饋,所以并行廣播沒有ANR。
在處理串行廣播時:
首先,判斷是否已經有一個廣播超時消息;然后,根據目標進程優先級,分別在前臺隊列和后臺隊列(超時時限不同)中排隊處理;接下來,根據不同的隊列,發出不同延時的ANR消息;如果處理及時,取消延時消息;如果處理超時,觸發ANR;
ANR處理
廣播的ANR處理相對簡單,主要是再次判斷是否超時、記錄日志,記錄ANR次數等。
然后就繼續調用processNextBroadcast函數,處理下一條廣播了。
2.Service
Service真正的管理者是ActiveServices,AMS雖然會去交互與通信,但在啟動服務時,是交給ActiveServices去做的。
時間定義
服務的超時時間是定義在AS里:
SERVICE_TIMEOUT:20s;
SERVICE_BACKGROUND_TIMEOUT:200s;
在ActiveService執行startServiceLocked啟動服務時,會判斷啟動服務的發起方的進程(Process.THREAD_GROUP_BG_NONINTERACTIVE),以便選擇不同的超時時間。
觸發時機
ActivityServices會調用realStartServiceLocked函數啟動Service,最前面會先發送一個延遲消息,sendMessageAtTime(msg,time);其中的time,是在最開始startServiceLocked函數中判斷出前/后臺進程,然后裝在ServiceRecord中,一路傳過來的。
如果Service操作執行完畢,會執行serviceDoneExecutingLocked,這里面會移除延遲消息。
如果Service執行超時,會執行mServices.serviceTimeout。
ANR處理
其實Service的ANR處理也相對簡單,記錄日志,清理anr活動等。
mServices.serviceTimeout((ProcessRecord)msg.obj)函數里,提供了進程信息。
3.ContentProvider
ContentProvider也是會ANR的,如果AMS中的ContentProviderClient在處理中超時,也可以啟動ANR,超時時間和是否使用,由開發者決定:
CONTENT_PROVIDER_PUBLISH_TIMEOUT:10s
CONTENT_PROVIDER_RETAIN_TIME:20s
4.Application
Application的啟動是執行在主線程的,attachBaseContext和onCreate等回調也是在主線程的,這里如果出現ANR,會影響到當前組件的運行。
5.Activity
Activity的ANR是相對最復雜的,也只有Activity中出現的ANR會彈出ANR提示框。
InputDispatching
Activity最主要的功能之一是交互,為了方便交互,Android中的InputDispatcher會發出操作事件,最終在Input Manager Service中發出事件,通過InputChannel,向Activity分發事件。
交互事件必須得到響應,如果不能及時處理,IMS就會報出ANR,交給AMS去彈出ANR提示框。
KeyDispatching
如果輸入是個Key事件,會從IMS進入ActivityRecord.Token.keyDispatchingTimeOut,然后進入AMS處理,不同的是,在ActivityRecord中,會先截留一次Key的不響應,只有當Key連續第二次處理超時,才會彈出ANR提示框。
窗口焦點
Activity總是需要有一個當前窗口來響應事件的,但如果遲遲沒有當前窗口(獲得焦點),比如在Activity切換時,舊Activity已經onPause,新的Activity一直沒有onResume,持續超過5秒,就會ANR。
App的生命周期太慢,或CPU資源不足,或WMS異常,都可能導致窗口焦點。
時間定義
在AMS中定義
KEY_DISPATCHING_TIMEOUT:5s
INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT :60s
觸發時機
輸入界面的觸發時機,絕不是盡快提示ANR,而是盡量不提示ANR,因為ANR一旦提示出來,App一般也就關掉了。
對于InputDispatcher來說,如果有新的輸入事件時,上一個輸入事件還沒有處理完,才會通知IMS去判斷,是否需要處理ANR。
ANR處理
首先,寫日志(data/anr/traces.txt)。
然后,會發出一個Message,彈出ANR提示框。
ANR的處理和日志
ANR是在AMS的appNotResponding函數中處理的,主要是記錄日志,和彈出提示。
如何記錄
log日志記錄在data/anr/traces.txt文件中,這個文件每次只記錄最近的一次ANR,有可能記錄失敗。
文件內容包括dump棧,CPU負載,IO Wait等
如何解讀
分析ANR,除了檢查代碼的生命周期函數是否有耗時操作,還可以分析traces日志,分析角度主要包括:
- 棧信息,一般可以知道在哪段代碼附近發生了ANR,可能不是直接原因,但一般在問題點附近。
- CPU用量,看負載比例和平均負載,判斷是不是有別的App占用了過多的CPU。
- IO Wait,看IOWait的占比是否很高,判斷是否在等待IO。
ANR的原因
如果從根源上劃分的話,導致ANR的原因有如下幾點:
- IO操作,如數據庫、文件、網絡
- CPU不足,一般是別的App占用了大量的CPU,導致App無法及時處理
- 硬件操作,如camera
- 線程問題,如主線程被join/sleep,或wait鎖等導致超時
- service問題,如service忙導致超時無響應,或service binder的數量達到上限
- system server問題,如WatchDog發現ANR
總結
以上是生活随笔為你收集整理的android token机制_对Android 中的 ANR 进行详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 贵州陈酿酒v15酱香酒多少钱?
- 下一篇: 嘎着怎么做好吃?