summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Siarhei Vishniakou <svv@google.com> 2024-11-13 15:13:29 -0800
committer Siarhei Vishniakou <svv@google.com> 2024-11-25 17:24:29 +0000
commiteb63bbfd16ed9732be13d2ea6699edc6d7e4b545 (patch)
tree7e5e92ea910edbb7c09a21b8e70ddd15666b32b2
parentcdde6f555488b6a1e6d3bb2a782394dece4bfc03 (diff)
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
-rw-r--r--libs/input/InputConsumerNoResampling.cpp15
-rw-r--r--libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp48
2 files changed, 48 insertions, 15 deletions
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index 2c0f77a814..cd8582182a 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -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 << ")";
diff --git a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
index 39bb841c0a..1dadae98e4 100644
--- a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
@@ -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;