关于android输入事件,比如滑动,点击,按键涉及到的主要流程
事件的window分发过程
用户事件 -> /dev/下设备文件 -> InputReaderThread -> InputDispatherThread -> Window
事件的注册过程
ViewRootImpl构造(构造InputChannel)->WindowManager.openSession->WindowSession.addToDisplay->WindowManagerSerive端构造InputChannel->通过InputManager注册到InputDispatherThread
window到ViewRootImpl发送过程
InputDispatherThread选择window分发的关键代码
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
// Reset the key repeat timer whenever normal dispatch is suspended while the
// device is in a non-interactive state. This is to ensure that we abort a key
// repeat if the device is just coming out of sleep.
if (!mDispatchEnabled) {
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.");
}
return;
}
// Optimize latency of app switches.
// Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
// been pressed. When it expires, we preempt dispatch and drop all other pending events.
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (!mPendingEvent) {
if (mInboundQueue.empty()) {
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 {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.front();
mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(*mPendingEvent);
}
}
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != nullptr);
bool done = false;
DropReason dropReason = DropReason::NOT_DROPPED;
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
dropReason = DropReason::POLICY;
} else if (!mDispatchEnabled) {
dropReason = DropReason::DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
mNextUnblockedEvent = nullptr;
}
switch (mPendingEvent->type) {
......
case EventEntry::Type::KEY: {
KeyEntry* typedEntry = static_cast(mPendingEvent);
if (isAppSwitchDue) {
if (isAppSwitchKeyEvent(*typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DropReason::NOT_DROPPED) {
dropReason = DropReason::APP_SWITCH;
}
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::Type::MOTION: {
MotionEntry* typedEntry = static_cast(mPendingEvent);
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
dropReason = DropReason::APP_SWITCH;
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
......
}
dispatchOnceInnerLocked 获取pendingEvent 判断是不同类型的事件,比如是按键事件,通过dispatchKeyLocked处理,触摸事件通过dispatchMotionLocked处理
按键事件处理,看到就是分发给focus window
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
......
// Identify targets.
std::vector inputTargets;
int32_t injectionResult =
findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
setInjectionResult(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
return true;
}
// Add monitor channels from event's or focused display.
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
findFocusedWindowTargetsLocked的实现主要就是从mFocusedWindowHandlesByDisplay取出对应的focus window
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry& entry,
std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime) {
std::string reason;
int32_t displayId = getTargetDisplayId(entry);
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
sp<InputApplicationHandle> focusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
......
// Success! Output targets.
addWindowTargetLocked(focusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0), inputTargets);
// Done.
return INPUT_EVENT_INJECTION_SUCCEEDED;
}
mFocusedWindowHandlesByDisplay何时设置的呢,在
/** * Called from InputManagerService, update window handle list by displayId that can receive input. * A window handle contains information about InputChannel, Touch Region, Types, Focused,... * If set an empty list, remove all handles from the specific display. * For focused handle, check if need to change and send a cancel event to previous one. * For removed handle, check if need to send a cancel event if already in touch. */ void InputDispatcher::setInputWindowsLocked( const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) { // Copy old handles for release if they are no longer present. const std::vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId); updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId); sp<InputWindowHandle> newFocusedWindowHandle = nullptr; bool foundHoveredWindow = false; for (const sp<InputWindowHandle>& windowHandle : getWindowHandlesLocked(displayId)) { // Set newFocusedWindowHandle to the top most focused window instead of the last one if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus && windowHandle->getInfo()->visible) { newFocusedWindowHandle = windowHandle; } if (windowHandle == mLastHoverWindowHandle) { foundHoveredWindow = true; } } if (!foundHoveredWindow) { mLastHoverWindowHandle = nullptr; } sp<InputWindowHandle> oldFocusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, displayId); if (!haveSameToken(oldFocusedWindowHandle, newFocusedWindowHandle)) { if (oldFocusedWindowHandle != nullptr) { if (DEBUG_FOCUS) { ALOGD("Focus left window: %s in display %" PRId32, oldFocusedWindowHandle->getName().c_str(), displayId); } sp<InputChannel> focusedInputChannel = getInputChannelLocked(oldFocusedWindowHandle->getToken()); if (focusedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, "focus left window"); synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options); enqueueFocusEventLocked(*oldFocusedWindowHandle, false /*hasFocus*/); } mFocusedWindowHandlesByDisplay.erase(displayId); } if (newFocusedWindowHandle != nullptr) { if (DEBUG_FOCUS) { ALOGD("Focus entered window: %s in display %" PRId32, newFocusedWindowHandle->getName().c_str(), displayId); } mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle; enqueueFocusEventLocked(*newFocusedWindowHandle, true /*hasFocus*/); //MIUI ADD: resetNoFocusedWindowTimeoutLocked(); } if (mFocusedDisplayId == displayId) { onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle); } } std::unordered_map<int32_t, TouchState>::iterator stateIt = mTouchStatesByDisplay.find(displayId); if (stateIt != mTouchStatesByDisplay.end()) { TouchState& state = stateIt->second; for (size_t i = 0; i < state.windows.size();) { TouchedWindow& touchedWindow = state.windows[i]; if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { if (DEBUG_FOCUS) { ALOGD("Touched window was removed: %s in display %" PRId32, touchedWindow.windowHandle->getName().c_str(), displayId); } sp<InputChannel> touchedInputChannel = getInputChannelLocked(touchedWindow.windowHandle->getToken()); if (touchedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "touched window was removed"); synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options); } state.windows.erase(state.windows.begin() + i); } else { ++i; } } } // Release information for windows that are no longer present. // This ensures that unused input channels are released promptly. // Otherwise, they might stick around until the window handle is destroyed // which might not happen until the next GC. for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) { if (!hasWindowHandleLocked(oldWindowHandle)) { if (DEBUG_FOCUS) { ALOGD("Window went away: %s", oldWindowHandle->getName().c_str()); } oldWindowHandle->releaseChannel(); } } }
查看window状态命令
activity切换对应window状态
popwindow对应window状态
本文详细探讨了Android系统的输入事件处理流程,包括窗口分发过程:用户事件经由设备文件传递到InputReaderThread,然后由InputDispatcherThread分发到Window。同时解析了事件注册过程,从ViewRootImpl构造到InputChannel的创建,再到WindowManagerService端的InputChannel注册。此外,还介绍了事件如何从Window发送到ViewRootImpl,重点分析了InputDispatcherThread的关键分发代码和焦点窗口的处理策略。
1535

被折叠的 条评论
为什么被折叠?



