原創(chuàng)內(nèi)容,轉(zhuǎn)載請(qǐng)注明出處,多謝配合。
先針對(duì)前面的Input調(diào)用流程進(jìn)行一個(gè)簡(jiǎn)單總結(jié):
EventHub: 收集底層硬件設(shè)備tp報(bào)點(diǎn)。打開(kāi)"/dev/input/"目錄下的input設(shè)備,并將其注冊(cè)到epoll的監(jiān)控隊(duì)列中。一旦對(duì)應(yīng)設(shè)備上有可讀的input事件,馬上包裝成event,上報(bào)給InputReader。
InputReader: 獲取EventHub上報(bào)的input事件,通過(guò)deviceid,找到具體的InputDevice,然后匹配上對(duì)應(yīng)的InputMapper來(lái)處理對(duì)應(yīng)input事件。InputMapper最終會(huì)按對(duì)應(yīng)的NotifyArgs數(shù)據(jù)結(jié)構(gòu)對(duì)事件進(jìn)行封裝,并加入到ArgsQueue中。最終flush操作會(huì)將ArgsQueue中的每一個(gè)Arg取出來(lái)轉(zhuǎn)成對(duì)應(yīng)的Entry加入到InputDispatcher的mInboundQueue。
InputDispatcher: InboundQueue隊(duì)頭取出事件,匹配焦點(diǎn)窗口,通過(guò)mConnectionsByFd 獲取到對(duì)應(yīng)的Connection,將eventEntry轉(zhuǎn)化為DispatchEntry并加入到Connection的outboundQueue隊(duì)列,同時(shí)通過(guò)Connection獲取InputChannel將事件發(fā)送到客戶(hù)端,再將DispatchEntry從outboundQueue移到waitQueue里,等待客戶(hù)端完成處理反饋完成消息,而InputDispatcher收到消息后回調(diào)handleReceiveCallback,將DispatchEntry從waitQueue里移出。
ViewRootImpl: 調(diào)用NaitveInputEventReceiver的handleEvent()接收input事件,轉(zhuǎn)成java層對(duì)應(yīng)的事件,通過(guò)InputStage體系相關(guān)類(lèi)按責(zé)任鏈的模式進(jìn)行事件分發(fā)操作。事件分發(fā)處理完畢后會(huì)執(zhí)行finishInputEvent,通過(guò)InputChannel 發(fā)送完成的message,給到服務(wù)端InputDispatcher回調(diào)InputDispatcher.handleReceiveCallback()。
接下來(lái)解析Input ANR原理(代碼來(lái)源: Android 8.0)。
一、ANR觸發(fā)條件
frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
//ANR計(jì)算的起點(diǎn)時(shí)間
nsecs_t currentTime = now();
...
//如果正在處理的mPendingEvent為空才會(huì)進(jìn)來(lái)
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
return;
}
} else {
//從mInboundQueue頭部取出一個(gè)事件
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
resetANRTimeoutsLocked();
}
...
switch (mPendingEvent->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
...
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
…
if (done) {
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
void InputDispatcher::releasePendingEventLocked() {
if (mPendingEvent) {
resetANRTimeoutsLocked();
releaseInboundEventLocked(mPendingEvent);
mPendingEvent = NULL;
}
}
void InputDispatcher::resetANRTimeoutsLocked() {
// 這里reset等待超時(shí)原因和handle
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
mInputTargetWaitApplicationHandle.clear();
}
InputDispatcher從dispatchOnceInnerLocked開(kāi)始事件的分發(fā)流程:
- 先獲取anr計(jì)算的起點(diǎn)時(shí)間
- 獲取事件,mPendingEvent不等于空才會(huì)進(jìn)獲取事件邏輯,mInboundQueue不為空的情況下,從頭部取出事件,通過(guò)resetANRTimeoutsLocked來(lái)reset等待超時(shí)原因和handle。
- 針對(duì)不同類(lèi)型進(jìn)行對(duì)應(yīng)的事件分發(fā)
- 事件處理完之后通過(guò)releasePendingEventLocked重置mPendingEvent = NULL;
因此前一個(gè)事件沒(méi)有處理完,下一次分發(fā)是不會(huì)進(jìn)入到獲取事件邏輯的。
繼續(xù)跟dispatchKeyLocked流程:
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
… //尋找焦點(diǎn)窗口
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
...
//分發(fā)事件
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
再看findFocusedWindowTargetsLocked
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
...
if (mFocusedWindowHandle == NULL) {
if (mFocusedApplicationHandle != NULL) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle, NULL, nextWakeupTime,
"Waiting because no window has focus but there is a "
"focused application that may eventually add a window "
"when it finishes starting up.");
goto Unresponsive;
}
ALOGI("Dropping event because there is no focused window or focused application.");
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
…
// Check whether the window is ready for more input.
reason = checkWindowReadyForMoreInputLocked(currentTime,
mFocusedWindowHandle, entry, "focused");
...
if (!reason.isEmpty()) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
goto Unresponsive;
}
...
return injectionResult;
}
這里先看checkWindowReadyForMoreInputLocked,這個(gè)方法主要是針對(duì)window還沒(méi)有準(zhǔn)備好的情況,收集對(duì)應(yīng)的reason:
String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
const char* targetType) {
//窗口暫停
if (windowHandle->getInfo()->paused) {
return String8::format("Waiting because the %s window is paused.", targetType);
}
ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
//窗口未連接
if (connectionIndex < 0) {
return String8::format("Waiting because the %s window's input channel is not "
"registered with the input dispatcher. The window may be in the process "
"of being removed.", targetType);
}
//窗口連接已死亡
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
if (connection->status != Connection::STATUS_NORMAL) {
return String8::format("Waiting because the %s window's input connection is %s."
"The window may be in the process of being removed.", targetType,
connection->getStatusLabel());
}
//窗口連接已滿(mǎn)
if (connection->inputPublisherBlocked) {
return String8::format("Waiting because the %s window's input channel is full. "
"Outbound queue length: %d. Wait queue length: %d.",
targetType, connection->outboundQueue.count(), connection->waitQueue.count());
}
if (eventEntry->type == EventEntry::TYPE_KEY) {
//按鍵事件,輸出隊(duì)列或事件等待隊(duì)列不為空
if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) {
return String8::format("Waiting to send key event because the %s window has not "
"finished processing all of the input events that were previously "
"delivered to it. Outbound queue length: %d. Wait queue length: %d.",
targetType, connection->outboundQueue.count(), connection->waitQueue.count());
}
} else {
//非按鍵事件,事件等待隊(duì)列不為空且頭事件分發(fā)超時(shí)500ms
if (!connection->waitQueue.isEmpty()
&& currentTime >= connection->waitQueue.head->deliveryTime
+ STREAM_AHEAD_EVENT_TIMEOUT) {
return String8::format("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 String8::empty();
}
然后再看handleTargetsNotReadyLocked,這里currentTime作為參數(shù)一直從dispatchOnceInnerLocked傳遞到handleTargetsNotReadyLocked,這里是ANR計(jì)算的核心方法:
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 (applicationHandle == NULL && windowHandle == NULL) {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
#if DEBUG_FOCUS
ALOGD("Waiting for system to become ready for input. Reason: %s", reason);
#endif
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
mInputTargetWaitTimeoutExpired = false;
mInputTargetWaitApplicationHandle.clear();
}
} else {
//前面resetANRTimeoutsLocked執(zhí)行時(shí)reset mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE,所以能進(jìn)方法
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
#if DEBUG_FOCUS
ALOGD("Waiting for application to become ready for input: %s. Reason: %s",
getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
reason);
#endif
nsecs_t timeout;
if (windowHandle != NULL) {
timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
} else if (applicationHandle != NULL) {
timeout = applicationHandle->getDispatchingTimeout(
DEFAULT_INPUT_DISPATCHING_TIMEOUT);
} else {
timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; //5S
}
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = currentTime + timeout; //當(dāng)前時(shí)間+5S
mInputTargetWaitTimeoutExpired = false;
mInputTargetWaitApplicationHandle.clear();
if (windowHandle != NULL) {
mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
}
if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
mInputTargetWaitApplicationHandle = applicationHandle;
}
}
}
if (mInputTargetWaitTimeoutExpired) {
return INPUT_EVENT_INJECTION_TIMED_OUT;
}
//當(dāng)前時(shí)間大于設(shè)置的超時(shí)時(shí)間就會(huì)走ANR觸發(fā)流程
if (currentTime >= mInputTargetWaitTimeoutTime) {
onANRLocked(currentTime, applicationHandle, windowHandle,
entry->eventTime, mInputTargetWaitStartTime, reason);
// Force poll loop to wake up immediately on next iteration once we get the
// ANR response back from the policy.
*nextWakeupTime = LONG_LONG_MIN;
return INPUT_EVENT_INJECTION_PENDING;
} else {
// Force poll loop to wake up when timeout is due.
if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {
*nextWakeupTime = mInputTargetWaitTimeoutTime;
}
return INPUT_EVENT_INJECTION_PENDING;
}
}
可見(jiàn)ANR超時(shí)時(shí)間區(qū)間是從dispatchOnceInnerLocked()開(kāi)始,到下次執(zhí)行handleTargetsNotReadyLocked()這段應(yīng)用為準(zhǔn)備就緒的時(shí)間來(lái)決定是否觸發(fā)ANR。
二、ANR執(zhí)行流程
handleTargetsNotReadyLocked方法中,當(dāng)前時(shí)間大于設(shè)置的超時(shí)時(shí)間就會(huì)走ANR觸發(fā)流程onANRLocked。
void InputDispatcher::onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) {
float dispatchLatency = (currentTime - eventTime) * 0.000001f;
float waitDuration = (currentTime - waitStartTime) * 0.000001f;
ALOGI("Application is not responding: %s. "
"It has been %0.1fms since event, %0.1fms since wait started. Reason: %s",
getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
dispatchLatency, waitDuration, reason);
// 收集ANR現(xiàn)場(chǎng)信息
time_t t = time(NULL);
struct tm tm;
localtime_r(&t, &tm);
char timestr[64];
strftime(timestr, sizeof(timestr), "%F %T", &tm);
mLastANRState.clear();
mLastANRState.append(INDENT "ANR:\n");
mLastANRState.appendFormat(INDENT2 "Time: %s\n", timestr);
mLastANRState.appendFormat(INDENT2 "Window: %s\n",
getApplicationWindowLabelLocked(applicationHandle, windowHandle).string());
mLastANRState.appendFormat(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
mLastANRState.appendFormat(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
mLastANRState.appendFormat(INDENT2 "Reason: %s\n", reason);
//dump信息
dumpDispatchStateLocked(mLastANRState);
//將ANR命令加入commandQueue
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
commandEntry->inputWindowHandle = windowHandle;
commandEntry->reason = reason;
}
這里收集ANR現(xiàn)場(chǎng)信息并執(zhí)行dump操作,然后將ANR命令加入commandQueue,在下一輪InputDispatcher.dispatchOnce中是先通過(guò)runCommandsLockedInterruptible()方法取出 mCommandQueue隊(duì)列的所有命令逐一執(zhí)行。ANR對(duì)應(yīng)的command為doNotifyANRLockedInterruptible。
void InputDispatcher::doNotifyANRLockedInterruptible(
CommandEntry* commandEntry) {
mLock.unlock();
//mPolicy是指NativeInputManager
nsecs_t newTimeout = mPolicy->notifyANR(
commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,
commandEntry->reason);
mLock.lock();
resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
commandEntry->inputWindowHandle != NULL
? commandEntry->inputWindowHandle->getInputChannel() : NULL);
}
這里調(diào)用NativeInputManager的notifyANR方法。
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputWindowHandle>& inputWindowHandle, const String8& reason) {
...
//jni調(diào)用java方法
jlong newTimeout = env->CallLongMethod(mServiceObj,
gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj,
reasonObj);
...
return newTimeout;
}
這里通過(guò)JNI調(diào)用InputManagerService執(zhí)行notifyANR。
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// Native callback.
private long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
return mWindowManagerCallbacks.notifyANR(
inputApplicationHandle, inputWindowHandle, reason);
}
此處mWindowManagerCallbacks是指InputMonitor對(duì)象。
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
AppWindowToken appWindowToken = null;
WindowState windowState = null;
...
// All the calls below need to happen without the WM lock held since they call into AM.
mService.mAmInternal.saveANRState(reason);
…
else if (windowState != null) {
try {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
long timeout = ActivityManager.getService().inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
...
}
這里通過(guò)token打通對(duì)應(yīng)Activity與Window的聯(lián)系,最終調(diào)用AMS的inputDispatchingTimedOut
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.FILTER_EVENTS);
}
ProcessRecord proc;
long timeout;
synchronized (this) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pid);
}
timeout = getInputDispatchingTimeoutLocked(proc);
}
if (!inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
return -1;
}
return timeout;
}
最終調(diào)用inputDispatchingTimedOut
public boolean inputDispatchingTimedOut(final ProcessRecord proc,
final ActivityRecord activity, final ActivityRecord parent,
final boolean aboveSystem, String reason) {
...
if (proc != null) {
...
mHandler.post(new Runnable() {
@Override
public void run() {
mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);
}
});
}
return true;
}
通過(guò)handler機(jī)制,交由“ActivityManager”線(xiàn)程執(zhí)行ANR處理過(guò)程, appNotResponding會(huì)dump信息以及彈窗提示ANR等。
frameworks/base/services/core/java/com/android/server/am/AppErrors.java
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, boolean aboveSystem, final String annotation) {
...
// For background ANRs, don't pass the ProcessCpuTracker to
// avoid spending 1/2 second collecting stats to rank lastPids.
//dump信息
File tracesFile = mService.dumpStackTraces(true, firstPids,
(isSilentANR) ? null : processCpuTracker,
(isSilentANR) ? null : lastPids,
nativePids);
...
//DropBox收集信息
mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
...
// 彈App Not Responding dialog
Message msg = Message.obtain();
HashMap<String, Object> map = new HashMap<String, Object>();
msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
msg.obj = map;
msg.arg1 = aboveSystem ? 1 : 0;
map.put("app", app);
if (activity != null) {
map.put("activity", activity);
}
mService.mUiHandler.sendMessage(msg);
}
}
最后,可以通過(guò)adb shell dumpsys input來(lái)查看手機(jī)當(dāng)前的input狀態(tài), 輸出內(nèi)容分別為EventHub.dump(), InputReader.dump(),InputDispatcher.dump()這3類(lèi),另外如果發(fā)生過(guò)input ANR,那么也會(huì)輸出上一個(gè)ANR的狀態(tài)。
最后借輝輝一張圖:

ANR原理分析總結(jié):
InputReader線(xiàn)程通過(guò)EventHub監(jiān)聽(tīng)底層上報(bào)的輸入事件,一旦收到輸入事件則將其放至mInBoundQueue隊(duì)列,并喚醒InputDispatcher線(xiàn)程
InputDispatcher開(kāi)始分發(fā)輸入事件,設(shè)置ANR監(jiān)控的起點(diǎn)時(shí)間。先檢測(cè)是否有正在處理的事件:mPendingEvent,如果沒(méi)有則從mInBoundQueue隊(duì)頭取事件,并將其賦值給mPendingEvent,且重置ANR的timeout;否則不會(huì)從mInBoundQueue中取出事件,也不會(huì)重置timeout。然后檢查窗口是否就緒:checkWindowReadyForMoreInputLocked,
滿(mǎn)足以下任一情況,則會(huì)進(jìn)入ANR檢測(cè)狀態(tài):
- 窗口暫停
- 窗口未連接
- 窗口連接已死亡
- 窗口連接已滿(mǎn)
- 按鍵事件,outboundQueue或者waitQueue不為空
- 非按鍵事件,waitQueue不為空且頭事件分發(fā)超時(shí)500ms
若窗口未準(zhǔn)備就緒,即滿(mǎn)足以上條件:
就是窗口還沒(méi)準(zhǔn)備好跟你進(jìn)行socket通信,那么你就只能等待,這個(gè)時(shí)候如果滿(mǎn)足ANR超時(shí)時(shí)間會(huì)觸發(fā)ANR。收集ANR信息,生成doNotifyANRLockedInterruptible加入commandQueue中,下次執(zhí)行InputDispatcher::dispatchOnce 時(shí)候,先執(zhí)行command,走notifyANR
流程,最終通過(guò)AMS發(fā)送消息來(lái)執(zhí)行ANR處理過(guò)程:appNotResponding會(huì)dump信息以及彈窗提示ANR等。
若窗口準(zhǔn)備就緒,連接成功:
則將mPendingEvent轉(zhuǎn)移到outBoundQueue隊(duì)列,當(dāng)outBoundQueue不為空,且應(yīng)用管道對(duì)端連接狀態(tài)正常,則將數(shù)據(jù)從outboundQueue中取出事件,放入waitQueue隊(duì)列,InputDispatcher通過(guò)socket告知目標(biāo)應(yīng)用所在進(jìn)程可以準(zhǔn)備開(kāi)始干活,App在初始化時(shí)默認(rèn)已創(chuàng)建跟中控系統(tǒng)雙向通信的socketpair,此時(shí)App的主線(xiàn)程收到輸入事件后,會(huì)層層轉(zhuǎn)發(fā)到目標(biāo)窗口來(lái)處理。完成工作后,會(huì)通過(guò)socket向中控系統(tǒng)匯報(bào)工作完成,則中控系統(tǒng)會(huì)將該事件從waitQueue隊(duì)列中移除。