summaryrefslogtreecommitdiff
path: root/libs/input/InputConsumerNoResampling.cpp
diff options
context:
space:
mode:
author Siarhei Vishniakou <svv@google.com> 2024-10-08 15:41:51 -0700
committer Siarhei Vishniakou <svv@google.com> 2024-10-11 20:17:47 +0000
commitbc72309b1463a77c4548e0f9596d7a7a5dd75db0 (patch)
tree62c2775456512decd8c4ed0e6456d820d048983f /libs/input/InputConsumerNoResampling.cpp
parentccd7147281c5a180dbdb0b5b65b8d1bbe4b7373b (diff)
Do not invoke callbacks when InputConsumer is destroyed
Before this CL, the InputConsumer would try to finish all of the pending events that haven't been received by the app by forcefully consuming everything in the destructor. Unfortunately, this leads to the following crash: the callbacks (app) is storing the consumer inside unique_ptr. When the destructor of consumer runs, the unique_ptr will first assign the raw pointer to nullptr and then run the destructor. Next, inside the destructor, the callbacks are invoked, and the app may try to finish an input event that it receives. However, to finish, app needs to call back into the consumer, which is being destroyed. Since the only way the app can talk to the consumer is via unique_ptr, that pointer has already been set to nullptr, and this causes an NPE. To fix this, we will no longer be invoking the callbacks when the consumer destructor is invoked (this is done in this CL). The logic is as follows: - All events that have already been delivered to the app should still be finished by the app (this piece is debatable. we can fix this later if this becomes a problem). - Events that are batched, and not yet delivered to the app, will be automatically finished by the consumer, without sending them to the app. Since the app is destroying the consumer, it's unlikely that it cares about handling these events, anyways. If we want to finish _all_ pending messages (the messages that app hasn't yet called "finish" on), then we should probably iterate through mConsumeTimes, which is the only struct that keeps track of _all_ events that have been sent to the app, and not yet finished. However, to do this, we would need to rename this data structure, since it will no longer be solely used for keeping track of consume times, but also for "unprocessed events" that were read from the channel. Bug: 332613662 Flag: EXEMPT refactor Test: TEST=libinput_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I9b0128291f6197f099cb9e3c305f9717c0198c90
Diffstat (limited to 'libs/input/InputConsumerNoResampling.cpp')
-rw-r--r--libs/input/InputConsumerNoResampling.cpp18
1 files changed, 17 insertions, 1 deletions
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index ce8bb43a76..9665de799f 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -193,13 +193,29 @@ InputConsumerNoResampling::InputConsumerNoResampling(
InputConsumerNoResampling::~InputConsumerNoResampling() {
ensureCalledOnLooperThread(__func__);
- consumeBatchedInputEvents(/*requestedFrameTime=*/std::nullopt);
while (!mOutboundQueue.empty()) {
processOutboundEvents();
// This is our last chance to ack the events. If we don't ack them here, we will get an ANR,
// so keep trying to send the events as long as they are present in the queue.
}
+
setFdEvents(0);
+ // If there are any remaining unread batches, send an ack for them and don't deliver
+ // them to callbacks.
+ for (auto& [_, batches] : mBatches) {
+ while (!batches.empty()) {
+ finishInputEvent(batches.front().header.seq, /*handled=*/false);
+ batches.pop();
+ }
+ }
+ // However, it is still up to the app to finish any events that have already been delivered
+ // to the callbacks. If we wanted to change that behaviour and auto-finish all unfinished events
+ // that were already sent to callbacks, we could potentially loop through "mConsumeTimes"
+ // instead. We can't use "mBatchedSequenceNumbers" for this purpose, because it only contains
+ // batchable (i.e., ACTION_MOVE) events that were sent to the callbacks.
+ const size_t unfinishedEvents = mConsumeTimes.size();
+ LOG_IF(INFO, unfinishedEvents != 0)
+ << getName() << " has " << unfinishedEvents << " unfinished event(s)";
}
int InputConsumerNoResampling::handleReceiveCallback(int events) {