Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ab3b931 authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge "InputDispatcher: Ensure synthesized events are associated with windows" into main

parents daacc553 bb3f1c03
Loading
Loading
Loading
Loading
+106 −51
Original line number Diff line number Diff line
@@ -804,6 +804,20 @@ int32_t getUserActivityEventType(const EventEntry& eventEntry) {
    }
}

std::pair<bool /*cancelPointers*/, bool /*cancelNonPointers*/> expandCancellationMode(
        CancelationOptions::Mode mode) {
    switch (mode) {
        case CancelationOptions::Mode::CANCEL_ALL_EVENTS:
            return {true, true};
        case CancelationOptions::Mode::CANCEL_POINTER_EVENTS:
            return {true, false};
        case CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS:
            return {false, true};
        case CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS:
            return {false, true};
    }
}

} // namespace

// --- InputDispatcher ---
@@ -2078,7 +2092,9 @@ void InputDispatcher::cancelEventsForAnrLocked(const std::shared_ptr<Connection>
    if (connection->status == Connection::Status::NORMAL) {
        CancelationOptions options(CancelationOptions::Mode::CANCEL_ALL_EVENTS,
                                   "application not responding");
        synthesizeCancelationEventsForConnectionLocked(connection, options);
        synthesizeCancelationEventsForConnectionLocked(connection, options,
                                                       getWindowHandleLocked(
                                                               connection->getToken()));
    }
}

@@ -3328,7 +3344,13 @@ void InputDispatcher::enqueueDispatchEntryAndStartDispatchCycleLocked(
void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connection>& connection,
                                                 std::shared_ptr<const EventEntry> eventEntry,
                                                 const InputTarget& inputTarget) {
    // TODO(b/210460522): Verify all targets excluding global monitors are associated with a window.
    const bool isKeyOrMotion = eventEntry->type == EventEntry::Type::KEY ||
            eventEntry->type == EventEntry::Type::MOTION;
    if (isKeyOrMotion && !inputTarget.windowHandle && !connection->monitor) {
        LOG(FATAL) << "All InputTargets for non-monitors must be associated with a window; target: "
                   << inputTarget << " connection: " << connection->getInputChannelName()
                   << " entry: " << eventEntry->getDescription();
    }
    // This is a new event.
    // Enqueue a new dispatch entry onto the outbound queue for this connection.
    std::unique_ptr<DispatchEntry> dispatchEntry =
@@ -3977,22 +3999,78 @@ int InputDispatcher::handleReceiveCallback(int events, sp<IBinder> connectionTok

void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
        const CancelationOptions& options) {
    for (const auto& [token, connection] : mConnectionsByToken) {
        synthesizeCancelationEventsForConnectionLocked(connection, options);
    // Cancel windows (i.e. non-monitors).
    // A channel must have at least one window to receive any input. If a window was removed, the
    // event streams directed to the window will already have been canceled during window removal.
    // So there is no need to generate cancellations for connections without any windows.
    const auto [cancelPointers, cancelNonPointers] = expandCancellationMode(options.mode);
    // Generate cancellations for touched windows first. This is to avoid generating cancellations
    // through a non-touched window if there are more than one window for an input channel.
    if (cancelPointers) {
        for (const auto& [displayId, touchState] : mTouchStatesByDisplay) {
            if (options.displayId.has_value() && options.displayId != displayId) {
                continue;
            }
            for (const auto& touchedWindow : touchState.windows) {
                synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options);
            }
        }
    }
    // Follow up by generating cancellations for all windows, because we don't explicitly track
    // the windows that have an ongoing focus event stream.
    if (cancelNonPointers) {
        for (const auto& [_, handles] : mWindowHandlesByDisplay) {
            for (const auto& windowHandle : handles) {
                synthesizeCancelationEventsForWindowLocked(windowHandle, options);
            }
        }
    }

    // Cancel monitors.
    synthesizeCancelationEventsForMonitorsLocked(options);
}

void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
        const CancelationOptions& options) {
    for (const auto& [_, monitors] : mGlobalMonitorsByDisplay) {
        for (const Monitor& monitor : monitors) {
            synthesizeCancelationEventsForConnectionLocked(monitor.connection, options);
            synthesizeCancelationEventsForConnectionLocked(monitor.connection, options,
                                                           /*window=*/nullptr);
        }
    }
}

void InputDispatcher::synthesizeCancelationEventsForWindowLocked(
        const sp<WindowInfoHandle>& windowHandle, const CancelationOptions& options,
        const std::shared_ptr<Connection>& connection) {
    if (windowHandle == nullptr) {
        LOG(FATAL) << __func__ << ": Window handle must not be null";
    }
    if (connection) {
        // The connection can be optionally provided to avoid multiple lookups.
        if (windowHandle->getToken() != connection->getToken()) {
            LOG(FATAL) << __func__
                       << ": Wrong connection provided for window: " << windowHandle->getName();
        }
    }

    std::shared_ptr<Connection> resolvedConnection =
            connection ? connection : getConnectionLocked(windowHandle->getToken());
    if (!resolvedConnection) {
        LOG(DEBUG) << __func__ << "No connection found for window: " << windowHandle->getName();
        return;
    }
    synthesizeCancelationEventsForConnectionLocked(resolvedConnection, options, windowHandle);
}

void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
        const std::shared_ptr<Connection>& connection, const CancelationOptions& options) {
        const std::shared_ptr<Connection>& connection, const CancelationOptions& options,
        const sp<WindowInfoHandle>& window) {
    if (!connection->monitor && window == nullptr) {
        LOG(FATAL) << __func__
                   << ": Cannot send event to non-monitor channel without a window - channel: "
                   << connection->getInputChannelName();
    }
    if (connection->status != Connection::Status::NORMAL) {
        return;
    }
@@ -4029,10 +4107,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
        switch (cancelationEventEntry->type) {
            case EventEntry::Type::KEY: {
                const auto& keyEntry = static_cast<const KeyEntry&>(*cancelationEventEntry);
                const std::optional<int32_t> targetDisplay = keyEntry.displayId != ADISPLAY_ID_NONE
                        ? std::make_optional(keyEntry.displayId)
                        : std::nullopt;
                if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) {
                if (window) {
                    addWindowTargetLocked(window, InputTarget::DispatchMode::AS_IS,
                                          /*targetFlags=*/{}, keyEntry.downTime, targets);
                } else {
@@ -4043,11 +4118,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
            }
            case EventEntry::Type::MOTION: {
                const auto& motionEntry = static_cast<const MotionEntry&>(*cancelationEventEntry);
                const std::optional<int32_t> targetDisplay =
                        motionEntry.displayId != ADISPLAY_ID_NONE
                        ? std::make_optional(motionEntry.displayId)
                        : std::nullopt;
                if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) {
                if (window) {
                    std::bitset<MAX_POINTER_ID + 1> pointerIds;
                    for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.getPointerCount();
                         pointerIndex++) {
@@ -4175,17 +4246,6 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
    }
}

void InputDispatcher::synthesizeCancelationEventsForWindowLocked(
        const sp<WindowInfoHandle>& windowHandle, const CancelationOptions& options) {
    if (windowHandle != nullptr) {
        std::shared_ptr<Connection> wallpaperConnection =
                getConnectionLocked(windowHandle->getToken());
        if (wallpaperConnection != nullptr) {
            synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, options);
        }
    }
}

std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
        const MotionEntry& originalMotionEntry, std::bitset<MAX_POINTER_ID + 1> pointerIds,
        nsecs_t splitDownTime) {
@@ -5216,19 +5276,16 @@ void InputDispatcher::setInputWindowsLocked(
            if (getWindowHandleLocked(touchedWindow.windowHandle) == nullptr) {
                LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName()
                          << " in display %" << displayId;
                std::shared_ptr<Connection> touchedConnection =
                        getConnectionLocked(touchedWindow.windowHandle->getToken());
                if (touchedConnection != nullptr) {
                CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
                                           "touched window was removed");
                    synthesizeCancelationEventsForConnectionLocked(touchedConnection, options);
                synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options);
                // Since we are about to drop the touch, cancel the events for the wallpaper as
                // well.
                if (touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND) &&
                    touchedWindow.windowHandle->getInfo()->inputConfig.test(
                            gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
                        sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();
                        synthesizeCancelationEventsForWindowLocked(wallpaper, options);
                    if (const auto& ww = state.getWallpaperWindow(); ww) {
                        synthesizeCancelationEventsForWindowLocked(ww, options);
                    }
                }
                state.windows.erase(state.windows.begin() + i);
@@ -5515,9 +5572,10 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<
        }
        const int32_t deviceId = *deviceIds.begin();

        sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(toToken, displayId);
        if (toWindowHandle == nullptr) {
            ALOGW("Cannot transfer touch because to window not found.");
        const sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle;
        const sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(toToken, displayId);
        if (!toWindowHandle) {
            ALOGW("Cannot transfer touch because the transfer target window was not found.");
            return false;
        }

@@ -5530,7 +5588,6 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<
        // Erase old window.
        ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags;
        std::vector<PointerProperties> pointers = touchedWindow->getTouchingPointers(deviceId);
        sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle;
        state->removeWindowByToken(fromToken);

        // Add new window.
@@ -5562,7 +5619,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<
            fromConnection->inputState.mergePointerStateTo(toConnection->inputState);
            CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
                                       "transferring touch from this window to another window");
            synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
            synthesizeCancelationEventsForWindowLocked(fromWindowHandle, options, fromConnection);
            synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection,
                                                           newTargetFlags);

@@ -6044,12 +6101,10 @@ status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) {

        std::string canceledWindows;
        for (const TouchedWindow& w : state.windows) {
            const std::shared_ptr<Connection> connection =
                    getConnectionLocked(w.windowHandle->getToken());
            if (connection != nullptr && connection->getToken() != token) {
                synthesizeCancelationEventsForConnectionLocked(connection, options);
            if (w.windowHandle->getToken() != token) {
                synthesizeCancelationEventsForWindowLocked(w.windowHandle, options);
                canceledWindows += canceledWindows.empty() ? "[" : ", ";
                canceledWindows += connection->getInputChannelName();
                canceledWindows += w.windowHandle->getName();
            }
        }
        canceledWindows += canceledWindows.empty() ? "[]" : "]";
@@ -6463,7 +6518,7 @@ std::unique_ptr<const KeyEntry> InputDispatcher::afterKeyEventLockedInterruptabl
                                               "or is no longer a foreground target, "
                                               "canceling previously dispatched fallback key");
                    options.keyCode = *fallbackKeyCode;
                    synthesizeCancelationEventsForConnectionLocked(connection, options);
                    synthesizeCancelationEventsForWindowLocked(windowHandle, options, connection);
                }
            }
            connection->inputState.removeFallbackKey(originalKeyCode);
@@ -6545,7 +6600,7 @@ std::unique_ptr<const KeyEntry> InputDispatcher::afterKeyEventLockedInterruptabl
                CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
                                           "canceling fallback, policy no longer desires it");
                options.keyCode = *fallbackKeyCode;
                synthesizeCancelationEventsForConnectionLocked(connection, options);
                synthesizeCancelationEventsForWindowLocked(windowHandle, options, connection);
            }

            fallback = false;
+9 −6
Original line number Diff line number Diff line
@@ -615,18 +615,21 @@ private:
            REQUIRES(mLock);
    void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options)
            REQUIRES(mLock);
    void synthesizeCancelationEventsForConnectionLocked(
            const std::shared_ptr<Connection>& connection, const CancelationOptions& options)
    void synthesizeCancelationEventsForWindowLocked(const sp<gui::WindowInfoHandle>&,
                                                    const CancelationOptions&,
                                                    const std::shared_ptr<Connection>& = nullptr)
            REQUIRES(mLock);
    // This is a convenience function used to generate cancellation for a connection without having
    // to check whether it's a monitor or a window. For non-monitors, the window handle must not be
    // null. Always prefer the "-ForWindow" method above when explicitly dealing with windows.
    void synthesizeCancelationEventsForConnectionLocked(
            const std::shared_ptr<Connection>& connection, const CancelationOptions& options,
            const sp<gui::WindowInfoHandle>& window) REQUIRES(mLock);

    void synthesizePointerDownEventsForConnectionLocked(
            const nsecs_t downTime, const std::shared_ptr<Connection>& connection,
            ftl::Flags<InputTarget::Flags> targetFlags) REQUIRES(mLock);

    void synthesizeCancelationEventsForWindowLocked(
            const sp<android::gui::WindowInfoHandle>& windowHandle,
            const CancelationOptions& options) REQUIRES(mLock);

    // Splitting motion events across windows. When splitting motion event for a target,
    // splitDownTime refers to the time of first 'down' event on that particular target
    std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry,
+38 −35

File changed.

Preview size limit exceeded, changes collapsed.