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