Loading libs/gui/WindowInfo.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,10 @@ bool WindowInfo::supportsSplitTouch() const { return flags.test(Flag::SPLIT_TOUCH); } bool WindowInfo::isSpy() const { return inputFeatures.test(Feature::SPY); } bool WindowInfo::overlaps(const WindowInfo* other) const { return frameLeft < other->frameRight && frameRight > other->frameLeft && frameTop < other->frameBottom && frameBottom > other->frameTop; Loading libs/gui/include/gui/WindowInfo.h +3 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ struct WindowInfo : public Parcelable { DISABLE_USER_ACTIVITY = 1u << 2, DROP_INPUT = 1u << 3, DROP_INPUT_IF_OBSCURED = 1u << 4, SPY = 1u << 5, }; /* These values are filled in by the WM and passed through SurfaceFlinger Loading Loading @@ -215,6 +216,8 @@ struct WindowInfo : public Parcelable { bool supportsSplitTouch() const; bool isSpy() const; bool overlaps(const WindowInfo* other) const; bool operator==(const WindowInfo& inputChannel) const; Loading services/inputflinger/dispatcher/InputDispatcher.cpp +92 −40 Original line number Diff line number Diff line Loading @@ -1051,14 +1051,14 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets"); } // 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) { if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) { continue; } const WindowInfo& info = *windowHandle->getInfo(); if (windowAcceptsTouchAt(info, displayId, x, y)) { if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y)) { return windowHandle; } Loading @@ -1070,6 +1070,27 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI 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) { const char* reason; switch (dropReason) { Loading Loading @@ -2078,9 +2099,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } } std::vector<sp<WindowInfoHandle>> newTouchedWindows; std::vector<sp<WindowInfoHandle>> newTouchedWindows = findTouchedSpyWindowsAtLocked(displayId, x, y); 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) { Loading Loading @@ -2128,8 +2151,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Set target flags. int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS; if (!info.isSpy()) { // There should only be one new foreground (non-spy) window at this location. targetFlags |= InputTarget::FLAG_FOREGROUND; } if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; Loading Loading @@ -2268,10 +2293,17 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Check permission to inject into all touched foreground windows and ensure there // is at least one touched foreground window. { bool haveForegroundWindow = false; bool haveForegroundOrSpyWindow = false; for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { haveForegroundWindow = true; const bool isForeground = (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)) { injectionResult = InputEventInjectionResult::PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; Loading @@ -2280,8 +2312,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } } bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty(); if (!haveForegroundWindow && !hasGestureMonitor) { ALOGI("Dropping event because there is no touched foreground window in display " if (!haveForegroundOrSpyWindow && !hasGestureMonitor) { ALOGI("Dropping event because there is no touched window in display " "%" PRId32 " or gesture monitor to receive it.", displayId); injectionResult = InputEventInjectionResult::FAILED; Loading Loading @@ -5521,58 +5553,78 @@ void InputDispatcher::removeMonitorChannelLocked( status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { { // acquire lock std::scoped_lock _l(mLock); std::optional<int32_t> foundDisplayId = findGestureMonitorDisplayByTokenLocked(token); if (!foundDisplayId) { ALOGW("Attempted to pilfer pointers from an un-registered monitor or invalid token"); return BAD_VALUE; } int32_t displayId = foundDisplayId.value(); std::unordered_map<int32_t, TouchState>::iterator stateIt = mTouchStatesByDisplay.find(displayId); TouchState* statePtr = nullptr; std::shared_ptr<InputChannel> requestingChannel; int32_t displayId; int32_t deviceId; const std::optional<int32_t> foundGestureMonitorDisplayId = findGestureMonitorDisplayByTokenLocked(token); // 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()) { ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId); return BAD_VALUE; } statePtr = &stateIt->second; TouchState& state = stateIt->second; std::shared_ptr<InputChannel> requestingChannel; std::optional<int32_t> foundDeviceId; for (const auto& monitor : state.gestureMonitors) { for (const auto& monitor : statePtr->gestureMonitors) { if (monitor.inputChannel->getConnectionToken() == token) { 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."); return BAD_VALUE; } int32_t deviceId = foundDeviceId.value(); // Send cancel events to all the input channels we're stealing from. CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "gesture monitor stole pointer stream"); "input channel stole pointer stream"); options.deviceId = deviceId; options.displayId = displayId; std::string canceledWindows = "["; std::string canceledWindows; for (const TouchedWindow& window : state.windows) { std::shared_ptr<InputChannel> channel = getInputChannelLocked(window.windowHandle->getToken()); if (channel != nullptr) { if (channel != nullptr && channel->getConnectionToken() != token) { synthesizeCancelationEventsForInputChannelLocked(channel, options); canceledWindows += channel->getName() + ", "; canceledWindows += canceledWindows.empty() ? "[" : ", "; canceledWindows += channel->getName(); } } canceledWindows += "]"; ALOGI("Monitor %s is stealing touch from %s", requestingChannel->getName().c_str(), canceledWindows += canceledWindows.empty() ? "[]" : "]"; ALOGI("Channel %s is stealing touch from %s", requestingChannel->getName().c_str(), canceledWindows.c_str()); // Then clear the current touch state so we stop dispatching to them as well. state.split = false; state.filterNonMonitors(); state.filterWindowsExcept(token); } return OK; } Loading services/inputflinger/dispatcher/InputDispatcher.h +5 −0 Original line number Diff line number Diff line Loading @@ -240,6 +240,11 @@ private: bool ignoreDragWindow = false) 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 REQUIRES(mLock); Loading services/inputflinger/dispatcher/TouchState.cpp +15 −2 Original line number Diff line number Diff line Loading @@ -105,8 +105,11 @@ void TouchState::filterNonAsIsTouchWindows() { } } void TouchState::filterNonMonitors() { windows.clear(); void TouchState::filterWindowsExcept(const sp<IBinder>& token) { 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 { Loading Loading @@ -144,4 +147,14 @@ sp<WindowInfoHandle> TouchState::getWallpaperWindow() const { 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 Loading
libs/gui/WindowInfo.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,10 @@ bool WindowInfo::supportsSplitTouch() const { return flags.test(Flag::SPLIT_TOUCH); } bool WindowInfo::isSpy() const { return inputFeatures.test(Feature::SPY); } bool WindowInfo::overlaps(const WindowInfo* other) const { return frameLeft < other->frameRight && frameRight > other->frameLeft && frameTop < other->frameBottom && frameBottom > other->frameTop; Loading
libs/gui/include/gui/WindowInfo.h +3 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ struct WindowInfo : public Parcelable { DISABLE_USER_ACTIVITY = 1u << 2, DROP_INPUT = 1u << 3, DROP_INPUT_IF_OBSCURED = 1u << 4, SPY = 1u << 5, }; /* These values are filled in by the WM and passed through SurfaceFlinger Loading Loading @@ -215,6 +216,8 @@ struct WindowInfo : public Parcelable { bool supportsSplitTouch() const; bool isSpy() const; bool overlaps(const WindowInfo* other) const; bool operator==(const WindowInfo& inputChannel) const; Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +92 −40 Original line number Diff line number Diff line Loading @@ -1051,14 +1051,14 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets"); } // 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) { if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) { continue; } const WindowInfo& info = *windowHandle->getInfo(); if (windowAcceptsTouchAt(info, displayId, x, y)) { if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y)) { return windowHandle; } Loading @@ -1070,6 +1070,27 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI 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) { const char* reason; switch (dropReason) { Loading Loading @@ -2078,9 +2099,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } } std::vector<sp<WindowInfoHandle>> newTouchedWindows; std::vector<sp<WindowInfoHandle>> newTouchedWindows = findTouchedSpyWindowsAtLocked(displayId, x, y); 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) { Loading Loading @@ -2128,8 +2151,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Set target flags. int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS; if (!info.isSpy()) { // There should only be one new foreground (non-spy) window at this location. targetFlags |= InputTarget::FLAG_FOREGROUND; } if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; Loading Loading @@ -2268,10 +2293,17 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Check permission to inject into all touched foreground windows and ensure there // is at least one touched foreground window. { bool haveForegroundWindow = false; bool haveForegroundOrSpyWindow = false; for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { haveForegroundWindow = true; const bool isForeground = (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)) { injectionResult = InputEventInjectionResult::PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; Loading @@ -2280,8 +2312,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } } bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty(); if (!haveForegroundWindow && !hasGestureMonitor) { ALOGI("Dropping event because there is no touched foreground window in display " if (!haveForegroundOrSpyWindow && !hasGestureMonitor) { ALOGI("Dropping event because there is no touched window in display " "%" PRId32 " or gesture monitor to receive it.", displayId); injectionResult = InputEventInjectionResult::FAILED; Loading Loading @@ -5521,58 +5553,78 @@ void InputDispatcher::removeMonitorChannelLocked( status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { { // acquire lock std::scoped_lock _l(mLock); std::optional<int32_t> foundDisplayId = findGestureMonitorDisplayByTokenLocked(token); if (!foundDisplayId) { ALOGW("Attempted to pilfer pointers from an un-registered monitor or invalid token"); return BAD_VALUE; } int32_t displayId = foundDisplayId.value(); std::unordered_map<int32_t, TouchState>::iterator stateIt = mTouchStatesByDisplay.find(displayId); TouchState* statePtr = nullptr; std::shared_ptr<InputChannel> requestingChannel; int32_t displayId; int32_t deviceId; const std::optional<int32_t> foundGestureMonitorDisplayId = findGestureMonitorDisplayByTokenLocked(token); // 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()) { ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId); return BAD_VALUE; } statePtr = &stateIt->second; TouchState& state = stateIt->second; std::shared_ptr<InputChannel> requestingChannel; std::optional<int32_t> foundDeviceId; for (const auto& monitor : state.gestureMonitors) { for (const auto& monitor : statePtr->gestureMonitors) { if (monitor.inputChannel->getConnectionToken() == token) { 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."); return BAD_VALUE; } int32_t deviceId = foundDeviceId.value(); // Send cancel events to all the input channels we're stealing from. CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "gesture monitor stole pointer stream"); "input channel stole pointer stream"); options.deviceId = deviceId; options.displayId = displayId; std::string canceledWindows = "["; std::string canceledWindows; for (const TouchedWindow& window : state.windows) { std::shared_ptr<InputChannel> channel = getInputChannelLocked(window.windowHandle->getToken()); if (channel != nullptr) { if (channel != nullptr && channel->getConnectionToken() != token) { synthesizeCancelationEventsForInputChannelLocked(channel, options); canceledWindows += channel->getName() + ", "; canceledWindows += canceledWindows.empty() ? "[" : ", "; canceledWindows += channel->getName(); } } canceledWindows += "]"; ALOGI("Monitor %s is stealing touch from %s", requestingChannel->getName().c_str(), canceledWindows += canceledWindows.empty() ? "[]" : "]"; ALOGI("Channel %s is stealing touch from %s", requestingChannel->getName().c_str(), canceledWindows.c_str()); // Then clear the current touch state so we stop dispatching to them as well. state.split = false; state.filterNonMonitors(); state.filterWindowsExcept(token); } return OK; } Loading
services/inputflinger/dispatcher/InputDispatcher.h +5 −0 Original line number Diff line number Diff line Loading @@ -240,6 +240,11 @@ private: bool ignoreDragWindow = false) 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 REQUIRES(mLock); Loading
services/inputflinger/dispatcher/TouchState.cpp +15 −2 Original line number Diff line number Diff line Loading @@ -105,8 +105,11 @@ void TouchState::filterNonAsIsTouchWindows() { } } void TouchState::filterNonMonitors() { windows.clear(); void TouchState::filterWindowsExcept(const sp<IBinder>& token) { 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 { Loading Loading @@ -144,4 +147,14 @@ sp<WindowInfoHandle> TouchState::getWallpaperWindow() const { 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