blob: da494b5ba34fbba16f393b1df9a1333039fba061 [file] [log] [blame]
Siarhei Vishniakou2b920272024-02-27 19:49:51 -08001/**
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "InputTransport"
18#define ATRACE_TAG ATRACE_TAG_INPUT
19
20#include <inttypes.h>
21
22#include <android-base/logging.h>
23#include <android-base/properties.h>
24#include <android-base/stringprintf.h>
25#include <cutils/properties.h>
26#include <ftl/enum.h>
27#include <utils/Trace.h>
28
29#include <com_android_input_flags.h>
30#include <input/InputConsumerNoResampling.h>
31#include <input/PrintTools.h>
32#include <input/TraceTools.h>
33
34namespace input_flags = com::android::input::flags;
35
36namespace android {
37
38namespace {
39
40/**
41 * Log debug messages relating to the consumer end of the transport channel.
42 * Enable this via "adb shell setprop log.tag.InputTransportConsumer DEBUG" (requires restart)
43 */
44const bool DEBUG_TRANSPORT_CONSUMER =
45 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Consumer", ANDROID_LOG_INFO);
46
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -070047std::unique_ptr<KeyEvent> createKeyEvent(const InputMessage& msg) {
48 std::unique_ptr<KeyEvent> event = std::make_unique<KeyEvent>();
49 event->initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source,
Linnan Li13bf76a2024-05-05 19:18:02 +080050 ui::LogicalDisplayId{msg.body.key.displayId}, msg.body.key.hmac,
51 msg.body.key.action, msg.body.key.flags, msg.body.key.keyCode,
52 msg.body.key.scanCode, msg.body.key.metaState, msg.body.key.repeatCount,
53 msg.body.key.downTime, msg.body.key.eventTime);
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -070054 return event;
Siarhei Vishniakou2b920272024-02-27 19:49:51 -080055}
56
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -070057std::unique_ptr<FocusEvent> createFocusEvent(const InputMessage& msg) {
58 std::unique_ptr<FocusEvent> event = std::make_unique<FocusEvent>();
59 event->initialize(msg.body.focus.eventId, msg.body.focus.hasFocus);
60 return event;
Siarhei Vishniakou2b920272024-02-27 19:49:51 -080061}
62
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -070063std::unique_ptr<CaptureEvent> createCaptureEvent(const InputMessage& msg) {
64 std::unique_ptr<CaptureEvent> event = std::make_unique<CaptureEvent>();
65 event->initialize(msg.body.capture.eventId, msg.body.capture.pointerCaptureEnabled);
66 return event;
Siarhei Vishniakou2b920272024-02-27 19:49:51 -080067}
68
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -070069std::unique_ptr<DragEvent> createDragEvent(const InputMessage& msg) {
70 std::unique_ptr<DragEvent> event = std::make_unique<DragEvent>();
71 event->initialize(msg.body.drag.eventId, msg.body.drag.x, msg.body.drag.y,
72 msg.body.drag.isExiting);
73 return event;
Siarhei Vishniakou2b920272024-02-27 19:49:51 -080074}
75
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -070076std::unique_ptr<MotionEvent> createMotionEvent(const InputMessage& msg) {
77 std::unique_ptr<MotionEvent> event = std::make_unique<MotionEvent>();
Siarhei Vishniakou2b920272024-02-27 19:49:51 -080078 const uint32_t pointerCount = msg.body.motion.pointerCount;
79 std::vector<PointerProperties> pointerProperties;
80 pointerProperties.reserve(pointerCount);
81 std::vector<PointerCoords> pointerCoords;
82 pointerCoords.reserve(pointerCount);
83 for (uint32_t i = 0; i < pointerCount; i++) {
84 pointerProperties.push_back(msg.body.motion.pointers[i].properties);
85 pointerCoords.push_back(msg.body.motion.pointers[i].coords);
86 }
87
88 ui::Transform transform;
89 transform.set({msg.body.motion.dsdx, msg.body.motion.dtdx, msg.body.motion.tx,
90 msg.body.motion.dtdy, msg.body.motion.dsdy, msg.body.motion.ty, 0, 0, 1});
91 ui::Transform displayTransform;
92 displayTransform.set({msg.body.motion.dsdxRaw, msg.body.motion.dtdxRaw, msg.body.motion.txRaw,
93 msg.body.motion.dtdyRaw, msg.body.motion.dsdyRaw, msg.body.motion.tyRaw,
94 0, 0, 1});
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -070095 event->initialize(msg.body.motion.eventId, msg.body.motion.deviceId, msg.body.motion.source,
Linnan Li13bf76a2024-05-05 19:18:02 +080096 ui::LogicalDisplayId{msg.body.motion.displayId}, msg.body.motion.hmac,
97 msg.body.motion.action, msg.body.motion.actionButton, msg.body.motion.flags,
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -070098 msg.body.motion.edgeFlags, msg.body.motion.metaState,
99 msg.body.motion.buttonState, msg.body.motion.classification, transform,
100 msg.body.motion.xPrecision, msg.body.motion.yPrecision,
101 msg.body.motion.xCursorPosition, msg.body.motion.yCursorPosition,
102 displayTransform, msg.body.motion.downTime, msg.body.motion.eventTime,
103 pointerCount, pointerProperties.data(), pointerCoords.data());
104 return event;
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800105}
106
107void addSample(MotionEvent& event, const InputMessage& msg) {
108 uint32_t pointerCount = msg.body.motion.pointerCount;
109 std::vector<PointerCoords> pointerCoords;
110 pointerCoords.reserve(pointerCount);
111 for (uint32_t i = 0; i < pointerCount; i++) {
112 pointerCoords.push_back(msg.body.motion.pointers[i].coords);
113 }
114
115 // TODO(b/329770983): figure out if it's safe to combine events with mismatching metaState
116 event.setMetaState(event.getMetaState() | msg.body.motion.metaState);
117 event.addSample(msg.body.motion.eventTime, pointerCoords.data());
118}
119
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700120std::unique_ptr<TouchModeEvent> createTouchModeEvent(const InputMessage& msg) {
121 std::unique_ptr<TouchModeEvent> event = std::make_unique<TouchModeEvent>();
122 event->initialize(msg.body.touchMode.eventId, msg.body.touchMode.isInTouchMode);
123 return event;
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800124}
125
126std::string outboundMessageToString(const InputMessage& outboundMsg) {
127 switch (outboundMsg.header.type) {
128 case InputMessage::Type::FINISHED: {
129 return android::base::StringPrintf(" Finish: seq=%" PRIu32 " handled=%s",
130 outboundMsg.header.seq,
131 toString(outboundMsg.body.finished.handled));
132 }
133 case InputMessage::Type::TIMELINE: {
134 return android::base::
135 StringPrintf(" Timeline: inputEventId=%" PRId32 " gpuCompletedTime=%" PRId64
136 ", presentTime=%" PRId64,
137 outboundMsg.body.timeline.eventId,
138 outboundMsg.body.timeline
139 .graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME],
140 outboundMsg.body.timeline
141 .graphicsTimeline[GraphicsTimeline::PRESENT_TIME]);
142 }
143 default: {
144 LOG(FATAL) << "Outbound message must be FINISHED or TIMELINE, got "
145 << ftl::enum_string(outboundMsg.header.type);
146 return "Unreachable";
147 }
148 }
149}
150
151InputMessage createFinishedMessage(uint32_t seq, bool handled, nsecs_t consumeTime) {
152 InputMessage msg;
153 msg.header.type = InputMessage::Type::FINISHED;
154 msg.header.seq = seq;
155 msg.body.finished.handled = handled;
156 msg.body.finished.consumeTime = consumeTime;
157 return msg;
158}
159
160InputMessage createTimelineMessage(int32_t inputEventId, nsecs_t gpuCompletedTime,
161 nsecs_t presentTime) {
162 InputMessage msg;
163 msg.header.type = InputMessage::Type::TIMELINE;
164 msg.header.seq = 0;
165 msg.body.timeline.eventId = inputEventId;
166 msg.body.timeline.graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = gpuCompletedTime;
167 msg.body.timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = presentTime;
168 return msg;
169}
170
171} // namespace
172
173using android::base::Result;
174using android::base::StringPrintf;
175
176// --- InputConsumerNoResampling ---
177
178InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
179 sp<Looper> looper,
180 InputConsumerCallbacks& callbacks)
181 : mChannel(channel), mLooper(looper), mCallbacks(callbacks), mFdEvents(0) {
182 LOG_ALWAYS_FATAL_IF(mLooper == nullptr);
183 mCallback = sp<LooperEventCallback>::make(
184 std::bind(&InputConsumerNoResampling::handleReceiveCallback, this,
185 std::placeholders::_1));
186 // In the beginning, there are no pending outbounds events; we only care about receiving
187 // incoming data.
188 setFdEvents(ALOOPER_EVENT_INPUT);
189}
190
191InputConsumerNoResampling::~InputConsumerNoResampling() {
192 ensureCalledOnLooperThread(__func__);
193 consumeBatchedInputEvents(std::nullopt);
194 while (!mOutboundQueue.empty()) {
195 processOutboundEvents();
196 // This is our last chance to ack the events. If we don't ack them here, we will get an ANR,
197 // so keep trying to send the events as long as they are present in the queue.
198 }
199 setFdEvents(0);
200}
201
202int InputConsumerNoResampling::handleReceiveCallback(int events) {
203 // Allowed return values of this function as documented in LooperCallback::handleEvent
204 constexpr int REMOVE_CALLBACK = 0;
205 constexpr int KEEP_CALLBACK = 1;
206
207 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
208 // This error typically occurs when the publisher has closed the input channel
209 // as part of removing a window or finishing an IME session, in which case
210 // the consumer will soon be disposed as well.
211 if (DEBUG_TRANSPORT_CONSUMER) {
212 LOG(INFO) << "The channel was hung up or an error occurred: " << mChannel->getName();
213 }
214 return REMOVE_CALLBACK;
215 }
216
217 int handledEvents = 0;
218 if (events & ALOOPER_EVENT_INPUT) {
219 std::vector<InputMessage> messages = readAllMessages();
220 handleMessages(std::move(messages));
221 handledEvents |= ALOOPER_EVENT_INPUT;
222 }
223
224 if (events & ALOOPER_EVENT_OUTPUT) {
225 processOutboundEvents();
226 handledEvents |= ALOOPER_EVENT_OUTPUT;
227 }
228 if (handledEvents != events) {
229 LOG(FATAL) << "Mismatch: handledEvents=" << handledEvents << ", events=" << events;
230 }
231 return KEEP_CALLBACK;
232}
233
234void InputConsumerNoResampling::processOutboundEvents() {
235 while (!mOutboundQueue.empty()) {
236 const InputMessage& outboundMsg = mOutboundQueue.front();
237
238 const status_t result = mChannel->sendMessage(&outboundMsg);
239 if (result == OK) {
240 if (outboundMsg.header.type == InputMessage::Type::FINISHED) {
241 ATRACE_ASYNC_END("InputConsumer processing", /*cookie=*/outboundMsg.header.seq);
242 }
243 // Successful send. Erase the entry and keep trying to send more
244 mOutboundQueue.pop();
245 continue;
246 }
247
248 // Publisher is busy, try again later. Keep this entry (do not erase)
249 if (result == WOULD_BLOCK) {
250 setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
251 return; // try again later
252 }
253
254 // Some other error. Give up
255 LOG(FATAL) << "Failed to send outbound event on channel '" << mChannel->getName()
256 << "'. status=" << statusToString(result) << "(" << result << ")";
257 }
258
259 // The queue is now empty. Tell looper there's no more output to expect.
260 setFdEvents(ALOOPER_EVENT_INPUT);
261}
262
263void InputConsumerNoResampling::finishInputEvent(uint32_t seq, bool handled) {
264 ensureCalledOnLooperThread(__func__);
265 mOutboundQueue.push(createFinishedMessage(seq, handled, popConsumeTime(seq)));
266 // also produce finish events for all batches for this seq (if any)
267 const auto it = mBatchedSequenceNumbers.find(seq);
268 if (it != mBatchedSequenceNumbers.end()) {
269 for (uint32_t subSeq : it->second) {
270 mOutboundQueue.push(createFinishedMessage(subSeq, handled, popConsumeTime(subSeq)));
271 }
272 mBatchedSequenceNumbers.erase(it);
273 }
274 processOutboundEvents();
275}
276
277bool InputConsumerNoResampling::probablyHasInput() const {
278 // Ideally, this would only be allowed to run on the looper thread, and in production, it will.
279 // However, for testing, it's convenient to call this while the looper thread is blocked, so
280 // we do not call ensureCalledOnLooperThread here.
281 return (!mBatches.empty()) || mChannel->probablyHasInput();
282}
283
284void InputConsumerNoResampling::reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime,
285 nsecs_t presentTime) {
286 ensureCalledOnLooperThread(__func__);
287 mOutboundQueue.push(createTimelineMessage(inputEventId, gpuCompletedTime, presentTime));
288 processOutboundEvents();
289}
290
291nsecs_t InputConsumerNoResampling::popConsumeTime(uint32_t seq) {
292 auto it = mConsumeTimes.find(seq);
293 // Consume time will be missing if either 'finishInputEvent' is called twice, or if it was
294 // called for the wrong (synthetic?) input event. Either way, it is a bug that should be fixed.
295 LOG_ALWAYS_FATAL_IF(it == mConsumeTimes.end(), "Could not find consume time for seq=%" PRIu32,
296 seq);
297 nsecs_t consumeTime = it->second;
298 mConsumeTimes.erase(it);
299 return consumeTime;
300}
301
302void InputConsumerNoResampling::setFdEvents(int events) {
303 if (mFdEvents != events) {
304 mFdEvents = events;
305 if (events != 0) {
306 mLooper->addFd(mChannel->getFd(), 0, events, mCallback, nullptr);
307 } else {
308 mLooper->removeFd(mChannel->getFd());
309 }
310 }
311}
312
313void InputConsumerNoResampling::handleMessages(std::vector<InputMessage>&& messages) {
314 // TODO(b/297226446) : add resampling
315 for (const InputMessage& msg : messages) {
316 if (msg.header.type == InputMessage::Type::MOTION) {
317 const int32_t action = msg.body.motion.action;
318 const DeviceId deviceId = msg.body.motion.deviceId;
319 const int32_t source = msg.body.motion.source;
320 const bool batchableEvent = (action == AMOTION_EVENT_ACTION_MOVE ||
321 action == AMOTION_EVENT_ACTION_HOVER_MOVE) &&
322 (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER) ||
323 isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK));
324 if (batchableEvent) {
325 // add it to batch
326 mBatches[deviceId].emplace(msg);
327 } else {
328 // consume all pending batches for this event immediately
329 // TODO(b/329776327): figure out if this could be smarter by limiting the
330 // consumption only to the current device.
331 consumeBatchedInputEvents(std::nullopt);
332 handleMessage(msg);
333 }
334 } else {
335 // Non-motion events shouldn't force the consumption of pending batched events
336 handleMessage(msg);
337 }
338 }
339 // At the end of this, if we still have pending batches, notify the receiver about it.
340
341 // We need to carefully notify the InputConsumerCallbacks about the pending batch. The receiver
342 // could choose to consume all events when notified about the batch. That means that the
343 // "mBatches" variable could change when 'InputConsumerCallbacks::onBatchedInputEventPending' is
344 // invoked. We also can't notify the InputConsumerCallbacks in a while loop until mBatches is
345 // empty, because the receiver could choose to not consume the batch immediately.
346 std::set<int32_t> pendingBatchSources;
347 for (const auto& [_, pendingMessages] : mBatches) {
348 // Assume that all messages for a given device has the same source.
349 pendingBatchSources.insert(pendingMessages.front().body.motion.source);
350 }
351 for (const int32_t source : pendingBatchSources) {
352 const bool sourceStillRemaining =
353 std::any_of(mBatches.begin(), mBatches.end(), [=](const auto& pair) {
354 return pair.second.front().body.motion.source == source;
355 });
356 if (sourceStillRemaining) {
357 mCallbacks.onBatchedInputEventPending(source);
358 }
359 }
360}
361
362std::vector<InputMessage> InputConsumerNoResampling::readAllMessages() {
363 std::vector<InputMessage> messages;
364 while (true) {
Paul Ramirez0c25e862024-06-18 21:33:33 +0000365 android::base::Result<InputMessage> result = mChannel->receiveMessage();
366 if (result.ok()) {
367 const InputMessage& msg = *result;
368 const auto [_, inserted] =
369 mConsumeTimes.emplace(msg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
370 LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32,
371 msg.header.seq);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800372
Paul Ramirez0c25e862024-06-18 21:33:33 +0000373 // Trace the event processing timeline - event was just read from the socket
374 // TODO(b/329777420): distinguish between multiple instances of InputConsumer
375 // in the same process.
376 ATRACE_ASYNC_BEGIN("InputConsumer processing", /*cookie=*/msg.header.seq);
377 messages.push_back(msg);
378 } else { // !result.ok()
379 switch (result.error().code()) {
380 case WOULD_BLOCK: {
381 return messages;
382 }
383 case DEAD_OBJECT: {
384 LOG(FATAL) << "Got a dead object for " << mChannel->getName();
385 break;
386 }
387 case BAD_VALUE: {
388 LOG(FATAL) << "Got a bad value for " << mChannel->getName();
389 break;
390 }
391 default: {
392 LOG(FATAL) << "Unexpected error: " << result.error().message();
393 break;
394 }
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800395 }
396 }
397 }
398}
399
400void InputConsumerNoResampling::handleMessage(const InputMessage& msg) const {
401 switch (msg.header.type) {
402 case InputMessage::Type::KEY: {
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700403 std::unique_ptr<KeyEvent> keyEvent = createKeyEvent(msg);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800404 mCallbacks.onKeyEvent(std::move(keyEvent), msg.header.seq);
405 break;
406 }
407
408 case InputMessage::Type::MOTION: {
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700409 std::unique_ptr<MotionEvent> motionEvent = createMotionEvent(msg);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800410 mCallbacks.onMotionEvent(std::move(motionEvent), msg.header.seq);
411 break;
412 }
413
414 case InputMessage::Type::FINISHED:
415 case InputMessage::Type::TIMELINE: {
Siarhei Vishniakou11d223b2024-03-26 21:52:38 +0000416 LOG(FATAL) << "Consumed a " << ftl::enum_string(msg.header.type)
417 << " message, which should never be seen by InputConsumer on "
418 << mChannel->getName();
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800419 break;
420 }
421
422 case InputMessage::Type::FOCUS: {
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700423 std::unique_ptr<FocusEvent> focusEvent = createFocusEvent(msg);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800424 mCallbacks.onFocusEvent(std::move(focusEvent), msg.header.seq);
425 break;
426 }
427
428 case InputMessage::Type::CAPTURE: {
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700429 std::unique_ptr<CaptureEvent> captureEvent = createCaptureEvent(msg);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800430 mCallbacks.onCaptureEvent(std::move(captureEvent), msg.header.seq);
431 break;
432 }
433
434 case InputMessage::Type::DRAG: {
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700435 std::unique_ptr<DragEvent> dragEvent = createDragEvent(msg);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800436 mCallbacks.onDragEvent(std::move(dragEvent), msg.header.seq);
437 break;
438 }
439
440 case InputMessage::Type::TOUCH_MODE: {
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700441 std::unique_ptr<TouchModeEvent> touchModeEvent = createTouchModeEvent(msg);
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800442 mCallbacks.onTouchModeEvent(std::move(touchModeEvent), msg.header.seq);
443 break;
444 }
445 }
446}
447
Paul Ramirezb41d38e2024-07-16 17:44:20 +0000448std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>>
449InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t frameTime,
450 std::queue<InputMessage>& messages) {
451 std::unique_ptr<MotionEvent> motionEvent;
452 std::optional<uint32_t> firstSeqForBatch;
453 while (!messages.empty() && !(messages.front().body.motion.eventTime > frameTime)) {
454 if (motionEvent == nullptr) {
455 motionEvent = createMotionEvent(messages.front());
456 firstSeqForBatch = messages.front().header.seq;
457 const auto [_, inserted] = mBatchedSequenceNumbers.insert({*firstSeqForBatch, {}});
458 LOG_IF(FATAL, !inserted)
459 << "The sequence " << messages.front().header.seq << " was already present!";
460 } else {
461 addSample(*motionEvent, messages.front());
462 mBatchedSequenceNumbers[*firstSeqForBatch].push_back(messages.front().header.seq);
463 }
464 messages.pop();
465 }
466 return std::make_pair(std::move(motionEvent), firstSeqForBatch);
467}
468
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800469bool InputConsumerNoResampling::consumeBatchedInputEvents(
470 std::optional<nsecs_t> requestedFrameTime) {
471 ensureCalledOnLooperThread(__func__);
472 // When batching is not enabled, we want to consume all events. That's equivalent to having an
473 // infinite frameTime.
474 const nsecs_t frameTime = requestedFrameTime.value_or(std::numeric_limits<nsecs_t>::max());
475 bool producedEvents = false;
Paul Ramirezb41d38e2024-07-16 17:44:20 +0000476 for (auto& [_, messages] : mBatches) {
477 auto [motion, firstSeqForBatch] = createBatchedMotionEvent(frameTime, messages);
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700478 if (motion != nullptr) {
479 LOG_ALWAYS_FATAL_IF(!firstSeqForBatch.has_value());
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800480 mCallbacks.onMotionEvent(std::move(motion), *firstSeqForBatch);
481 producedEvents = true;
482 } else {
483 // This is OK, it just means that the frameTime is too old (all events that we have
484 // pending are in the future of the frametime). Maybe print a
485 // warning? If there are multiple devices active though, this might be normal and can
486 // just be ignored, unless none of them resulted in any consumption (in that case, this
487 // function would already return "false" so we could just leave it up to the caller).
488 }
489 }
490 std::erase_if(mBatches, [](const auto& pair) { return pair.second.empty(); });
491 return producedEvents;
492}
493
494void InputConsumerNoResampling::ensureCalledOnLooperThread(const char* func) const {
495 sp<Looper> callingThreadLooper = Looper::getForThread();
496 if (callingThreadLooper != mLooper) {
497 LOG(FATAL) << "The function " << func << " can only be called on the looper thread";
498 }
499}
500
501std::string InputConsumerNoResampling::dump() const {
502 ensureCalledOnLooperThread(__func__);
503 std::string out;
504 if (mOutboundQueue.empty()) {
505 out += "mOutboundQueue: <empty>\n";
506 } else {
507 out += "mOutboundQueue:\n";
508 // Make a copy of mOutboundQueue for printing destructively. Unfortunately std::queue
509 // doesn't provide a good way to iterate over the entire container.
510 std::queue<InputMessage> tmpQueue = mOutboundQueue;
511 while (!tmpQueue.empty()) {
512 out += std::string(" ") + outboundMessageToString(tmpQueue.front()) + "\n";
513 tmpQueue.pop();
514 }
515 }
516
517 if (mBatches.empty()) {
518 out += "mBatches: <empty>\n";
519 } else {
520 out += "mBatches:\n";
521 for (const auto& [deviceId, messages] : mBatches) {
522 out += " Device id ";
523 out += std::to_string(deviceId);
524 out += ":\n";
525 // Make a copy of mOutboundQueue for printing destructively. Unfortunately std::queue
526 // doesn't provide a good way to iterate over the entire container.
527 std::queue<InputMessage> tmpQueue = messages;
528 while (!tmpQueue.empty()) {
529 LOG_ALWAYS_FATAL_IF(tmpQueue.front().header.type != InputMessage::Type::MOTION);
Siarhei Vishniakou3891ec92024-03-15 13:29:57 -0700530 std::unique_ptr<MotionEvent> motion = createMotionEvent(tmpQueue.front());
531 out += std::string(" ") + streamableToString(*motion) + "\n";
Siarhei Vishniakou2b920272024-02-27 19:49:51 -0800532 tmpQueue.pop();
533 }
534 }
535 }
536
537 return out;
538}
539
540} // namespace android