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