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

Commit 48710e42 authored by Antonio Kantek's avatar Antonio Kantek
Browse files

Add last interacted window check in setInTouchMode

Allow touch mode switch if caller owns the focused window.
If no window is currently focused, then touch will be still allowed if
caller owned one of the previously interacted window.

Bug: 218541064
Test: atest inputflinger_tests
Test: atest InputDispatcherTouchModeChangedTests
Change-Id: I5cfa879a6e1358efe3781061c5712707da813967
parent 1f692ead
Loading
Loading
Loading
Loading
+34 −15
Original line number Diff line number Diff line
@@ -567,6 +567,17 @@ bool canReceiveForegroundTouches(const WindowInfo& info) {
    return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy();
}

bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int32_t uid) {
    if (windowHandle == nullptr) {
        return false;
    }
    const WindowInfo* windowInfo = windowHandle->getInfo();
    if (pid == windowInfo->ownerPid && uid == windowInfo->ownerUid) {
        return true;
    }
    return false;
}

} // namespace

// --- InputDispatcher ---
@@ -4990,21 +5001,11 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid,
                  toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission));
        }
        if (!hasPermission) {
            const sp<IBinder> focusedToken =
                    mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);

            //  TODO(b/218541064): if no window is currently focused, then we need to check the last
            //      interacted window (within 1 second timeout). We should allow touch mode change
            //      if the last interacted window owner's pid/uid match the calling ones.
            if (focusedToken == nullptr) {
                return false;
            }
            const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
            if (windowHandle == nullptr) {
                return false;
            }
            const WindowInfo* windowInfo = windowHandle->getInfo();
            if (pid != windowInfo->ownerPid || uid != windowInfo->ownerUid) {
            if (!focusedWindowIsOwnedByLocked(pid, uid) &&
                !recentWindowsAreOwnedByLocked(pid, uid)) {
                ALOGD("Touch mode switch rejected, caller (pid=%d, uid=%d) doesn't own the focused "
                      "window nor none of the previously interacted window",
                      pid, uid);
                return false;
            }
        }
@@ -5022,6 +5023,24 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid,
    return true;
}

bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) {
    const sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
    if (focusedToken == nullptr) {
        return false;
    }
    sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
    return isWindowOwnedBy(windowHandle, pid, uid);
}

bool InputDispatcher::recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) {
    return std::find_if(mInteractionConnectionTokens.begin(), mInteractionConnectionTokens.end(),
                        [&](const sp<IBinder>& connectionToken) REQUIRES(mLock) {
                            const sp<WindowInfoHandle> windowHandle =
                                    getWindowHandleLocked(connectionToken);
                            return isWindowOwnedBy(windowHandle, pid, uid);
                        }) != mInteractionConnectionTokens.end();
}

void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
    if (opacity < 0 || opacity > 1) {
        LOG_ALWAYS_FATAL("Maximum obscuring opacity for touch should be >= 0 and <= 1");
+6 −1
Original line number Diff line number Diff line
@@ -433,7 +433,8 @@ private:
    // Dispatcher state at time of last ANR.
    std::string mLastAnrState GUARDED_BY(mLock);

    // The connection tokens of the channels that the user last interacted, for debugging
    // The connection tokens of the channels that the user last interacted (used for debugging and
    // when switching touch mode state).
    std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> mInteractionConnectionTokens
            GUARDED_BY(mLock);
    void updateInteractionTokensLocked(const EventEntry& entry,
@@ -677,6 +678,10 @@ private:
    void traceOutboundQueueLength(const Connection& connection);
    void traceWaitQueueLength(const Connection& connection);

    // Check window ownership
    bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
    bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);

    sp<InputReporterInterface> mReporter;
};

+22 −2
Original line number Diff line number Diff line
@@ -6335,8 +6335,11 @@ protected:
        mWindow->consumeFocusEvent(true);

        // Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
        mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
                                    INJECTOR_UID, /* hasPermission */ true);
        if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
                                        INJECTOR_UID, /* hasPermission */ true)) {
            mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
            mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
        }
    }

    void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
@@ -6381,6 +6384,23 @@ TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTou
    mSecondWindow->assertNoEvents();
}

TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
    // Interact with the window first.
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
            << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
    mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);

    // Then remove focus.
    mWindow->setFocusable(false);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});

    // Assert that caller can switch touch mode by owning one of the last interacted window.
    const WindowInfo& windowInfo = *mWindow->getInfo();
    ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
                                            windowInfo.ownerPid, windowInfo.ownerUid,
                                            /* hasPermission= */ false));
}

class InputDispatcherSpyWindowTest : public InputDispatcherTest {
public:
    sp<FakeWindowHandle> createSpy() {