• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2010 The Android Open Source Project
3 //
4 // Provides a shared memory transport for input events.
5 //
6 #define LOG_TAG "InputTransport"
7 
8 //#define LOG_NDEBUG 0
9 
10 // Log debug messages about channel messages (send message, receive message)
11 #define DEBUG_CHANNEL_MESSAGES 0
12 
13 // Log debug messages whenever InputChannel objects are created/destroyed
14 #define DEBUG_CHANNEL_LIFECYCLE 0
15 
16 // Log debug messages about transport actions
17 #define DEBUG_TRANSPORT_ACTIONS 0
18 
19 // Log debug messages about touch event resampling
20 #define DEBUG_RESAMPLING 0
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <math.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 
30 #include <android-base/stringprintf.h>
31 #include <binder/Parcel.h>
32 #include <cutils/properties.h>
33 #include <log/log.h>
34 #include <utils/Trace.h>
35 
36 #include <input/InputTransport.h>
37 
38 using android::base::StringPrintf;
39 
40 namespace android {
41 
42 // Socket buffer size.  The default is typically about 128KB, which is much larger than
43 // we really need.  So we make it smaller.  It just needs to be big enough to hold
44 // a few dozen large multi-finger motion events in the case where an application gets
45 // behind processing touches.
46 static const size_t SOCKET_BUFFER_SIZE = 32 * 1024;
47 
48 // Nanoseconds per milliseconds.
49 static const nsecs_t NANOS_PER_MS = 1000000;
50 
51 // Latency added during resampling.  A few milliseconds doesn't hurt much but
52 // reduces the impact of mispredicted touch positions.
53 static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS;
54 
55 // Minimum time difference between consecutive samples before attempting to resample.
56 static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS;
57 
58 // Maximum time difference between consecutive samples before attempting to resample
59 // by extrapolation.
60 static const nsecs_t RESAMPLE_MAX_DELTA = 20 * NANOS_PER_MS;
61 
62 // Maximum time to predict forward from the last known state, to avoid predicting too
63 // far into the future.  This time is further bounded by 50% of the last time delta.
64 static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS;
65 
66 /**
67  * System property for enabling / disabling touch resampling.
68  * Resampling extrapolates / interpolates the reported touch event coordinates to better
69  * align them to the VSYNC signal, thus resulting in smoother scrolling performance.
70  * Resampling is not needed (and should be disabled) on hardware that already
71  * has touch events triggered by VSYNC.
72  * Set to "1" to enable resampling (default).
73  * Set to "0" to disable resampling.
74  * Resampling is enabled by default.
75  */
76 static const char* PROPERTY_RESAMPLING_ENABLED = "ro.input.resampling";
77 
78 template<typename T>
min(const T & a,const T & b)79 inline static T min(const T& a, const T& b) {
80     return a < b ? a : b;
81 }
82 
lerp(float a,float b,float alpha)83 inline static float lerp(float a, float b, float alpha) {
84     return a + alpha * (b - a);
85 }
86 
isPointerEvent(int32_t source)87 inline static bool isPointerEvent(int32_t source) {
88     return (source & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER;
89 }
90 
91 // --- InputMessage ---
92 
isValid(size_t actualSize) const93 bool InputMessage::isValid(size_t actualSize) const {
94     if (size() == actualSize) {
95         switch (header.type) {
96         case TYPE_KEY:
97             return true;
98         case TYPE_MOTION:
99             return body.motion.pointerCount > 0
100                     && body.motion.pointerCount <= MAX_POINTERS;
101         case TYPE_FINISHED:
102             return true;
103         }
104     }
105     return false;
106 }
107 
size() const108 size_t InputMessage::size() const {
109     switch (header.type) {
110     case TYPE_KEY:
111         return sizeof(Header) + body.key.size();
112     case TYPE_MOTION:
113         return sizeof(Header) + body.motion.size();
114     case TYPE_FINISHED:
115         return sizeof(Header) + body.finished.size();
116     }
117     return sizeof(Header);
118 }
119 
120 /**
121  * There could be non-zero bytes in-between InputMessage fields. Force-initialize the entire
122  * memory to zero, then only copy the valid bytes on a per-field basis.
123  */
getSanitizedCopy(InputMessage * msg) const124 void InputMessage::getSanitizedCopy(InputMessage* msg) const {
125     memset(msg, 0, sizeof(*msg));
126 
127     // Write the header
128     msg->header.type = header.type;
129 
130     // Write the body
131     switch(header.type) {
132         case InputMessage::TYPE_KEY: {
133             // uint32_t seq
134             msg->body.key.seq = body.key.seq;
135             // nsecs_t eventTime
136             msg->body.key.eventTime = body.key.eventTime;
137             // int32_t deviceId
138             msg->body.key.deviceId = body.key.deviceId;
139             // int32_t source
140             msg->body.key.source = body.key.source;
141             // int32_t displayId
142             msg->body.key.displayId = body.key.displayId;
143             // int32_t action
144             msg->body.key.action = body.key.action;
145             // int32_t flags
146             msg->body.key.flags = body.key.flags;
147             // int32_t keyCode
148             msg->body.key.keyCode = body.key.keyCode;
149             // int32_t scanCode
150             msg->body.key.scanCode = body.key.scanCode;
151             // int32_t metaState
152             msg->body.key.metaState = body.key.metaState;
153             // int32_t repeatCount
154             msg->body.key.repeatCount = body.key.repeatCount;
155             // nsecs_t downTime
156             msg->body.key.downTime = body.key.downTime;
157             break;
158         }
159         case InputMessage::TYPE_MOTION: {
160             // uint32_t seq
161             msg->body.motion.seq = body.motion.seq;
162             // nsecs_t eventTime
163             msg->body.motion.eventTime = body.motion.eventTime;
164             // int32_t deviceId
165             msg->body.motion.deviceId = body.motion.deviceId;
166             // int32_t source
167             msg->body.motion.source = body.motion.source;
168             // int32_t displayId
169             msg->body.motion.displayId = body.motion.displayId;
170             // int32_t action
171             msg->body.motion.action = body.motion.action;
172             // int32_t actionButton
173             msg->body.motion.actionButton = body.motion.actionButton;
174             // int32_t flags
175             msg->body.motion.flags = body.motion.flags;
176             // int32_t metaState
177             msg->body.motion.metaState = body.motion.metaState;
178             // int32_t buttonState
179             msg->body.motion.buttonState = body.motion.buttonState;
180             // MotionClassification classification
181             msg->body.motion.classification = body.motion.classification;
182             // int32_t edgeFlags
183             msg->body.motion.edgeFlags = body.motion.edgeFlags;
184             // nsecs_t downTime
185             msg->body.motion.downTime = body.motion.downTime;
186             // float xOffset
187             msg->body.motion.xOffset = body.motion.xOffset;
188             // float yOffset
189             msg->body.motion.yOffset = body.motion.yOffset;
190             // float xPrecision
191             msg->body.motion.xPrecision = body.motion.xPrecision;
192             // float yPrecision
193             msg->body.motion.yPrecision = body.motion.yPrecision;
194             // uint32_t pointerCount
195             msg->body.motion.pointerCount = body.motion.pointerCount;
196             //struct Pointer pointers[MAX_POINTERS]
197             for (size_t i = 0; i < body.motion.pointerCount; i++) {
198                 // PointerProperties properties
199                 msg->body.motion.pointers[i].properties.id = body.motion.pointers[i].properties.id;
200                 msg->body.motion.pointers[i].properties.toolType =
201                         body.motion.pointers[i].properties.toolType,
202                 // PointerCoords coords
203                 msg->body.motion.pointers[i].coords.bits = body.motion.pointers[i].coords.bits;
204                 const uint32_t count = BitSet64::count(body.motion.pointers[i].coords.bits);
205                 memcpy(&msg->body.motion.pointers[i].coords.values[0],
206                         &body.motion.pointers[i].coords.values[0],
207                         count * (sizeof(body.motion.pointers[i].coords.values[0])));
208             }
209             break;
210         }
211         case InputMessage::TYPE_FINISHED: {
212             msg->body.finished.seq = body.finished.seq;
213             msg->body.finished.handled = body.finished.handled;
214             break;
215         }
216         default: {
217             LOG_FATAL("Unexpected message type %i", header.type);
218             break;
219         }
220     }
221 }
222 
223 // --- InputChannel ---
224 
InputChannel(const std::string & name,int fd)225 InputChannel::InputChannel(const std::string& name, int fd) :
226         mName(name) {
227 #if DEBUG_CHANNEL_LIFECYCLE
228     ALOGD("Input channel constructed: name='%s', fd=%d",
229             mName.c_str(), fd);
230 #endif
231 
232     setFd(fd);
233 }
234 
~InputChannel()235 InputChannel::~InputChannel() {
236 #if DEBUG_CHANNEL_LIFECYCLE
237     ALOGD("Input channel destroyed: name='%s', fd=%d",
238             mName.c_str(), mFd);
239 #endif
240 
241     ::close(mFd);
242 }
243 
setFd(int fd)244 void InputChannel::setFd(int fd) {
245     if (mFd > 0) {
246         ::close(mFd);
247     }
248     mFd = fd;
249     if (mFd > 0) {
250         int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
251         LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
252             "non-blocking.  errno=%d", mName.c_str(), errno);
253     }
254 }
255 
openInputChannelPair(const std::string & name,sp<InputChannel> & outServerChannel,sp<InputChannel> & outClientChannel)256 status_t InputChannel::openInputChannelPair(const std::string& name,
257         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
258     int sockets[2];
259     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
260         status_t result = -errno;
261         ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
262                 name.c_str(), errno);
263         outServerChannel.clear();
264         outClientChannel.clear();
265         return result;
266     }
267 
268     int bufferSize = SOCKET_BUFFER_SIZE;
269     setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
270     setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
271     setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
272     setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
273 
274     std::string serverChannelName = name;
275     serverChannelName += " (server)";
276     outServerChannel = new InputChannel(serverChannelName, sockets[0]);
277 
278     std::string clientChannelName = name;
279     clientChannelName += " (client)";
280     outClientChannel = new InputChannel(clientChannelName, sockets[1]);
281     return OK;
282 }
283 
sendMessage(const InputMessage * msg)284 status_t InputChannel::sendMessage(const InputMessage* msg) {
285     const size_t msgLength = msg->size();
286     InputMessage cleanMsg;
287     msg->getSanitizedCopy(&cleanMsg);
288     ssize_t nWrite;
289     do {
290         nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
291     } while (nWrite == -1 && errno == EINTR);
292 
293     if (nWrite < 0) {
294         int error = errno;
295 #if DEBUG_CHANNEL_MESSAGES
296         ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(),
297                 msg->header.type, error);
298 #endif
299         if (error == EAGAIN || error == EWOULDBLOCK) {
300             return WOULD_BLOCK;
301         }
302         if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {
303             return DEAD_OBJECT;
304         }
305         return -error;
306     }
307 
308     if (size_t(nWrite) != msgLength) {
309 #if DEBUG_CHANNEL_MESSAGES
310         ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
311                 mName.c_str(), msg->header.type);
312 #endif
313         return DEAD_OBJECT;
314     }
315 
316 #if DEBUG_CHANNEL_MESSAGES
317     ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type);
318 #endif
319     return OK;
320 }
321 
receiveMessage(InputMessage * msg)322 status_t InputChannel::receiveMessage(InputMessage* msg) {
323     ssize_t nRead;
324     do {
325         nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
326     } while (nRead == -1 && errno == EINTR);
327 
328     if (nRead < 0) {
329         int error = errno;
330 #if DEBUG_CHANNEL_MESSAGES
331         ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno);
332 #endif
333         if (error == EAGAIN || error == EWOULDBLOCK) {
334             return WOULD_BLOCK;
335         }
336         if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
337             return DEAD_OBJECT;
338         }
339         return -error;
340     }
341 
342     if (nRead == 0) { // check for EOF
343 #if DEBUG_CHANNEL_MESSAGES
344         ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str());
345 #endif
346         return DEAD_OBJECT;
347     }
348 
349     if (!msg->isValid(nRead)) {
350 #if DEBUG_CHANNEL_MESSAGES
351         ALOGD("channel '%s' ~ received invalid message", mName.c_str());
352 #endif
353         return BAD_VALUE;
354     }
355 
356 #if DEBUG_CHANNEL_MESSAGES
357     ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type);
358 #endif
359     return OK;
360 }
361 
dup() const362 sp<InputChannel> InputChannel::dup() const {
363     int fd = ::dup(getFd());
364     return fd >= 0 ? new InputChannel(getName(), fd) : nullptr;
365 }
366 
367 
write(Parcel & out) const368 status_t InputChannel::write(Parcel& out) const {
369     status_t s = out.writeString8(String8(getName().c_str()));
370 
371     if (s != OK) {
372         return s;
373     }
374     s = out.writeStrongBinder(mToken);
375     if (s != OK) {
376         return s;
377     }
378 
379     s = out.writeDupFileDescriptor(getFd());
380 
381     return s;
382 }
383 
read(const Parcel & from)384 status_t InputChannel::read(const Parcel& from) {
385     mName = from.readString8();
386     mToken = from.readStrongBinder();
387 
388     int rawFd = from.readFileDescriptor();
389     setFd(::dup(rawFd));
390 
391     if (mFd < 0) {
392         return BAD_VALUE;
393     }
394 
395     return OK;
396 }
397 
getToken() const398 sp<IBinder> InputChannel::getToken() const {
399     return mToken;
400 }
401 
setToken(const sp<IBinder> & token)402 void InputChannel::setToken(const sp<IBinder>& token) {
403     if (mToken != nullptr) {
404         ALOGE("Assigning InputChannel (%s) a second handle?", mName.c_str());
405     }
406     mToken = token;
407 }
408 
409 // --- InputPublisher ---
410 
InputPublisher(const sp<InputChannel> & channel)411 InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
412         mChannel(channel) {
413 }
414 
~InputPublisher()415 InputPublisher::~InputPublisher() {
416 }
417 
publishKeyEvent(uint32_t seq,int32_t deviceId,int32_t source,int32_t displayId,int32_t action,int32_t flags,int32_t keyCode,int32_t scanCode,int32_t metaState,int32_t repeatCount,nsecs_t downTime,nsecs_t eventTime)418 status_t InputPublisher::publishKeyEvent(
419         uint32_t seq,
420         int32_t deviceId,
421         int32_t source,
422         int32_t displayId,
423         int32_t action,
424         int32_t flags,
425         int32_t keyCode,
426         int32_t scanCode,
427         int32_t metaState,
428         int32_t repeatCount,
429         nsecs_t downTime,
430         nsecs_t eventTime) {
431     if (ATRACE_ENABLED()) {
432         std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")",
433                 mChannel->getName().c_str(), keyCode);
434         ATRACE_NAME(message.c_str());
435     }
436 #if DEBUG_TRANSPORT_ACTIONS
437     ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
438             "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
439             "downTime=%" PRId64 ", eventTime=%" PRId64,
440             mChannel->getName().c_str(), seq,
441             deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
442             downTime, eventTime);
443 #endif
444 
445     if (!seq) {
446         ALOGE("Attempted to publish a key event with sequence number 0.");
447         return BAD_VALUE;
448     }
449 
450     InputMessage msg;
451     msg.header.type = InputMessage::TYPE_KEY;
452     msg.body.key.seq = seq;
453     msg.body.key.deviceId = deviceId;
454     msg.body.key.source = source;
455     msg.body.key.displayId = displayId;
456     msg.body.key.action = action;
457     msg.body.key.flags = flags;
458     msg.body.key.keyCode = keyCode;
459     msg.body.key.scanCode = scanCode;
460     msg.body.key.metaState = metaState;
461     msg.body.key.repeatCount = repeatCount;
462     msg.body.key.downTime = downTime;
463     msg.body.key.eventTime = eventTime;
464     return mChannel->sendMessage(&msg);
465 }
466 
publishMotionEvent(uint32_t seq,int32_t deviceId,int32_t source,int32_t displayId,int32_t action,int32_t actionButton,int32_t flags,int32_t edgeFlags,int32_t metaState,int32_t buttonState,MotionClassification classification,float xOffset,float yOffset,float xPrecision,float yPrecision,nsecs_t downTime,nsecs_t eventTime,uint32_t pointerCount,const PointerProperties * pointerProperties,const PointerCoords * pointerCoords)467 status_t InputPublisher::publishMotionEvent(
468         uint32_t seq,
469         int32_t deviceId,
470         int32_t source,
471         int32_t displayId,
472         int32_t action,
473         int32_t actionButton,
474         int32_t flags,
475         int32_t edgeFlags,
476         int32_t metaState,
477         int32_t buttonState,
478         MotionClassification classification,
479         float xOffset,
480         float yOffset,
481         float xPrecision,
482         float yPrecision,
483         nsecs_t downTime,
484         nsecs_t eventTime,
485         uint32_t pointerCount,
486         const PointerProperties* pointerProperties,
487         const PointerCoords* pointerCoords) {
488     if (ATRACE_ENABLED()) {
489         std::string message = StringPrintf(
490                 "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",
491                 mChannel->getName().c_str(), action);
492         ATRACE_NAME(message.c_str());
493     }
494 #if DEBUG_TRANSPORT_ACTIONS
495     ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
496             "displayId=%" PRId32 ", "
497             "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
498             "metaState=0x%x, buttonState=0x%x, classification=%s, xOffset=%f, yOffset=%f, "
499             "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
500             "pointerCount=%" PRIu32,
501             mChannel->getName().c_str(), seq,
502             deviceId, source, displayId, action, actionButton, flags, edgeFlags, metaState,
503             buttonState, motionClassificationToString(classification),
504             xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
505 #endif
506 
507     if (!seq) {
508         ALOGE("Attempted to publish a motion event with sequence number 0.");
509         return BAD_VALUE;
510     }
511 
512     if (pointerCount > MAX_POINTERS || pointerCount < 1) {
513         ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".",
514                 mChannel->getName().c_str(), pointerCount);
515         return BAD_VALUE;
516     }
517 
518     InputMessage msg;
519     msg.header.type = InputMessage::TYPE_MOTION;
520     msg.body.motion.seq = seq;
521     msg.body.motion.deviceId = deviceId;
522     msg.body.motion.source = source;
523     msg.body.motion.displayId = displayId;
524     msg.body.motion.action = action;
525     msg.body.motion.actionButton = actionButton;
526     msg.body.motion.flags = flags;
527     msg.body.motion.edgeFlags = edgeFlags;
528     msg.body.motion.metaState = metaState;
529     msg.body.motion.buttonState = buttonState;
530     msg.body.motion.classification = classification;
531     msg.body.motion.xOffset = xOffset;
532     msg.body.motion.yOffset = yOffset;
533     msg.body.motion.xPrecision = xPrecision;
534     msg.body.motion.yPrecision = yPrecision;
535     msg.body.motion.downTime = downTime;
536     msg.body.motion.eventTime = eventTime;
537     msg.body.motion.pointerCount = pointerCount;
538     for (uint32_t i = 0; i < pointerCount; i++) {
539         msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
540         msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
541     }
542     return mChannel->sendMessage(&msg);
543 }
544 
receiveFinishedSignal(uint32_t * outSeq,bool * outHandled)545 status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
546 #if DEBUG_TRANSPORT_ACTIONS
547     ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
548             mChannel->getName().c_str());
549 #endif
550 
551     InputMessage msg;
552     status_t result = mChannel->receiveMessage(&msg);
553     if (result) {
554         *outSeq = 0;
555         *outHandled = false;
556         return result;
557     }
558     if (msg.header.type != InputMessage::TYPE_FINISHED) {
559         ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
560                 mChannel->getName().c_str(), msg.header.type);
561         return UNKNOWN_ERROR;
562     }
563     *outSeq = msg.body.finished.seq;
564     *outHandled = msg.body.finished.handled;
565     return OK;
566 }
567 
568 // --- InputConsumer ---
569 
InputConsumer(const sp<InputChannel> & channel)570 InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
571         mResampleTouch(isTouchResamplingEnabled()),
572         mChannel(channel), mMsgDeferred(false) {
573 }
574 
~InputConsumer()575 InputConsumer::~InputConsumer() {
576 }
577 
isTouchResamplingEnabled()578 bool InputConsumer::isTouchResamplingEnabled() {
579     return property_get_bool(PROPERTY_RESAMPLING_ENABLED, true);
580 }
581 
consume(InputEventFactoryInterface * factory,bool consumeBatches,nsecs_t frameTime,uint32_t * outSeq,InputEvent ** outEvent)582 status_t InputConsumer::consume(InputEventFactoryInterface* factory,
583         bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
584 #if DEBUG_TRANSPORT_ACTIONS
585     ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
586             mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime);
587 #endif
588 
589     *outSeq = 0;
590     *outEvent = nullptr;
591 
592     // Fetch the next input message.
593     // Loop until an event can be returned or no additional events are received.
594     while (!*outEvent) {
595         if (mMsgDeferred) {
596             // mMsg contains a valid input message from the previous call to consume
597             // that has not yet been processed.
598             mMsgDeferred = false;
599         } else {
600             // Receive a fresh message.
601             status_t result = mChannel->receiveMessage(&mMsg);
602             if (result) {
603                 // Consume the next batched event unless batches are being held for later.
604                 if (consumeBatches || result != WOULD_BLOCK) {
605                     result = consumeBatch(factory, frameTime, outSeq, outEvent);
606                     if (*outEvent) {
607 #if DEBUG_TRANSPORT_ACTIONS
608                         ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
609                                 mChannel->getName().c_str(), *outSeq);
610 #endif
611                         break;
612                     }
613                 }
614                 return result;
615             }
616         }
617 
618         switch (mMsg.header.type) {
619         case InputMessage::TYPE_KEY: {
620             KeyEvent* keyEvent = factory->createKeyEvent();
621             if (!keyEvent) return NO_MEMORY;
622 
623             initializeKeyEvent(keyEvent, &mMsg);
624             *outSeq = mMsg.body.key.seq;
625             *outEvent = keyEvent;
626 #if DEBUG_TRANSPORT_ACTIONS
627             ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
628                     mChannel->getName().c_str(), *outSeq);
629 #endif
630             break;
631         }
632 
633         case InputMessage::TYPE_MOTION: {
634             ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
635             if (batchIndex >= 0) {
636                 Batch& batch = mBatches.editItemAt(batchIndex);
637                 if (canAddSample(batch, &mMsg)) {
638                     batch.samples.push(mMsg);
639 #if DEBUG_TRANSPORT_ACTIONS
640                     ALOGD("channel '%s' consumer ~ appended to batch event",
641                             mChannel->getName().c_str());
642 #endif
643                     break;
644                 } else if (isPointerEvent(mMsg.body.motion.source) &&
645                         mMsg.body.motion.action == AMOTION_EVENT_ACTION_CANCEL) {
646                     // No need to process events that we are going to cancel anyways
647                     const size_t count = batch.samples.size();
648                     for (size_t i = 0; i < count; i++) {
649                         const InputMessage& msg = batch.samples.itemAt(i);
650                         sendFinishedSignal(msg.body.motion.seq, false);
651                     }
652                     batch.samples.removeItemsAt(0, count);
653                     mBatches.removeAt(batchIndex);
654                 } else {
655                     // We cannot append to the batch in progress, so we need to consume
656                     // the previous batch right now and defer the new message until later.
657                     mMsgDeferred = true;
658                     status_t result = consumeSamples(factory,
659                             batch, batch.samples.size(), outSeq, outEvent);
660                     mBatches.removeAt(batchIndex);
661                     if (result) {
662                         return result;
663                     }
664 #if DEBUG_TRANSPORT_ACTIONS
665                     ALOGD("channel '%s' consumer ~ consumed batch event and "
666                             "deferred current event, seq=%u",
667                             mChannel->getName().c_str(), *outSeq);
668 #endif
669                     break;
670                 }
671             }
672 
673             // Start a new batch if needed.
674             if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
675                     || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
676                 mBatches.push();
677                 Batch& batch = mBatches.editTop();
678                 batch.samples.push(mMsg);
679 #if DEBUG_TRANSPORT_ACTIONS
680                 ALOGD("channel '%s' consumer ~ started batch event",
681                         mChannel->getName().c_str());
682 #endif
683                 break;
684             }
685 
686             MotionEvent* motionEvent = factory->createMotionEvent();
687             if (! motionEvent) return NO_MEMORY;
688 
689             updateTouchState(mMsg);
690             initializeMotionEvent(motionEvent, &mMsg);
691             *outSeq = mMsg.body.motion.seq;
692             *outEvent = motionEvent;
693 
694 #if DEBUG_TRANSPORT_ACTIONS
695             ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
696                     mChannel->getName().c_str(), *outSeq);
697 #endif
698             break;
699         }
700 
701         default:
702             ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
703                     mChannel->getName().c_str(), mMsg.header.type);
704             return UNKNOWN_ERROR;
705         }
706     }
707     return OK;
708 }
709 
consumeBatch(InputEventFactoryInterface * factory,nsecs_t frameTime,uint32_t * outSeq,InputEvent ** outEvent)710 status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
711         nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
712     status_t result;
713     for (size_t i = mBatches.size(); i > 0; ) {
714         i--;
715         Batch& batch = mBatches.editItemAt(i);
716         if (frameTime < 0) {
717             result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent);
718             mBatches.removeAt(i);
719             return result;
720         }
721 
722         nsecs_t sampleTime = frameTime;
723         if (mResampleTouch) {
724             sampleTime -= RESAMPLE_LATENCY;
725         }
726         ssize_t split = findSampleNoLaterThan(batch, sampleTime);
727         if (split < 0) {
728             continue;
729         }
730 
731         result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
732         const InputMessage* next;
733         if (batch.samples.isEmpty()) {
734             mBatches.removeAt(i);
735             next = nullptr;
736         } else {
737             next = &batch.samples.itemAt(0);
738         }
739         if (!result && mResampleTouch) {
740             resampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next);
741         }
742         return result;
743     }
744 
745     return WOULD_BLOCK;
746 }
747 
consumeSamples(InputEventFactoryInterface * factory,Batch & batch,size_t count,uint32_t * outSeq,InputEvent ** outEvent)748 status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
749         Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
750     MotionEvent* motionEvent = factory->createMotionEvent();
751     if (! motionEvent) return NO_MEMORY;
752 
753     uint32_t chain = 0;
754     for (size_t i = 0; i < count; i++) {
755         InputMessage& msg = batch.samples.editItemAt(i);
756         updateTouchState(msg);
757         if (i) {
758             SeqChain seqChain;
759             seqChain.seq = msg.body.motion.seq;
760             seqChain.chain = chain;
761             mSeqChains.push(seqChain);
762             addSample(motionEvent, &msg);
763         } else {
764             initializeMotionEvent(motionEvent, &msg);
765         }
766         chain = msg.body.motion.seq;
767     }
768     batch.samples.removeItemsAt(0, count);
769 
770     *outSeq = chain;
771     *outEvent = motionEvent;
772     return OK;
773 }
774 
updateTouchState(InputMessage & msg)775 void InputConsumer::updateTouchState(InputMessage& msg) {
776     if (!mResampleTouch || !isPointerEvent(msg.body.motion.source)) {
777         return;
778     }
779 
780     int32_t deviceId = msg.body.motion.deviceId;
781     int32_t source = msg.body.motion.source;
782 
783     // Update the touch state history to incorporate the new input message.
784     // If the message is in the past relative to the most recently produced resampled
785     // touch, then use the resampled time and coordinates instead.
786     switch (msg.body.motion.action & AMOTION_EVENT_ACTION_MASK) {
787     case AMOTION_EVENT_ACTION_DOWN: {
788         ssize_t index = findTouchState(deviceId, source);
789         if (index < 0) {
790             mTouchStates.push();
791             index = mTouchStates.size() - 1;
792         }
793         TouchState& touchState = mTouchStates.editItemAt(index);
794         touchState.initialize(deviceId, source);
795         touchState.addHistory(msg);
796         break;
797     }
798 
799     case AMOTION_EVENT_ACTION_MOVE: {
800         ssize_t index = findTouchState(deviceId, source);
801         if (index >= 0) {
802             TouchState& touchState = mTouchStates.editItemAt(index);
803             touchState.addHistory(msg);
804             rewriteMessage(touchState, msg);
805         }
806         break;
807     }
808 
809     case AMOTION_EVENT_ACTION_POINTER_DOWN: {
810         ssize_t index = findTouchState(deviceId, source);
811         if (index >= 0) {
812             TouchState& touchState = mTouchStates.editItemAt(index);
813             touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
814             rewriteMessage(touchState, msg);
815         }
816         break;
817     }
818 
819     case AMOTION_EVENT_ACTION_POINTER_UP: {
820         ssize_t index = findTouchState(deviceId, source);
821         if (index >= 0) {
822             TouchState& touchState = mTouchStates.editItemAt(index);
823             rewriteMessage(touchState, msg);
824             touchState.lastResample.idBits.clearBit(msg.body.motion.getActionId());
825         }
826         break;
827     }
828 
829     case AMOTION_EVENT_ACTION_SCROLL: {
830         ssize_t index = findTouchState(deviceId, source);
831         if (index >= 0) {
832             TouchState& touchState = mTouchStates.editItemAt(index);
833             rewriteMessage(touchState, msg);
834         }
835         break;
836     }
837 
838     case AMOTION_EVENT_ACTION_UP:
839     case AMOTION_EVENT_ACTION_CANCEL: {
840         ssize_t index = findTouchState(deviceId, source);
841         if (index >= 0) {
842             TouchState& touchState = mTouchStates.editItemAt(index);
843             rewriteMessage(touchState, msg);
844             mTouchStates.removeAt(index);
845         }
846         break;
847     }
848     }
849 }
850 
851 /**
852  * Replace the coordinates in msg with the coordinates in lastResample, if necessary.
853  *
854  * If lastResample is no longer valid for a specific pointer (i.e. the lastResample time
855  * is in the past relative to msg and the past two events do not contain identical coordinates),
856  * then invalidate the lastResample data for that pointer.
857  * If the two past events have identical coordinates, then lastResample data for that pointer will
858  * remain valid, and will be used to replace these coordinates. Thus, if a certain coordinate x0 is
859  * resampled to the new value x1, then x1 will always be used to replace x0 until some new value
860  * not equal to x0 is received.
861  */
rewriteMessage(TouchState & state,InputMessage & msg)862 void InputConsumer::rewriteMessage(TouchState& state, InputMessage& msg) {
863     nsecs_t eventTime = msg.body.motion.eventTime;
864     for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
865         uint32_t id = msg.body.motion.pointers[i].properties.id;
866         if (state.lastResample.idBits.hasBit(id)) {
867             if (eventTime < state.lastResample.eventTime ||
868                     state.recentCoordinatesAreIdentical(id)) {
869                 PointerCoords& msgCoords = msg.body.motion.pointers[i].coords;
870                 const PointerCoords& resampleCoords = state.lastResample.getPointerById(id);
871 #if DEBUG_RESAMPLING
872                 ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
873                         resampleCoords.getX(), resampleCoords.getY(),
874                         msgCoords.getX(), msgCoords.getY());
875 #endif
876                 msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
877                 msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
878             } else {
879                 state.lastResample.idBits.clearBit(id);
880             }
881         }
882     }
883 }
884 
resampleTouchState(nsecs_t sampleTime,MotionEvent * event,const InputMessage * next)885 void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
886     const InputMessage* next) {
887     if (!mResampleTouch
888             || !(isPointerEvent(event->getSource()))
889             || event->getAction() != AMOTION_EVENT_ACTION_MOVE) {
890         return;
891     }
892 
893     ssize_t index = findTouchState(event->getDeviceId(), event->getSource());
894     if (index < 0) {
895 #if DEBUG_RESAMPLING
896         ALOGD("Not resampled, no touch state for device.");
897 #endif
898         return;
899     }
900 
901     TouchState& touchState = mTouchStates.editItemAt(index);
902     if (touchState.historySize < 1) {
903 #if DEBUG_RESAMPLING
904         ALOGD("Not resampled, no history for device.");
905 #endif
906         return;
907     }
908 
909     // Ensure that the current sample has all of the pointers that need to be reported.
910     const History* current = touchState.getHistory(0);
911     size_t pointerCount = event->getPointerCount();
912     for (size_t i = 0; i < pointerCount; i++) {
913         uint32_t id = event->getPointerId(i);
914         if (!current->idBits.hasBit(id)) {
915 #if DEBUG_RESAMPLING
916             ALOGD("Not resampled, missing id %d", id);
917 #endif
918             return;
919         }
920     }
921 
922     // Find the data to use for resampling.
923     const History* other;
924     History future;
925     float alpha;
926     if (next) {
927         // Interpolate between current sample and future sample.
928         // So current->eventTime <= sampleTime <= future.eventTime.
929         future.initializeFrom(*next);
930         other = &future;
931         nsecs_t delta = future.eventTime - current->eventTime;
932         if (delta < RESAMPLE_MIN_DELTA) {
933 #if DEBUG_RESAMPLING
934             ALOGD("Not resampled, delta time is too small: %" PRId64 " ns.", delta);
935 #endif
936             return;
937         }
938         alpha = float(sampleTime - current->eventTime) / delta;
939     } else if (touchState.historySize >= 2) {
940         // Extrapolate future sample using current sample and past sample.
941         // So other->eventTime <= current->eventTime <= sampleTime.
942         other = touchState.getHistory(1);
943         nsecs_t delta = current->eventTime - other->eventTime;
944         if (delta < RESAMPLE_MIN_DELTA) {
945 #if DEBUG_RESAMPLING
946             ALOGD("Not resampled, delta time is too small: %" PRId64 " ns.", delta);
947 #endif
948             return;
949         } else if (delta > RESAMPLE_MAX_DELTA) {
950 #if DEBUG_RESAMPLING
951             ALOGD("Not resampled, delta time is too large: %" PRId64 " ns.", delta);
952 #endif
953             return;
954         }
955         nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION);
956         if (sampleTime > maxPredict) {
957 #if DEBUG_RESAMPLING
958             ALOGD("Sample time is too far in the future, adjusting prediction "
959                     "from %" PRId64 " to %" PRId64 " ns.",
960                     sampleTime - current->eventTime, maxPredict - current->eventTime);
961 #endif
962             sampleTime = maxPredict;
963         }
964         alpha = float(current->eventTime - sampleTime) / delta;
965     } else {
966 #if DEBUG_RESAMPLING
967         ALOGD("Not resampled, insufficient data.");
968 #endif
969         return;
970     }
971 
972     // Resample touch coordinates.
973     History oldLastResample;
974     oldLastResample.initializeFrom(touchState.lastResample);
975     touchState.lastResample.eventTime = sampleTime;
976     touchState.lastResample.idBits.clear();
977     for (size_t i = 0; i < pointerCount; i++) {
978         uint32_t id = event->getPointerId(i);
979         touchState.lastResample.idToIndex[id] = i;
980         touchState.lastResample.idBits.markBit(id);
981         if (oldLastResample.hasPointerId(id) && touchState.recentCoordinatesAreIdentical(id)) {
982             // We maintain the previously resampled value for this pointer (stored in
983             // oldLastResample) when the coordinates for this pointer haven't changed since then.
984             // This way we don't introduce artificial jitter when pointers haven't actually moved.
985 
986             // We know here that the coordinates for the pointer haven't changed because we
987             // would've cleared the resampled bit in rewriteMessage if they had. We can't modify
988             // lastResample in place becasue the mapping from pointer ID to index may have changed.
989             touchState.lastResample.pointers[i].copyFrom(oldLastResample.getPointerById(id));
990             continue;
991         }
992 
993         PointerCoords& resampledCoords = touchState.lastResample.pointers[i];
994         const PointerCoords& currentCoords = current->getPointerById(id);
995         resampledCoords.copyFrom(currentCoords);
996         if (other->idBits.hasBit(id)
997                 && shouldResampleTool(event->getToolType(i))) {
998             const PointerCoords& otherCoords = other->getPointerById(id);
999             resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X,
1000                     lerp(currentCoords.getX(), otherCoords.getX(), alpha));
1001             resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y,
1002                     lerp(currentCoords.getY(), otherCoords.getY(), alpha));
1003 #if DEBUG_RESAMPLING
1004             ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), "
1005                     "other (%0.3f, %0.3f), alpha %0.3f",
1006                     id, resampledCoords.getX(), resampledCoords.getY(),
1007                     currentCoords.getX(), currentCoords.getY(),
1008                     otherCoords.getX(), otherCoords.getY(),
1009                     alpha);
1010 #endif
1011         } else {
1012 #if DEBUG_RESAMPLING
1013             ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)",
1014                     id, resampledCoords.getX(), resampledCoords.getY(),
1015                     currentCoords.getX(), currentCoords.getY());
1016 #endif
1017         }
1018     }
1019 
1020     event->addSample(sampleTime, touchState.lastResample.pointers);
1021 }
1022 
shouldResampleTool(int32_t toolType)1023 bool InputConsumer::shouldResampleTool(int32_t toolType) {
1024     return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
1025             || toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
1026 }
1027 
sendFinishedSignal(uint32_t seq,bool handled)1028 status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
1029 #if DEBUG_TRANSPORT_ACTIONS
1030     ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
1031             mChannel->getName().c_str(), seq, handled ? "true" : "false");
1032 #endif
1033 
1034     if (!seq) {
1035         ALOGE("Attempted to send a finished signal with sequence number 0.");
1036         return BAD_VALUE;
1037     }
1038 
1039     // Send finished signals for the batch sequence chain first.
1040     size_t seqChainCount = mSeqChains.size();
1041     if (seqChainCount) {
1042         uint32_t currentSeq = seq;
1043         uint32_t chainSeqs[seqChainCount];
1044         size_t chainIndex = 0;
1045         for (size_t i = seqChainCount; i > 0; ) {
1046              i--;
1047              const SeqChain& seqChain = mSeqChains.itemAt(i);
1048              if (seqChain.seq == currentSeq) {
1049                  currentSeq = seqChain.chain;
1050                  chainSeqs[chainIndex++] = currentSeq;
1051                  mSeqChains.removeAt(i);
1052              }
1053         }
1054         status_t status = OK;
1055         while (!status && chainIndex > 0) {
1056             chainIndex--;
1057             status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
1058         }
1059         if (status) {
1060             // An error occurred so at least one signal was not sent, reconstruct the chain.
1061             for (;;) {
1062                 SeqChain seqChain;
1063                 seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
1064                 seqChain.chain = chainSeqs[chainIndex];
1065                 mSeqChains.push(seqChain);
1066                 if (!chainIndex) break;
1067                 chainIndex--;
1068             }
1069             return status;
1070         }
1071     }
1072 
1073     // Send finished signal for the last message in the batch.
1074     return sendUnchainedFinishedSignal(seq, handled);
1075 }
1076 
sendUnchainedFinishedSignal(uint32_t seq,bool handled)1077 status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
1078     InputMessage msg;
1079     msg.header.type = InputMessage::TYPE_FINISHED;
1080     msg.body.finished.seq = seq;
1081     msg.body.finished.handled = handled;
1082     return mChannel->sendMessage(&msg);
1083 }
1084 
hasDeferredEvent() const1085 bool InputConsumer::hasDeferredEvent() const {
1086     return mMsgDeferred;
1087 }
1088 
hasPendingBatch() const1089 bool InputConsumer::hasPendingBatch() const {
1090     return !mBatches.isEmpty();
1091 }
1092 
findBatch(int32_t deviceId,int32_t source) const1093 ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
1094     for (size_t i = 0; i < mBatches.size(); i++) {
1095         const Batch& batch = mBatches.itemAt(i);
1096         const InputMessage& head = batch.samples.itemAt(0);
1097         if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) {
1098             return i;
1099         }
1100     }
1101     return -1;
1102 }
1103 
findTouchState(int32_t deviceId,int32_t source) const1104 ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const {
1105     for (size_t i = 0; i < mTouchStates.size(); i++) {
1106         const TouchState& touchState = mTouchStates.itemAt(i);
1107         if (touchState.deviceId == deviceId && touchState.source == source) {
1108             return i;
1109         }
1110     }
1111     return -1;
1112 }
1113 
initializeKeyEvent(KeyEvent * event,const InputMessage * msg)1114 void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
1115     event->initialize(
1116             msg->body.key.deviceId,
1117             msg->body.key.source,
1118             msg->body.key.displayId,
1119             msg->body.key.action,
1120             msg->body.key.flags,
1121             msg->body.key.keyCode,
1122             msg->body.key.scanCode,
1123             msg->body.key.metaState,
1124             msg->body.key.repeatCount,
1125             msg->body.key.downTime,
1126             msg->body.key.eventTime);
1127 }
1128 
initializeMotionEvent(MotionEvent * event,const InputMessage * msg)1129 void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
1130     uint32_t pointerCount = msg->body.motion.pointerCount;
1131     PointerProperties pointerProperties[pointerCount];
1132     PointerCoords pointerCoords[pointerCount];
1133     for (uint32_t i = 0; i < pointerCount; i++) {
1134         pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
1135         pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
1136     }
1137 
1138     event->initialize(
1139             msg->body.motion.deviceId,
1140             msg->body.motion.source,
1141             msg->body.motion.displayId,
1142             msg->body.motion.action,
1143             msg->body.motion.actionButton,
1144             msg->body.motion.flags,
1145             msg->body.motion.edgeFlags,
1146             msg->body.motion.metaState,
1147             msg->body.motion.buttonState,
1148             msg->body.motion.classification,
1149             msg->body.motion.xOffset,
1150             msg->body.motion.yOffset,
1151             msg->body.motion.xPrecision,
1152             msg->body.motion.yPrecision,
1153             msg->body.motion.downTime,
1154             msg->body.motion.eventTime,
1155             pointerCount,
1156             pointerProperties,
1157             pointerCoords);
1158 }
1159 
addSample(MotionEvent * event,const InputMessage * msg)1160 void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
1161     uint32_t pointerCount = msg->body.motion.pointerCount;
1162     PointerCoords pointerCoords[pointerCount];
1163     for (uint32_t i = 0; i < pointerCount; i++) {
1164         pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
1165     }
1166 
1167     event->setMetaState(event->getMetaState() | msg->body.motion.metaState);
1168     event->addSample(msg->body.motion.eventTime, pointerCoords);
1169 }
1170 
canAddSample(const Batch & batch,const InputMessage * msg)1171 bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) {
1172     const InputMessage& head = batch.samples.itemAt(0);
1173     uint32_t pointerCount = msg->body.motion.pointerCount;
1174     if (head.body.motion.pointerCount != pointerCount
1175             || head.body.motion.action != msg->body.motion.action) {
1176         return false;
1177     }
1178     for (size_t i = 0; i < pointerCount; i++) {
1179         if (head.body.motion.pointers[i].properties
1180                 != msg->body.motion.pointers[i].properties) {
1181             return false;
1182         }
1183     }
1184     return true;
1185 }
1186 
findSampleNoLaterThan(const Batch & batch,nsecs_t time)1187 ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, nsecs_t time) {
1188     size_t numSamples = batch.samples.size();
1189     size_t index = 0;
1190     while (index < numSamples
1191             && batch.samples.itemAt(index).body.motion.eventTime <= time) {
1192         index += 1;
1193     }
1194     return ssize_t(index) - 1;
1195 }
1196 
1197 } // namespace android
1198