小工具知识网

当前位置: 首页 > 行业知识 > [Android 13]Input系列--获取触摸窗口

行业知识

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

2026-10-21 22:40:26 来源:互联网转载

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

hongxi.zhu 2023-7-25

()

Android 13

InputDispatcher::dispatchMotionLocked

bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr 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& 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 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& 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 responsive            const 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 occlusion            if (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 feature            if (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 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 feature            if (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 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 = 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 foregroundWindowHandle =                tempTouchState.getFirstForegroundWindowHandle();        if (foregroundWindowHandle &&            foregroundWindowHandle->getInfo()->inputConfig.test(                    WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {            const std::vector& windowHandles =                    getWindowHandlesLocked(displayId);            for (const sp& 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 = 0) {                mTouchStatesByDisplay[displayId] = tempTouchState;            } else {                mTouchStatesByDisplay.erase(displayId);            }        }        // Update hover state.        mLastHoverWindowHandle = newHoverWindowHandle;    }    return injectionResult;}

InputDispatcher::findTouchedWindowAtLocked

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

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

()

void InputDispatcher::updateWindowHandlesForDisplayLocked(        const std::vector& 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& oldHandles = getWindowHandlesLocked(displayId);    std::unordered_map oldHandlesById;    for (const sp& handle : oldHandles) {        oldHandlesById[handle->getId()] = handle;    }    std::vector newHandles;    for (const sp& 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& oldHandle = oldHandlesById.at(handle->getId());            oldHandle->updateFrom(handle);            newHandles.push_back(oldHandle);        } else {            newHandles.push_back(handle);        }    }    // Insert or replace    // 将插入mWindowHandlesByDisplay    mWindowHandlesByDisplay[displayId] = newHandles;}

谁调用的updateWindowHandlesForDisplayLocked

InputDispatcher::setInputWindowsLocked

void InputDispatcher::setInputWindowsLocked(        const std::vector& windowInfoHandles, int32_t displayId) {    if (DEBUG_FOCUS) {        std::string windowList;        for (const sp& iwh : windowInfoHandles) {            windowList += iwh->getName() + " ";        }        ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str());    }    // Check preconditions for new input windows    for (const sp& window : windowInfoHandles) {        const WindowInfo& info = *window->getInfo();        // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL        const 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 overlays        LOG_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 overlays        LOG_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 oldWindowHandles = getWindowHandlesLocked(displayId);    // Save the old windows' orientation by ID before it gets updated.    std::unordered_map oldWindowOrientations;    for (const sp& handle : oldWindowHandles) {        oldWindowOrientations.emplace(handle->getId(),                                      handle->getInfo()->transform.getOrientation());    }    updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);  //更新并插入mWindowHandlesByDisplay    const std::vector& windowHandles = getWindowHandlesLocked(displayId);    if (mLastHoverWindowHandle &&        std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) ==                windowHandles.end()) {        mLastHoverWindowHandle = nullptr;    }    std::optional changes =            mFocusResolver.setInputWindows(displayId, windowHandles);    if (changes) {        onFocusChangedLocked(*changes);    }    std::unordered_map::iterator stateIt =            mTouchStatesByDisplay.find(displayId);    if (stateIt != mTouchStatesByDisplay.end()) {        TouchState& state = stateIt->second;        for (size_t i = 0; i getName().c_str(), displayId);                }                std::shared_ptr 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 wallpaper = state.getWallpaperWindow();                        if (wallpaper != nullptr) {                            sp 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& oldWindowHandle : oldWindowHandles) {        const sp newWindowHandle = getWindowHandleLocked(oldWindowHandle);        if (newWindowHandle != nullptr &&            newWindowHandle->getInfo()->transform.getOrientation() !=                    oldWindowOrientations[oldWindowHandle->getId()]) {            std::shared_ptr 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& 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& windowInfos,                                           const std::vector& displayInfos) {    // The listener sends the windows as a flattened array. Separate the windows by display for    // more convenient parsing.    std::unordered_map handlesPerDisplay;    for (const auto& info : windowInfos) {        handlesPerDisplay.emplace(info.displayId, std::vector());        handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));    }    { // acquire lock        std::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& windowInfos,        const std::vector& displayInfos) {    mDispatcher.onWindowInfosChanged(windowInfos, displayInfos);}

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

InputDispatcher::InputDispatcher
InputDispatcher::InputDispatcher(const sp& 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,也就是SurfaceFlinger    mWindowInfoListener = 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& windowInfosListener) const {    mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener);    return NO_ERROR;}
WindowInfosListenerInvoker::addWindowInfosListener
void WindowInfosListenerInvoker::addWindowInfosListener(sp listener) {    sp 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& windowInfos,     const std::vector& displayInfos,     bool shouldSync) {    ftl::SmallVector 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中的onWindowInfosChanged        listener->onWindowInfosChanged(windowInfos, displayInfos,                                       shouldSync ? mWindowInfosReportedListener : nullptr);    }}

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

途径二

InputDispatcher::displayRemoved
void InputDispatcher::displayRemoved(int32_t displayId) {    { // acquire lock        std::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.Stub        implements 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

    @Override    void 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对窗口管理的内容了,不是本次探索的目的,到这里就明白当事件分发前寻找的触摸目标窗口信息是谁来告知的。

上一篇:Win10不激活后果大解析,影响与使用揭秘!

下一篇:环保局登记备案