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

Commit 94b4ec82 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Update mKeyIsWaitingForEventsTimeout separately from the prune check" into main

parents 8b159e5e ef2b4502
Loading
Loading
Loading
Loading
+18 −18
Original line number Diff line number Diff line
@@ -121,11 +121,6 @@ constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2
// Log a warning when an interception call takes longer than this to process.
constexpr std::chrono::milliseconds SLOW_INTERCEPTION_THRESHOLD = 50ms;

// Additional key latency in case a connection is still processing some motion events.
// This will help with the case when a user touched a button that opens a new window,
// and gives us the chance to dispatch the key to this new window.
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;

@@ -1192,7 +1187,7 @@ bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry)
 * Return true if the events preceding this incoming motion event should be dropped
 * Return false otherwise (the default behaviour)
 */
bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) {
bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) const {
    const bool isPointerDownEvent = motionEntry.action == AMOTION_EVENT_ACTION_DOWN &&
            isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER);

@@ -1234,16 +1229,6 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt
        }
    }

    // Prevent getting stuck: if we have a pending key event, and some motion events that have not
    // yet been processed by some connections, the dispatcher will wait for these motion
    // events to be processed before dispatching the key event. This is because these motion events
    // may cause a new window to be launched, which the user might expect to receive focus.
    // To prevent waiting forever for such events, just send the key to the currently focused window
    if (isPointerDownEvent && mKeyIsWaitingForEventsTimeout) {
        ALOGD("Received a new pointer down event, stop waiting for events to process and "
              "just send the pending key event to the focused window.");
        mKeyIsWaitingForEventsTimeout = now();
    }
    return false;
}

@@ -1291,6 +1276,20 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE
                mNextUnblockedEvent = mInboundQueue.back();
                needWake = true;
            }

            const bool isPointerDownEvent = motionEntry.action == AMOTION_EVENT_ACTION_DOWN &&
                    isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER);
            if (isPointerDownEvent && mKeyIsWaitingForEventsTimeout) {
                // Prevent waiting too long for unprocessed events: if we have a pending key event,
                // and some other events have not yet been processed, the dispatcher will wait for
                // these events to be processed before dispatching the key event. This is because
                // the unprocessed events may cause the focus to change (for example, by launching a
                // new window or tapping a different window). To prevent waiting too long, we force
                // the key to be sent to the currently focused window when a new tap comes in.
                ALOGD("Received a new pointer down event, stop waiting for events to process and "
                      "just send the pending key event to the currently focused window.");
                mKeyIsWaitingForEventsTimeout = now();
            }
            break;
        }
        case EventEntry::Type::FOCUS: {
@@ -2137,7 +2136,8 @@ bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime,
        // Start the timer
        // Wait to send key because there are unprocessed events that may cause focus to change
        mKeyIsWaitingForEventsTimeout = currentTime +
                std::chrono::duration_cast<std::chrono::nanoseconds>(KEY_WAITING_FOR_EVENTS_TIMEOUT)
                std::chrono::duration_cast<std::chrono::nanoseconds>(
                        mPolicy.getKeyWaitingForEventsTimeout())
                        .count();
        return true;
    }
@@ -4879,7 +4879,7 @@ std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const Inpu
            break;
        }
        default: {
            ALOGE("Cannot verify events of type %" PRId32, event.getType());
            LOG(ERROR) << "Cannot verify events of type " << ftl::enum_string(event.getType());
            return nullptr;
        }
    }
+1 −1
Original line number Diff line number Diff line
@@ -470,7 +470,7 @@ private:

    bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry);

    bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock);
    bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) const REQUIRES(mLock);

    /**
     * Time to stop waiting for the events to be processed while trying to dispatch a key.
+19 −0
Original line number Diff line number Diff line
@@ -131,6 +131,18 @@ public:
        return std::chrono::nanoseconds(currentTime - eventTime) >= STALE_EVENT_TIMEOUT;
    }

    /**
     * Get the additional latency to add while waiting for other input events to process before
     * dispatching the pending key.
     * If there are unprocessed events, the pending key will not be dispatched immediately. Instead,
     * the dispatcher will wait for this timeout, to account for the possibility that the focus
     * might change due to touch or other events (such as another app getting launched by keys).
     * This would give the pending key the opportunity to go to a newly focused window instead.
     */
    virtual std::chrono::nanoseconds getKeyWaitingForEventsTimeout() {
        return KEY_WAITING_FOR_EVENTS_TIMEOUT;
    }

    /* Notifies the policy that a pointer down event has occurred outside the current focused
     * window.
     *
@@ -150,6 +162,13 @@ public:
    /* Notifies the policy that there was an input device interaction with apps. */
    virtual void notifyDeviceInteraction(DeviceId deviceId, nsecs_t timestamp,
                                         const std::set<gui::Uid>& uids) = 0;

private:
    // Additional key latency in case a connection is still processing some motion events.
    // This will help with the case when a user touched a button that opens a new window,
    // and gives us the chance to dispatch the key to this new window.
    static constexpr std::chrono::nanoseconds KEY_WAITING_FOR_EVENTS_TIMEOUT =
            std::chrono::milliseconds(500);
};

} // namespace android
+38 −39
Original line number Diff line number Diff line
@@ -363,6 +363,8 @@ public:
        mInterceptKeyTimeout = timeout;
    }
    std::chrono::nanoseconds getKeyWaitingForEventsTimeout() override { return 500ms; }
    void setStaleEventTimeout(std::chrono::nanoseconds timeout) { mStaleEventTimeout = timeout; }
    void assertUserActivityNotPoked() {
@@ -1083,8 +1085,8 @@ public:
        EXPECT_EQ(inTouchMode, touchModeEvent.isInTouchMode());
    }
    void assertNoEvents() {
        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
    void assertNoEvents(std::chrono::milliseconds timeout) {
        std::unique_ptr<InputEvent> event = consume(timeout);
        if (event == nullptr) {
            return;
        }
@@ -1412,14 +1414,14 @@ public:
        mInputReceiver->sendTimeline(inputEventId, timeline);
    }
    void assertNoEvents() {
    void assertNoEvents(std::chrono::milliseconds timeout = CONSUME_TIMEOUT_NO_EVENT_EXPECTED) {
        if (mInputReceiver == nullptr &&
            mInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
            return; // Can't receive events if the window does not have input channel
        }
        ASSERT_NE(nullptr, mInputReceiver)
                << "Window without InputReceiver must specify feature NO_INPUT_CHANNEL";
        mInputReceiver->assertNoEvents();
        mInputReceiver->assertNoEvents(timeout);
    }
    sp<IBinder> getToken() { return mInfo.token; }
@@ -1437,13 +1439,6 @@ public:
    int getChannelFd() { return mInputReceiver->getChannelFd(); }
private:
    FakeWindowHandle(std::string name) : mName(name){};
    const std::string mName;
    std::shared_ptr<FakeInputReceiver> mInputReceiver;
    static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger
    friend class sp<FakeWindowHandle>;
    std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = true) {
        if (mInputReceiver == nullptr) {
            LOG(FATAL) << "Cannot consume event from a window with no input event receiver";
@@ -1454,6 +1449,13 @@ private:
        }
        return event;
    }
private:
    FakeWindowHandle(std::string name) : mName(name){};
    const std::string mName;
    std::shared_ptr<FakeInputReceiver> mInputReceiver;
    static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger
    friend class sp<FakeWindowHandle>;
};
std::atomic<int32_t> FakeWindowHandle::sId{1};
@@ -1512,7 +1514,7 @@ public:
    std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
    void assertNoEvents() { mInputReceiver.assertNoEvents(); }
    void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); }
private:
    FakeInputReceiver mInputReceiver;
@@ -8824,16 +8826,11 @@ TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) {
/**
 * If a window is processing a motion event, and then a key event comes in, the key event should
 * not get delivered to the focused window until the motion is processed.
 *
 * Warning!!!
 * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT
 * and the injection timeout that we specify when injecting the key.
 * We must have the injection timeout (100ms) be smaller than
 *  KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms).
 *
 * If that value changes, this test should also change.
 */
TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
    // The timeouts in this test are established by relying on the fact that the "key waiting for
    // events timeout" is equal to 500ms.
    ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
    mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
    mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
@@ -8842,23 +8839,18 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
    ASSERT_TRUE(downSequenceNum);
    const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
    ASSERT_TRUE(upSequenceNum);
    // Don't finish the events yet, and send a key
    // Injection will "succeed" because we will eventually give up and send the key to the focused
    // window even if motions are still being processed. But because the injection timeout is short,
    // we will receive INJECTION_TIMED_OUT as the result.
    InputEventInjectionResult result =
            injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT,
                      InputEventInjectionSync::WAIT_FOR_RESULT, 100ms);
    ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
    // Don't finish the events yet, and send a key
    mDispatcher->notifyKey(
            KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
                    .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
                    .build());
    // Key will not be sent to the window, yet, because the window is still processing events
    // and the key remains pending, waiting for the touch events to be processed
    // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR.
    // Rely here on the fact that it uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood.
    static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
    mWindow->assertNoEvents();
    mWindow->assertNoEvents(100ms);
    std::this_thread::sleep_for(500ms);
    std::this_thread::sleep_for(400ms);
    // if we wait long enough though, dispatcher will give up, and still send the key
    // to the focused window, even though we have not yet finished the motion event
    mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
@@ -8873,7 +8865,10 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) {
 * focused window right away.
 */
TEST_F(InputDispatcherSingleWindowAnr,
       PendingKey_IsDroppedWhileMotionIsProcessedAndNewTouchComesIn) {
       PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) {
    // The timeouts in this test are established by relying on the fact that the "key waiting for
    // events timeout" is equal to 500ms.
    ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms);
    mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering
    mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
@@ -8888,15 +8883,19 @@ TEST_F(InputDispatcherSingleWindowAnr,
                    .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT)
                    .build());
    // At this point, key is still pending, and should not be sent to the application yet.
    // Make sure the `assertNoEvents` check doesn't take too long. It uses
    // CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood.
    static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms);
    mWindow->assertNoEvents();
    mWindow->assertNoEvents(100ms);
    // Now tap down again. It should cause the pending key to go to the focused window right away.
    tapOnWindow();
    mWindow->consumeKeyEvent(WithKeyAction(AKEY_EVENT_ACTION_DOWN)); // it doesn't matter that we
    // haven't ack'd the other events yet. We can finish events in any order.
    // Now that we tapped, we should receive the key immediately.
    // Since there's still room for slowness, we use 200ms, which is much less than
    // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration.
    std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms);
    ASSERT_NE(nullptr, keyEvent);
    ASSERT_EQ(InputEventType::KEY, keyEvent->getType());
    ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN));
    // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any
    // order.
    mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN
    mWindow->finishEvent(*upSequenceNum);   // first tap's ACTION_UP
    mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));