【問題分析】Android 5.0版本SystemUI反覆發生ANR crash
問題描述
Android 5.0版本上按照下述的步驟, 會觸發SystemUI程序反覆ANR然後crash的問題
1. 下拉systemui面板
2. adb –host shell
3. ps –ax systemui
4. kill -SIGSTOP <systemui pid>
5. 然後在systemui面板中不停觸控,由於systemui 已經stop 所以會觸發一次ANR,緊接著就進一步觸發本問題中提到的systemui 反覆ANR,AMS 反覆restart system
Root Cause分析:
如上面的ANR 時序分析圖所示, 導致問題的關鍵步驟是InputMonitor模組處理notifyANR過程中
longtimeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(...
這裡timeout的返回值會被InputDispacther模組作為下一次超時判斷的計算變數,AMS 返回的timeout 單位是ms,而InputDispatcher模組中使用的單位是nanos,差別為10^6級別. InputMonitor模組沒有及時將ms級別的timeout轉換成nanos,就直接將timeout值送回InputDispacther了(實際上這裡的timeout要求下次檢查時間超時等待為8秒鐘)
最終導致InputDispatcher模組錯誤的將一個ms級別的timout(沒有在換算成為nano second,差了10^6級別)值去計算下一次事件超時等待時間
mInputTargetWaitTimeoutTime= now() + newTimeout;
從而導致systemui 還沒有足夠的時間去重新啟動(本來應用有8秒超時等待時間),而下一次InputDispatcher dispatchOnce呼叫馬上發生事件派發超時,進而導致重複發生了 ANR kill systemui 的時序過程
解決方案
try {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
if (timeout >= 0) {
// The activity manager declined to abort dispatching.
// Wait a bit longer and timeout again later.
return timeout * 1000000L; // nanoseconds
}
} catch (RemoteException ex) {
}
如上圖所示, 在<AOSP>/framework/base/services/core/java/com/android/server/wm/InputMonitor.java 的notifyANR 函式中將return 的timeout (ms) 乘以 1000000換算為nanosecond再進行返回. Google 在後續的Android 版本中已經按照這個方式做了fix