android的ANR原理剖析及圖解(基於android9.0)

android中如果在主線程執行耗時操作,那麼將會彈出系統彈窗ANR,那麼framework層是如何實現超時的判定、都有哪些情況會產生ANR呢?
經過分析framework源碼發現,有以下四種場景會引起ANR

  • InputDispatching Timeout: 輸入事件分發超時5s,包括按鍵分發事件的超時
  • Service Timeout:服務在12s內未執行完成
  • BroadcastQueue Timeout:比如前臺廣播在10s內執行完成
  • ContentProvider Timeout:內容提供者執行超時

Service的ANR判定及處理

首先我們來看一下從啓動service到彈出ANR dialog的調用時序圖
在這裏插入圖片描述
一共有4個大步驟

  1. ams先startService
  2. ActiveServices啓動service後,通過ams中的handler發送一個延遲執行消息,低版本android是20秒,9.0的android是12秒,期間如果service執行完成,將會移除這個msg,如果未移除,則在12秒後,ams會執行ActiveServices的serviceTimeout方法進行超時判定
  3. 執行ActiveServices的serviceTimeout方法,如果 執行開始時間 > (當前時間-超時時間) 時,則超時,調用AppErrors的appNotResponding方法進行超時處理
  4. AppErrors的appNotResponding超時處理分爲以下6個步驟
    - 忽略關機時的ANR
    - 記錄ANR事件
    - 記錄ANR,打印到main log中
    - dump棧信息,輸出CPU相關信息
    - 添加ANR信息到dropbox日誌
    - 通知UI線程彈出anr的dialog

輸入事件超時判定

和service不同的是,輸入事件的超時是在C層的InputDispatcher.cpp中進行判斷的,在c中判定超時後通知ams,ams再調用AppErrors進行處理ANR,詳細的時序圖如下
在這裏插入圖片描述
整個過程一共分爲4個大步驟

  1. dispatchMotionLocked: 分發輸入事件
  2. handleTargetsNotReadyLocked:處理輸入事件,並判定是否超時
  3. notifyANR:一步步通知ANR,通知次序如圖所示
  4. appNotResponding:處理超時,記錄日誌、彈出ANR的dialog等,此處和service中的處理邏輯一致

在這裏我們詳細剖析以下handleTargetsNotReadyLocked方法來看一下超時的判定

int32_t InputDispatcher::handleTargetsNotReadyLocked(){
	...
	//記錄當前事件爲第一次分發時間
    mInputTargetWaitStartTime = currentTime;
    //設置超時時間
    mInputTargetWaitTimeoutTime = currentTime + timeout;
	...
	//判斷是否超時超時,當前時間大於上次輸入事件記錄超時時間,說明有事件分發超時了,需要觸發ANR
    if (currentTime >= mInputTargetWaitTimeoutTime) {
        onANRLocked(currentTime, applicationHandle, windowHandle,
                entry->eventTime, mInputTargetWaitStartTime, reason);
        *nextWakeupTime = LONG_LONG_MIN;
        return INPUT_EVENT_INJECTION_PENDING;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章