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

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

Merge "Fix batching logic in InputConsumerNoResampling.cpp" into main

parents 2808d7eb cd7488c1
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -47,6 +47,13 @@ struct Resampler {
     */
    virtual void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
                                     const InputMessage* futureSample) = 0;

    /**
     * Returns resample latency. Resample latency is the time difference between frame time and
     * resample time. More precisely, let frameTime and resampleTime be two timestamps, and
     * frameTime > resampleTime. Resample latency is defined as frameTime - resampleTime.
     */
    virtual std::chrono::nanoseconds getResampleLatency() const = 0;
};

class LegacyResampler final : public Resampler {
@@ -63,6 +70,8 @@ public:
    void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
                             const InputMessage* futureSample) override;

    std::chrono::nanoseconds getResampleLatency() const override;

private:
    struct Pointer {
        PointerProperties properties;
+9 −3
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ namespace android {

namespace {

using std::chrono::nanoseconds;

/**
 * Log debug messages relating to the consumer end of the transport channel.
 * Enable this via "adb shell setprop log.tag.InputTransportConsumer DEBUG" (requires restart)
@@ -485,7 +487,12 @@ InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t frameTime,
                                                    std::queue<InputMessage>& messages) {
    std::unique_ptr<MotionEvent> motionEvent;
    std::optional<uint32_t> firstSeqForBatch;
    while (!messages.empty() && !(messages.front().body.motion.eventTime > frameTime)) {
    const nanoseconds resampleLatency =
            (mResampler != nullptr) ? mResampler->getResampleLatency() : nanoseconds{0};
    const nanoseconds adjustedFrameTime = nanoseconds{frameTime} - resampleLatency;

    while (!messages.empty() &&
           (messages.front().body.motion.eventTime <= adjustedFrameTime.count())) {
        if (motionEvent == nullptr) {
            motionEvent = createMotionEvent(messages.front());
            firstSeqForBatch = messages.front().header.seq;
@@ -504,8 +511,7 @@ InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t frameTime,
        if (!messages.empty()) {
            futureSample = &messages.front();
        }
        mResampler->resampleMotionEvent(static_cast<std::chrono::nanoseconds>(frameTime),
                                        *motionEvent, futureSample);
        mResampler->resampleMotionEvent(nanoseconds{frameTime}, *motionEvent, futureSample);
    }
    return std::make_pair(std::move(motionEvent), firstSeqForBatch);
}
+4 −0
Original line number Diff line number Diff line
@@ -241,6 +241,10 @@ inline void LegacyResampler::addSampleToMotionEvent(const Sample& sample,
                          motionEvent.getId());
}

nanoseconds LegacyResampler::getResampleLatency() const {
    return RESAMPLE_LATENCY;
}

void LegacyResampler::resampleMotionEvent(nanoseconds frameTime, MotionEvent& motionEvent,
                                          const InputMessage* futureSample) {
    if (mPreviousDeviceId && *mPreviousDeviceId != motionEvent.getDeviceId()) {
+77 −15
Original line number Diff line number Diff line
@@ -30,14 +30,21 @@

namespace android {

namespace {

using std::chrono::nanoseconds;

} // namespace

class InputConsumerTest : public testing::Test, public InputConsumerCallbacks {
protected:
    InputConsumerTest()
          : mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")},
            mTestLooper{std::make_shared<TestLooper>()} {
        Looper::setForThread(mTestLooper->getLooper());
        mConsumer = std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mTestLooper,
                                                                *this, /*resampler=*/nullptr);
        mConsumer =
                std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mTestLooper, *this,
                                                            std::make_unique<LegacyResampler>());
    }

    void assertOnBatchedInputEventPendingWasCalled();
@@ -54,7 +61,7 @@ protected:
    BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;

private:
    size_t onBatchedInputEventPendingInvocationCount{0};
    size_t mOnBatchedInputEventPendingInvocationCount{0};

    // InputConsumerCallbacks interface
    void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override {
@@ -69,7 +76,7 @@ private:
        if (!mConsumer->probablyHasInput()) {
            ADD_FAILURE() << "should deterministically have input because there is a batch";
        }
        ++onBatchedInputEventPendingInvocationCount;
        ++mOnBatchedInputEventPendingInvocationCount;
    };
    void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override {
        mFocusEvents.push(std::move(event));
@@ -90,18 +97,24 @@ private:
};

void InputConsumerTest::assertOnBatchedInputEventPendingWasCalled() {
    ASSERT_GT(onBatchedInputEventPendingInvocationCount, 0UL)
    ASSERT_GT(mOnBatchedInputEventPendingInvocationCount, 0UL)
            << "onBatchedInputEventPending has not been called.";
    --onBatchedInputEventPendingInvocationCount;
    --mOnBatchedInputEventPendingInvocationCount;
}

TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) {
    mClientTestChannel->enqueueMessage(
            InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}.build());
    mClientTestChannel->enqueueMessage(
            InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}.build());
    mClientTestChannel->enqueueMessage(
            InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}.build());
    mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}
                                               .eventTime(nanoseconds{0ms}.count())
                                               .action(AMOTION_EVENT_ACTION_DOWN)
                                               .build());
    mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}
                                               .eventTime(nanoseconds{5ms}.count())
                                               .action(AMOTION_EVENT_ACTION_MOVE)
                                               .build());
    mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}
                                               .eventTime(nanoseconds{10ms}.count())
                                               .action(AMOTION_EVENT_ACTION_MOVE)
                                               .build());

    mClientTestChannel->assertNoSentMessages();

@@ -111,13 +124,62 @@ TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) {

    mConsumer->consumeBatchedInputEvents(std::nullopt);

    std::unique_ptr<MotionEvent> batchedMotionEvent = mMotionEvents.pop();
    ASSERT_NE(batchedMotionEvent, nullptr);
    std::unique_ptr<MotionEvent> downMotionEvent = mMotionEvents.pop();
    ASSERT_NE(downMotionEvent, nullptr);

    std::unique_ptr<MotionEvent> moveMotionEvent = mMotionEvents.pop();
    ASSERT_NE(moveMotionEvent, nullptr);
    EXPECT_EQ(moveMotionEvent->getHistorySize() + 1, 3UL);

    mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true);
    mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
    mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
}

TEST_F(InputConsumerTest, LastBatchedSampleIsLessThanResampleTime) {
    mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}
                                               .eventTime(nanoseconds{0ms}.count())
                                               .action(AMOTION_EVENT_ACTION_DOWN)
                                               .build());
    mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}
                                               .eventTime(nanoseconds{5ms}.count())
                                               .action(AMOTION_EVENT_ACTION_MOVE)
                                               .build());
    mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}
                                               .eventTime(nanoseconds{10ms}.count())
                                               .action(AMOTION_EVENT_ACTION_MOVE)
                                               .build());
    mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/3}
                                               .eventTime(nanoseconds{15ms}.count())
                                               .action(AMOTION_EVENT_ACTION_MOVE)
                                               .build());

    mClientTestChannel->assertNoSentMessages();

    mTestLooper->invokeCallback(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT);

    assertOnBatchedInputEventPendingWasCalled();

    mConsumer->consumeBatchedInputEvents(16'000'000 /*ns*/);

    std::unique_ptr<MotionEvent> downMotionEvent = mMotionEvents.pop();
    ASSERT_NE(downMotionEvent, nullptr);

    std::unique_ptr<MotionEvent> moveMotionEvent = mMotionEvents.pop();
    ASSERT_NE(moveMotionEvent, nullptr);
    const size_t numSamples = moveMotionEvent->getHistorySize() + 1;
    EXPECT_LT(moveMotionEvent->getHistoricalEventTime(numSamples - 2),
              moveMotionEvent->getEventTime());

    // Consume all remaining events before ending the test. Otherwise, the smart pointer that owns
    // consumer is set to null before destroying consumer. This leads to a member function call on a
    // null object.
    // TODO(b/332613662): Remove this workaround.
    mConsumer->consumeBatchedInputEvents(std::nullopt);

    EXPECT_EQ(batchedMotionEvent->getHistorySize() + 1, 3UL);
    mClientTestChannel->assertFinishMessage(/*seq=*/0, true);
    mClientTestChannel->assertFinishMessage(/*seq=*/1, true);
    mClientTestChannel->assertFinishMessage(/*seq=*/2, true);
    mClientTestChannel->assertFinishMessage(/*seq=*/3, true);
}
} // namespace android