blob: 1462c9059aef03c1e72c4c9617381d07c2e93b19 [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
47void initializeKeyEvent(KeyEvent& event, const InputMessage& msg) {
48 event.initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source,
49 msg.body.key.displayId, msg.body.key.hmac, msg.body.key.action,
50 msg.body.key.flags, msg.body.key.keyCode, msg.body.key.scanCode,
51 msg.body.key.metaState, msg.body.key.repeatCount, msg.body.key.downTime,
52 msg.body.key.eventTime);
53}
54
55void initializeFocusEvent(FocusEvent& event, const InputMessage& msg) {
56 event.initialize(msg.body.focus.eventId, msg.body.focus.hasFocus);
57}
58
59void initializeCaptureEvent(CaptureEvent& event, const InputMessage& msg) {
60 event.initialize(msg.body.capture.eventId, msg.body.capture.pointerCaptureEnabled);
61}
62
63void initializeDragEvent(DragEvent& event, const InputMessage& msg) {
64 event.initialize(msg.body.drag.eventId, msg.body.drag.x, msg.body.drag.y,
65 msg.body.drag.isExiting);
66}
67
68void initializeMotionEvent(MotionEvent& event, const InputMessage& msg) {
69 const uint32_t pointerCount = msg.body.motion.pointerCount;
70 std::vector<PointerProperties> pointerProperties;
71 pointerProperties.reserve(pointerCount);
72 std::vector<PointerCoords> pointerCoords;
73 pointerCoords.reserve(pointerCount);
74 for (uint32_t i = 0; i < pointerCount; i++) {
75 pointerProperties.push_back(msg.body.motion.pointers[i].properties);
76 pointerCoords.push_back(msg.body.motion.pointers[i].coords);
77 }
78
79 ui::Transform transform;
80 transform.set({msg.body.motion.dsdx, msg.body.motion.dtdx, msg.body.motion.tx,
81 msg.body.motion.dtdy, msg.body.motion.dsdy, msg.body.motion.ty, 0, 0, 1});
82 ui::Transform displayTransform;
83 displayTransform.set({msg.body.motion.dsdxRaw, msg.body.motion.dtdxRaw, msg.body.motion.txRaw,
84 msg.body.motion.dtdyRaw, msg.body.motion.dsdyRaw, msg.body.motion.tyRaw,
85 0, 0, 1});
86 event.initialize(msg.body.motion.eventId, msg.body.motion.deviceId, msg.body.motion.source,
87 msg.body.motion.displayId, msg.body.motion.hmac, msg.body.motion.action,
88 msg.body.motion.actionButton, msg.body.motion.flags, msg.body.motion.edgeFlags,
89 msg.body.motion.metaState, msg.body.motion.buttonState,
90 msg.body.motion.classification, transform, msg.body.motion.xPrecision,
91 msg.body.motion.yPrecision, msg.body.motion.xCursorPosition,
92 msg.body.motion.yCursorPosition, displayTransform, msg.body.motion.downTime,
93 msg.body.motion.eventTime, pointerCount, pointerProperties.data(),
94 pointerCoords.data());
95}
96
97void addSample(MotionEvent& event, const InputMessage& msg) {
98 uint32_t pointerCount = msg.body.motion.pointerCount;
99 std::vector<PointerCoords> pointerCoords;
100 pointerCoords.reserve(pointerCount);
101 for (uint32_t i = 0; i < pointerCount; i++) {
102 pointerCoords.push_back(msg.body.motion.pointers[i].coords);
103 }
104
105 // TODO(b/329770983): figure out if it's safe to combine events with mismatching metaState
106 event.setMetaState(event.getMetaState() | msg.body.motion.metaState);
107 event.addSample(msg.body.motion.eventTime, pointerCoords.data());
108}
109
110void initializeTouchModeEvent(TouchModeEvent& event, const InputMessage& msg) {
111 event.initialize(msg.body.touchMode.eventId, msg.body.touchMode.isInTouchMode);
112}
113
114std::string outboundMessageToString(const InputMessage& outboundMsg) {
115 switch (outboundMsg.header.type) {
116 case InputMessage::Type::FINISHED: {
117 return android::base::StringPrintf(" Finish: seq=%" PRIu32 " handled=%s",
118 outboundMsg.header.seq,
119 toString(outboundMsg.body.finished.handled));
120 }
121 case InputMessage::Type::TIMELINE: {
122 return android::base::
123 StringPrintf(" Timeline: inputEventId=%" PRId32 " gpuCompletedTime=%" PRId64
124 ", presentTime=%" PRId64,
125 outboundMsg.body.timeline.eventId,
126 outboundMsg.body.timeline
127 .graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME],
128 outboundMsg.body.timeline
129 .graphicsTimeline[GraphicsTimeline::PRESENT_TIME]);
130 }
131 default: {
132 LOG(FATAL) << "Outbound message must be FINISHED or TIMELINE, got "
133 << ftl::enum_string(outboundMsg.header.type);
134 return "Unreachable";
135 }
136 }
137}
138
139InputMessage createFinishedMessage(uint32_t seq, bool handled, nsecs_t consumeTime) {
140 InputMessage msg;
141 msg.header.type = InputMessage::Type::FINISHED;
142 msg.header.seq = seq;
143 msg.body.finished.handled = handled;
144 msg.body.finished.consumeTime = consumeTime;
145 return msg;
146}
147
148InputMessage createTimelineMessage(int32_t inputEventId, nsecs_t gpuCompletedTime,
149 nsecs_t presentTime) {
150 InputMessage msg;
151 msg.header.type = InputMessage::Type::TIMELINE;
152 msg.header.seq = 0;
153 msg.body.timeline.eventId = inputEventId;
154 msg.body.timeline.graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = gpuCompletedTime;
155 msg.body.timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = presentTime;
156 return msg;
157}
158
159} // namespace
160
161using android::base::Result;
162using android::base::StringPrintf;
163
164// --- InputConsumerNoResampling ---
165
166InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
167 sp<Looper> looper,
168 InputConsumerCallbacks& callbacks)
169 : mChannel(channel), mLooper(looper), mCallbacks(callbacks), mFdEvents(0) {
170 LOG_ALWAYS_FATAL_IF(mLooper == nullptr);
171 mCallback = sp<LooperEventCallback>::make(
172 std::bind(&InputConsumerNoResampling::handleReceiveCallback, this,
173 std::placeholders::_1));
174 // In the beginning, there are no pending outbounds events; we only care about receiving
175 // incoming data.
176 setFdEvents(ALOOPER_EVENT_INPUT);
177}
178
179InputConsumerNoResampling::~InputConsumerNoResampling() {
180 ensureCalledOnLooperThread(__func__);
181 consumeBatchedInputEvents(std::nullopt);
182 while (!mOutboundQueue.empty()) {
183 processOutboundEvents();
184 // This is our last chance to ack the events. If we don't ack them here, we will get an ANR,
185 // so keep trying to send the events as long as they are present in the queue.
186 }
187 setFdEvents(0);
188}
189
190int InputConsumerNoResampling::handleReceiveCallback(int events) {
191 // Allowed return values of this function as documented in LooperCallback::handleEvent
192 constexpr int REMOVE_CALLBACK = 0;
193 constexpr int KEEP_CALLBACK = 1;
194
195 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
196 // This error typically occurs when the publisher has closed the input channel
197 // as part of removing a window or finishing an IME session, in which case
198 // the consumer will soon be disposed as well.
199 if (DEBUG_TRANSPORT_CONSUMER) {
200 LOG(INFO) << "The channel was hung up or an error occurred: " << mChannel->getName();
201 }
202 return REMOVE_CALLBACK;
203 }
204
205 int handledEvents = 0;
206 if (events & ALOOPER_EVENT_INPUT) {
207 std::vector<InputMessage> messages = readAllMessages();
208 handleMessages(std::move(messages));
209 handledEvents |= ALOOPER_EVENT_INPUT;
210 }
211
212 if (events & ALOOPER_EVENT_OUTPUT) {
213 processOutboundEvents();
214 handledEvents |= ALOOPER_EVENT_OUTPUT;
215 }
216 if (handledEvents != events) {
217 LOG(FATAL) << "Mismatch: handledEvents=" << handledEvents << ", events=" << events;
218 }
219 return KEEP_CALLBACK;
220}
221
222void InputConsumerNoResampling::processOutboundEvents() {
223 while (!mOutboundQueue.empty()) {
224 const InputMessage& outboundMsg = mOutboundQueue.front();
225
226 const status_t result = mChannel->sendMessage(&outboundMsg);
227 if (result == OK) {
228 if (outboundMsg.header.type == InputMessage::Type::FINISHED) {
229 ATRACE_ASYNC_END("InputConsumer processing", /*cookie=*/outboundMsg.header.seq);
230 }
231 // Successful send. Erase the entry and keep trying to send more
232 mOutboundQueue.pop();
233 continue;
234 }
235
236 // Publisher is busy, try again later. Keep this entry (do not erase)
237 if (result == WOULD_BLOCK) {
238 setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
239 return; // try again later
240 }
241
242 // Some other error. Give up
243 LOG(FATAL) << "Failed to send outbound event on channel '" << mChannel->getName()
244 << "'. status=" << statusToString(result) << "(" << result << ")";
245 }
246
247 // The queue is now empty. Tell looper there's no more output to expect.
248 setFdEvents(ALOOPER_EVENT_INPUT);
249}
250
251void InputConsumerNoResampling::finishInputEvent(uint32_t seq, bool handled) {
252 ensureCalledOnLooperThread(__func__);
253 mOutboundQueue.push(createFinishedMessage(seq, handled, popConsumeTime(seq)));
254 // also produce finish events for all batches for this seq (if any)
255 const auto it = mBatchedSequenceNumbers.find(seq);
256 if (it != mBatchedSequenceNumbers.end()) {
257 for (uint32_t subSeq : it->second) {
258 mOutboundQueue.push(createFinishedMessage(subSeq, handled, popConsumeTime(subSeq)));
259 }
260 mBatchedSequenceNumbers.erase(it);
261 }
262 processOutboundEvents();
263}
264
265bool InputConsumerNoResampling::probablyHasInput() const {
266 // Ideally, this would only be allowed to run on the looper thread, and in production, it will.
267 // However, for testing, it's convenient to call this while the looper thread is blocked, so
268 // we do not call ensureCalledOnLooperThread here.
269 return (!mBatches.empty()) || mChannel->probablyHasInput();
270}
271
272void InputConsumerNoResampling::reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime,
273 nsecs_t presentTime) {
274 ensureCalledOnLooperThread(__func__);
275 mOutboundQueue.push(createTimelineMessage(inputEventId, gpuCompletedTime, presentTime));
276 processOutboundEvents();
277}
278
279nsecs_t InputConsumerNoResampling::popConsumeTime(uint32_t seq) {
280 auto it = mConsumeTimes.find(seq);
281 // Consume time will be missing if either 'finishInputEvent' is called twice, or if it was
282 // called for the wrong (synthetic?) input event. Either way, it is a bug that should be fixed.
283 LOG_ALWAYS_FATAL_IF(it == mConsumeTimes.end(), "Could not find consume time for seq=%" PRIu32,
284 seq);
285 nsecs_t consumeTime = it->second;
286 mConsumeTimes.erase(it);
287 return consumeTime;
288}
289
290void InputConsumerNoResampling::setFdEvents(int events) {
291 if (mFdEvents != events) {
292 mFdEvents = events;
293 if (events != 0) {
294 mLooper->addFd(mChannel->getFd(), 0, events, mCallback, nullptr);
295 } else {
296 mLooper->removeFd(mChannel->getFd());
297 }
298 }
299}
300
301void InputConsumerNoResampling::handleMessages(std::vector<InputMessage>&& messages) {
302 // TODO(b/297226446) : add resampling
303 for (const InputMessage& msg : messages) {
304 if (msg.header.type == InputMessage::Type::MOTION) {
305 const int32_t action = msg.body.motion.action;
306 const DeviceId deviceId = msg.body.motion.deviceId;
307 const int32_t source = msg.body.motion.source;
308 const bool batchableEvent = (action == AMOTION_EVENT_ACTION_MOVE ||
309 action == AMOTION_EVENT_ACTION_HOVER_MOVE) &&
310 (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER) ||
311 isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK));
312 if (batchableEvent) {
313 // add it to batch
314 mBatches[deviceId].emplace(msg);
315 } else {
316 // consume all pending batches for this event immediately
317 // TODO(b/329776327): figure out if this could be smarter by limiting the
318 // consumption only to the current device.
319 consumeBatchedInputEvents(std::nullopt);
320 handleMessage(msg);
321 }
322 } else {
323 // Non-motion events shouldn't force the consumption of pending batched events
324 handleMessage(msg);
325 }
326 }
327 // At the end of this, if we still have pending batches, notify the receiver about it.
328
329 // We need to carefully notify the InputConsumerCallbacks about the pending batch. The receiver
330 // could choose to consume all events when notified about the batch. That means that the
331 // "mBatches" variable could change when 'InputConsumerCallbacks::onBatchedInputEventPending' is
332 // invoked. We also can't notify the InputConsumerCallbacks in a while loop until mBatches is
333 // empty, because the receiver could choose to not consume the batch immediately.
334 std::set<int32_t> pendingBatchSources;
335 for (const auto& [_, pendingMessages] : mBatches) {
336 // Assume that all messages for a given device has the same source.
337 pendingBatchSources.insert(pendingMessages.front().body.motion.source);
338 }
339 for (const int32_t source : pendingBatchSources) {
340 const bool sourceStillRemaining =
341 std::any_of(mBatches.begin(), mBatches.end(), [=](const auto& pair) {
342 return pair.second.front().body.motion.source == source;
343 });
344 if (sourceStillRemaining) {
345 mCallbacks.onBatchedInputEventPending(source);
346 }
347 }
348}
349
350std::vector<InputMessage> InputConsumerNoResampling::readAllMessages() {
351 std::vector<InputMessage> messages;
352 while (true) {
353 InputMessage msg;
354 status_t result = mChannel->receiveMessage(&msg);
355 switch (result) {
356 case OK: {
357 const auto [_, inserted] =
358 mConsumeTimes.emplace(msg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
359 LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32,
360 msg.header.seq);
361
362 // Trace the event processing timeline - event was just read from the socket
363 // TODO(b/329777420): distinguish between multiple instances of InputConsumer
364 // in the same process.
365 ATRACE_ASYNC_BEGIN("InputConsumer processing", /*cookie=*/msg.header.seq);
366 messages.push_back(msg);
367 break;
368 }
369 case WOULD_BLOCK: {
370 return messages;
371 }
372 case DEAD_OBJECT: {
373 LOG(FATAL) << "Got a dead object for " << mChannel->getName();
374 break;
375 }
376 case BAD_VALUE: {
377 LOG(FATAL) << "Got a bad value for " << mChannel->getName();
378 break;
379 }
380 default: {
381 LOG(FATAL) << "Unexpected error: " << result;
382 break;
383 }
384 }
385 }
386}
387
388void InputConsumerNoResampling::handleMessage(const InputMessage& msg) const {
389 switch (msg.header.type) {
390 case InputMessage::Type::KEY: {
391 KeyEvent keyEvent;
392 initializeKeyEvent(keyEvent, msg);
393 mCallbacks.onKeyEvent(std::move(keyEvent), msg.header.seq);
394 break;
395 }
396
397 case InputMessage::Type::MOTION: {
398 MotionEvent motionEvent;
399 initializeMotionEvent(motionEvent, msg);
400 mCallbacks.onMotionEvent(std::move(motionEvent), msg.header.seq);
401 break;
402 }
403
404 case InputMessage::Type::FINISHED:
405 case InputMessage::Type::TIMELINE: {
406 LOG_ALWAYS_FATAL("Consumed a %s message, which should never be seen by "
407 "InputConsumer on %s",
408 ftl::enum_string(msg.header.type).c_str(),
409 mChannel->getName().c_str());
410 break;
411 }
412
413 case InputMessage::Type::FOCUS: {
414 FocusEvent focusEvent;
415 initializeFocusEvent(focusEvent, msg);
416 mCallbacks.onFocusEvent(std::move(focusEvent), msg.header.seq);
417 break;
418 }
419
420 case InputMessage::Type::CAPTURE: {
421 CaptureEvent captureEvent;
422 initializeCaptureEvent(captureEvent, msg);
423 mCallbacks.onCaptureEvent(std::move(captureEvent), msg.header.seq);
424 break;
425 }
426
427 case InputMessage::Type::DRAG: {
428 DragEvent dragEvent;
429 initializeDragEvent(dragEvent, msg);
430 mCallbacks.onDragEvent(std::move(dragEvent), msg.header.seq);
431 break;
432 }
433
434 case InputMessage::Type::TOUCH_MODE: {
435 TouchModeEvent touchModeEvent;
436 initializeTouchModeEvent(touchModeEvent, msg);
437 mCallbacks.onTouchModeEvent(std::move(touchModeEvent), msg.header.seq);
438 break;
439 }
440 }
441}
442
443bool InputConsumerNoResampling::consumeBatchedInputEvents(
444 std::optional<nsecs_t> requestedFrameTime) {
445 ensureCalledOnLooperThread(__func__);
446 // When batching is not enabled, we want to consume all events. That's equivalent to having an
447 // infinite frameTime.
448 const nsecs_t frameTime = requestedFrameTime.value_or(std::numeric_limits<nsecs_t>::max());
449 bool producedEvents = false;
450 for (auto& [deviceId, messages] : mBatches) {
451 MotionEvent motion;
452 std::optional<uint32_t> firstSeqForBatch;
453 std::vector<uint32_t> sequences;
454 while (!messages.empty()) {
455 const InputMessage& msg = messages.front();
456 if (msg.body.motion.eventTime > frameTime) {
457 break;
458 }
459 if (!firstSeqForBatch.has_value()) {
460 initializeMotionEvent(motion, msg);
461 firstSeqForBatch = msg.header.seq;
462 const auto [_, inserted] = mBatchedSequenceNumbers.insert({*firstSeqForBatch, {}});
463 if (!inserted) {
464 LOG(FATAL) << "The sequence " << msg.header.seq << " was already present!";
465 }
466 } else {
467 addSample(motion, msg);
468 mBatchedSequenceNumbers[*firstSeqForBatch].push_back(msg.header.seq);
469 }
470 messages.pop();
471 }
472 if (firstSeqForBatch.has_value()) {
473 mCallbacks.onMotionEvent(std::move(motion), *firstSeqForBatch);
474 producedEvents = true;
475 } else {
476 // This is OK, it just means that the frameTime is too old (all events that we have
477 // pending are in the future of the frametime). Maybe print a
478 // warning? If there are multiple devices active though, this might be normal and can
479 // just be ignored, unless none of them resulted in any consumption (in that case, this
480 // function would already return "false" so we could just leave it up to the caller).
481 }
482 }
483 std::erase_if(mBatches, [](const auto& pair) { return pair.second.empty(); });
484 return producedEvents;
485}
486
487void InputConsumerNoResampling::ensureCalledOnLooperThread(const char* func) const {
488 sp<Looper> callingThreadLooper = Looper::getForThread();
489 if (callingThreadLooper != mLooper) {
490 LOG(FATAL) << "The function " << func << " can only be called on the looper thread";
491 }
492}
493
494std::string InputConsumerNoResampling::dump() const {
495 ensureCalledOnLooperThread(__func__);
496 std::string out;
497 if (mOutboundQueue.empty()) {
498 out += "mOutboundQueue: <empty>\n";
499 } else {
500 out += "mOutboundQueue:\n";
501 // Make a copy of mOutboundQueue for printing destructively. Unfortunately std::queue
502 // doesn't provide a good way to iterate over the entire container.
503 std::queue<InputMessage> tmpQueue = mOutboundQueue;
504 while (!tmpQueue.empty()) {
505 out += std::string(" ") + outboundMessageToString(tmpQueue.front()) + "\n";
506 tmpQueue.pop();
507 }
508 }
509
510 if (mBatches.empty()) {
511 out += "mBatches: <empty>\n";
512 } else {
513 out += "mBatches:\n";
514 for (const auto& [deviceId, messages] : mBatches) {
515 out += " Device id ";
516 out += std::to_string(deviceId);
517 out += ":\n";
518 // Make a copy of mOutboundQueue for printing destructively. Unfortunately std::queue
519 // doesn't provide a good way to iterate over the entire container.
520 std::queue<InputMessage> tmpQueue = messages;
521 while (!tmpQueue.empty()) {
522 LOG_ALWAYS_FATAL_IF(tmpQueue.front().header.type != InputMessage::Type::MOTION);
523 MotionEvent motion;
524 initializeMotionEvent(motion, tmpQueue.front());
525 out += std::string(" ") + streamableToString(motion) + "\n";
526 tmpQueue.pop();
527 }
528 }
529 }
530
531 return out;
532}
533
534} // namespace android