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

Commit 59943ee2 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "InputDispatcher: Implement spy windows"

parents 914371c4 07e05b60
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -43,6 +43,10 @@ bool WindowInfo::supportsSplitTouch() const {
    return flags.test(Flag::SPLIT_TOUCH);
    return flags.test(Flag::SPLIT_TOUCH);
}
}


bool WindowInfo::isSpy() const {
    return inputFeatures.test(Feature::SPY);
}

bool WindowInfo::overlaps(const WindowInfo* other) const {
bool WindowInfo::overlaps(const WindowInfo* other) const {
    return frameLeft < other->frameRight && frameRight > other->frameLeft &&
    return frameLeft < other->frameRight && frameRight > other->frameLeft &&
            frameTop < other->frameBottom && frameBottom > other->frameTop;
            frameTop < other->frameBottom && frameBottom > other->frameTop;
+3 −0
Original line number Original line Diff line number Diff line
@@ -137,6 +137,7 @@ struct WindowInfo : public Parcelable {
        DISABLE_USER_ACTIVITY = 1u << 2,
        DISABLE_USER_ACTIVITY = 1u << 2,
        DROP_INPUT = 1u << 3,
        DROP_INPUT = 1u << 3,
        DROP_INPUT_IF_OBSCURED = 1u << 4,
        DROP_INPUT_IF_OBSCURED = 1u << 4,
        SPY = 1u << 5,
    };
    };


    /* These values are filled in by the WM and passed through SurfaceFlinger
    /* These values are filled in by the WM and passed through SurfaceFlinger
@@ -215,6 +216,8 @@ struct WindowInfo : public Parcelable {


    bool supportsSplitTouch() const;
    bool supportsSplitTouch() const;


    bool isSpy() const;

    bool overlaps(const WindowInfo* other) const;
    bool overlaps(const WindowInfo* other) const;


    bool operator==(const WindowInfo& inputChannel) const;
    bool operator==(const WindowInfo& inputChannel) const;
+92 −40
Original line number Original line Diff line number Diff line
@@ -1051,14 +1051,14 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI
        LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets");
        LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets");
    }
    }
    // Traverse windows from front to back to find touched window.
    // Traverse windows from front to back to find touched window.
    const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
    const auto& windowHandles = getWindowHandlesLocked(displayId);
    for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
    for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
        if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
        if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
            continue;
            continue;
        }
        }


        const WindowInfo& info = *windowHandle->getInfo();
        const WindowInfo& info = *windowHandle->getInfo();
        if (windowAcceptsTouchAt(info, displayId, x, y)) {
        if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y)) {
            return windowHandle;
            return windowHandle;
        }
        }


@@ -1070,6 +1070,27 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI
    return nullptr;
    return nullptr;
}
}


std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAtLocked(int32_t displayId,
                                                                                 int32_t x,
                                                                                 int32_t y) const {
    // Traverse windows from front to back and gather the touched spy windows.
    std::vector<sp<WindowInfoHandle>> spyWindows;
    const auto& windowHandles = getWindowHandlesLocked(displayId);
    for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
        const WindowInfo& info = *windowHandle->getInfo();

        if (!windowAcceptsTouchAt(info, displayId, x, y)) {
            continue;
        }
        if (!info.isSpy()) {
            // The first touched non-spy window was found, so return the spy windows touched so far.
            return spyWindows;
        }
        spyWindows.push_back(windowHandle);
    }
    return spyWindows;
}

void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) {
void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) {
    const char* reason;
    const char* reason;
    switch (dropReason) {
    switch (dropReason) {
@@ -2078,9 +2099,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            }
            }
        }
        }


        std::vector<sp<WindowInfoHandle>> newTouchedWindows;
        std::vector<sp<WindowInfoHandle>> newTouchedWindows =
                findTouchedSpyWindowsAtLocked(displayId, x, y);
        if (newTouchedWindowHandle != nullptr) {
        if (newTouchedWindowHandle != nullptr) {
            newTouchedWindows.push_back(newTouchedWindowHandle);
            // Process the foreground window first so that it is the first to receive the event.
            newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle);
        }
        }


        for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
        for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
@@ -2128,8 +2151,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            // Set target flags.
            // Set target flags.
            int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS;
            int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS;


            if (!info.isSpy()) {
                // There should only be one new foreground (non-spy) window at this location.
                // There should only be one new foreground (non-spy) window at this location.
                targetFlags |= InputTarget::FLAG_FOREGROUND;
                targetFlags |= InputTarget::FLAG_FOREGROUND;
            }


            if (isSplit) {
            if (isSplit) {
                targetFlags |= InputTarget::FLAG_SPLIT;
                targetFlags |= InputTarget::FLAG_SPLIT;
@@ -2268,10 +2293,17 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
    // Check permission to inject into all touched foreground windows and ensure there
    // Check permission to inject into all touched foreground windows and ensure there
    // is at least one touched foreground window.
    // is at least one touched foreground window.
    {
    {
        bool haveForegroundWindow = false;
        bool haveForegroundOrSpyWindow = false;
        for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
        for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
            if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
            const bool isForeground =
                haveForegroundWindow = true;
                    (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0;
            if (touchedWindow.windowHandle->getInfo()->isSpy()) {
                haveForegroundOrSpyWindow = true;
                LOG_ALWAYS_FATAL_IF(isForeground,
                                    "Spy window cannot be dispatched as a foreground window.");
            }
            if (isForeground) {
                haveForegroundOrSpyWindow = true;
                if (!checkInjectionPermission(touchedWindow.windowHandle, entry.injectionState)) {
                if (!checkInjectionPermission(touchedWindow.windowHandle, entry.injectionState)) {
                    injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
                    injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
                    injectionPermission = INJECTION_PERMISSION_DENIED;
                    injectionPermission = INJECTION_PERMISSION_DENIED;
@@ -2280,8 +2312,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            }
            }
        }
        }
        bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty();
        bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty();
        if (!haveForegroundWindow && !hasGestureMonitor) {
        if (!haveForegroundOrSpyWindow && !hasGestureMonitor) {
            ALOGI("Dropping event because there is no touched foreground window in display "
            ALOGI("Dropping event because there is no touched window in display "
                  "%" PRId32 " or gesture monitor to receive it.",
                  "%" PRId32 " or gesture monitor to receive it.",
                  displayId);
                  displayId);
            injectionResult = InputEventInjectionResult::FAILED;
            injectionResult = InputEventInjectionResult::FAILED;
@@ -5521,58 +5553,78 @@ void InputDispatcher::removeMonitorChannelLocked(
status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
    { // acquire lock
    { // acquire lock
        std::scoped_lock _l(mLock);
        std::scoped_lock _l(mLock);
        std::optional<int32_t> foundDisplayId = findGestureMonitorDisplayByTokenLocked(token);


        if (!foundDisplayId) {
        TouchState* statePtr = nullptr;
            ALOGW("Attempted to pilfer pointers from an un-registered monitor or invalid token");
        std::shared_ptr<InputChannel> requestingChannel;
            return BAD_VALUE;
        int32_t displayId;
        }
        int32_t deviceId;
        int32_t displayId = foundDisplayId.value();
        const std::optional<int32_t> foundGestureMonitorDisplayId =

                findGestureMonitorDisplayByTokenLocked(token);
        std::unordered_map<int32_t, TouchState>::iterator stateIt =

                mTouchStatesByDisplay.find(displayId);
        // TODO: Optimize this function for pilfering from windows when removing gesture monitors.
        if (foundGestureMonitorDisplayId) {
            // A gesture monitor has requested to pilfer pointers.
            displayId = *foundGestureMonitorDisplayId;
            auto stateIt = mTouchStatesByDisplay.find(displayId);
            if (stateIt == mTouchStatesByDisplay.end()) {
            if (stateIt == mTouchStatesByDisplay.end()) {
                ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId);
                ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId);
                return BAD_VALUE;
                return BAD_VALUE;
            }
            }
            statePtr = &stateIt->second;


        TouchState& state = stateIt->second;
            for (const auto& monitor : statePtr->gestureMonitors) {
        std::shared_ptr<InputChannel> requestingChannel;
        std::optional<int32_t> foundDeviceId;
        for (const auto& monitor : state.gestureMonitors) {
                if (monitor.inputChannel->getConnectionToken() == token) {
                if (monitor.inputChannel->getConnectionToken() == token) {
                    requestingChannel = monitor.inputChannel;
                    requestingChannel = monitor.inputChannel;
                foundDeviceId = state.deviceId;
                    deviceId = statePtr->deviceId;
                }
            }
        } else {
            // Check if a window has requested to pilfer pointers.
            for (auto& [curDisplayId, state] : mTouchStatesByDisplay) {
                const sp<WindowInfoHandle>& windowHandle = state.getWindow(token);
                if (windowHandle != nullptr) {
                    displayId = curDisplayId;
                    requestingChannel = getInputChannelLocked(token);
                    deviceId = state.deviceId;
                    statePtr = &state;
                    break;
                }
            }
            }
        }
        }
        if (!foundDeviceId || !state.down) {

            ALOGW("Attempted to pilfer points from a monitor without any on-going pointer streams."
        if (requestingChannel == nullptr) {
            ALOGW("Attempted to pilfer pointers from an un-registered channel or invalid token");
            return BAD_VALUE;
        }
        TouchState& state = *statePtr;
        if (!state.down) {
            ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams."
                  " Ignoring.");
                  " Ignoring.");
            return BAD_VALUE;
            return BAD_VALUE;
        }
        }
        int32_t deviceId = foundDeviceId.value();


        // Send cancel events to all the input channels we're stealing from.
        // Send cancel events to all the input channels we're stealing from.
        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                                   "gesture monitor stole pointer stream");
                                   "input channel stole pointer stream");
        options.deviceId = deviceId;
        options.deviceId = deviceId;
        options.displayId = displayId;
        options.displayId = displayId;
        std::string canceledWindows = "[";
        std::string canceledWindows;
        for (const TouchedWindow& window : state.windows) {
        for (const TouchedWindow& window : state.windows) {
            std::shared_ptr<InputChannel> channel =
            std::shared_ptr<InputChannel> channel =
                    getInputChannelLocked(window.windowHandle->getToken());
                    getInputChannelLocked(window.windowHandle->getToken());
            if (channel != nullptr) {
            if (channel != nullptr && channel->getConnectionToken() != token) {
                synthesizeCancelationEventsForInputChannelLocked(channel, options);
                synthesizeCancelationEventsForInputChannelLocked(channel, options);
                canceledWindows += channel->getName() + ", ";
                canceledWindows += canceledWindows.empty() ? "[" : ", ";
                canceledWindows += channel->getName();
            }
            }
        }
        }
        canceledWindows += "]";
        canceledWindows += canceledWindows.empty() ? "[]" : "]";
        ALOGI("Monitor %s is stealing touch from %s", requestingChannel->getName().c_str(),
        ALOGI("Channel %s is stealing touch from %s", requestingChannel->getName().c_str(),
              canceledWindows.c_str());
              canceledWindows.c_str());


        // Then clear the current touch state so we stop dispatching to them as well.
        // Then clear the current touch state so we stop dispatching to them as well.
        state.split = false;
        state.split = false;
        state.filterNonMonitors();
        state.filterWindowsExcept(token);
    }
    }
    return OK;
    return OK;
}
}
+5 −0
Original line number Original line Diff line number Diff line
@@ -240,6 +240,11 @@ private:
                                                                 bool ignoreDragWindow = false)
                                                                 bool ignoreDragWindow = false)
            REQUIRES(mLock);
            REQUIRES(mLock);


    std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked(int32_t displayId,
                                                                                  int32_t x,
                                                                                  int32_t y) const
            REQUIRES(mLock);

    sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
    sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
            REQUIRES(mLock);
            REQUIRES(mLock);


+15 −2
Original line number Original line Diff line number Diff line
@@ -105,8 +105,11 @@ void TouchState::filterNonAsIsTouchWindows() {
    }
    }
}
}


void TouchState::filterNonMonitors() {
void TouchState::filterWindowsExcept(const sp<IBinder>& token) {
    windows.clear();
    auto it = std::remove_if(windows.begin(), windows.end(), [&token](const TouchedWindow& w) {
        return w.windowHandle->getToken() != token;
    });
    windows.erase(it, windows.end());
}
}


sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
@@ -144,4 +147,14 @@ sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
    return nullptr;
    return nullptr;
}
}


sp<WindowInfoHandle> TouchState::getWindow(const sp<IBinder>& token) const {
    for (const TouchedWindow& touchedWindow : windows) {
        const auto& windowHandle = touchedWindow.windowHandle;
        if (windowHandle->getToken() == token) {
            return windowHandle;
        }
    }
    return nullptr;
}

} // namespace android::inputdispatcher
} // namespace android::inputdispatcher
Loading