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

Commit ea47acbc authored by Antonio Kantek's avatar Antonio Kantek
Browse files

(TouchMode Permission 2.1/n) Add permission check when switching touch mode

This CL adds the following permission checks when switching touch mode state:
1. Allow touch mode switch if caller is granted with MODIFY_TOUCH_MODE_STATE;
2. If caller is not granted with MODIFY_TOUCH_MODE_STATE, touch mode
state change will be allowed if the caller's uid matches the focused
window owner's uid.

Touch mode switch will be denied if none of the conditions above match.

Bug: 198487159
Test: atest inputflinger_tests
Test: atest libinput_tests

Change-Id: Ic704682ac41fe470207d9be132b4c0f1a8019f39
parent 8d5a4376
Loading
Loading
Loading
Loading
+27 −7
Original line number Diff line number Diff line
@@ -137,7 +137,7 @@ constexpr std::chrono::nanoseconds KEY_WAITING_FOR_EVENTS_TIMEOUT = 500ms;
// Number of recent events to keep for debugging purposes.
constexpr size_t RECENT_QUEUE_MAX_SIZE = 10;

// Event log tags. See EventLogTags.logtags for reference
// Event log tags. See EventLogTags.logtags for reference.
constexpr int LOGTAG_INPUT_INTERACTION = 62000;
constexpr int LOGTAG_INPUT_FOCUS = 62001;
constexpr int LOGTAG_INPUT_CANCEL = 62003;
@@ -4950,23 +4950,42 @@ void InputDispatcher::setInputFilterEnabled(bool enabled) {
    mLooper->wake();
}

void InputDispatcher::setInTouchMode(bool inTouchMode) {
bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid,
                                     bool hasPermission) {
    bool needWake = false;
    {
        std::scoped_lock lock(mLock);
        if (mInTouchMode == inTouchMode) {
            return;
            return false;
        }
        if (DEBUG_TOUCH_MODE) {
            ALOGD("Request to change touch mode from %s to %s", toString(mInTouchMode),
                  toString(inTouchMode));
            // TODO(b/198487159): Also print the current last interacted apps.
            ALOGD("Request to change touch mode from %s to %s (calling pid=%d, uid=%d, "
                  "hasPermission=%s)",
                  toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission));
        }
        if (!hasPermission) {
            const sp<IBinder> focusedToken =
                    mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);

            //  TODO(b/198487159): 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) {
                return false;
            }
        }

        // TODO(b/198499018): Store touch mode per display.
        mInTouchMode = inTouchMode;

        // TODO(b/198487159): Enforce that only last interacted apps can change touch mode.
        auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode);
        needWake = enqueueInboundEventLocked(std::move(entry));
    } // release lock
@@ -4974,6 +4993,7 @@ void InputDispatcher::setInTouchMode(bool inTouchMode) {
    if (needWake) {
        mLooper->wake();
    }
    return true;
}

void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
+1 −1
Original line number Diff line number Diff line
@@ -117,7 +117,7 @@ public:
    void setFocusedDisplay(int32_t displayId) override;
    void setInputDispatchMode(bool enabled, bool frozen) override;
    void setInputFilterEnabled(bool enabled) override;
    void setInTouchMode(bool inTouchMode) override;
    bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) override;
    void setMaximumObscuringOpacityForTouch(float opacity) override;
    void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override;

+3 −1
Original line number Diff line number Diff line
@@ -123,8 +123,10 @@ public:
     * Touch mode is a global state that apps may enter / exit based on specific
     * user interactions with input devices.
     * If true, the device is in touch mode.
     *
     * Returns true when changing touch mode state.
     */
    virtual void setInTouchMode(bool inTouchMode) = 0;
    virtual bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) = 0;

    /**
     * Sets the maximum allowed obscuring opacity by UID to propagate touches.
+16 −6
Original line number Diff line number Diff line
@@ -3112,6 +3112,7 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> window =
            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
    const WindowInfo& windowInfo = *window->getInfo();

    // Set focused application.
    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -3128,7 +3129,8 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
    window->consumeFocusEvent(false /*hasFocus*/, true /*inTouchMode*/);

    SCOPED_TRACE("Disable touch mode");
    mDispatcher->setInTouchMode(false);
    mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
                                /* hasPermission */ true);
    window->consumeTouchModeEvent(false);
    window->setFocusable(true);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -3141,7 +3143,8 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
    window->consumeFocusEvent(false /*hasFocus*/, false /*inTouchMode*/);

    SCOPED_TRACE("Enable touch mode again");
    mDispatcher->setInTouchMode(true);
    mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
                                /* hasPermission */ true);
    window->consumeTouchModeEvent(true);
    window->setFocusable(true);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -6300,19 +6303,23 @@ protected:
        mWindow->consumeFocusEvent(true);
    }

    void changeAndVerifyTouchMode(bool inTouchMode) {
        mDispatcher->setInTouchMode(inTouchMode);
    void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
        mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission);
        mWindow->consumeTouchModeEvent(inTouchMode);
        mSecondWindow->consumeTouchModeEvent(inTouchMode);
    }
};

TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchModeOnFocusedWindow) {
    changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode);
    const WindowInfo& windowInfo = *mWindow->getInfo();
    changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
                             windowInfo.ownerUid, /* hasPermission */ false);
}

TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
    mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode);
    const WindowInfo& windowInfo = *mWindow->getInfo();
    mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
                                windowInfo.ownerUid, /* hasPermission */ true);
    mWindow->assertNoEvents();
    mSecondWindow->assertNoEvents();
}
@@ -6712,4 +6719,7 @@ TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
    window->assertNoEvents();
}

// TODO(b/198487159): Add permission tests for touch mode switch once the validation is put in
//     place.

} // namespace android::inputdispatcher