Loading services/inputflinger/dispatcher/InputDispatcher.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -4003,7 +4003,7 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( const std::shared_ptr<Connection>& connection, const CancelationOptions& options) { if (connection->status == Connection::Status::BROKEN) { if (connection->status != Connection::Status::NORMAL) { return; } Loading services/inputflinger/tests/InputDispatcher_test.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -6974,6 +6974,39 @@ TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) { mWindow->assertNoEvents(); } TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) { 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)); consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), WithFlags(AKEY_EVENT_FLAG_FALLBACK))); mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) { // When the unhandled key is reported to the policy next, remove the input channel. mDispatcher->removeInputChannel(mWindow->getToken()); return KeyEventBuilder(event).keyCode(AKEYCODE_B).build(); }); // Release the original key, and let the app now handle the previously unhandled key. // This should result in the previously generated fallback key to be cancelled. // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified // of the UP event for consistency. The Dispatcher calls into the policy from its own thread // without holding the lock, because it need to synchronously fetch the fallback key. While in // the policy call, we will now remove the input channel. Once the policy call returns, the // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does // not cause any crashes. mDispatcher->notifyKey( KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0))); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); } class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms; Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -4003,7 +4003,7 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( const std::shared_ptr<Connection>& connection, const CancelationOptions& options) { if (connection->status == Connection::Status::BROKEN) { if (connection->status != Connection::Status::NORMAL) { return; } Loading
services/inputflinger/tests/InputDispatcher_test.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -6974,6 +6974,39 @@ TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) { mWindow->assertNoEvents(); } TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) { 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)); consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B), WithFlags(AKEY_EVENT_FLAG_FALLBACK))); mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) { // When the unhandled key is reported to the policy next, remove the input channel. mDispatcher->removeInputChannel(mWindow->getToken()); return KeyEventBuilder(event).keyCode(AKEYCODE_B).build(); }); // Release the original key, and let the app now handle the previously unhandled key. // This should result in the previously generated fallback key to be cancelled. // Since the policy was notified of the unhandled DOWN event earlier, it will also be notified // of the UP event for consistency. The Dispatcher calls into the policy from its own thread // without holding the lock, because it need to synchronously fetch the fallback key. While in // the policy call, we will now remove the input channel. Once the policy call returns, the // Dispatcher will no longer have a channel to send cancellation events to. Ensure this does // not cause any crashes. mDispatcher->notifyKey( KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build()); consumeKey(/*handled=*/true, AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0))); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A)); } class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms; Loading