blob: e0d874ef7632774bca13cfc986e159ce0864452d [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: {
328 LOG_ALWAYS_FATAL("Consumed a %s message, which should never be seen by "
329 "InputConsumer!",
330 ftl::enum_string(mMsg.header.type).c_str());
331 break;
332 }
333
334 case InputMessage::Type::FOCUS: {
335 FocusEvent* focusEvent = factory->createFocusEvent();
336 if (!focusEvent) return NO_MEMORY;
337
338 initializeFocusEvent(*focusEvent, mMsg);
339 *outSeq = mMsg.header.seq;
340 *outEvent = focusEvent;
341 break;
342 }
343
344 case InputMessage::Type::CAPTURE: {
345 CaptureEvent* captureEvent = factory->createCaptureEvent();
346 if (!captureEvent) return NO_MEMORY;
347
348 initializeCaptureEvent(*captureEvent, mMsg);
349 *outSeq = mMsg.header.seq;
350 *outEvent = captureEvent;
351 break;
352 }
353
354 case InputMessage::Type::DRAG: {
355 DragEvent* dragEvent = factory->createDragEvent();
356 if (!dragEvent) return NO_MEMORY;
357
358 initializeDragEvent(*dragEvent, mMsg);
359 *outSeq = mMsg.header.seq;
360 *outEvent = dragEvent;
361 break;
362 }
363
364 case InputMessage::Type::TOUCH_MODE: {
365 TouchModeEvent* touchModeEvent = factory->createTouchModeEvent();
366 if (!touchModeEvent) return NO_MEMORY;
367
368 initializeTouchModeEvent(*touchModeEvent, mMsg);
369 *outSeq = mMsg.header.seq;
370 *outEvent = touchModeEvent;
371 break;
372 }
373 }
374 }
375 return OK;
376}
377
378status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, nsecs_t frameTime,
379 uint32_t* outSeq, InputEvent** outEvent) {
380 status_t result;
381 for (size_t i = mBatches.size(); i > 0;) {
382 i--;
383 Batch& batch = mBatches[i];
384 if (frameTime < 0) {
385 result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent);
386 mBatches.erase(mBatches.begin() + i);
387 return result;
388 }
389
390 nsecs_t sampleTime = frameTime;
391 if (mResampleTouch) {
392 sampleTime -= std::chrono::nanoseconds(RESAMPLE_LATENCY).count();
393 }
394 ssize_t split = findSampleNoLaterThan(batch, sampleTime);
395 if (split < 0) {
396 continue;
397 }
398
399 result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
400 const InputMessage* next;
401 if (batch.samples.empty()) {
402 mBatches.erase(mBatches.begin() + i);
403 next = nullptr;
404 } else {
405 next = &batch.samples[0];
406 }
407 if (!result && mResampleTouch) {
408 resampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next);
409 }
410 return result;
411 }
412
413 return WOULD_BLOCK;
414}
415
416status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory, Batch& batch,
417 size_t count, uint32_t* outSeq, InputEvent** outEvent) {
418 MotionEvent* motionEvent = factory->createMotionEvent();
419 if (!motionEvent) return NO_MEMORY;
420
421 uint32_t chain = 0;
422 for (size_t i = 0; i < count; i++) {
423 InputMessage& msg = batch.samples[i];
424 updateTouchState(msg);
425 if (i) {
426 SeqChain seqChain;
427 seqChain.seq = msg.header.seq;
428 seqChain.chain = chain;
429 mSeqChains.push_back(seqChain);
430 addSample(*motionEvent, msg);
431 } else {
432 initializeMotionEvent(*motionEvent, msg);
433 }
434 chain = msg.header.seq;
435 }
436 batch.samples.erase(batch.samples.begin(), batch.samples.begin() + count);
437
438 *outSeq = chain;
439 *outEvent = motionEvent;
440 return OK;
441}
442
443void InputConsumer::updateTouchState(InputMessage& msg) {
444 if (!mResampleTouch || !isPointerEvent(msg.body.motion.source)) {
445 return;
446 }
447
448 int32_t deviceId = msg.body.motion.deviceId;
449 int32_t source = msg.body.motion.source;
450
451 // Update the touch state history to incorporate the new input message.
452 // If the message is in the past relative to the most recently produced resampled
453 // touch, then use the resampled time and coordinates instead.
454 switch (msg.body.motion.action & AMOTION_EVENT_ACTION_MASK) {
455 case AMOTION_EVENT_ACTION_DOWN: {
456 ssize_t index = findTouchState(deviceId, source);
457 if (index < 0) {
458 mTouchStates.push_back({});
459 index = mTouchStates.size() - 1;
460 }
461 TouchState& touchState = mTouchStates[index];
462 touchState.initialize(deviceId, source);
463 touchState.addHistory(msg);
464 break;
465 }
466
467 case AMOTION_EVENT_ACTION_MOVE: {
468 ssize_t index = findTouchState(deviceId, source);
469 if (index >= 0) {
470 TouchState& touchState = mTouchStates[index];
471 touchState.addHistory(msg);
472 rewriteMessage(touchState, msg);
473 }
474 break;
475 }
476
477 case AMOTION_EVENT_ACTION_POINTER_DOWN: {
478 ssize_t index = findTouchState(deviceId, source);
479 if (index >= 0) {
480 TouchState& touchState = mTouchStates[index];
481 touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
482 rewriteMessage(touchState, msg);
483 }
484 break;
485 }
486
487 case AMOTION_EVENT_ACTION_POINTER_UP: {
488 ssize_t index = findTouchState(deviceId, source);
489 if (index >= 0) {
490 TouchState& touchState = mTouchStates[index];
491 rewriteMessage(touchState, msg);
492 touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
493 }
494 break;
495 }
496
497 case AMOTION_EVENT_ACTION_SCROLL: {
498 ssize_t index = findTouchState(deviceId, source);
499 if (index >= 0) {
500 TouchState& touchState = mTouchStates[index];
501 rewriteMessage(touchState, msg);
502 }
503 break;
504 }
505
506 case AMOTION_EVENT_ACTION_UP:
507 case AMOTION_EVENT_ACTION_CANCEL: {
508 ssize_t index = findTouchState(deviceId, source);
509 if (index >= 0) {
510 TouchState& touchState = mTouchStates[index];
511 rewriteMessage(touchState, msg);
512 mTouchStates.erase(mTouchStates.begin() + index);
513 }
514 break;
515 }
516 }
517}
518
519/**
520 * Replace the coordinates in msg with the coordinates in lastResample, if necessary.
521 *
522 * If lastResample is no longer valid for a specific pointer (i.e. the lastResample time
523 * is in the past relative to msg and the past two events do not contain identical coordinates),
524 * then invalidate the lastResample data for that pointer.
525 * If the two past events have identical coordinates, then lastResample data for that pointer will
526 * remain valid, and will be used to replace these coordinates. Thus, if a certain coordinate x0 is
527 * resampled to the new value x1, then x1 will always be used to replace x0 until some new value
528 * not equal to x0 is received.
529 */
530void InputConsumer::rewriteMessage(TouchState& state, InputMessage& msg) {
531 nsecs_t eventTime = msg.body.motion.eventTime;
532 for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
533 uint32_t id = msg.body.motion.pointers[i].properties.id;
534 if (state.lastResample.idBits.hasBit(id)) {
535 if (eventTime < state.lastResample.eventTime ||
536 state.recentCoordinatesAreIdentical(id)) {
537 PointerCoords& msgCoords = msg.body.motion.pointers[i].coords;
538 const PointerCoords& resampleCoords = state.lastResample.getPointerById(id);
539 ALOGD_IF(debugResampling(), "[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
540 resampleCoords.getX(), resampleCoords.getY(), msgCoords.getX(),
541 msgCoords.getY());
542 msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
543 msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
544 msgCoords.isResampled = true;
545 } else {
546 state.lastResample.idBits.clearBit(id);
547 }
548 }
549 }
550}
551
552void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
553 const InputMessage* next) {
554 if (!mResampleTouch || !(isPointerEvent(event->getSource())) ||
555 event->getAction() != AMOTION_EVENT_ACTION_MOVE) {
556 return;
557 }
558
559 ssize_t index = findTouchState(event->getDeviceId(), event->getSource());
560 if (index < 0) {
561 ALOGD_IF(debugResampling(), "Not resampled, no touch state for device.");
562 return;
563 }
564
565 TouchState& touchState = mTouchStates[index];
566 if (touchState.historySize < 1) {
567 ALOGD_IF(debugResampling(), "Not resampled, no history for device.");
568 return;
569 }
570
571 // Ensure that the current sample has all of the pointers that need to be reported.
572 const History* current = touchState.getHistory(0);
573 size_t pointerCount = event->getPointerCount();
574 for (size_t i = 0; i < pointerCount; i++) {
575 uint32_t id = event->getPointerId(i);
576 if (!current->idBits.hasBit(id)) {
577 ALOGD_IF(debugResampling(), "Not resampled, missing id %d", id);
578 return;
579 }
580 }
581
582 // Find the data to use for resampling.
583 const History* other;
584 History future;
585 float alpha;
586 if (next) {
587 // Interpolate between current sample and future sample.
588 // So current->eventTime <= sampleTime <= future.eventTime.
589 future.initializeFrom(*next);
590 other = &future;
591 nsecs_t delta = future.eventTime - current->eventTime;
592 if (delta < RESAMPLE_MIN_DELTA) {
593 ALOGD_IF(debugResampling(), "Not resampled, delta time is too small: %" PRId64 " ns.",
594 delta);
595 return;
596 }
597 alpha = float(sampleTime - current->eventTime) / delta;
598 } else if (touchState.historySize >= 2) {
599 // Extrapolate future sample using current sample and past sample.
600 // So other->eventTime <= current->eventTime <= sampleTime.
601 other = touchState.getHistory(1);
602 nsecs_t delta = current->eventTime - other->eventTime;
603 if (delta < RESAMPLE_MIN_DELTA) {
604 ALOGD_IF(debugResampling(), "Not resampled, delta time is too small: %" PRId64 " ns.",
605 delta);
606 return;
607 } else if (delta > RESAMPLE_MAX_DELTA) {
608 ALOGD_IF(debugResampling(), "Not resampled, delta time is too large: %" PRId64 " ns.",
609 delta);
610 return;
611 }
612 nsecs_t maxPredict = current->eventTime + std::min(delta / 2, RESAMPLE_MAX_PREDICTION);
613 if (sampleTime > maxPredict) {
614 ALOGD_IF(debugResampling(),
615 "Sample time is too far in the future, adjusting prediction "
616 "from %" PRId64 " to %" PRId64 " ns.",
617 sampleTime - current->eventTime, maxPredict - current->eventTime);
618 sampleTime = maxPredict;
619 }
620 alpha = float(current->eventTime - sampleTime) / delta;
621 } else {
622 ALOGD_IF(debugResampling(), "Not resampled, insufficient data.");
623 return;
624 }
625
626 if (current->eventTime == sampleTime) {
627 // Prevents having 2 events with identical times and coordinates.
628 return;
629 }
630
631 // Resample touch coordinates.
632 History oldLastResample;
633 oldLastResample.initializeFrom(touchState.lastResample);
634 touchState.lastResample.eventTime = sampleTime;
635 touchState.lastResample.idBits.clear();
636 for (size_t i = 0; i < pointerCount; i++) {
637 uint32_t id = event->getPointerId(i);
638 touchState.lastResample.idToIndex[id] = i;
639 touchState.lastResample.idBits.markBit(id);
640 if (oldLastResample.hasPointerId(id) && touchState.recentCoordinatesAreIdentical(id)) {
641 // We maintain the previously resampled value for this pointer (stored in
642 // oldLastResample) when the coordinates for this pointer haven't changed since then.
643 // This way we don't introduce artificial jitter when pointers haven't actually moved.
644 // The isResampled flag isn't cleared as the values don't reflect what the device is
645 // actually reporting.
646
647 // We know here that the coordinates for the pointer haven't changed because we
648 // would've cleared the resampled bit in rewriteMessage if they had. We can't modify
649 // lastResample in place because the mapping from pointer ID to index may have changed.
650 touchState.lastResample.pointers[i] = oldLastResample.getPointerById(id);
651 continue;
652 }
653
654 PointerCoords& resampledCoords = touchState.lastResample.pointers[i];
655 const PointerCoords& currentCoords = current->getPointerById(id);
656 resampledCoords = currentCoords;
657 resampledCoords.isResampled = true;
658 if (other->idBits.hasBit(id) && shouldResampleTool(event->getToolType(i))) {
659 const PointerCoords& otherCoords = other->getPointerById(id);
660 resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X,
661 lerp(currentCoords.getX(), otherCoords.getX(), alpha));
662 resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y,
663 lerp(currentCoords.getY(), otherCoords.getY(), alpha));
664 ALOGD_IF(debugResampling(),
665 "[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), "
666 "other (%0.3f, %0.3f), alpha %0.3f",
667 id, resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(),
668 currentCoords.getY(), otherCoords.getX(), otherCoords.getY(), alpha);
669 } else {
670 ALOGD_IF(debugResampling(), "[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)", id,
671 resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(),
672 currentCoords.getY());
673 }
674 }
675
676 event->addSample(sampleTime, touchState.lastResample.pointers);
677}
678
679status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
680 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
681 "channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
682 mChannel->getName().c_str(), seq, toString(handled));
683
684 if (!seq) {
685 ALOGE("Attempted to send a finished signal with sequence number 0.");
686 return BAD_VALUE;
687 }
688
689 // Send finished signals for the batch sequence chain first.
690 size_t seqChainCount = mSeqChains.size();
691 if (seqChainCount) {
692 uint32_t currentSeq = seq;
693 uint32_t chainSeqs[seqChainCount];
694 size_t chainIndex = 0;
695 for (size_t i = seqChainCount; i > 0;) {
696 i--;
697 const SeqChain& seqChain = mSeqChains[i];
698 if (seqChain.seq == currentSeq) {
699 currentSeq = seqChain.chain;
700 chainSeqs[chainIndex++] = currentSeq;
701 mSeqChains.erase(mSeqChains.begin() + i);
702 }
703 }
704 status_t status = OK;
705 while (!status && chainIndex > 0) {
706 chainIndex--;
707 status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
708 }
709 if (status) {
710 // An error occurred so at least one signal was not sent, reconstruct the chain.
711 for (;;) {
712 SeqChain seqChain;
713 seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
714 seqChain.chain = chainSeqs[chainIndex];
715 mSeqChains.push_back(seqChain);
716 if (!chainIndex) break;
717 chainIndex--;
718 }
719 return status;
720 }
721 }
722
723 // Send finished signal for the last message in the batch.
724 return sendUnchainedFinishedSignal(seq, handled);
725}
726
727status_t InputConsumer::sendTimeline(int32_t inputEventId,
728 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline) {
729 ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
730 "channel '%s' consumer ~ sendTimeline: inputEventId=%" PRId32
731 ", gpuCompletedTime=%" PRId64 ", presentTime=%" PRId64,
732 mChannel->getName().c_str(), inputEventId,
733 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME],
734 graphicsTimeline[GraphicsTimeline::PRESENT_TIME]);
735
736 InputMessage msg;
737 msg.header.type = InputMessage::Type::TIMELINE;
738 msg.header.seq = 0;
739 msg.body.timeline.eventId = inputEventId;
740 msg.body.timeline.graphicsTimeline = std::move(graphicsTimeline);
741 return mChannel->sendMessage(&msg);
742}
743
744nsecs_t InputConsumer::getConsumeTime(uint32_t seq) const {
745 auto it = mConsumeTimes.find(seq);
746 // Consume time will be missing if either 'finishInputEvent' is called twice, or if it was
747 // called for the wrong (synthetic?) input event. Either way, it is a bug that should be fixed.
748 LOG_ALWAYS_FATAL_IF(it == mConsumeTimes.end(), "Could not find consume time for seq=%" PRIu32,
749 seq);
750 return it->second;
751}
752
753void InputConsumer::popConsumeTime(uint32_t seq) {
754 mConsumeTimes.erase(seq);
755}
756
757status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
758 InputMessage msg;
759 msg.header.type = InputMessage::Type::FINISHED;
760 msg.header.seq = seq;
761 msg.body.finished.handled = handled;
762 msg.body.finished.consumeTime = getConsumeTime(seq);
763 status_t result = mChannel->sendMessage(&msg);
764 if (result == OK) {
765 // Remove the consume time if the socket write succeeded. We will not need to ack this
766 // message anymore. If the socket write did not succeed, we will try again and will still
767 // need consume time.
768 popConsumeTime(seq);
769
770 // Trace the event processing timeline - event was just finished
771 ATRACE_ASYNC_END("InputConsumer processing", /*cookie=*/seq);
772 }
773 return result;
774}
775
776bool InputConsumer::hasPendingBatch() const {
777 return !mBatches.empty();
778}
779
780int32_t InputConsumer::getPendingBatchSource() const {
781 if (mBatches.empty()) {
782 return AINPUT_SOURCE_CLASS_NONE;
783 }
784
785 const Batch& batch = mBatches[0];
786 const InputMessage& head = batch.samples[0];
787 return head.body.motion.source;
788}
789
790bool InputConsumer::probablyHasInput() const {
791 return hasPendingBatch() || mChannel->probablyHasInput();
792}
793
794ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
795 for (size_t i = 0; i < mBatches.size(); i++) {
796 const Batch& batch = mBatches[i];
797 const InputMessage& head = batch.samples[0];
798 if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) {
799 return i;
800 }
801 }
802 return -1;
803}
804
805ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const {
806 for (size_t i = 0; i < mTouchStates.size(); i++) {
807 const TouchState& touchState = mTouchStates[i];
808 if (touchState.deviceId == deviceId && touchState.source == source) {
809 return i;
810 }
811 }
812 return -1;
813}
814
815bool InputConsumer::canAddSample(const Batch& batch, const InputMessage* msg) {
816 const InputMessage& head = batch.samples[0];
817 uint32_t pointerCount = msg->body.motion.pointerCount;
818 if (head.body.motion.pointerCount != pointerCount ||
819 head.body.motion.action != msg->body.motion.action) {
820 return false;
821 }
822 for (size_t i = 0; i < pointerCount; i++) {
823 if (head.body.motion.pointers[i].properties != msg->body.motion.pointers[i].properties) {
824 return false;
825 }
826 }
827 return true;
828}
829
830ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, nsecs_t time) {
831 size_t numSamples = batch.samples.size();
832 size_t index = 0;
833 while (index < numSamples && batch.samples[index].body.motion.eventTime <= time) {
834 index += 1;
835 }
836 return ssize_t(index) - 1;
837}
838
839std::string InputConsumer::dump() const {
840 std::string out;
841 out = out + "mResampleTouch = " + toString(mResampleTouch) + "\n";
842 out = out + "mChannel = " + mChannel->getName() + "\n";
843 out = out + "mMsgDeferred: " + toString(mMsgDeferred) + "\n";
844 if (mMsgDeferred) {
845 out = out + "mMsg : " + ftl::enum_string(mMsg.header.type) + "\n";
846 }
847 out += "Batches:\n";
848 for (const Batch& batch : mBatches) {
849 out += " Batch:\n";
850 for (const InputMessage& msg : batch.samples) {
851 out += android::base::StringPrintf(" Message %" PRIu32 ": %s ", msg.header.seq,
852 ftl::enum_string(msg.header.type).c_str());
853 switch (msg.header.type) {
854 case InputMessage::Type::KEY: {
855 out += android::base::StringPrintf("action=%s keycode=%" PRId32,
856 KeyEvent::actionToString(
857 msg.body.key.action),
858 msg.body.key.keyCode);
859 break;
860 }
861 case InputMessage::Type::MOTION: {
862 out = out + "action=" + MotionEvent::actionToString(msg.body.motion.action);
863 for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
864 const float x = msg.body.motion.pointers[i].coords.getX();
865 const float y = msg.body.motion.pointers[i].coords.getY();
866 out += android::base::StringPrintf("\n Pointer %" PRIu32
867 " : x=%.1f y=%.1f",
868 i, x, y);
869 }
870 break;
871 }
872 case InputMessage::Type::FINISHED: {
873 out += android::base::StringPrintf("handled=%s, consumeTime=%" PRId64,
874 toString(msg.body.finished.handled),
875 msg.body.finished.consumeTime);
876 break;
877 }
878 case InputMessage::Type::FOCUS: {
879 out += android::base::StringPrintf("hasFocus=%s",
880 toString(msg.body.focus.hasFocus));
881 break;
882 }
883 case InputMessage::Type::CAPTURE: {
884 out += android::base::StringPrintf("hasCapture=%s",
885 toString(msg.body.capture
886 .pointerCaptureEnabled));
887 break;
888 }
889 case InputMessage::Type::DRAG: {
890 out += android::base::StringPrintf("x=%.1f y=%.1f, isExiting=%s",
891 msg.body.drag.x, msg.body.drag.y,
892 toString(msg.body.drag.isExiting));
893 break;
894 }
895 case InputMessage::Type::TIMELINE: {
896 const nsecs_t gpuCompletedTime =
897 msg.body.timeline
898 .graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME];
899 const nsecs_t presentTime =
900 msg.body.timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME];
901 out += android::base::StringPrintf("inputEventId=%" PRId32
902 ", gpuCompletedTime=%" PRId64
903 ", presentTime=%" PRId64,
904 msg.body.timeline.eventId, gpuCompletedTime,
905 presentTime);
906 break;
907 }
908 case InputMessage::Type::TOUCH_MODE: {
909 out += android::base::StringPrintf("isInTouchMode=%s",
910 toString(msg.body.touchMode.isInTouchMode));
911 break;
912 }
913 }
914 out += "\n";
915 }
916 }
917 if (mBatches.empty()) {
918 out += " <empty>\n";
919 }
920 out += "mSeqChains:\n";
921 for (const SeqChain& chain : mSeqChains) {
922 out += android::base::StringPrintf(" chain: seq = %" PRIu32 " chain=%" PRIu32, chain.seq,
923 chain.chain);
924 }
925 if (mSeqChains.empty()) {
926 out += " <empty>\n";
927 }
928 out += "mConsumeTimes:\n";
929 for (const auto& [seq, consumeTime] : mConsumeTimes) {
930 out += android::base::StringPrintf(" seq = %" PRIu32 " consumeTime = %" PRId64, seq,
931 consumeTime);
932 }
933 if (mConsumeTimes.empty()) {
934 out += " <empty>\n";
935 }
936 return out;
937}
938
939} // namespace android