标签:style os java io ar for art 问题 cti
文章仅记录自己的一点理解,仅供自己参考。
1、mInputFocus
WMS.addWindow()-->WMS.finishUpdateFocusedWindowAfterAssignLayersLocked()-->InputMonitor.setInputFocusLw()-->mInputFocus = newWindow;
add一个window的时候会重新寻找焦点窗口,并把焦点窗口保存在WMS.mCurrentFocus中,这个焦点窗口也会保存到InputMonitor.mInputFocus 中。关键代码:
<span style="font-size:18px;"><span style="font-size:18px;">addWindow(){ …… boolean focusChanged = false; if (win.canReceiveKeys()) { focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS, false /*updateInputWindows*/); if (focusChanged) { imMayMove = false; } } if (imMayMove) { moveInputMethodWindowsIfNeededLocked(false); } assignLayersLocked(displayContent.getWindowList()); // Don't do layout here, the window must call // relayout to be displayed, so we'll do it there. if (focusChanged) { finishUpdateFocusedWindowAfterAssignLayersLocked(false /*updateInputWindows*/); } mInputMonitor.updateInputWindowsLw(false /*force*/); ………… } </span></span>这几行代码虽短,逻辑也很简单,但是调用了很多方法。对于canReceiveKeys()函数:
<span style="font-size:18px;"> public final boolean canReceiveKeys() { return isVisibleOrAdding() && (mViewVisibility == View.VISIBLE) && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0); }</span>
如果窗口设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE属性,那么该窗口是不能获得焦点的,即canReceiveKeys()会返回false,也就是说焦点窗口是不会更改的。对于悬浮的窗口一般来说是不需要获得焦点的,故一般设置WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE属性,不然会存在一些问题。如果该窗口可以接受key事件(这个key事件有点歧义,并不是只接受按键事件),那么就调用updateFocusedWindowLocked(),这个以后再研究。如果焦点窗口发生变更,那么就调用moveInputMethodWindowsIfNeededLocked(false)来移动输入法窗口到合适的位置。
mInputFocus中保存的窗口在调用InputMonitor.updateInputWindowsLw()时最终设置到InputDispatcher.mFocusedWindowHandle中去了。
2、mInputDispatchFrozen
冻结InputDispatcher标志,“ When true, prevents input dispatch from proceeding until set to false again.”。
①WMS.startFreezingDisplayLocked()-->InputMonitor.freezeInputDispatchingLw()-->mInputDispatchFrozen = true; updateInputDispatchModeLw();
②WMS.stopFreezingDisplayLocked()-->InputMonitor.thawInputDispatchingLw()-->mInputDispatchFrozen = false; updateInputDispatchModeLw();-->InputManagerService.setInputDispatchMode()-->InputDispatcher.setInputDispatchMode(bool enabled, bool frozen)-->mDispatchFrozen = frozen;
<span style="font-size:18px;">void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now(); // Reset the key repeat timer whenever we disallow key events, even if the next event // is not a key. This is to ensure that we abort a key repeat if the device is just coming // out of sleep. if (!mPolicy->isKeyRepeatEnabled()) { resetKeyRepeatLocked(); } // If dispatching is frozen, do not process timeouts or try to deliver any new events. if (mDispatchFrozen) { #if DEBUG_FOCUS ALOGD("Dispatch frozen. Waiting some more."); #endif return; } ………. } </span>调用dispatchOnceInnerLocked()分发事件时,直接return掉。上面的调用逻辑可以知道冻结/解冻显示屏时,会冻结InputDispatcher的分发流程。
3、mInputDispatchEnabled
一个java层控制InputDispatcher的开关。
①WMS.setEventDispatching()-->InputMonitor.setEventDispatchingLw()
②WMS.performEnableScreen()-->InputMonitor.setEventDispatchingLw()-->mInputDispatchEnabled = enabled;updateInputDispatchModeLw();-->InputManagerService.setInputDispatchMode()-->InputDispatcher.setInputDispatchMode(bool enabled, bool frozen)-->mDispatchEnabled = enabled;
具体是怎么使能InputDispatcher的?
<span style="font-size:18px;"> if (!mDispatchEnabled) { dropReason = DROP_REASON_DISABLED; } </span>在dispatchOnceInnerLocked()中会设置dropReason(放弃原因),如果dropReason不为0表示输入事件将被放弃掉,不会分发。
4、mUpdateInputWindowsNeeded
是否需要更新窗口信息到InputDispatcher中的标志。在非强制性更新窗口信息到InputDispatcher中去时,必须先调用InputMonitor.setUpdateInputWindowsNeededLw()设置该标志,然后再调用InputMonitor.updateInputWindowsLw()。如果强制性更新窗口信息到InputDispatcher中去时就不必设置该变量了。
5、notifyInputChannelBroken()
InputManager通知WMS输入通道破裂函数。
public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { if (inputWindowHandle == null) { return; } synchronized (mService.mWindowMap) { WindowState windowState = (WindowState) inputWindowHandle.windowState; if (windowState != null) { Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState); mService.removeWindowLocked(windowState.mSession, windowState); } } }函数处理逻辑非常简单,就是将输入通道破裂的窗口直接调用removeWindowLocked()进行移除。
startDispatchCycleLocked()中在publish event不成功,就会走下面的逻辑:
if (status) { if (status == WOULD_BLOCK) { if (connection->waitQueue.isEmpty()) { ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " "This is unexpected because the wait queue is empty, so the pipe " "should be empty and we shouldn't have any problems writing an " "event to it, status=%d", connection->getInputChannelName(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } else { // Pipe is full and we are waiting for the app to finish process some events // before sending more events to it. #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Could not publish event because the pipe is full, " "waiting for the application to catch up", connection->getInputChannelName()); #endif connection->inputPublisherBlocked = true; } } else { ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " "status=%d", connection->getInputChannelName(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } return; }在正常pipe full的情况下是不会调用abortBrokenDispatchCycleLocked()的,其他情况则调用abortBrokenDispatchCycleLocked()来处理。
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, bool notify) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s", connection->getInputChannelName(), toString(notify)); #endif // Clear the dispatch queues. drainDispatchQueueLocked(&connection->outboundQueue); traceOutboundQueueLengthLocked(connection); drainDispatchQueueLocked(&connection->waitQueue); traceWaitQueueLengthLocked(connection); // The connection appears to be unrecoverably broken. // Ignore already broken or zombie connections. if (connection->status == Connection::STATUS_NORMAL) { connection->status = Connection::STATUS_BROKEN; if (notify) { // Notify other system components. onDispatchCycleBrokenLocked(currentTime, connection); } } }函数中清理outboundQueue和waitQueue两个队列中的消息,然后调用onDispatchCycleBrokenLocked()-->.....来通知WMS移除对应的窗口。
outboundQueue:Queue of events that need to be published to the connection.
waitQueue:Queue of events that have been published to the connection but that have not yet received a "finished" response from the application.
输入事件只有收到应用回复的finished消息才算真正分发成功。
6、notifyANR()
源码对这个函数的注释已经非常清楚:
<span style="font-size:18px;"> /* Notifies the window manager about an application that is not responding. * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch. * * Called by the InputManager. */</span>调用流程:InputDispatcher.handleTargetsNotReadyLocked()--> InputDispatcher.onANRLocked()-->InputDispatcher.doNotifyANRLockedInterruptible()-->NativeInputManager.notifyANR()-->InputManagerService.notifyANR()-->InputMonitor.notifyANR();
标签:style os java io ar for art 问题 cti
原文地址:http://blog.csdn.net/guoqifa29/article/details/38905347