当前位置: 首页 > news >正文

[Android 13]Input系列--获取触摸窗口

[Android 13]Input系列–获取触摸窗口

hongxi.zhu 2023-7-25
Android 13

InputDispatcher::dispatchMotionLocked

bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,DropReason* dropReason, nsecs_t* nextWakeupTime) {...if (isPointerEvent) {// Pointer event.  (eg. touchscreen)// 获取触摸目标窗口injectionResult =findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,&conflictingPointerActions);} else {// Non touch event.  (eg. trackball)...}...dispatchEventLocked(currentTime, entry, inputTargets);return true;
}

InputDispatcher::findTouchedWindowTargetsLocked

InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {...if (newGesture) {  //如果是down事件(说明是一个新的触摸行为)bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;tempTouchState.reset();tempTouchState.down = down;tempTouchState.deviceId = entry.deviceId;tempTouchState.source = entry.source;tempTouchState.displayId = displayId;isSplit = false;} else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) {...}if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {// 如果是down事件/* Case 1: New splittable pointer going down, or need target for hover or scroll. */int32_t x;int32_t y;const int32_t pointerIndex = getMotionEventActionPointerIndex(action);// Always dispatch mouse events to cursor position.if (isFromMouse) {x = int32_t(entry.xCursorPosition);y = int32_t(entry.yCursorPosition);} else {x = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));}const bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;const bool isStylus = isPointerFromStylus(entry, pointerIndex);newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,isStylus, isDown /*addOutsideTargets*/);// Handle the case where we did not find a window.if (newTouchedWindowHandle == nullptr) {ALOGD("No new touched window at (%" PRId32 ", %" PRId32 ") in display %" PRId32, x, y,displayId);// Try to assign the pointer to the first foreground window we find, if there is one.newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();}// Verify targeted injection.if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {ALOGW("Dropping injected touch event: %s", (*err).c_str());injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;newTouchedWindowHandle = nullptr;goto Failed;}// Figure out whether splitting will be allowed for this window.if (newTouchedWindowHandle != nullptr) {if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {// New window supports splitting, but we should never split mouse events.isSplit = !isFromMouse;} else if (isSplit) {// New window does not support splitting but we have already split events.// Ignore the new window.newTouchedWindowHandle = nullptr;}} else {// No window is touched, so set split to true. This will allow the next pointer down to// be delivered to a new window which supports split touch. Pointers from a mouse device// should never be split.tempTouchState.split = isSplit = !isFromMouse;}// Update hover state.if (newTouchedWindowHandle != nullptr) {if (maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT) {newHoverWindowHandle = nullptr;} else if (isHoverAction) {newHoverWindowHandle = newTouchedWindowHandle;}}std::vector<sp<WindowInfoHandle>> newTouchedWindows =findTouchedSpyWindowsAtLocked(displayId, x, y, isStylus);if (newTouchedWindowHandle != nullptr) {// Process the foreground window first so that it is the first to receive the event.newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle);}if (newTouchedWindows.empty()) {ALOGI("Dropping event because there is no touchable window at (%d, %d) on display %d.",x, y, displayId);injectionResult = InputEventInjectionResult::FAILED;goto Failed;}for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {const WindowInfo& info = *windowHandle->getInfo();// Skip spy window targets that are not valid for targeted injection.if (const auto err = verifyTargetedInjection(windowHandle, entry); err) {continue;}if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {ALOGI("Not sending touch event to %s because it is paused",windowHandle->getName().c_str());continue;}// Ensure the window has a connection and the connection is responsiveconst bool isResponsive = hasResponsiveConnectionLocked(*windowHandle);if (!isResponsive) {ALOGW("Not sending touch gesture to %s because it is not responsive",windowHandle->getName().c_str());continue;}// Drop events that can't be trusted due to occlusionif (mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) {TouchOcclusionInfo occlusionInfo =computeTouchOcclusionInfoLocked(windowHandle, x, y);if (!isTouchTrustedLocked(occlusionInfo)) {if (DEBUG_TOUCH_OCCLUSION) {ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);for (const auto& log : occlusionInfo.debugInfo) {ALOGD("%s", log.c_str());}}sendUntrustedTouchCommandLocked(occlusionInfo.obscuringPackage);if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {ALOGW("Dropping untrusted touch event due to %s/%d",occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);continue;}}}// Drop touch events if requested by input featureif (shouldDropInput(entry, windowHandle)) {continue;}// Set target flags.int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS;if (canReceiveForegroundTouches(*windowHandle->getInfo())) {// There should only be one touched window that can be "foreground" for the pointer.targetFlags |= InputTarget::FLAG_FOREGROUND;}if (isSplit) {targetFlags |= InputTarget::FLAG_SPLIT;}if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;} else if (isWindowObscuredLocked(windowHandle)) {targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;}// Update the temporary touch state.BitSet32 pointerIds;if (isSplit) {uint32_t pointerId = entry.pointerProperties[pointerIndex].id;pointerIds.markBit(pointerId);}tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds);}} else {/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */// If the pointer is not currently down, then ignore the event.if (!tempTouchState.down) {if (DEBUG_FOCUS) {ALOGD("Dropping event because the pointer is not down or we previously ""dropped the pointer down event in display %" PRId32,displayId);}injectionResult = InputEventInjectionResult::FAILED;goto Failed;}addDragEventLocked(entry);// Check whether touches should slip outside of the current foreground window.if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.pointerCount == 1 &&tempTouchState.isSlippery()) {const int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));const int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));const bool isStylus = isPointerFromStylus(entry, 0 /*pointerIndex*/);sp<WindowInfoHandle> oldTouchedWindowHandle =tempTouchState.getFirstForegroundWindowHandle();newTouchedWindowHandle =findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus);// Verify targeted injection.if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {ALOGW("Dropping injected event: %s", (*err).c_str());injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;newTouchedWindowHandle = nullptr;goto Failed;}// Drop touch events if requested by input featureif (newTouchedWindowHandle != nullptr &&shouldDropInput(entry, newTouchedWindowHandle)) {newTouchedWindowHandle = nullptr;}if (oldTouchedWindowHandle != newTouchedWindowHandle &&oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) {if (DEBUG_FOCUS) {ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,oldTouchedWindowHandle->getName().c_str(),newTouchedWindowHandle->getName().c_str(), displayId);}// Make a slippery exit from the old window.tempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT,BitSet32(0));// Make a slippery entrance into the new window.if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {isSplit = !isFromMouse;}int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;if (canReceiveForegroundTouches(*newTouchedWindowHandle->getInfo())) {targetFlags |= InputTarget::FLAG_FOREGROUND;}if (isSplit) {targetFlags |= InputTarget::FLAG_SPLIT;}if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;} else if (isWindowObscuredLocked(newTouchedWindowHandle)) {targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;}BitSet32 pointerIds;if (isSplit) {pointerIds.markBit(entry.pointerProperties[0].id);}tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);}}}// Update dispatching for hover enter and exit.if (newHoverWindowHandle != mLastHoverWindowHandle) {// Let the previous window know that the hover sequence is over, unless we already did// it when dispatching it as is to newTouchedWindowHandle.if (mLastHoverWindowHandle != nullptr &&(maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT ||mLastHoverWindowHandle != newTouchedWindowHandle)) {if (DEBUG_HOVER) {ALOGD("Sending hover exit event to window %s.",mLastHoverWindowHandle->getName().c_str());}tempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));}// Let the new window know that the hover sequence is starting, unless we already did it// when dispatching it as is to newTouchedWindowHandle.if (newHoverWindowHandle != nullptr &&(maskedAction != AMOTION_EVENT_ACTION_HOVER_ENTER ||newHoverWindowHandle != newTouchedWindowHandle)) {if (DEBUG_HOVER) {ALOGD("Sending hover enter event to window %s.",newHoverWindowHandle->getName().c_str());}tempTouchState.addOrUpdateWindow(newHoverWindowHandle,InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER,BitSet32(0));}}// Ensure that we have at least one foreground window or at least one window that cannot be a// foreground target. If we only have windows that are not receiving foreground touches (e.g. we// only have windows getting ACTION_OUTSIDE), then drop the event, because there is no window// that is actually receiving the entire gesture.if (std::none_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),[](const TouchedWindow& touchedWindow) {return !canReceiveForegroundTouches(*touchedWindow.windowHandle->getInfo()) ||(touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0;})) {ALOGI("Dropping event because there is no touched window on display %d to receive it: %s",displayId, entry.getDescription().c_str());injectionResult = InputEventInjectionResult::FAILED;goto Failed;}// Ensure that all touched windows are valid for injection.if (entry.injectionState != nullptr) {std::string errs;for (const TouchedWindow& touchedWindow : tempTouchState.windows) {if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {// Allow ACTION_OUTSIDE events generated by targeted injection to be// dispatched to any uid, since the coords will be zeroed out later.continue;}const auto err = verifyTargetedInjection(touchedWindow.windowHandle, entry);if (err) errs += "\n  - " + *err;}if (!errs.empty()) {ALOGW("Dropping targeted injection: At least one touched window is not owned by uid ""%d:%s",*entry.injectionState->targetUid, errs.c_str());injectionResult = InputEventInjectionResult::TARGET_MISMATCH;goto Failed;}}// Check whether windows listening for outside touches are owned by the same UID. If it is// set the policy flag that we will not reveal coordinate information to this window.if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {sp<WindowInfoHandle> foregroundWindowHandle =tempTouchState.getFirstForegroundWindowHandle();if (foregroundWindowHandle) {const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;for (const TouchedWindow& touchedWindow : tempTouchState.windows) {if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {sp<WindowInfoHandle> windowInfoHandle = touchedWindow.windowHandle;if (windowInfoHandle->getInfo()->ownerUid != foregroundWindowUid) {tempTouchState.addOrUpdateWindow(windowInfoHandle,InputTarget::FLAG_ZERO_COORDS,BitSet32(0));}}}}}// If this is the first pointer going down and the touched window has a wallpaper// then also add the touched wallpaper windows so they are locked in for the duration// of the touch gesture.// We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper// engine only supports touch events.  We would need to add a mechanism similar// to View.onGenericMotionEvent to enable wallpapers to handle these events.if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {sp<WindowInfoHandle> foregroundWindowHandle =tempTouchState.getFirstForegroundWindowHandle();if (foregroundWindowHandle &&foregroundWindowHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {const std::vector<sp<WindowInfoHandle>>& windowHandles =getWindowHandlesLocked(displayId);for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {const WindowInfo* info = windowHandle->getInfo();if (info->displayId == displayId &&windowHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::IS_WALLPAPER)) {tempTouchState.addOrUpdateWindow(windowHandle,InputTarget::FLAG_WINDOW_IS_OBSCURED |InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED |InputTarget::FLAG_DISPATCH_AS_IS,BitSet32(0));}}}}// Success!  Output targets.injectionResult = InputEventInjectionResult::SUCCEEDED;for (const TouchedWindow& touchedWindow : tempTouchState.windows) {addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,touchedWindow.pointerIds, inputTargets);}// Drop the outside or hover touch windows since we will not care about them// in the next iteration.tempTouchState.filterNonAsIsTouchWindows();Failed:// Update final pieces of touch state if the injector had permission.if (!wrongDevice) {if (switchedDevice) {if (DEBUG_FOCUS) {ALOGD("Conflicting pointer actions: Switched to a different device.");}*outConflictingPointerActions = true;}if (isHoverAction) {// Started hovering, therefore no longer down.if (oldState && oldState->down) {if (DEBUG_FOCUS) {ALOGD("Conflicting pointer actions: Hover received while pointer was ""down.");}*outConflictingPointerActions = true;}tempTouchState.reset();if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {tempTouchState.deviceId = entry.deviceId;tempTouchState.source = entry.source;tempTouchState.displayId = displayId;}} else if (maskedAction == AMOTION_EVENT_ACTION_UP ||maskedAction == AMOTION_EVENT_ACTION_CANCEL) {// All pointers up or canceled.tempTouchState.reset();} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {// First pointer went down.if (oldState && oldState->down) {if (DEBUG_FOCUS) {ALOGD("Conflicting pointer actions: Down received while already down.");}*outConflictingPointerActions = true;}} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {// One pointer went up.if (isSplit) {int32_t pointerIndex = getMotionEventActionPointerIndex(action);uint32_t pointerId = entry.pointerProperties[pointerIndex].id;for (size_t i = 0; i < tempTouchState.windows.size();) {TouchedWindow& touchedWindow = tempTouchState.windows[i];if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {touchedWindow.pointerIds.clearBit(pointerId);if (touchedWindow.pointerIds.isEmpty()) {tempTouchState.windows.erase(tempTouchState.windows.begin() + i);continue;}}i += 1;}}}// Save changes unless the action was scroll in which case the temporary touch// state was only valid for this one action.if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {if (tempTouchState.displayId >= 0) {mTouchStatesByDisplay[displayId] = tempTouchState;} else {mTouchStatesByDisplay.erase(displayId);}}// Update hover state.mLastHoverWindowHandle = newHoverWindowHandle;}return injectionResult;
}

InputDispatcher::findTouchedWindowAtLocked

sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,int32_t y, TouchState* touchState,bool isStylus,bool addOutsideTargets,bool ignoreDragWindow) {if (addOutsideTargets && touchState == nullptr) {LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets");}// Traverse windows from front to back to find touched window.const auto& windowHandles = getWindowHandlesLocked(displayId);for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {continue;}const WindowInfo& info = *windowHandle->getInfo();if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {return windowHandle;}if (addOutsideTargets &&info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) {touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE,BitSet32(0));}}return nullptr;
}

InputDispatcher::getWindowHandlesLocked

const std::vector<sp<WindowInfoHandle>>& InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {static const std::vector<sp<WindowInfoHandle>> EMPTY_WINDOW_HANDLES;auto it = mWindowHandlesByDisplay.find(displayId);return it != mWindowHandlesByDisplay.end() ? it->second : EMPTY_WINDOW_HANDLES;
}

mWindowHandlesByDisplay又是谁来添加插入数据的

void InputDispatcher::updateWindowHandlesForDisplayLocked(const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {if (windowInfoHandles.empty()) {// Remove all handles on a display if there are no windows left.mWindowHandlesByDisplay.erase(displayId);return;}// Since we compare the pointer of input window handles across window updates, we need// to make sure the handle object for the same window stays unchanged across updates.const std::vector<sp<WindowInfoHandle>>& oldHandles = getWindowHandlesLocked(displayId);std::unordered_map<int32_t /*id*/, sp<WindowInfoHandle>> oldHandlesById;for (const sp<WindowInfoHandle>& handle : oldHandles) {oldHandlesById[handle->getId()] = handle;}std::vector<sp<WindowInfoHandle>> newHandles;for (const sp<WindowInfoHandle>& handle : windowInfoHandles) {const WindowInfo* info = handle->getInfo();if (getInputChannelLocked(handle->getToken()) == nullptr) {const bool noInputChannel =info->inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);const bool canReceiveInput =!info->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) ||!info->inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE);if (canReceiveInput && !noInputChannel) {ALOGV("Window handle %s has no registered input channel",handle->getName().c_str());continue;}}if (info->displayId != displayId) {ALOGE("Window %s updated by wrong display %d, should belong to display %d",handle->getName().c_str(), displayId, info->displayId);continue;}if ((oldHandlesById.find(handle->getId()) != oldHandlesById.end()) &&(oldHandlesById.at(handle->getId())->getToken() == handle->getToken())) {const sp<WindowInfoHandle>& oldHandle = oldHandlesById.at(handle->getId());oldHandle->updateFrom(handle);newHandles.push_back(oldHandle);} else {newHandles.push_back(handle);}}// Insert or replace// 将<displayId, newHandles>插入mWindowHandlesByDisplaymWindowHandlesByDisplay[displayId] = newHandles;
}

谁调用的updateWindowHandlesForDisplayLocked

InputDispatcher::setInputWindowsLocked

void InputDispatcher::setInputWindowsLocked(const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {if (DEBUG_FOCUS) {std::string windowList;for (const sp<WindowInfoHandle>& iwh : windowInfoHandles) {windowList += iwh->getName() + " ";}ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str());}// Check preconditions for new input windowsfor (const sp<WindowInfoHandle>& window : windowInfoHandles) {const WindowInfo& info = *window->getInfo();// Ensure all tokens are null if the window has feature NO_INPUT_CHANNELconst bool noInputWindow = info.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);if (noInputWindow && window->getToken() != nullptr) {ALOGE("%s has feature NO_INPUT_WINDOW, but a non-null token. Clearing",window->getName().c_str());window->releaseChannel();}// Ensure all spy windows are trusted overlaysLOG_ALWAYS_FATAL_IF(info.isSpy() &&!info.inputConfig.test(WindowInfo::InputConfig::TRUSTED_OVERLAY),"%s has feature SPY, but is not a trusted overlay.",window->getName().c_str());// Ensure all stylus interceptors are trusted overlaysLOG_ALWAYS_FATAL_IF(info.interceptsStylus() &&!info.inputConfig.test(WindowInfo::InputConfig::TRUSTED_OVERLAY),"%s has feature INTERCEPTS_STYLUS, but is not a trusted overlay.",window->getName().c_str());}// Copy old handles for release if they are no longer present.const std::vector<sp<WindowInfoHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);// Save the old windows' orientation by ID before it gets updated.std::unordered_map<int32_t, uint32_t> oldWindowOrientations;for (const sp<WindowInfoHandle>& handle : oldWindowHandles) {oldWindowOrientations.emplace(handle->getId(),handle->getInfo()->transform.getOrientation());}updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);  //更新并插入mWindowHandlesByDisplayconst std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);if (mLastHoverWindowHandle &&std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) ==windowHandles.end()) {mLastHoverWindowHandle = nullptr;}std::optional<FocusResolver::FocusChanges> changes =mFocusResolver.setInputWindows(displayId, windowHandles);if (changes) {onFocusChangedLocked(*changes);}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 (getWindowHandleLocked(touchedWindow.windowHandle) == nullptr) {if (DEBUG_FOCUS) {ALOGD("Touched window was removed: %s in display %" PRId32,touchedWindow.windowHandle->getName().c_str(), displayId);}std::shared_ptr<InputChannel> touchedInputChannel =getInputChannelLocked(touchedWindow.windowHandle->getToken());if (touchedInputChannel != nullptr) {CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,"touched window was removed");synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options);// Since we are about to drop the touch, cancel the events for the wallpaper as// well.if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND &&touchedWindow.windowHandle->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();if (wallpaper != nullptr) {sp<Connection> wallpaperConnection =getConnectionLocked(wallpaper->getToken());if (wallpaperConnection != nullptr) {synthesizeCancelationEventsForConnectionLocked(wallpaperConnection,options);}}}}state.windows.erase(state.windows.begin() + i);} else {++i;}}// If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We// could just clear the state here.if (mDragState && mDragState->dragWindow->getInfo()->displayId == displayId &&std::find(windowHandles.begin(), windowHandles.end(), mDragState->dragWindow) ==windowHandles.end()) {ALOGI("Drag window went away: %s", mDragState->dragWindow->getName().c_str());sendDropWindowCommandLocked(nullptr, 0, 0);mDragState.reset();}}// Determine if the orientation of any of the input windows have changed, and cancel all// pointer events if necessary.for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {const sp<WindowInfoHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle);if (newWindowHandle != nullptr &&newWindowHandle->getInfo()->transform.getOrientation() !=oldWindowOrientations[oldWindowHandle->getId()]) {std::shared_ptr<InputChannel> inputChannel =getInputChannelLocked(newWindowHandle->getToken());if (inputChannel != nullptr) {CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,"touched window's orientation changed");synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);}}}// 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<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {if (getWindowHandleLocked(oldWindowHandle) == nullptr) {if (DEBUG_FOCUS) {ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());}oldWindowHandle->releaseChannel();}}
}

谁来调用setInputWindowsLocked, 主要是两个地方:

  1. InputDispatcher::onWindowInfosChanged
  2. InputDispatcher::displayRemoved

途径一

InputDispatcher::onWindowInfosChanged
void InputDispatcher::onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos,const std::vector<DisplayInfo>& displayInfos) {// The listener sends the windows as a flattened array. Separate the windows by display for// more convenient parsing.std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;for (const auto& info : windowInfos) {handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));}{ // acquire lockstd::scoped_lock _l(mLock);mDisplayInfos.clear();for (const auto& displayInfo : displayInfos) {mDisplayInfos.emplace(displayInfo.displayId, displayInfo);}for (const auto& [displayId, handles] : handlesPerDisplay) {setInputWindowsLocked(handles, displayId);}}// Wake up poll loop since it may need to make new input dispatching choices.// 唤醒dispatcher线程,处理窗口信息改变的相关事项mLooper->wake();
}

寻找onWindowInfosChanged的调用地方

InputDispatcher::DispatcherWindowListener::onWindowInfosChanged
void InputDispatcher::DispatcherWindowListener::onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos,const std::vector<DisplayInfo>& displayInfos) {mDispatcher.onWindowInfosChanged(windowInfos, displayInfos);
}

看起来是个监听器的回调,应该是给别的地方持有这个监听器,寻找下这个DispatcherWindowListener的实例化

InputDispatcher::InputDispatcher
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,std::chrono::nanoseconds staleEventTimeout): mPolicy(policy),mPendingEvent(nullptr),mLastDropReason(DropReason::NOT_DROPPED),mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),mAppSwitchSawKeyDown(false),mAppSwitchDueTime(LONG_LONG_MAX),mNextUnblockedEvent(nullptr),mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT),mDispatchEnabled(false),mDispatchFrozen(false),mInputFilterEnabled(false),// mInTouchMode will be initialized by the WindowManager to the default device config.// To avoid leaking stack in case that call never comes, and for tests,// initialize it here anyways.mInTouchMode(kDefaultInTouchMode),mMaximumObscuringOpacityForTouch(1.0f),mFocusedDisplayId(ADISPLAY_ID_DEFAULT),mWindowTokenWithPointerCapture(nullptr),mStaleEventTimeout(staleEventTimeout),mLatencyAggregator(),mLatencyTracker(&mLatencyAggregator) {mLooper = new Looper(false);mReporter = createInputReporter();//实例化DispatcherWindowListener,并通过binder传给SurfaceComposerClient,也就是SurfaceFlingermWindowInfoListener = new DispatcherWindowListener(*this);SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);...
}

到这里我们明白Android 13通过途径1(InputDispatcher::onWindowInfosChanged)来更新触摸窗口信息的发起者是SurfaceFlinger

SurfaceFlinger::addWindowInfosListener

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

status_t SurfaceFlinger::addWindowInfosListener(const sp<IWindowInfosListener>& windowInfosListener) const {mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener);return NO_ERROR;
}
WindowInfosListenerInvoker::addWindowInfosListener
void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {sp<IBinder> asBinder = IInterface::asBinder(listener);asBinder->linkToDeath(this);std::scoped_lock lock(mListenersMutex);mWindowInfosListeners.try_emplace(asBinder, std::move(listener));
}

inputdispatcher实例化时调用上面流程跨进程向SurfaceFlinger注册了DispatcherWindowListener, 回到上面,我们找到回调这个监听器的onWindowInfosChanged的地方

WindowInfosListenerInvoker::windowInfosChanged

frameworks/native/services/surfaceflinger/WindowInfosListenerInvoker.cpp

void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,const std::vector<DisplayInfo>& displayInfos,bool shouldSync) {ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;{std::scoped_lock lock(mListenersMutex);for (const auto& [_, listener] : mWindowInfosListeners) {windowInfosListeners.push_back(listener);}}mCallbacksPending = windowInfosListeners.size();for (const auto& listener : windowInfosListeners) {//向所有向SurfaceFlinger注册了WindowInfosListener的进程回调onWindowInfosChanged//其中包括inputDispatcher中的onWindowInfosChangedlistener->onWindowInfosChanged(windowInfos, displayInfos,shouldSync ? mWindowInfosReportedListener : nullptr);}
}

到这里途径1(InputDispatcher::onWindowInfosChanged)来更新触摸窗口信息的流程就找到了。

途径二

InputDispatcher::displayRemoved
void InputDispatcher::displayRemoved(int32_t displayId) {{ // acquire lockstd::scoped_lock _l(mLock);// Set an empty list to remove all handles from the specific display.setInputWindowsLocked(/* window handles */ {}, displayId);setFocusedApplicationLocked(displayId, nullptr);// Call focus resolver to clean up stale requests. This must be called after input windows// have been removed for the removed display.mFocusResolver.displayRemoved(displayId);// Reset pointer capture eligibility, regardless of previous state.std::erase(mIneligibleDisplaysForPointerCapture, displayId);} // release lock// Wake up poll loop since it may need to make new input dispatching choices.mLooper->wake();
}
NativeInputManager::displayRemoved

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

void NativeInputManager::displayRemoved(JNIEnv* env, int32_t displayId) {mInputManager->getDispatcher().displayRemoved(displayId);
}
nativeDisplayRemoved
static const JNINativeMethod gInputManagerMethods[] = {/* name, signature, funcPtr */...{"displayRemoved", "(I)V", (void*)nativeDisplayRemoved},  //动态注册函数表
};static void nativeDisplayRemoved(JNIEnv* env, jobject nativeImplObj, jint displayId) {NativeInputManager* im = getNativeInputManager(env, nativeImplObj);im->displayRemoved(env, displayId);
}

看这里就知道是java层调下来的, 那就到java层找找

NativeInputManagerService::displayRemoved

frameworks/base/services/core/java/com/android/server/input/NativeInputManagerService.java

public interface NativeInputManagerService {...void displayRemoved(int displayId);...class NativeImpl implements NativeInputManagerService {...public native void displayRemoved(int displayId);...}
}
InputManagerService::onDisplayRemoved

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

/** The system implementation of {@link IInputManager} that manages input devices. */
public class InputManagerService extends IInputManager.Stubimplements Watchdog.Monitor {.../** Clean up input window handles of the given display. */public void onDisplayRemoved(int displayId) {if (mPointerIconDisplayContext != null&& mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) {mPointerIconDisplayContext = null;}updateAdditionalDisplayInputProperties(displayId, AdditionalDisplayInputProperties::reset);mNative.displayRemoved(displayId);}...
}
InputMonitor::onDisplayRemoved

frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java

    void onDisplayRemoved() {mHandler.removeCallbacks(mUpdateInputWindows);mHandler.post(() -> {// Make sure any pending setInputWindowInfo transactions are completed. That prevents// the timing of updating input info of removed display after cleanup.mService.mTransactionFactory.get().syncInputWindows().apply();// It calls InputDispatcher::setInputWindows directly.//mService是WindowManagerService,构造时向它传入了java层InputManagerService对象mService.mInputManager.onDisplayRemoved(mDisplayId);});mDisplayRemoved = true;}
DisplayContent::removeImmediately

frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    @Overridevoid removeImmediately() {mDeferredRemoval = false;try {// Clear all transitions & screen frozen states when removing display....mInputMonitor.onDisplayRemoved();...} finally {mDisplayReady = false;}// Apply the pending transaction here since we may not be able to reach the DisplayContent// on the next traversal if it's removed from RootWindowContainer child list.getPendingTransaction().apply();mWmService.mWindowPlacerLocked.requestTraversal();}

到这里差不多了,再往上查就是WMS对窗口管理的内容了,不是本次探索的目的,到这里就明白当事件分发前寻找的触摸目标窗口信息是谁来告知的。

相关文章:

  • ros2 launch如何控制node的启动顺序
  • 基于Java springboot+VUE+redis实现的前后端分类版网上商城项目
  • 【OJ】日期差值与日期累加
  • Java 设计模式
  • OSPF NSSA实验简述
  • Spring AOP在什么场景下会失效?
  • CDH6.3.1离线安装
  • 组合_回溯法_java
  • 【数据集】MSWEP(多源加权集合降水)再分析数据
  • 大模型交互-超拟人合成
  • 【算法可视化】模拟算法专题
  • Python接口自动化测试框架运行原理及流程
  • 【leetcode】随机链表的复制
  • Nginx使用—基础应用
  • 图像处理与视觉感知---期末复习重点(1)
  • [deviceone开发]-do_Webview的基本示例
  • centos安装java运行环境jdk+tomcat
  • CSS 三角实现
  • CSS3 变换
  • ECS应用管理最佳实践
  • MySQL主从复制读写分离及奇怪的问题
  • PAT A1017 优先队列
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • yii2中session跨域名的问题
  • 番外篇1:在Windows环境下安装JDK
  • 反思总结然后整装待发
  • 分享几个不错的工具
  • 构建二叉树进行数值数组的去重及优化
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 漂亮刷新控件-iOS
  • 如何胜任知名企业的商业数据分析师?
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 白色的风信子
  • ionic异常记录
  • Java数据解析之JSON
  • Java性能优化之JVM GC(垃圾回收机制)
  • scrapy中间件源码分析及常用中间件大全
  • zabbix3.2监控linux磁盘IO
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ​如何防止网络攻击?
  • #14vue3生成表单并跳转到外部地址的方式
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (+4)2.2UML建模图
  • (1)(1.9) MSP (version 4.2)
  • (11)MATLAB PCA+SVM 人脸识别
  • (Git) gitignore基础使用
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (十三)Flask之特殊装饰器详解
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • .NET CORE Aws S3 使用
  • .NET Framework 服务实现监控可观测性最佳实践
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .Net6 Api Swagger配置