blob: abc039281a5ef9ae31ac3d99b2996261f70892ff [file] [log] [blame]
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -07001/**
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
Siarhei Vishniakouc0bf3892024-03-29 16:29:13 +000017#include <cstdint>
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -070018#define LOG_TAG "InputTransport"
19#define ATRACE_TAG ATRACE_TAG_INPUT
20
21#include <errno.h>
22#include <fcntl.h>
23#include <inttypes.h>
24#include <math.h>
25#include <poll.h>
26#include <sys/socket.h>
27#include <sys/types.h>
28#include <unistd.h>
29
30#include <android-base/logging.h>
31#include <android-base/properties.h>
32#include <android-base/stringprintf.h>
33#include <binder/Parcel.h>
34#include <cutils/properties.h>
35#include <ftl/enum.h>
36#include <log/log.h>
37#include <utils/Trace.h>
38
39#include <com_android_input_flags.h>
40#include <input/InputConsumer.h>
41#include <input/PrintTools.h>
42#include <input/TraceTools.h>
43
44namespace input_flags = com::android::input::flags;
45
46namespace android {
47
48namespace {
49
50/**
51 * Log debug messages relating to the consumer end of the transport channel.
52 * Enable this via "adb shell setprop log.tag.InputTransportConsumer DEBUG" (requires restart)
53 */
54
55const bool DEBUG_TRANSPORT_CONSUMER =
56 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Consumer", ANDROID_LOG_INFO);
57
58const bool IS_DEBUGGABLE_BUILD =
59#if defined(__ANDROID__)
60 android::base::GetBoolProperty("ro.debuggable", false);
61#else
62 true;
63#endif
64
65/**
66 * Log debug messages about touch event resampling.
67 *
68 * Enable this via "adb shell setprop log.tag.InputTransportResampling DEBUG".
69 * This requires a restart on non-debuggable (e.g. user) builds, but should take effect immediately
70 * on debuggable builds (e.g. userdebug).
71 */
72bool debugResampling() {
73 if (!IS_DEBUGGABLE_BUILD) {
74 static const bool DEBUG_TRANSPORT_RESAMPLING =
75 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Resampling",
76 ANDROID_LOG_INFO);
77 return DEBUG_TRANSPORT_RESAMPLING;
78 }
79 return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Resampling", ANDROID_LOG_INFO);
80}
81
82void initializeKeyEvent(KeyEvent& event, const InputMessage& msg) {
83 event.initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source,
Linnan Li13bf76a2024-05-05 19:18:02 +080084 ui::LogicalDisplayId{msg.body.key.displayId}, msg.body.key.hmac,
85 msg.body.key.action, msg.body.key.flags, msg.body.key.keyCode,
86 msg.body.key.scanCode, msg.body.key.metaState, msg.body.key.repeatCount,
87 msg.body.key.downTime, msg.body.key.eventTime);
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -070088}
89
90void initializeFocusEvent(FocusEvent& event, const InputMessage& msg) {
91 event.initialize(msg.body.focus.eventId, msg.body.focus.hasFocus);
92}
93
94void initializeCaptureEvent(CaptureEvent& event, const InputMessage& msg) {
95 event.initialize(msg.body.capture.eventId, msg.body.capture.pointerCaptureEnabled);
96}
97
98void initializeDragEvent(DragEvent& event, const InputMessage& msg) {
99 event.initialize(msg.body.drag.eventId, msg.body.drag.x, msg.body.drag.y,
100 msg.body.drag.isExiting);
101}
102
103void initializeMotionEvent(MotionEvent& event, const InputMessage& msg) {
104 uint32_t pointerCount = msg.body.motion.pointerCount;
105 PointerProperties pointerProperties[pointerCount];
106 PointerCoords pointerCoords[pointerCount];
107 for (uint32_t i = 0; i < pointerCount; i++) {
108 pointerProperties[i] = msg.body.motion.pointers[i].properties;
109 pointerCoords[i] = msg.body.motion.pointers[i].coords;
110 }
111
112 ui::Transform transform;
113 transform.set({msg.body.motion.dsdx, msg.body.motion.dtdx, msg.body.motion.tx,
114 msg.body.motion.dtdy, msg.body.motion.dsdy, msg.body.motion.ty, 0, 0, 1});
115 ui::Transform displayTransform;
116 displayTransform.set({msg.body.motion.dsdxRaw, msg.body.motion.dtdxRaw, msg.body.motion.txRaw,
117 msg.body.motion.dtdyRaw, msg.body.motion.dsdyRaw, msg.body.motion.tyRaw,
118 0, 0, 1});
119 event.initialize(msg.body.motion.eventId, msg.body.motion.deviceId, msg.body.motion.source,
Linnan Li13bf76a2024-05-05 19:18:02 +0800120 ui::LogicalDisplayId{msg.body.motion.displayId}, msg.body.motion.hmac,
121 msg.body.motion.action, msg.body.motion.actionButton, msg.body.motion.flags,
122 msg.body.motion.edgeFlags, msg.body.motion.metaState,
123 msg.body.motion.buttonState, msg.body.motion.classification, transform,
124 msg.body.motion.xPrecision, msg.body.motion.yPrecision,
125 msg.body.motion.xCursorPosition, msg.body.motion.yCursorPosition,
126 displayTransform, msg.body.motion.downTime, msg.body.motion.eventTime,
127 pointerCount, pointerProperties, pointerCoords);
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -0700128}
129
130void addSample(MotionEvent& event, const InputMessage& msg) {
131 uint32_t pointerCount = msg.body.motion.pointerCount;
132 PointerCoords pointerCoords[pointerCount];
133 for (uint32_t i = 0; i < pointerCount; i++) {
134 pointerCoords[i] = msg.body.motion.pointers[i].coords;
135 }
136
137 event.setMetaState(event.getMetaState() | msg.body.motion.metaState);
138 event.addSample(msg.body.motion.eventTime, pointerCoords);
139}
140
141void initializeTouchModeEvent(TouchModeEvent& event, const InputMessage& msg) {
142 event.initialize(msg.body.touchMode.eventId, msg.body.touchMode.isInTouchMode);
143}
144
145// Nanoseconds per milliseconds.
146constexpr nsecs_t NANOS_PER_MS = 1000000;
147
148// Latency added during resampling. A few milliseconds doesn't hurt much but
149// reduces the impact of mispredicted touch positions.
150const std::chrono::duration RESAMPLE_LATENCY = 5ms;
151
152// Minimum time difference between consecutive samples before attempting to resample.
153const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS;
154
155// Maximum time difference between consecutive samples before attempting to resample
156// by extrapolation.
157const nsecs_t RESAMPLE_MAX_DELTA = 20 * NANOS_PER_MS;
158
159// Maximum time to predict forward from the last known state, to avoid predicting too
160// far into the future. This time is further bounded by 50% of the last time delta.
161const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS;
162
163/**
164 * System property for enabling / disabling touch resampling.
165 * Resampling extrapolates / interpolates the reported touch event coordinates to better
166 * align them to the VSYNC signal, thus resulting in smoother scrolling performance.
167 * Resampling is not needed (and should be disabled) on hardware that already
168 * has touch events triggered by VSYNC.
169 * Set to "1" to enable resampling (default).
170 * Set to "0" to disable resampling.
171 * Resampling is enabled by default.
172 */
173const char* PROPERTY_RESAMPLING_ENABLED = "ro.input.resampling";
174
175inline float lerp(float a, float b, float alpha) {
176 return a + alpha * (b - a);
177}
178
179inline bool isPointerEvent(int32_t source) {
180 return (source & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER;
181}
182
183bool shouldResampleTool(ToolType toolType) {
184 return toolType == ToolType::FINGER || toolType == ToolType::UNKNOWN;
185}
186
187} // namespace
188
189using android::base::Result;
190using android::base::StringPrintf;
191
192// --- InputConsumer ---
193
194InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel)
195 : InputConsumer(channel, isTouchResamplingEnabled()) {}
196
197InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel,
198 bool enableTouchResampling)
Siarhei Vishniakouc0bf3892024-03-29 16:29:13 +0000199 : mResampleTouch(enableTouchResampling),
200 mChannel(channel),
201 mProcessingTraceTag(StringPrintf("InputConsumer processing on %s (%p)",
202 mChannel->getName().c_str(), this)),
203 mLifetimeTraceTag(StringPrintf("InputConsumer lifetime on %s (%p)",
204 mChannel->getName().c_str(), this)),
205 mLifetimeTraceCookie(
206 static_cast<int32_t>(reinterpret_cast<std::uintptr_t>(this) & 0xFFFFFFFF)),
207 mMsgDeferred(false) {
208 ATRACE_ASYNC_BEGIN(mLifetimeTraceTag.c_str(), /*cookie=*/mLifetimeTraceCookie);
209}
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -0700210
Siarhei Vishniakouc0bf3892024-03-29 16:29:13 +0000211InputConsumer::~InputConsumer() {
212 ATRACE_ASYNC_END(mLifetimeTraceTag.c_str(), /*cookie=*/mLifetimeTraceCookie);
213}
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -0700214
215bool InputConsumer::isTouchResamplingEnabled() {
216 return property_get_bool(PROPERTY_RESAMPLING_ENABLED, true);
217}
218
219status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
220 nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
221 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
222 "channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
223 mChannel->getName().c_str(), toString(consumeBatches), frameTime);
224
225 *outSeq = 0;
226 *outEvent = nullptr;
227
228 // Fetch the next input message.
229 // Loop until an event can be returned or no additional events are received.
230 while (!*outEvent) {
231 if (mMsgDeferred) {
232 // mMsg contains a valid input message from the previous call to consume
233 // that has not yet been processed.
234 mMsgDeferred = false;
235 } else {
236 // Receive a fresh message.
237 status_t result = mChannel->receiveMessage(&mMsg);
238 if (result == OK) {
239 const auto [_, inserted] =
240 mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
241 LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32,
242 mMsg.header.seq);
243
244 // Trace the event processing timeline - event was just read from the socket
Siarhei Vishniakouc0bf3892024-03-29 16:29:13 +0000245 ATRACE_ASYNC_BEGIN(mProcessingTraceTag.c_str(), /*cookie=*/mMsg.header.seq);
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -0700246 }
247 if (result) {
248 // Consume the next batched event unless batches are being held for later.
249 if (consumeBatches || result != WOULD_BLOCK) {
250 result = consumeBatch(factory, frameTime, outSeq, outEvent);
251 if (*outEvent) {
252 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
253 "channel '%s' consumer ~ consumed batch event, seq=%u",
254 mChannel->getName().c_str(), *outSeq);
255 break;
256 }
257 }
258 return result;
259 }
260 }
261
262 switch (mMsg.header.type) {
263 case InputMessage::Type::KEY: {
264 KeyEvent* keyEvent = factory->createKeyEvent();
265 if (!keyEvent) return NO_MEMORY;
266
267 initializeKeyEvent(*keyEvent, mMsg);
268 *outSeq = mMsg.header.seq;
269 *outEvent = keyEvent;
270 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
271 "channel '%s' consumer ~ consumed key event, seq=%u",
272 mChannel->getName().c_str(), *outSeq);
273 break;
274 }
275
276 case InputMessage::Type::MOTION: {
277 ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
278 if (batchIndex >= 0) {
279 Batch& batch = mBatches[batchIndex];
280 if (canAddSample(batch, &mMsg)) {
281 batch.samples.push_back(mMsg);
282 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
283 "channel '%s' consumer ~ appended to batch event",
284 mChannel->getName().c_str());
285 break;
286 } else if (isPointerEvent(mMsg.body.motion.source) &&
287 mMsg.body.motion.action == AMOTION_EVENT_ACTION_CANCEL) {
288 // No need to process events that we are going to cancel anyways
289 const size_t count = batch.samples.size();
290 for (size_t i = 0; i < count; i++) {
291 const InputMessage& msg = batch.samples[i];
292 sendFinishedSignal(msg.header.seq, false);
293 }
294 batch.samples.erase(batch.samples.begin(), batch.samples.begin() + count);
295 mBatches.erase(mBatches.begin() + batchIndex);
296 } else {
297 // We cannot append to the batch in progress, so we need to consume
298 // the previous batch right now and defer the new message until later.
299 mMsgDeferred = true;
300 status_t result = consumeSamples(factory, batch, batch.samples.size(),
301 outSeq, outEvent);
302 mBatches.erase(mBatches.begin() + batchIndex);
303 if (result) {
304 return result;
305 }
306 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
307 "channel '%s' consumer ~ consumed batch event and "
308 "deferred current event, seq=%u",
309 mChannel->getName().c_str(), *outSeq);
310 break;
311 }
312 }
313
314 // Start a new batch if needed.
315 if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE ||
316 mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
317 Batch batch;
318 batch.samples.push_back(mMsg);
319 mBatches.push_back(batch);
320 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
321 "channel '%s' consumer ~ started batch event",
322 mChannel->getName().c_str());
323 break;
324 }
325
326 MotionEvent* motionEvent = factory->createMotionEvent();
327 if (!motionEvent) return NO_MEMORY;
328
329 updateTouchState(mMsg);
330 initializeMotionEvent(*motionEvent, mMsg);
331 *outSeq = mMsg.header.seq;
332 *outEvent = motionEvent;
333
334 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
335 "channel '%s' consumer ~ consumed motion event, seq=%u",
336 mChannel->getName().c_str(), *outSeq);
337 break;
338 }
339
340 case InputMessage::Type::FINISHED:
341 case InputMessage::Type::TIMELINE: {
Siarhei Vishniakou11d223b2024-03-26 21:52:38 +0000342 LOG(FATAL) << "Consumed a " << ftl::enum_string(mMsg.header.type)
343 << " message, which should never be seen by "
344 "InputConsumer on "
345 << mChannel->getName();
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -0700346 break;
347 }
348
349 case InputMessage::Type::FOCUS: {
350 FocusEvent* focusEvent = factory->createFocusEvent();
351 if (!focusEvent) return NO_MEMORY;
352
353 initializeFocusEvent(*focusEvent, mMsg);
354 *outSeq = mMsg.header.seq;
355 *outEvent = focusEvent;
356 break;
357 }
358
359 case InputMessage::Type::CAPTURE: {
360 CaptureEvent* captureEvent = factory->createCaptureEvent();
361 if (!captureEvent) return NO_MEMORY;
362
363 initializeCaptureEvent(*captureEvent, mMsg);
364 *outSeq = mMsg.header.seq;
365 *outEvent = captureEvent;
366 break;
367 }
368
369 case InputMessage::Type::DRAG: {
370 DragEvent* dragEvent = factory->createDragEvent();
371 if (!dragEvent) return NO_MEMORY;
372
373 initializeDragEvent(*dragEvent, mMsg);
374 *outSeq = mMsg.header.seq;
375 *outEvent = dragEvent;
376 break;
377 }
378
379 case InputMessage::Type::TOUCH_MODE: {
380 TouchModeEvent* touchModeEvent = factory->createTouchModeEvent();
381 if (!touchModeEvent) return NO_MEMORY;
382
383 initializeTouchModeEvent(*touchModeEvent, mMsg);
384 *outSeq = mMsg.header.seq;
385 *outEvent = touchModeEvent;
386 break;
387 }
388 }
389 }
390 return OK;
391}
392
393status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, nsecs_t frameTime,
394 uint32_t* outSeq, InputEvent** outEvent) {
395 status_t result;
396 for (size_t i = mBatches.size(); i > 0;) {
397 i--;
398 Batch& batch = mBatches[i];
399 if (frameTime < 0) {
400 result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent);
401 mBatches.erase(mBatches.begin() + i);
402 return result;
403 }
404
405 nsecs_t sampleTime = frameTime;
406 if (mResampleTouch) {
407 sampleTime -= std::chrono::nanoseconds(RESAMPLE_LATENCY).count();
408 }
409 ssize_t split = findSampleNoLaterThan(batch, sampleTime);
410 if (split < 0) {
411 continue;
412 }
413
414 result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
415 const InputMessage* next;
416 if (batch.samples.empty()) {
417 mBatches.erase(mBatches.begin() + i);
418 next = nullptr;
419 } else {
420 next = &batch.samples[0];
421 }
422 if (!result && mResampleTouch) {
423 resampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next);
424 }
425 return result;
426 }
427
428 return WOULD_BLOCK;
429}
430
431status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory, Batch& batch,
432 size_t count, uint32_t* outSeq, InputEvent** outEvent) {
433 MotionEvent* motionEvent = factory->createMotionEvent();
434 if (!motionEvent) return NO_MEMORY;
435
436 uint32_t chain = 0;
437 for (size_t i = 0; i < count; i++) {
438 InputMessage& msg = batch.samples[i];
439 updateTouchState(msg);
440 if (i) {
441 SeqChain seqChain;
442 seqChain.seq = msg.header.seq;
443 seqChain.chain = chain;
444 mSeqChains.push_back(seqChain);
445 addSample(*motionEvent, msg);
446 } else {
447 initializeMotionEvent(*motionEvent, msg);
448 }
449 chain = msg.header.seq;
450 }
451 batch.samples.erase(batch.samples.begin(), batch.samples.begin() + count);
452
453 *outSeq = chain;
454 *outEvent = motionEvent;
455 return OK;
456}
457
458void InputConsumer::updateTouchState(InputMessage& msg) {
459 if (!mResampleTouch || !isPointerEvent(msg.body.motion.source)) {
460 return;
461 }
462
463 int32_t deviceId = msg.body.motion.deviceId;
464 int32_t source = msg.body.motion.source;
465
466 // Update the touch state history to incorporate the new input message.
467 // If the message is in the past relative to the most recently produced resampled
468 // touch, then use the resampled time and coordinates instead.
469 switch (msg.body.motion.action & AMOTION_EVENT_ACTION_MASK) {
470 case AMOTION_EVENT_ACTION_DOWN: {
471 ssize_t index = findTouchState(deviceId, source);
472 if (index < 0) {
473 mTouchStates.push_back({});
474 index = mTouchStates.size() - 1;
475 }
476 TouchState& touchState = mTouchStates[index];
477 touchState.initialize(deviceId, source);
478 touchState.addHistory(msg);
479 break;
480 }
481
482 case AMOTION_EVENT_ACTION_MOVE: {
483 ssize_t index = findTouchState(deviceId, source);
484 if (index >= 0) {
485 TouchState& touchState = mTouchStates[index];
486 touchState.addHistory(msg);
487 rewriteMessage(touchState, msg);
488 }
489 break;
490 }
491
492 case AMOTION_EVENT_ACTION_POINTER_DOWN: {
493 ssize_t index = findTouchState(deviceId, source);
494 if (index >= 0) {
495 TouchState& touchState = mTouchStates[index];
496 touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
497 rewriteMessage(touchState, msg);
498 }
499 break;
500 }
501
502 case AMOTION_EVENT_ACTION_POINTER_UP: {
503 ssize_t index = findTouchState(deviceId, source);
504 if (index >= 0) {
505 TouchState& touchState = mTouchStates[index];
506 rewriteMessage(touchState, msg);
507 touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
508 }
509 break;
510 }
511
512 case AMOTION_EVENT_ACTION_SCROLL: {
513 ssize_t index = findTouchState(deviceId, source);
514 if (index >= 0) {
515 TouchState& touchState = mTouchStates[index];
516 rewriteMessage(touchState, msg);
517 }
518 break;
519 }
520
521 case AMOTION_EVENT_ACTION_UP:
522 case AMOTION_EVENT_ACTION_CANCEL: {
523 ssize_t index = findTouchState(deviceId, source);
524 if (index >= 0) {
525 TouchState& touchState = mTouchStates[index];
526 rewriteMessage(touchState, msg);
527 mTouchStates.erase(mTouchStates.begin() + index);
528 }
529 break;
530 }
531 }
532}
533
534/**
535 * Replace the coordinates in msg with the coordinates in lastResample, if necessary.
536 *
537 * If lastResample is no longer valid for a specific pointer (i.e. the lastResample time
538 * is in the past relative to msg and the past two events do not contain identical coordinates),
539 * then invalidate the lastResample data for that pointer.
540 * If the two past events have identical coordinates, then lastResample data for that pointer will
541 * remain valid, and will be used to replace these coordinates. Thus, if a certain coordinate x0 is
542 * resampled to the new value x1, then x1 will always be used to replace x0 until some new value
543 * not equal to x0 is received.
544 */
545void InputConsumer::rewriteMessage(TouchState& state, InputMessage& msg) {
546 nsecs_t eventTime = msg.body.motion.eventTime;
547 for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
548 uint32_t id = msg.body.motion.pointers[i].properties.id;
549 if (state.lastResample.idBits.hasBit(id)) {
550 if (eventTime < state.lastResample.eventTime ||
551 state.recentCoordinatesAreIdentical(id)) {
552 PointerCoords& msgCoords = msg.body.motion.pointers[i].coords;
553 const PointerCoords& resampleCoords = state.lastResample.getPointerById(id);
554 ALOGD_IF(debugResampling(), "[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
555 resampleCoords.getX(), resampleCoords.getY(), msgCoords.getX(),
556 msgCoords.getY());
557 msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
558 msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
559 msgCoords.isResampled = true;
560 } else {
561 state.lastResample.idBits.clearBit(id);
562 }
563 }
564 }
565}
566
567void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
568 const InputMessage* next) {
569 if (!mResampleTouch || !(isPointerEvent(event->getSource())) ||
570 event->getAction() != AMOTION_EVENT_ACTION_MOVE) {
571 return;
572 }
573
574 ssize_t index = findTouchState(event->getDeviceId(), event->getSource());
575 if (index < 0) {
576 ALOGD_IF(debugResampling(), "Not resampled, no touch state for device.");
577 return;
578 }
579
580 TouchState& touchState = mTouchStates[index];
581 if (touchState.historySize < 1) {
582 ALOGD_IF(debugResampling(), "Not resampled, no history for device.");
583 return;
584 }
585
586 // Ensure that the current sample has all of the pointers that need to be reported.
587 const History* current = touchState.getHistory(0);
588 size_t pointerCount = event->getPointerCount();
589 for (size_t i = 0; i < pointerCount; i++) {
590 uint32_t id = event->getPointerId(i);
591 if (!current->idBits.hasBit(id)) {
592 ALOGD_IF(debugResampling(), "Not resampled, missing id %d", id);
593 return;
594 }
595 }
596
597 // Find the data to use for resampling.
598 const History* other;
599 History future;
600 float alpha;
601 if (next) {
602 // Interpolate between current sample and future sample.
603 // So current->eventTime <= sampleTime <= future.eventTime.
604 future.initializeFrom(*next);
605 other = &future;
606 nsecs_t delta = future.eventTime - current->eventTime;
607 if (delta < RESAMPLE_MIN_DELTA) {
608 ALOGD_IF(debugResampling(), "Not resampled, delta time is too small: %" PRId64 " ns.",
609 delta);
610 return;
611 }
612 alpha = float(sampleTime - current->eventTime) / delta;
613 } else if (touchState.historySize >= 2) {
614 // Extrapolate future sample using current sample and past sample.
615 // So other->eventTime <= current->eventTime <= sampleTime.
616 other = touchState.getHistory(1);
617 nsecs_t delta = current->eventTime - other->eventTime;
618 if (delta < RESAMPLE_MIN_DELTA) {
619 ALOGD_IF(debugResampling(), "Not resampled, delta time is too small: %" PRId64 " ns.",
620 delta);
621 return;
622 } else if (delta > RESAMPLE_MAX_DELTA) {
623 ALOGD_IF(debugResampling(), "Not resampled, delta time is too large: %" PRId64 " ns.",
624 delta);
625 return;
626 }
627 nsecs_t maxPredict = current->eventTime + std::min(delta / 2, RESAMPLE_MAX_PREDICTION);
628 if (sampleTime > maxPredict) {
629 ALOGD_IF(debugResampling(),
630 "Sample time is too far in the future, adjusting prediction "
631 "from %" PRId64 " to %" PRId64 " ns.",
632 sampleTime - current->eventTime, maxPredict - current->eventTime);
633 sampleTime = maxPredict;
634 }
635 alpha = float(current->eventTime - sampleTime) / delta;
636 } else {
637 ALOGD_IF(debugResampling(), "Not resampled, insufficient data.");
638 return;
639 }
640
641 if (current->eventTime == sampleTime) {
642 // Prevents having 2 events with identical times and coordinates.
643 return;
644 }
645
646 // Resample touch coordinates.
647 History oldLastResample;
648 oldLastResample.initializeFrom(touchState.lastResample);
649 touchState.lastResample.eventTime = sampleTime;
650 touchState.lastResample.idBits.clear();
651 for (size_t i = 0; i < pointerCount; i++) {
652 uint32_t id = event->getPointerId(i);
653 touchState.lastResample.idToIndex[id] = i;
654 touchState.lastResample.idBits.markBit(id);
655 if (oldLastResample.hasPointerId(id) && touchState.recentCoordinatesAreIdentical(id)) {
656 // We maintain the previously resampled value for this pointer (stored in
657 // oldLastResample) when the coordinates for this pointer haven't changed since then.
658 // This way we don't introduce artificial jitter when pointers haven't actually moved.
659 // The isResampled flag isn't cleared as the values don't reflect what the device is
660 // actually reporting.
661
662 // We know here that the coordinates for the pointer haven't changed because we
663 // would've cleared the resampled bit in rewriteMessage if they had. We can't modify
664 // lastResample in place because the mapping from pointer ID to index may have changed.
665 touchState.lastResample.pointers[i] = oldLastResample.getPointerById(id);
666 continue;
667 }
668
669 PointerCoords& resampledCoords = touchState.lastResample.pointers[i];
670 const PointerCoords& currentCoords = current->getPointerById(id);
671 resampledCoords = currentCoords;
672 resampledCoords.isResampled = true;
673 if (other->idBits.hasBit(id) && shouldResampleTool(event->getToolType(i))) {
674 const PointerCoords& otherCoords = other->getPointerById(id);
675 resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X,
676 lerp(currentCoords.getX(), otherCoords.getX(), alpha));
677 resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y,
678 lerp(currentCoords.getY(), otherCoords.getY(), alpha));
679 ALOGD_IF(debugResampling(),
680 "[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), "
681 "other (%0.3f, %0.3f), alpha %0.3f",
682 id, resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(),
683 currentCoords.getY(), otherCoords.getX(), otherCoords.getY(), alpha);
684 } else {
685 ALOGD_IF(debugResampling(), "[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)", id,
686 resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(),
687 currentCoords.getY());
688 }
689 }
690
691 event->addSample(sampleTime, touchState.lastResample.pointers);
692}
693
694status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
695 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
696 "channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
697 mChannel->getName().c_str(), seq, toString(handled));
698
699 if (!seq) {
700 ALOGE("Attempted to send a finished signal with sequence number 0.");
701 return BAD_VALUE;
702 }
703
704 // Send finished signals for the batch sequence chain first.
705 size_t seqChainCount = mSeqChains.size();
706 if (seqChainCount) {
707 uint32_t currentSeq = seq;
708 uint32_t chainSeqs[seqChainCount];
709 size_t chainIndex = 0;
710 for (size_t i = seqChainCount; i > 0;) {
711 i--;
712 const SeqChain& seqChain = mSeqChains[i];
713 if (seqChain.seq == currentSeq) {
714 currentSeq = seqChain.chain;
715 chainSeqs[chainIndex++] = currentSeq;
716 mSeqChains.erase(mSeqChains.begin() + i);
717 }
718 }
719 status_t status = OK;
720 while (!status && chainIndex > 0) {
721 chainIndex--;
722 status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
723 }
724 if (status) {
725 // An error occurred so at least one signal was not sent, reconstruct the chain.
726 for (;;) {
727 SeqChain seqChain;
728 seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
729 seqChain.chain = chainSeqs[chainIndex];
730 mSeqChains.push_back(seqChain);
731 if (!chainIndex) break;
732 chainIndex--;
733 }
734 return status;
735 }
736 }
737
738 // Send finished signal for the last message in the batch.
739 return sendUnchainedFinishedSignal(seq, handled);
740}
741
742status_t InputConsumer::sendTimeline(int32_t inputEventId,
743 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline) {
744 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
745 "channel '%s' consumer ~ sendTimeline: inputEventId=%" PRId32
746 ", gpuCompletedTime=%" PRId64 ", presentTime=%" PRId64,
747 mChannel->getName().c_str(), inputEventId,
748 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME],
749 graphicsTimeline[GraphicsTimeline::PRESENT_TIME]);
750
751 InputMessage msg;
752 msg.header.type = InputMessage::Type::TIMELINE;
753 msg.header.seq = 0;
754 msg.body.timeline.eventId = inputEventId;
755 msg.body.timeline.graphicsTimeline = std::move(graphicsTimeline);
756 return mChannel->sendMessage(&msg);
757}
758
759nsecs_t InputConsumer::getConsumeTime(uint32_t seq) const {
760 auto it = mConsumeTimes.find(seq);
761 // Consume time will be missing if either 'finishInputEvent' is called twice, or if it was
762 // called for the wrong (synthetic?) input event. Either way, it is a bug that should be fixed.
763 LOG_ALWAYS_FATAL_IF(it == mConsumeTimes.end(), "Could not find consume time for seq=%" PRIu32,
764 seq);
765 return it->second;
766}
767
768void InputConsumer::popConsumeTime(uint32_t seq) {
769 mConsumeTimes.erase(seq);
770}
771
772status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
773 InputMessage msg;
774 msg.header.type = InputMessage::Type::FINISHED;
775 msg.header.seq = seq;
776 msg.body.finished.handled = handled;
777 msg.body.finished.consumeTime = getConsumeTime(seq);
778 status_t result = mChannel->sendMessage(&msg);
779 if (result == OK) {
780 // Remove the consume time if the socket write succeeded. We will not need to ack this
781 // message anymore. If the socket write did not succeed, we will try again and will still
782 // need consume time.
783 popConsumeTime(seq);
784
785 // Trace the event processing timeline - event was just finished
Siarhei Vishniakouc0bf3892024-03-29 16:29:13 +0000786 ATRACE_ASYNC_END(mProcessingTraceTag.c_str(), /*cookie=*/seq);
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -0700787 }
788 return result;
789}
790
791bool InputConsumer::hasPendingBatch() const {
792 return !mBatches.empty();
793}
794
795int32_t InputConsumer::getPendingBatchSource() const {
796 if (mBatches.empty()) {
797 return AINPUT_SOURCE_CLASS_NONE;
798 }
799
800 const Batch& batch = mBatches[0];
801 const InputMessage& head = batch.samples[0];
802 return head.body.motion.source;
803}
804
805bool InputConsumer::probablyHasInput() const {
806 return hasPendingBatch() || mChannel->probablyHasInput();
807}
808
809ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
810 for (size_t i = 0; i < mBatches.size(); i++) {
811 const Batch& batch = mBatches[i];
812 const InputMessage& head = batch.samples[0];
813 if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) {
814 return i;
815 }
816 }
817 return -1;
818}
819
820ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const {
821 for (size_t i = 0; i < mTouchStates.size(); i++) {
822 const TouchState& touchState = mTouchStates[i];
823 if (touchState.deviceId == deviceId && touchState.source == source) {
824 return i;
825 }
826 }
827 return -1;
828}
829
830bool InputConsumer::canAddSample(const Batch& batch, const InputMessage* msg) {
831 const InputMessage& head = batch.samples[0];
832 uint32_t pointerCount = msg->body.motion.pointerCount;
833 if (head.body.motion.pointerCount != pointerCount ||
834 head.body.motion.action != msg->body.motion.action) {
835 return false;
836 }
837 for (size_t i = 0; i < pointerCount; i++) {
838 if (head.body.motion.pointers[i].properties != msg->body.motion.pointers[i].properties) {
839 return false;
840 }
841 }
842 return true;
843}
844
845ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, nsecs_t time) {
846 size_t numSamples = batch.samples.size();
847 size_t index = 0;
848 while (index < numSamples && batch.samples[index].body.motion.eventTime <= time) {
849 index += 1;
850 }
851 return ssize_t(index) - 1;
852}
853
854std::string InputConsumer::dump() const {
855 std::string out;
856 out = out + "mResampleTouch = " + toString(mResampleTouch) + "\n";
857 out = out + "mChannel = " + mChannel->getName() + "\n";
858 out = out + "mMsgDeferred: " + toString(mMsgDeferred) + "\n";
859 if (mMsgDeferred) {
860 out = out + "mMsg : " + ftl::enum_string(mMsg.header.type) + "\n";
861 }
862 out += "Batches:\n";
863 for (const Batch& batch : mBatches) {
864 out += " Batch:\n";
865 for (const InputMessage& msg : batch.samples) {
866 out += android::base::StringPrintf(" Message %" PRIu32 ": %s ", msg.header.seq,
867 ftl::enum_string(msg.header.type).c_str());
868 switch (msg.header.type) {
869 case InputMessage::Type::KEY: {
870 out += android::base::StringPrintf("action=%s keycode=%" PRId32,
871 KeyEvent::actionToString(
872 msg.body.key.action),
873 msg.body.key.keyCode);
874 break;
875 }
876 case InputMessage::Type::MOTION: {
877 out = out + "action=" + MotionEvent::actionToString(msg.body.motion.action);
878 for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
879 const float x = msg.body.motion.pointers[i].coords.getX();
880 const float y = msg.body.motion.pointers[i].coords.getY();
881 out += android::base::StringPrintf("\n Pointer %" PRIu32
882 " : x=%.1f y=%.1f",
883 i, x, y);
884 }
885 break;
886 }
887 case InputMessage::Type::FINISHED: {
888 out += android::base::StringPrintf("handled=%s, consumeTime=%" PRId64,
889 toString(msg.body.finished.handled),
890 msg.body.finished.consumeTime);
891 break;
892 }
893 case InputMessage::Type::FOCUS: {
894 out += android::base::StringPrintf("hasFocus=%s",
895 toString(msg.body.focus.hasFocus));
896 break;
897 }
898 case InputMessage::Type::CAPTURE: {
899 out += android::base::StringPrintf("hasCapture=%s",
900 toString(msg.body.capture
901 .pointerCaptureEnabled));
902 break;
903 }
904 case InputMessage::Type::DRAG: {
905 out += android::base::StringPrintf("x=%.1f y=%.1f, isExiting=%s",
906 msg.body.drag.x, msg.body.drag.y,
907 toString(msg.body.drag.isExiting));
908 break;
909 }
910 case InputMessage::Type::TIMELINE: {
911 const nsecs_t gpuCompletedTime =
912 msg.body.timeline
913 .graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME];
914 const nsecs_t presentTime =
915 msg.body.timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME];
916 out += android::base::StringPrintf("inputEventId=%" PRId32
917 ", gpuCompletedTime=%" PRId64
918 ", presentTime=%" PRId64,
919 msg.body.timeline.eventId, gpuCompletedTime,
920 presentTime);
921 break;
922 }
923 case InputMessage::Type::TOUCH_MODE: {
924 out += android::base::StringPrintf("isInTouchMode=%s",
925 toString(msg.body.touchMode.isInTouchMode));
926 break;
927 }
928 }
929 out += "\n";
930 }
931 }
932 if (mBatches.empty()) {
933 out += " <empty>\n";
934 }
935 out += "mSeqChains:\n";
936 for (const SeqChain& chain : mSeqChains) {
937 out += android::base::StringPrintf(" chain: seq = %" PRIu32 " chain=%" PRIu32, chain.seq,
938 chain.chain);
939 }
940 if (mSeqChains.empty()) {
941 out += " <empty>\n";
942 }
943 out += "mConsumeTimes:\n";
944 for (const auto& [seq, consumeTime] : mConsumeTimes) {
945 out += android::base::StringPrintf(" seq = %" PRIu32 " consumeTime = %" PRId64, seq,
946 consumeTime);
947 }
948 if (mConsumeTimes.empty()) {
949 out += " <empty>\n";
950 }
951 return out;
952}
953
954} // namespace android