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

Commit eb63bbfd authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Do not crash when server channel has closed

If the publisher has been destroyed (or, equivalently, if the server
channel was closed), the consumer should not crash. Instead, we should
allow consumer to exit gracefully.

In this CL, we specifically check for DEAD_OBJECT and drain the queue,
printing all of the events that will never be delivered to the publisher
for useful debugging purposes.

Bug: 305165753
Test: TEST=libinput_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST
Flag: EXEMPT bugfix

Change-Id: I00973ebb87e0f59bfd3c0f58edf7355b28988c15
parent cdde6f55
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -169,6 +169,12 @@ InputMessage createTimelineMessage(int32_t inputEventId, nsecs_t gpuCompletedTim
    msg.body.timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = presentTime;
    return msg;
}

std::ostream& operator<<(std::ostream& out, const InputMessage& msg) {
    out << ftl::enum_string(msg.header.type);
    return out;
}

} // namespace

// --- InputConsumerNoResampling ---
@@ -272,6 +278,15 @@ void InputConsumerNoResampling::processOutboundEvents() {
            return; // try again later
        }

        if (result == DEAD_OBJECT) {
            // If there's no one to receive events in the channel, there's no point in sending them.
            // Drop all outbound events.
            LOG(INFO) << "Channel " << mChannel->getName() << " died. Dropping outbound event "
                      << outboundMsg;
            mOutboundQueue.pop();
            setFdEvents(0);
            continue;
        }
        // Some other error. Give up
        LOG(FATAL) << "Failed to send outbound event on channel '" << mChannel->getName()
                   << "'.  status=" << statusToString(result) << "(" << result << ")";
+33 −15
Original line number Diff line number Diff line
@@ -319,6 +319,8 @@ protected:

protected:
    // Interaction with the looper thread
    void blockLooper();
    void unblockLooper();
    enum class LooperMessage : int {
        CALL_PROBABLY_HAS_INPUT,
        CREATE_CONSUMER,
@@ -389,6 +391,26 @@ private:
    };
};

void InputPublisherAndConsumerNoResamplingTest::blockLooper() {
    {
        std::scoped_lock l(mLock);
        mLooperMayProceed = false;
    }
    sendMessage(LooperMessage::BLOCK_LOOPER);
    {
        std::unique_lock l(mLock);
        mNotifyLooperWaiting.wait(l, [this] { return mLooperIsBlocked; });
    }
}

void InputPublisherAndConsumerNoResamplingTest::unblockLooper() {
    {
        std::scoped_lock l(mLock);
        mLooperMayProceed = true;
    }
    mNotifyLooperMayProceed.notify_all();
}

void InputPublisherAndConsumerNoResamplingTest::sendMessage(LooperMessage message) {
    Message msg{ftl::to_underlying(message)};
    mLooper->sendMessage(mMessageHandler, msg);
@@ -600,15 +622,7 @@ void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeSinglePointerMu
    std::queue<uint32_t> publishedSequenceNumbers;

    // Block Looper to increase the chance of batching events
    {
        std::scoped_lock l(mLock);
        mLooperMayProceed = false;
    }
    sendMessage(LooperMessage::BLOCK_LOOPER);
    {
        std::unique_lock l(mLock);
        mNotifyLooperWaiting.wait(l, [this] { return mLooperIsBlocked; });
    }
    blockLooper();

    uint32_t firstSampleId;
    for (size_t i = 0; i < nSamples; ++i) {
@@ -629,12 +643,7 @@ void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeSinglePointerMu

    std::vector<MotionEvent> singleSampledMotionEvents;

    // Unblock Looper
    {
        std::scoped_lock l(mLock);
        mLooperMayProceed = true;
    }
    mNotifyLooperMayProceed.notify_all();
    unblockLooper();

    // We have no control over the socket behavior, so the consumer can receive
    // the motion as a batched event, or as a sequence of multiple single-sample MotionEvents (or a
@@ -809,6 +818,15 @@ void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeTouchModeEvent(
    verifyFinishedSignal(*mPublisher, seq, publishTime);
}

/**
 * If the publisher has died, consumer should not crash when trying to send an outgoing message.
 */
TEST_F(InputPublisherAndConsumerNoResamplingTest, ConsumerWritesAfterPublisherDies) {
    mPublisher.reset(); // The publisher has died
    mReportTimelineArgs.emplace(/*inputEventId=*/10, /*gpuCompletedTime=*/20, /*presentTime=*/30);
    sendMessage(LooperMessage::CALL_REPORT_TIMELINE);
}

TEST_F(InputPublisherAndConsumerNoResamplingTest, SendTimeline) {
    const int32_t inputEventId = 20;
    const nsecs_t gpuCompletedTime = 30;