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

Commit 212dcf44 authored by Vishnu Nair's avatar Vishnu Nair
Browse files

InputFlinger: Add DROP_INPUT feature flags

If a window has the feature DROP_INPUT set, then all touch and
key events directed to the window will be dropped. For touch events,
the events will not go to the window behind it.

The flags are used to enable features that allow for a less trusted
interaction model between apps. See the bug for more details.

Test: atest libgui_test InputDispatcherDropInputFeatureTest
Bug: 197296414

Merged-In: I71d7cf5064c8ce4626cff09b92e15ca38b39cbbe
Change-Id: I71d7cf5064c8ce4626cff09b92e15ca38b39cbbe
parent 77daf700
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -128,7 +128,7 @@ struct InputWindowInfo : public Parcelable {
        DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
        NO_INPUT_CHANNEL = 0x00000002,
        DISABLE_USER_ACTIVITY = 0x00000004,
        INPUT_FEATURE_DROP_INPUT = 0x00000008,
        DROP_INPUT = 0x00000008,
    };

    /* These values are filled in by the WM and passed through SurfaceFlinger
+30 −0
Original line number Diff line number Diff line
@@ -1802,6 +1802,11 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked(
        return InputEventInjectionResult::FAILED;
    }

    // Drop key events if requested by input feature
    if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) {
        return InputEventInjectionResult::FAILED;
    }

    // Compatibility behavior: raise ANR if there is a focused application, but no focused window.
    // Only start counting when we have a focused event to dispatch. The ANR is canceled if we
    // start interacting with another application via touch (app switch). This code can be removed
@@ -2027,6 +2032,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            }
        }

        // Drop touch events if requested by input feature
        if (newTouchedWindowHandle != nullptr && shouldDropInput(entry, newTouchedWindowHandle)) {
            newTouchedWindowHandle = nullptr;
        }

        // Drop events that can't be trusted due to occlusion
        if (newTouchedWindowHandle != nullptr &&
            mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) {
@@ -2113,6 +2123,13 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            sp<InputWindowHandle> oldTouchedWindowHandle =
                    tempTouchState.getFirstForegroundWindowHandle();
            newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState);

            // Drop touch events if requested by input feature
            if (newTouchedWindowHandle != nullptr &&
                shouldDropInput(entry, newTouchedWindowHandle)) {
                newTouchedWindowHandle = nullptr;
            }

            if (oldTouchedWindowHandle != newTouchedWindowHandle &&
                oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) {
                if (DEBUG_FOCUS) {
@@ -6116,6 +6133,19 @@ bool InputDispatcher::waitForIdle() {
    return result == std::cv_status::no_timeout;
}

bool InputDispatcher::shouldDropInput(const EventEntry& entry,
                                      const sp<InputWindowHandle>& windowHandle) const {
    if (windowHandle->getInfo()->inputFeatures.test(InputWindowInfo::Feature::DROP_INPUT)) {
        ALOGW("Dropping %s event targeting %s as requested by inputFeatures={%s} on display "
              "%" PRId32 ".",
              entry.getDescription().c_str(), windowHandle->getName().c_str(),
              windowHandle->getInfo()->inputFeatures.string().c_str(),
              windowHandle->getInfo()->displayId);
        return true;
    }
    return false;
}

/**
 * Sets focus to the window identified by the token. This must be called
 * after updating any input window handles.
+3 −0
Original line number Diff line number Diff line
@@ -528,6 +528,9 @@ private:
    std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle,
                                          const sp<InputWindowHandle>& windowHandle);

    bool shouldDropInput(const EventEntry& entry, const sp<InputWindowHandle>& windowHandle) const
            REQUIRES(mLock);

    // Manage the dispatch cycle for a single connection.
    // These methods are deliberately not Interruptible because doing all of the work
    // with the mutex held makes it easier to ensure that connection invariants are maintained.
+40 −0
Original line number Diff line number Diff line
@@ -5305,4 +5305,44 @@ TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
    mSecondWindow->assertNoEvents();
}

class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};

TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
    std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();

    sp<FakeWindowHandle> window =
            new FakeWindowHandle(app, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
    window->setInputFeatures(InputWindowInfo::Feature::DROP_INPUT);
    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, app);
    window->setFocusable(true);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
    setFocusedWindow(window);
    window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);

    // With the flag set, window should not get any input
    NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyKey(&keyArgs);
    window->assertNoEvents();

    NotifyMotionArgs motionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                               ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&motionArgs);
    window->assertNoEvents();

    // With the flag cleared, the window should get input
    window->setInputFeatures(static_cast<InputWindowInfo::Feature>(0));
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});

    keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyKey(&keyArgs);
    window->consumeKeyUp(ADISPLAY_ID_DEFAULT);

    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                                    ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&motionArgs);
    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
    window->assertNoEvents();
}

} // namespace android::inputdispatcher