赞
踩
在看这篇博文,大家可以参考看gityuan 《Input系统—InputDispatcher线程》 《Input系统—ANR原理分析》
ANR时间区间便是指当前这次的事件dispatch过程中执行findFocusedWindowTargetsLocked()方法到下一次执行resetANRTimeoutsLocked()的时间区间. 以下5个时机会reset. 都位于InputDispatcher.cpp文件:
resetAndDropEverythingLocked
releasePendingEventLocked
setFocusedApplication
dispatchOnceInnerLocked
setInputDispatchMode
简单来说, 主要是以下4个场景,会有机会执行resetANRTimeoutsLocked:
解冻屏幕, 系统开/关机的时刻点 (thawInputDispatchingLw, setEventDispatchingLw)
wms聚焦app的改变 (WMS.setFocusedApp, WMS.removeAppToken)
设置input filter的过程 (IMS.setInputFilter)
再次分发事件的过程(dispatchOnceInnerLocked)
当InputDispatcher线程 findFocusedWindowTargetsLocked()过程调用到handleTargetsNotReadyLocked,且满足超时5s的情况则会调用onANRLocked().
5.1 dispatchMotionLocked
- bool InputDispatcher::dispatchMotionLocked(
- nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
- ATRACE_CALL();
- // Preprocessing.
- if (! entry->dispatchInProgress) {
- entry->dispatchInProgress = true;
-
- logOutboundMotionDetails("dispatchMotion - ", entry);
- }
-
- // Clean up if dropping the event.
- if (*dropReason != DROP_REASON_NOT_DROPPED) {
- setInjectionResult(entry, *dropReason == DROP_REASON_POLICY
- ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
- return true;
- }
-
- bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
-
- // Identify targets.
- std::vector<InputTarget> inputTargets;
-
- bool conflictingPointerActions = false;
- int32_t injectionResult;
- if (isPointerEvent) {//点击事件
- // Pointer event. (eg. touchscreen)
- injectionResult = findTouchedWindowTargetsLocked(currentTime,
- entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
- } else {//触摸事件
- // Non touch event. (eg. trackball)
- injectionResult = findFocusedWindowTargetsLocked(currentTime,
- entry, inputTargets, nextWakeupTime);
- }
- if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
- return false;
- }
-
- setInjectionResult(entry, injectionResult);
- if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
- if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
- CancelationOptions::Mode mode(isPointerEvent ?
- CancelationOptions::CANCEL_POINTER_EVENTS :
- CancelationOptions::CANCEL_NON_POINTER_EVENTS);
- CancelationOptions options(mode, "input event injection failed");
- synthesizeCancelationEventsForMonitorsLocked(options);
- }
- return true;
- }
-
- // Add monitor channels from event's or focused display.
- addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
- if (isPointerEvent) {
- ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId);
- if (stateIndex >= 0) {
- const TouchState& state = mTouchStatesByDisplay.valueAt(stateIndex);
- if (!state.portalWindows.empty()) {
- // The event has gone through these portal windows, so we add monitoring targets of
- // the corresponding displays as well.
- for (size_t i = 0; i < state.portalWindows.size(); i++) {
- const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo();
- addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
- -windowInfo->frameLeft, -windowInfo->frameTop);
- }
- }
- }
- }
- // Dispatch the motion.
- if (conflictingPointerActions) {
- CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
- "conflicting pointer actions");
- synthesizeCancelationEventsForAllConnectionsLocked(options);
- }
- dispatchEventLocked(currentTime, entry, inputTargets);
- return true;
- }

当事件到来系统会分:点击事件还触摸事件来处理。
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
injectionResult = findTouchedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
}
- int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
- const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
- int32_t injectionResult;
- String8 reason;
-
- 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;
- }
-
- //权限检查
- if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
- injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
- goto Failed;
- }
-
- //检测窗口是否为更多的输入操作而准备就绪
- reason = checkWindowReadyForMoreInputLocked(currentTime,
- mFocusedWindowHandle, entry, "focused");
- if (!reason.isEmpty()) {
-
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
- goto Unresponsive;
- }
-
- injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- //成功找到目标窗口,添加到目标窗口
- addWindowTargetLocked(mFocusedWindowHandle,
- InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
- inputTargets);
-
- Failed:
- Unresponsive:
- //TODO: 统计等待时长信息,目前没有实现,这个方法还是很值得去改造
- nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
- updateDispatchStatisticsLocked(currentTime, entry,
- injectionResult, timeSpentWaitingForApplication);
- return injectionResult;
- }

寻找聚焦窗口失败的情况:
另外,还有更多的失败场景见checkWindowReadyForMoreInputLocked的过程,如下
- 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());
- }
-
- // 当窗口连接已满,则保持等待
- 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) {
- // 按键事件,输出队列或事件等待队列不为空
- 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 {
- // 非按键事件,事件等待队列不为空且头事件分发超时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();

- int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
- const MotionEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
- bool* outConflictingPointerActions) {
- ATRACE_CALL();
- enum InjectionPermission {
- INJECTION_PERMISSION_UNKNOWN,
- INJECTION_PERMISSION_GRANTED,
- INJECTION_PERMISSION_DENIED
- };
- ......
- // Ensure all touched foreground windows are ready for new input.
- for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
- if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
- // Check whether the window is ready for more input.
- std::string reason = checkWindowReadyForMoreInputLocked(currentTime,
- touchedWindow.windowHandle, entry, "touched");
- if (!reason.empty()) {
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- nullptr, touchedWindow.windowHandle, nextWakeupTime, reason.c_str());
- goto Unresponsive;
- }
- }
- }
- .......
- }

- nt32_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) {
- mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;
- mInputTargetWaitStartTime = currentTime; //当前时间
- mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
- mInputTargetWaitTimeoutExpired = false;
- mInputTargetWaitApplicationHandle.clear();
- }
- } else {
- if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
- 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;
- //这里的currentTime是指执行dispatchOnceInnerLocked方法体的起点
- mInputTargetWaitStartTime = currentTime;
- mInputTargetWaitTimeoutTime = currentTime + timeout;
- 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; //等待超时已过期,则直接返回
- }
-
- //当超时5s,则进入ANR流程
- if (currentTime >= mInputTargetWaitTimeoutTime) {
- onANRLocked(currentTime, applicationHandle, windowHandle,
- entry->eventTime, mInputTargetWaitStartTime, reason);
-
- *nextWakeupTime = LONG_LONG_MIN; //强制立刻执行轮询来执行ANR策略
- return INPUT_EVENT_INJECTION_PENDING;
- } else {
- if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {
- *nextWakeupTime = mInputTargetWaitTimeoutTime; //当触发超时则强制执行轮询
- }
- return INPUT_EVENT_INJECTION_PENDING;
- }
- }

handleTargetsNotReadyLocked()的判断过程:
- 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的现场信息
- 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);
- dumpDispatchStateLocked(mLastANRState);
-
- //将ANR命令加入mCommandQueue
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyANRLockedInterruptible);
- commandEntry->inputApplicationHandle = applicationHandle;
- commandEntry->inputWindowHandle = windowHandle;
- commandEntry->reason = reason;
- }

- public long notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHandle inputWindowHandle, String reason) {
- AppWindowToken appWindowToken = null;
- WindowState windowState = null;
- boolean aboveSystem = false;
- synchronized (mService.mWindowMap) {
- if (inputWindowHandle != null) {
- windowState = (WindowState) inputWindowHandle.windowState;
- if (windowState != null) {
- appWindowToken = windowState.mAppToken;
- }
- }
- if (appWindowToken == null && inputApplicationHandle != null) {
- appWindowToken = (AppWindowToken)inputApplicationHandle.appWindowToken;
- }
- //输出input事件分发超时log
- if (windowState != null) {
- Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
- + "sending to " + windowState.mAttrs.getTitle()
- + ". Reason: " + reason);
- int systemAlertLayer = mService.mPolicy.windowTypeToLayerLw(
- WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- aboveSystem = windowState.mBaseLayer > systemAlertLayer;
- } else if (appWindowToken != null) {
- Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
- + "sending to application " + appWindowToken.stringName
- + ". Reason: " + reason);
- } else {
- Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
- + ". Reason: " + reason);
- }
- mService.saveANRStateLocked(appWindowToken, windowState, reason);
- }
-
- if (appWindowToken != null && appWindowToken.appToken != null) {
- //【见小节3.6.1】
- boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(reason);
- if (! abort) {
- return appWindowToken.inputDispatchingTimeoutNanos; //5s
- }
- } else if (windowState != null) {
- //【见小节3.6.2】
- long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(
- windowState.mSession.mPid, aboveSystem, reason);
- if (timeout >= 0) {
- return timeout * 1000000L; //5s
- }
- }
- return 0;
- }

- boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
- ApplicationInfo aInfo, String parentShortComponentName,
- WindowProcessController parentProcess, boolean aboveSystem, String reason) {
- if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission " + FILTER_EVENTS);
- }
-
- final String annotation;
- if (reason == null) {
- annotation = "Input dispatching timed out";
- } else {
- annotation = "Input dispatching timed out (" + reason + ")";
- }
- //如果进程没有被杀死
- if (proc != null) {
- synchronized (this) {
- if (proc.isDebugging()) {
- return false;
- }
-
- /// M: ANR Debug Mechanism @{
- if (mAnrManager.isAnrDeferrable())
- return false; /// @}
- //如果当前的activity还在进程内运行的情况。
- if (proc.getActiveInstrumentation() != null) {
- Bundle info = new Bundle();
- info.putString("shortMsg", "keyDispatchingTimedOut");
- info.putString("longMsg", annotation);
- finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);//先是finish activity 并且输出报告,然后再杀死进程。
- return true;
- }
- }
- //进程ANR的情况,这部分可以看《深入理解 ANR 触发原理:Service》
- proc.appNotResponding(activityShortComponentName, aInfo,
- parentShortComponentName, parentProcess, aboveSystem, annotation);
- }
-
- return true;
- }

- public void onInstrumentationFinishedLocked(ComponentName name, int resultCode,
- Bundle results) {
- // pretty printer mode?
- String pretty = null;
- if (!mRawMode && results != null) {
- pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
- }
- //会有一个system.out 的log 输出,输出内容大概是:Input dispatching timed out +reason
- if (pretty != null) {
- System.out.println(pretty);
- } else {
- if (results != null) {
- for (String key : sorted(results.keySet())) {
- System.out.println(
- "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key));
- }
- }
- System.out.println("INSTRUMENTATION_CODE: " + resultCode);
- }
- }

从上面的代码来看如果发生的activity 还没被杀掉的情况,就会先finish activiy ,然后结束进程,并且输出system.out。因此这个过程是不会在data/anr 目录下生成trace文件
[targetType]
window is paused.[targetType]
window’s input channel is not registered with the input dispatcher. The window may be in the process of being removed.[targetType]
window’s input connection is [Connection.Status]
. The window may be in the process of being removed.[targetType]
window’s input channel is full. Outbound queue length: [outboundQueue长度]
. Wait queue length: [waitQueue长度]
.[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长度]
.[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: [等待时长]
.1. 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);
2. Input event dispatching timed out xxx. Reason: + reason
, 其中xxx取值:
windowState.mAttrs.getTitle()
appWindowToken.stringName
3 当activity 不存在的时候: 1.)EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags,
annotation); 这个log的输出在某些情况是不会输出的,用户定义了ANR的处理。还有就是另外几种情况,isShuttingDown ,isNotResponding ,isCrashing ,killedByAm,killed
2)生成 data/anr/文件,里面保存了一些pid的trace 信息以及cpu信息。
3)DropBoxManager也会输出一些anr的trace信息。
4).如果是前台进程还会有一个AppNotRespondingDialog
4 当activity的进程存在的时候:就会先finish activiy ,然后结束进程,并且输出一个system.out 的log 输出,输出内容大概是:Input dispatching timed out +reason
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。