前言
有好多人向我咨詢過Input ANR問題,說實話,我也是一直無法徹底的解釋清楚,我下決心要徹底搞懂這塊知識點。
話不多說先上圖
一個event的正常流程
InputReader線程
1.InputReader線程一旦發現有新的event,判斷mInBoundQueue是否為空,如果為空,設置wakeup = true
2.添加event到mInBoundQueue,如果wakeup==true,喚醒InputDispatcher的mLooper
InputDispatcher線程
1.沒有事做的時候,mLooper.pollOnce(timeoutMillis)休眠, timeoutMillis為下次喚醒的delay時間。
2.mLooper被喚醒
a.發現mPendingEvnet為空且mInBoundQueue不為空,從mInBoundQueue獲取一個event,并賦值給mPendingEvnet,走到第3步
b.發現mPendingEvnet不為空,走第3步
c.發現mPendingEvnet為空且mInBoundQueue為空,回到第1步休眠
3.檢查當前的window是否可以接收mPendingEvnet,正常情況下是OK的,異常的情況,我們后面討論。
4.通過InputChannel分發mPendingEvnet到APP層后, mPendingEvnet保存到waitQueue
5.發送成功后releasePendingEventLocked(mPendingEvnet == null),并將mLooper的nextWakeupTime設置LONG_LONG_MIN,然后回到第1步。
6.當App層處理完event后會發送一個finish信號過來,然后移除waitQueue中event,并喚醒mLooper,觸發第2步
Input ANR的發生的原因:主線程的卡頓
怎么理解這句話如何導致的ANR?
主線程卡頓主要是導致的InputDispatcher線程中的正常流程第6步無法完成。
假設event1的沒有完成第6步,這時候來了一個event2這個流程是怎么樣子的:
第1步,第2步是一樣的
第3步:
waitQueue不為空,導致checkWindowReadyForMoreInputLocked返回值不為空,觸發handleTargetsNotReadyLocked,然后將當前時間+5s作為mInputTargetWaitTimeoutTime,并設置mInputTargetWaitTimeoutTime為mLooper下一次喚醒的時間
std::string reason = checkWindowReadyForMoreInputLocked(currentTime,
touchedWindow.windowHandle, entry, "touched");
if (!reason.empty()) {//reason不等于空
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
NULL, touchedWindow.windowHandle, nextWakeupTime, reason.c_str());
goto Unresponsive;
}
std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
const char* targetType) {
//省略好多代碼,因為不止一種請款,我們只分析一種
if (!connection->waitQueue.isEmpty()
&& currentTime >= connection->waitQueue.head->deliveryTime
+ STREAM_AHEAD_EVENT_TIMEOUT) {
return StringPrintf("Waiting to send non-key event because the %s window has not "
"finished processing certain input events that were delivered to it over "
"%0.1fms ago. Wait queue length: %d. Wait queue head age: %0.1fms.",
targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,
connection->waitQueue.count(),
(currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f);
}
return "";
}
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
const EventEntry* entry,
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime, const char* reason) {
//省略好多代碼
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
//省略好多代碼
//設置第一次卡頓的flag后面進來就不會設置了
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
mInputTargetWaitStartTime = currentTime;
//設置mInputTargetWaitTimeoutTime為當前時間+5s
mInputTargetWaitTimeoutTime = currentTime + timeout;//timeout = 5s
//省略好多代碼
}
//如何當前的時候大于mInputTargetWaitTimeoutTime就出現ANR,默認第一次進來是走else
if (currentTime >= mInputTargetWaitTimeoutTime) {
onANRLocked(currentTime, applicationHandle, windowHandle,
entry->eventTime, mInputTargetWaitStartTime, reason);
*nextWakeupTime = LONG_LONG_MIN;
return INPUT_EVENT_INJECTION_PENDING;
} else {
//將mInputTargetWaitTimeoutTime下一次wakeup的時間
if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {
*nextWakeupTime = mInputTargetWaitTimeoutTime;
}
return INPUT_EVENT_INJECTION_PENDING;
}
}
第4步:
因為無法發送event2,releasePendingEventLocked就不會觸發,mPendingEvnet就會保留發送失敗的event2。
第5步:
情況A:在mInputTargetWaitTimeoutTime之前event1完成了常規的操作中的第6步,發送finish信號,就會喚醒mLooper,然后繼續處理mPendingEvnet,也就是event2,因為waitQueue已經為空了,那么event2就會按照正常流程的處理了
情況B:在mInputTargetWaitTimeoutTime之前event1沒有完成常規的操作第6步,這時候mLooper被handleTargetsNotReadyLocked中設置的wakeuptime所喚醒,然后繼續處理mPendingEvnet,也就是event2,因為waitQueue不為空,event1還在,所以又會觸發handleTargetsNotReadyLocked,這一次只會走以下代碼,然后觸發ANR
if (currentTime >= mInputTargetWaitTimeoutTime) {
onANRLocked(currentTime, applicationHandle, windowHandle,
entry->eventTime, mInputTargetWaitStartTime, reason);
*nextWakeupTime = LONG_LONG_MIN;
return INPUT_EVENT_INJECTION_PENDING;
}
總結
Input ANR是所有ANR中最難理解的一種ANR,我只分析了其中一種情況的Input ANR,想要了解所有Input ANR,只需要在源碼中搜索handleTargetsNotReadyLocked出現的位置,結合代碼看就知道了。
記住一句話:InputDispatcher永遠只能單線程處理一個mPendingEvent,如果分發失敗,下一次會繼續分發同一個mPendingEvent。