整體架構(gòu)

觸摸屏幕的時候,Linux內(nèi)核往設(shè)備節(jié)點寫數(shù)據(jù)
EventHub會監(jiān)聽設(shè)備節(jié)點文件
InputReader無限循環(huán),從EventHub中讀取事件,加工后把事件放入InputDispatcher隊列
InputDispatcher無限循環(huán),從InputDispatcher中取出事件,找到合適的Window,把事件寫入這個Window的InputChannel
隨后串口端的Looper會被喚醒
派發(fā)架構(gòu)

以下是3個隊列的流轉(zhuǎn)流程,簡單記為A、B、C隊列

原理
簡而言之,并不是第一次發(fā)起點擊事件就會報ANR的
發(fā)起一次后就不管了
只有當(dāng)后面發(fā)起了,且檢測到前一次超時了,這個時候才算ANR
這個時候可以再深思一下,什么時候,會超時
先明確一個概念,輸入事件的處理,作為Handler中的一個msg
然后超時其實有2個因素:
1、輸入事件msg前可能還有另外的msg沒有處理完
2、輸入事件msg自身執(zhí)行的時間
所以得出公式:ANR = preMessageTime + inputMessageTime
側(cè)面也反映一個道理,輸入事件超時,不一定因為輸入事件太耗時,可能是其他msg的影響,也可能是兩者的共同作用
因此有時候看到ANR堆棧并不從onClick發(fā)起也不要太過驚奇
如何定位ANR?
發(fā)生ANR時,系統(tǒng)會輸出2個比較重要的信息
- longMsg
- 堆棧
堆棧是最友好的信息,但是它不一定準(zhǔn),很多時候你會看到不相關(guān)甚至是nativePollOnce這樣的正常堆棧(不準(zhǔn)的原因是無法精確確保AMS打印堆棧時機和ANR代碼處時機一致,畢竟在2個進程,而且邏輯上還是通信上都有一些時差)
所以longMsg就顯得很重要
Service、ContentProvider、Broadcast的原理是某個生命周期執(zhí)行超時,longMsg會輸出具體的堆棧和生命周期方法
我們可以找到對應(yīng)的生命周期方法,給其method做trace分析,即可定位得八九不離十
而輸入事件的longMsg則要復(fù)雜得多,所以下面展開對longMsg的分析
longMsg分析
1、Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.
InputChannel在onResume后創(chuàng)建,所以很可能onCreate、onStart、onResume執(zhí)行耗時邏輯,會引起這一點
2、Waiting because the [targetType] window is paused.
窗口暫停
3、Waiting because the [targetType] window’s input channel is not registered with the input dispatcher. The window may be in the process of being removed.
窗口為連接,窗口所在的進程可能正在被移除
4、Waiting because the [targetType] window’s input connection is [Connection.Status]. The window may be in the process of being removed.
窗口連接已死亡,窗口所在的進程可能正在被移除
5、Waiting because the [targetType] window’s input channel is full. Outbound queue length: [outboundQueue長度]. Wait queue length: [waitQueue長度].
窗口連接已滿
6、Waiting to send key event because the [targetType] window has not finished processing all of the input events that were previously delivered to it. Outbound queue length: [outboundQueue長度]. Wait queue length: [waitQueue長度].
點擊事件超時
7、Waiting to send non-key event because the [targetType] window has not finished processing certain input events that were delivered to it over 500ms ago. Wait queue length: [waitQueue長度]. Wait queue head age: [等待時長].
觸摸事件超時
其中2,3,4,5目前沒發(fā)現(xiàn)觸發(fā)條件,可能是比較極端的情況,很少見到
1,6,7是比較清楚的,但是6,7又得不到任何有用的結(jié)論
綜上只有1的情況,可以得知,很可能是Activity生命周期超時引起的
后記
學(xué)習(xí)自
http://gityuan.com/2019/04/06/android-anr/
http://gityuan.com/2017/01/01/input-anr/
有什么寫得錯誤、讓人費解或遺漏的地方,希望可以不吝賜教,我會馬上更改