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

Commit b0dad3ad authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

Add test cases for fallback key generation from InputDispatcher

Bug: 210460522
Bug: 309154937
Test: atest inputflinger_tests
Change-Id: If07a2d1dd0043e4959ed20b086fa5afef26bd751
parent b9dd164b
Loading
Loading
Loading
Loading
+86 −0
Original line number Diff line number Diff line
@@ -160,4 +160,90 @@ private:
    std::vector<PointerBuilder> mPointers;
};

class KeyEventBuilder {
public:
    KeyEventBuilder(int32_t action, int32_t source) {
        mAction = action;
        mSource = source;
        mEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
        mDownTime = mEventTime;
    }

    KeyEventBuilder(const KeyEvent& event) {
        mAction = event.getAction();
        mDeviceId = event.getDeviceId();
        mSource = event.getSource();
        mDownTime = event.getDownTime();
        mEventTime = event.getEventTime();
        mDisplayId = event.getDisplayId();
        mFlags = event.getFlags();
        mKeyCode = event.getKeyCode();
        mScanCode = event.getScanCode();
        mMetaState = event.getMetaState();
        mRepeatCount = event.getRepeatCount();
    }

    KeyEventBuilder& deviceId(int32_t deviceId) {
        mDeviceId = deviceId;
        return *this;
    }

    KeyEventBuilder& downTime(nsecs_t downTime) {
        mDownTime = downTime;
        return *this;
    }

    KeyEventBuilder& eventTime(nsecs_t eventTime) {
        mEventTime = eventTime;
        return *this;
    }

    KeyEventBuilder& displayId(int32_t displayId) {
        mDisplayId = displayId;
        return *this;
    }

    KeyEventBuilder& policyFlags(int32_t policyFlags) {
        mPolicyFlags = policyFlags;
        return *this;
    }

    KeyEventBuilder& addFlag(uint32_t flags) {
        mFlags |= flags;
        return *this;
    }

    KeyEventBuilder& keyCode(int32_t keyCode) {
        mKeyCode = keyCode;
        return *this;
    }

    KeyEventBuilder& repeatCount(int32_t repeatCount) {
        mRepeatCount = repeatCount;
        return *this;
    }

    KeyEvent build() const {
        KeyEvent event{};
        event.initialize(InputEvent::nextId(), mDeviceId, mSource, mDisplayId, INVALID_HMAC,
                         mAction, mFlags, mKeyCode, mScanCode, mMetaState, mRepeatCount, mDownTime,
                         mEventTime);
        return event;
    }

private:
    int32_t mAction;
    int32_t mDeviceId = DEFAULT_DEVICE_ID;
    uint32_t mSource;
    nsecs_t mDownTime;
    nsecs_t mEventTime;
    int32_t mDisplayId{ADISPLAY_ID_DEFAULT};
    uint32_t mPolicyFlags = DEFAULT_POLICY_FLAGS;
    int32_t mFlags{0};
    int32_t mKeyCode{AKEYCODE_UNKNOWN};
    int32_t mScanCode{0};
    int32_t mMetaState{AMETA_NONE};
    int32_t mRepeatCount{0};
};

} // namespace android
+249 −12
Original line number Diff line number Diff line
@@ -335,7 +335,7 @@ public:
        std::optional<sp<IBinder>> receivedToken =
                getItemFromStorageLockedInterruptible(100ms, mBrokenInputChannels, lock,
                                                      mNotifyInputChannelBroken);
        ASSERT_TRUE(receivedToken.has_value());
        ASSERT_TRUE(receivedToken.has_value()) << "Did not receive the broken channel token";
        ASSERT_EQ(token, *receivedToken);
    }
@@ -366,6 +366,30 @@ public:
        ASSERT_FALSE(mNotifiedInteractions.popWithTimeout(10ms));
    }
    void setUnhandledKeyHandler(std::function<std::optional<KeyEvent>(const KeyEvent&)> handler) {
        std::scoped_lock lock(mLock);
        mUnhandledKeyHandler = handler;
    }
    void assertUnhandledKeyReported(int32_t keycode) {
        std::unique_lock lock(mLock);
        base::ScopedLockAssertion assumeLocked(mLock);
        std::optional<int32_t> unhandledKeycode =
                getItemFromStorageLockedInterruptible(100ms, mReportedUnhandledKeycodes, lock,
                                                      mNotifyUnhandledKey);
        ASSERT_TRUE(unhandledKeycode) << "Expected unhandled key to be reported";
        ASSERT_EQ(unhandledKeycode, keycode);
    }
    void assertUnhandledKeyNotReported() {
        std::unique_lock lock(mLock);
        base::ScopedLockAssertion assumeLocked(mLock);
        std::optional<int32_t> unhandledKeycode =
                getItemFromStorageLockedInterruptible(10ms, mReportedUnhandledKeycodes, lock,
                                                      mNotifyUnhandledKey);
        ASSERT_FALSE(unhandledKeycode) << "Expected unhandled key NOT to be reported";
    }
private:
    std::mutex mLock;
    std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock);
@@ -395,6 +419,10 @@ private:
    BlockingQueue<std::pair<int32_t /*deviceId*/, std::set<gui::Uid>>> mNotifiedInteractions;
    std::condition_variable mNotifyUnhandledKey;
    std::queue<int32_t> mReportedUnhandledKeycodes GUARDED_BY(mLock);
    std::function<std::optional<KeyEvent>(const KeyEvent&)> mUnhandledKeyHandler GUARDED_BY(mLock);
    // All three ANR-related callbacks behave the same way, so we use this generic function to wait
    // for a specific container to become non-empty. When the container is non-empty, return the
    // first entry from the container and erase it.
@@ -437,7 +465,6 @@ private:
        condition.wait_for(lock, timeout,
                           [&storage]() REQUIRES(mLock) { return !storage.empty(); });
        if (storage.empty()) {
            ADD_FAILURE() << "Did not receive the expected callback";
            return std::nullopt;
        }
        T item = storage.front();
@@ -528,9 +555,12 @@ private:
        return delay;
    }
    std::optional<KeyEvent> dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent&,
    std::optional<KeyEvent> dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent& event,
                                                 uint32_t) override {
        return {};
        std::scoped_lock lock(mLock);
        mReportedUnhandledKeycodes.emplace(event.getKeyCode());
        mNotifyUnhandledKey.notify_all();
        return mUnhandledKeyHandler != nullptr ? mUnhandledKeyHandler(event) : std::nullopt;
    }
    void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
@@ -845,13 +875,13 @@ public:
        mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel));
    }
    InputEvent* consume(std::chrono::milliseconds timeout) {
    InputEvent* consume(std::chrono::milliseconds timeout, bool handled = false) {
        InputEvent* event;
        std::optional<uint32_t> consumeSeq = receiveEvent(timeout, &event);
        if (!consumeSeq) {
            return nullptr;
        }
        finishEvent(*consumeSeq);
        finishEvent(*consumeSeq, handled);
        return event;
    }
@@ -897,8 +927,8 @@ public:
    /**
     * To be used together with "receiveEvent" to complete the consumption of an event.
     */
    void finishEvent(uint32_t consumeSeq) {
        const status_t status = mConsumer->sendFinishedSignal(consumeSeq, true);
    void finishEvent(uint32_t consumeSeq, bool handled = true) {
        const status_t status = mConsumer->sendFinishedSignal(consumeSeq, handled);
        ASSERT_EQ(OK, status) << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
    }
@@ -1209,8 +1239,8 @@ public:
    void setWindowOffset(float offsetX, float offsetY) { mInfo.transform.set(offsetX, offsetY); }
    KeyEvent* consumeKey() {
        InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
    KeyEvent* consumeKey(bool handled = true) {
        InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED, handled);
        if (event == nullptr) {
            ADD_FAILURE() << "Consume failed : no event";
            return nullptr;
@@ -1349,11 +1379,11 @@ public:
        mInputReceiver->sendTimeline(inputEventId, timeline);
    }
    InputEvent* consume(std::chrono::milliseconds timeout) {
    InputEvent* consume(std::chrono::milliseconds timeout, bool handled = true) {
        if (mInputReceiver == nullptr) {
            return nullptr;
        }
        return mInputReceiver->consume(timeout);
        return mInputReceiver->consume(timeout, handled);
    }
    MotionEvent* consumeMotion() {
@@ -6534,6 +6564,213 @@ TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) {
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasNotCalled());
}
class InputDispatcherFallbackKeyTest : public InputDispatcherTest {
protected:
    std::shared_ptr<FakeApplicationHandle> mApp;
    sp<FakeWindowHandle> mWindow;
    virtual void SetUp() override {
        InputDispatcherTest::SetUp();
        mApp = std::make_shared<FakeApplicationHandle>();
        mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
        mWindow->setFrame(Rect(0, 0, 100, 100));
        mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
        setFocusedWindow(mWindow);
        ASSERT_NO_FATAL_FAILURE(mWindow->consumeFocusEvent(/*hasFocus=*/true));
    }
    void setFallback(int32_t keycode) {
        mFakePolicy->setUnhandledKeyHandler([keycode](const KeyEvent& event) {
            return KeyEventBuilder(event).keyCode(keycode).build();
        });
    }
    void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
        KeyEvent* event = mWindow->consumeKey(handled);
        ASSERT_NE(event, nullptr) << "Did not receive key event";
        ASSERT_THAT(*event, matcher);
    }
};
TEST_F(InputDispatcherFallbackKeyTest, PolicyNotNotifiedForHandledKey) {
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
}
TEST_F(InputDispatcherFallbackKeyTest, PolicyNotifiedForUnhandledKey) {
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    consumeKey(/*handled=*/false, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
}
TEST_F(InputDispatcherFallbackKeyTest, NoFallbackRequestedByPolicy) {
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    // Do not handle this key event.
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    // Since the policy did not request any fallback to be generated, ensure there are no events.
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
}
TEST_F(InputDispatcherFallbackKeyTest, FallbackDispatchForUnhandledKey) {
    setFallback(AKEYCODE_B);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    // Do not handle this key event.
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    // Since the key was not handled, ensure the fallback event was dispatched instead.
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
    // Release the original key, and ensure the fallback key is also released.
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
    mWindow->assertNoEvents();
}
TEST_F(InputDispatcherFallbackKeyTest, AppHandlesPreviouslyUnhandledKey) {
    setFallback(AKEYCODE_B);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    // Do not handle this key event, but handle the fallback.
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
    // Release the original key, and ensure the fallback key is also released.
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    // But this time, the app handles the original key.
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    // Ensure the fallback key is canceled.
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
    mWindow->assertNoEvents();
}
TEST_F(InputDispatcherFallbackKeyTest, AppDoesNotHandleFallback) {
    setFallback(AKEYCODE_B);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    // Do not handle this key event.
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    // App does not handle the fallback either, so ensure another fallback is not generated.
    setFallback(AKEYCODE_C);
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
    // Release the original key, and ensure the fallback key is also released.
    setFallback(AKEYCODE_B);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
    mWindow->assertNoEvents();
}
TEST_F(InputDispatcherFallbackKeyTest, InconsistentPolicyCancelsFallback) {
    setFallback(AKEYCODE_B);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    // Do not handle this key event, so fallback is generated.
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
    // Release the original key, but assume the policy is misbehaving and it
    // generates an inconsistent fallback to the one from the DOWN event.
    setFallback(AKEYCODE_C);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    // Ensure the fallback key reported before as DOWN is canceled due to the inconsistency.
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
    mWindow->assertNoEvents();
}
TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
    setFallback(AKEYCODE_B);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    // Do not handle this key event, so fallback is generated.
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
    // The original key is canceled.
    mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD)
                                   .keyCode(AKEYCODE_A)
                                   .addFlag(AKEY_EVENT_FLAG_CANCELED)
                                   .build());
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
                     WithFlags(AKEY_EVENT_FLAG_CANCELED)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    // Ensure the fallback key is also canceled due to the original key being canceled.
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyNotReported());
    mWindow->assertNoEvents();
}
class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
protected:
    static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms
+26 −3
Original line number Diff line number Diff line
@@ -464,9 +464,32 @@ inline WithPointersMatcher WithPointers(
    return WithPointersMatcher(pointers);
}

MATCHER_P(WithKeyCode, keyCode, "KeyEvent with specified key code") {
    *result_listener << "expected key code " << keyCode << ", but got " << arg.keyCode;
    return arg.keyCode == keyCode;
/// Key code
class WithKeyCodeMatcher {
public:
    using is_gtest_matcher = void;
    explicit WithKeyCodeMatcher(int32_t keyCode) : mKeyCode(keyCode) {}

    bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const {
        return mKeyCode == args.keyCode;
    }

    bool MatchAndExplain(const KeyEvent& event, std::ostream*) const {
        return mKeyCode == event.getKeyCode();
    }

    void DescribeTo(std::ostream* os) const {
        *os << "with key code " << KeyEvent::getLabel(mKeyCode);
    }

    void DescribeNegationTo(std::ostream* os) const { *os << "wrong key code"; }

private:
    const int32_t mKeyCode;
};

inline WithKeyCodeMatcher WithKeyCode(int32_t keyCode) {
    return WithKeyCodeMatcher(keyCode);
}

MATCHER_P(WithRepeatCount, repeatCount, "KeyEvent with specified repeat count") {