blob: a24180fca55f76df16790d1b68dcebc7d3f0c874 [file] [log] [blame]
Jeff Browne839a582010-04-22 18:58:52 -07001//
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 signalling (send signal, receive signal)
11#define DEBUG_CHANNEL_SIGNALS 1
12
13// Log debug messages whenever InputChannel objects are created/destroyed
14#define DEBUG_CHANNEL_LIFECYCLE 1
15
16// Log debug messages about transport actions (initialize, reset, publish, ...)
17#define DEBUG_TRANSPORT_ACTIONS 1
18
19
20#include <cutils/ashmem.h>
21#include <cutils/log.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <sys/mman.h>
25#include <ui/InputTransport.h>
26#include <unistd.h>
27
28namespace android {
29
30// Must be at least sizeof(InputMessage) + sufficient space for pointer data
31static const int DEFAULT_MESSAGE_BUFFER_SIZE = 16384;
32
33// Signal sent by the producer to the consumer to inform it that a new message is
34// available to be consumed in the shared memory buffer.
35static const char INPUT_SIGNAL_DISPATCH = 'D';
36
37// Signal sent by the consumer to the producer to inform it that it has finished
38// consuming the most recent message.
39static const char INPUT_SIGNAL_FINISHED = 'f';
40
41
42// --- InputChannel ---
43
44InputChannel::InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
45 int32_t sendPipeFd) :
46 mName(name), mAshmemFd(ashmemFd), mReceivePipeFd(receivePipeFd), mSendPipeFd(sendPipeFd) {
47#if DEBUG_CHANNEL_LIFECYCLE
48 LOGD("Input channel constructed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
49 mName.string(), ashmemFd, receivePipeFd, sendPipeFd);
50#endif
51
52 int result = fcntl(mReceivePipeFd, F_SETFL, O_NONBLOCK);
53 LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make receive pipe "
54 "non-blocking. errno=%d", mName.string(), errno);
55
56 result = fcntl(mSendPipeFd, F_SETFL, O_NONBLOCK);
57 LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make send pipe "
58 "non-blocking. errno=%d", mName.string(), errno);
59}
60
61InputChannel::~InputChannel() {
62#if DEBUG_CHANNEL_LIFECYCLE
63 LOGD("Input channel destroyed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
64 mName.string(), mAshmemFd, mReceivePipeFd, mSendPipeFd);
65#endif
66
67 ::close(mAshmemFd);
68 ::close(mReceivePipeFd);
69 ::close(mSendPipeFd);
70}
71
72status_t InputChannel::openInputChannelPair(const String8& name,
73 InputChannel** outServerChannel, InputChannel** outClientChannel) {
74 status_t result;
75
76 int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
77 if (serverAshmemFd < 0) {
78 result = -errno;
79 LOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
80 name.string(), errno);
81 } else {
82 result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE);
83 if (result < 0) {
84 LOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.",
85 name.string(), result, serverAshmemFd);
86 } else {
87 // Dup the file descriptor because the server and client input channel objects that
88 // are returned may have different lifetimes but they share the same shared memory region.
89 int clientAshmemFd;
90 clientAshmemFd = dup(serverAshmemFd);
91 if (clientAshmemFd < 0) {
92 result = -errno;
93 LOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d",
94 name.string(), errno);
95 } else {
96 int forward[2];
97 if (pipe(forward)) {
98 result = -errno;
99 LOGE("channel '%s' ~ Could not create forward pipe. errno=%d",
100 name.string(), errno);
101 } else {
102 int reverse[2];
103 if (pipe(reverse)) {
104 result = -errno;
105 LOGE("channel '%s' ~ Could not create reverse pipe. errno=%d",
106 name.string(), errno);
107 } else {
108 String8 serverChannelName = name;
109 serverChannelName.append(" (server)");
110 *outServerChannel = new InputChannel(serverChannelName,
111 serverAshmemFd, reverse[0], forward[1]);
112
113 String8 clientChannelName = name;
114 clientChannelName.append(" (client)");
115 *outClientChannel = new InputChannel(clientChannelName,
116 clientAshmemFd, forward[0], reverse[1]);
117 return OK;
118 }
119 ::close(forward[0]);
120 ::close(forward[1]);
121 }
122 ::close(clientAshmemFd);
123 }
124 }
125 ::close(serverAshmemFd);
126 }
127
128 *outServerChannel = NULL;
129 *outClientChannel = NULL;
130 return result;
131}
132
133status_t InputChannel::sendSignal(char signal) {
134 ssize_t nWrite = ::write(mSendPipeFd, & signal, 1);
135
136 if (nWrite == 1) {
137#if DEBUG_CHANNEL_SIGNALS
138 LOGD("channel '%s' ~ sent signal '%c'", mName.string(), signal);
139#endif
140 return OK;
141 }
142
143#if DEBUG_CHANNEL_SIGNALS
144 LOGD("channel '%s' ~ error sending signal '%c', errno=%d", mName.string(), signal, errno);
145#endif
146 return -errno;
147}
148
149status_t InputChannel::receiveSignal(char* outSignal) {
150 ssize_t nRead = ::read(mReceivePipeFd, outSignal, 1);
151 if (nRead == 1) {
152#if DEBUG_CHANNEL_SIGNALS
153 LOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal);
154#endif
155 return OK;
156 }
157
158 if (errno == EAGAIN) {
159#if DEBUG_CHANNEL_SIGNALS
160 LOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
161#endif
162 return WOULD_BLOCK;
163 }
164
165#if DEBUG_CHANNEL_SIGNALS
166 LOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno);
167#endif
168 return -errno;
169}
170
171
172// --- InputPublisher ---
173
174InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
175 mChannel(channel), mSharedMessage(NULL),
176 mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
177 mMotionEventSampleDataTail(NULL) {
178}
179
180InputPublisher::~InputPublisher() {
181 reset();
182
183 if (mSharedMessage) {
184 munmap(mSharedMessage, mAshmemSize);
185 }
186}
187
188status_t InputPublisher::initialize() {
189#if DEBUG_TRANSPORT_ACTIONS
190 LOGD("channel '%s' publisher ~ initialize",
191 mChannel->getName().string());
192#endif
193
194 int ashmemFd = mChannel->getAshmemFd();
195 int result = ashmem_get_size_region(ashmemFd);
196 if (result < 0) {
197 LOGE("channel '%s' publisher ~ Error %d getting size of ashmem fd %d.",
198 mChannel->getName().string(), result, ashmemFd);
199 return UNKNOWN_ERROR;
200 }
201 mAshmemSize = (size_t) result;
202
203 mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
204 PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
205 if (! mSharedMessage) {
206 LOGE("channel '%s' publisher ~ mmap failed on ashmem fd %d.",
207 mChannel->getName().string(), ashmemFd);
208 return NO_MEMORY;
209 }
210
211 mPinned = true;
212 mSharedMessage->consumed = false;
213
214 return reset();
215}
216
217status_t InputPublisher::reset() {
218#if DEBUG_TRANSPORT_ACTIONS
219 LOGD("channel '%s' publisher ~ reset",
220 mChannel->getName().string());
221#endif
222
223 if (mPinned) {
224 // Destroy the semaphore since we are about to unpin the memory region that contains it.
225 int result;
226 if (mSemaphoreInitialized) {
227 if (mSharedMessage->consumed) {
228 result = sem_post(& mSharedMessage->semaphore);
229 if (result < 0) {
230 LOGE("channel '%s' publisher ~ Error %d in sem_post.",
231 mChannel->getName().string(), errno);
232 return UNKNOWN_ERROR;
233 }
234 }
235
236 result = sem_destroy(& mSharedMessage->semaphore);
237 if (result < 0) {
238 LOGE("channel '%s' publisher ~ Error %d in sem_destroy.",
239 mChannel->getName().string(), errno);
240 return UNKNOWN_ERROR;
241 }
242
243 mSemaphoreInitialized = false;
244 }
245
246 // Unpin the region since we no longer care about its contents.
247 int ashmemFd = mChannel->getAshmemFd();
248 result = ashmem_unpin_region(ashmemFd, 0, 0);
249 if (result < 0) {
250 LOGE("channel '%s' publisher ~ Error %d unpinning ashmem fd %d.",
251 mChannel->getName().string(), result, ashmemFd);
252 return UNKNOWN_ERROR;
253 }
254
255 mPinned = false;
256 }
257
258 mMotionEventSampleDataTail = NULL;
259 mWasDispatched = false;
260 return OK;
261}
262
263status_t InputPublisher::publishInputEvent(
264 int32_t type,
265 int32_t deviceId,
266 int32_t nature) {
267 if (mPinned) {
268 LOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has "
269 "not yet been reset.", mChannel->getName().string());
270 return INVALID_OPERATION;
271 }
272
273 // Pin the region.
274 // We do not check for ASHMEM_NOT_PURGED because we don't care about the previous
275 // contents of the buffer so it does not matter whether it was purged in the meantime.
276 int ashmemFd = mChannel->getAshmemFd();
277 int result = ashmem_pin_region(ashmemFd, 0, 0);
278 if (result < 0) {
279 LOGE("channel '%s' publisher ~ Error %d pinning ashmem fd %d.",
280 mChannel->getName().string(), result, ashmemFd);
281 return UNKNOWN_ERROR;
282 }
283
284 mPinned = true;
285
286 result = sem_init(& mSharedMessage->semaphore, 1, 1);
287 if (result < 0) {
288 LOGE("channel '%s' publisher ~ Error %d in sem_init.",
289 mChannel->getName().string(), errno);
290 return UNKNOWN_ERROR;
291 }
292
293 mSemaphoreInitialized = true;
294
295 mSharedMessage->consumed = false;
296 mSharedMessage->type = type;
297 mSharedMessage->deviceId = deviceId;
298 mSharedMessage->nature = nature;
299 return OK;
300}
301
302status_t InputPublisher::publishKeyEvent(
303 int32_t deviceId,
304 int32_t nature,
305 int32_t action,
306 int32_t flags,
307 int32_t keyCode,
308 int32_t scanCode,
309 int32_t metaState,
310 int32_t repeatCount,
311 nsecs_t downTime,
312 nsecs_t eventTime) {
313#if DEBUG_TRANSPORT_ACTIONS
314 LOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, nature=%d, "
315 "action=%d, flags=%d, keyCode=%d, scanCode=%d, metaState=%d, repeatCount=%d,"
316 "downTime=%lld, eventTime=%lld",
317 mChannel->getName().string(),
318 deviceId, nature, action, flags, keyCode, scanCode, metaState, repeatCount,
319 downTime, eventTime);
320#endif
321
322 status_t result = publishInputEvent(INPUT_EVENT_TYPE_KEY, deviceId, nature);
323 if (result < 0) {
324 return result;
325 }
326
327 mSharedMessage->key.action = action;
328 mSharedMessage->key.flags = flags;
329 mSharedMessage->key.keyCode = keyCode;
330 mSharedMessage->key.scanCode = scanCode;
331 mSharedMessage->key.metaState = metaState;
332 mSharedMessage->key.repeatCount = repeatCount;
333 mSharedMessage->key.downTime = downTime;
334 mSharedMessage->key.eventTime = eventTime;
335 return OK;
336}
337
338status_t InputPublisher::publishMotionEvent(
339 int32_t deviceId,
340 int32_t nature,
341 int32_t action,
342 int32_t edgeFlags,
343 int32_t metaState,
344 float xOffset,
345 float yOffset,
346 float xPrecision,
347 float yPrecision,
348 nsecs_t downTime,
349 nsecs_t eventTime,
350 size_t pointerCount,
351 const int32_t* pointerIds,
352 const PointerCoords* pointerCoords) {
353#if DEBUG_TRANSPORT_ACTIONS
354 LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, nature=%d, "
355 "action=%d, edgeFlags=%d, metaState=%d, xOffset=%f, yOffset=%f, "
356 "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
357 "pointerCount=%d",
358 mChannel->getName().string(),
359 deviceId, nature, action, edgeFlags, metaState, xOffset, yOffset,
360 xPrecision, yPrecision, downTime, eventTime, pointerCount);
361#endif
362
363 if (pointerCount > MAX_POINTERS || pointerCount < 1) {
364 LOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
365 mChannel->getName().string(), pointerCount);
366 return BAD_VALUE;
367 }
368
369 status_t result = publishInputEvent(INPUT_EVENT_TYPE_MOTION, deviceId, nature);
370 if (result < 0) {
371 return result;
372 }
373
374 mSharedMessage->motion.action = action;
375 mSharedMessage->motion.edgeFlags = edgeFlags;
376 mSharedMessage->motion.metaState = metaState;
377 mSharedMessage->motion.xOffset = xOffset;
378 mSharedMessage->motion.yOffset = yOffset;
379 mSharedMessage->motion.xPrecision = xPrecision;
380 mSharedMessage->motion.yPrecision = yPrecision;
381 mSharedMessage->motion.downTime = downTime;
382 mSharedMessage->motion.pointerCount = pointerCount;
383
384 mSharedMessage->motion.sampleCount = 1;
385 mSharedMessage->motion.sampleData[0].eventTime = eventTime;
386
387 for (size_t i = 0; i < pointerCount; i++) {
388 mSharedMessage->motion.pointerIds[i] = pointerIds[i];
389 mSharedMessage->motion.sampleData[0].coords[i] = pointerCoords[i];
390 }
391
392 // Cache essential information about the motion event to ensure that a malicious consumer
393 // cannot confuse the publisher by modifying the contents of the shared memory buffer while
394 // it is being updated.
395 if (action == MOTION_EVENT_ACTION_MOVE) {
396 mMotionEventPointerCount = pointerCount;
397 mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
398 mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
399 mSharedMessage->motion.sampleData, mMotionEventSampleDataStride);
400 } else {
401 mMotionEventSampleDataTail = NULL;
402 }
403 return OK;
404}
405
406status_t InputPublisher::appendMotionSample(
407 nsecs_t eventTime,
408 const PointerCoords* pointerCoords) {
409#if DEBUG_TRANSPORT_ACTIONS
410 LOGD("channel '%s' publisher ~ appendMotionSample: eventTime=%lld",
411 mChannel->getName().string(), eventTime);
412#endif
413
414 if (! mPinned || ! mMotionEventSampleDataTail) {
415 LOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
416 "MOTION_EVENT_ACTION_MOVE event.", mChannel->getName().string());
417 return INVALID_OPERATION;
418 }
419
420 InputMessage::SampleData* newTail = InputMessage::sampleDataPtrIncrement(
421 mMotionEventSampleDataTail, mMotionEventSampleDataStride);
422 size_t newBytesUsed = reinterpret_cast<char*>(newTail) -
423 reinterpret_cast<char*>(mSharedMessage);
424
425 if (newBytesUsed > mAshmemSize) {
426 LOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory "
427 "buffer is full. Buffer size: %d bytes, pointers: %d, samples: %d",
428 mChannel->getName().string(),
429 mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount);
430 return NO_MEMORY;
431 }
432
433 int result;
434 if (mWasDispatched) {
435 result = sem_trywait(& mSharedMessage->semaphore);
436 if (result < 0) {
437 if (errno == EAGAIN) {
438 // Only possible source of contention is the consumer having consumed (or being in the
439 // process of consuming) the message and left the semaphore count at 0.
440 LOGD("channel '%s' publisher ~ Cannot append motion sample because the message has "
441 "already been consumed.", mChannel->getName().string());
442 return FAILED_TRANSACTION;
443 } else {
444 LOGE("channel '%s' publisher ~ Error %d in sem_trywait.",
445 mChannel->getName().string(), errno);
446 return UNKNOWN_ERROR;
447 }
448 }
449 }
450
451 mMotionEventSampleDataTail->eventTime = eventTime;
452 for (size_t i = 0; i < mMotionEventPointerCount; i++) {
453 mMotionEventSampleDataTail->coords[i] = pointerCoords[i];
454 }
455 mMotionEventSampleDataTail = newTail;
456
457 mSharedMessage->motion.sampleCount += 1;
458
459 if (mWasDispatched) {
460 result = sem_post(& mSharedMessage->semaphore);
461 if (result < 0) {
462 LOGE("channel '%s' publisher ~ Error %d in sem_post.",
463 mChannel->getName().string(), errno);
464 return UNKNOWN_ERROR;
465 }
466 }
467 return OK;
468}
469
470status_t InputPublisher::sendDispatchSignal() {
471#if DEBUG_TRANSPORT_ACTIONS
472 LOGD("channel '%s' publisher ~ sendDispatchSignal",
473 mChannel->getName().string());
474#endif
475
476 mWasDispatched = true;
477 return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
478}
479
480status_t InputPublisher::receiveFinishedSignal() {
481#if DEBUG_TRANSPORT_ACTIONS
482 LOGD("channel '%s' publisher ~ receiveFinishedSignal",
483 mChannel->getName().string());
484#endif
485
486 char signal;
487 status_t result = mChannel->receiveSignal(& signal);
488 if (result) {
489 return result;
490 }
491 if (signal != INPUT_SIGNAL_FINISHED) {
492 LOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
493 mChannel->getName().string(), signal);
494 return UNKNOWN_ERROR;
495 }
496 return OK;
497}
498
499// --- InputConsumer ---
500
501InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
502 mChannel(channel), mSharedMessage(NULL) {
503}
504
505InputConsumer::~InputConsumer() {
506 if (mSharedMessage) {
507 munmap(mSharedMessage, mAshmemSize);
508 }
509}
510
511status_t InputConsumer::initialize() {
512#if DEBUG_TRANSPORT_ACTIONS
513 LOGD("channel '%s' consumer ~ initialize",
514 mChannel->getName().string());
515#endif
516
517 int ashmemFd = mChannel->getAshmemFd();
518 int result = ashmem_get_size_region(ashmemFd);
519 if (result < 0) {
520 LOGE("channel '%s' consumer ~ Error %d getting size of ashmem fd %d.",
521 mChannel->getName().string(), result, ashmemFd);
522 return UNKNOWN_ERROR;
523 }
524
525 mAshmemSize = (size_t) result;
526
527 mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
528 PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
529 if (! mSharedMessage) {
530 LOGE("channel '%s' consumer ~ mmap failed on ashmem fd %d.",
531 mChannel->getName().string(), ashmemFd);
532 return NO_MEMORY;
533 }
534
535 return OK;
536}
537
538status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** event) {
539#if DEBUG_TRANSPORT_ACTIONS
540 LOGD("channel '%s' consumer ~ consume",
541 mChannel->getName().string());
542#endif
543
544 *event = NULL;
545
546 int ashmemFd = mChannel->getAshmemFd();
547 int result = ashmem_pin_region(ashmemFd, 0, 0);
548 if (result != ASHMEM_NOT_PURGED) {
549 if (result == ASHMEM_WAS_PURGED) {
550 LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "
551 "which probably indicates that the publisher and consumer are out of sync.",
552 mChannel->getName().string(), result, ashmemFd);
553 return INVALID_OPERATION;
554 }
555
556 LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
557 mChannel->getName().string(), result, ashmemFd);
558 return UNKNOWN_ERROR;
559 }
560
561 if (mSharedMessage->consumed) {
562 LOGE("channel '%s' consumer ~ The current message has already been consumed.",
563 mChannel->getName().string());
564 return INVALID_OPERATION;
565 }
566
567 // Acquire but *never release* the semaphore. Contention on the semaphore is used to signal
568 // to the publisher that the message has been consumed (or is in the process of being
569 // consumed). Eventually the publisher will reinitialize the semaphore for the next message.
570 result = sem_wait(& mSharedMessage->semaphore);
571 if (result < 0) {
572 LOGE("channel '%s' consumer ~ Error %d in sem_wait.",
573 mChannel->getName().string(), errno);
574 return UNKNOWN_ERROR;
575 }
576
577 mSharedMessage->consumed = true;
578
579 switch (mSharedMessage->type) {
580 case INPUT_EVENT_TYPE_KEY: {
581 KeyEvent* keyEvent = factory->createKeyEvent();
582 if (! keyEvent) return NO_MEMORY;
583
584 populateKeyEvent(keyEvent);
585
586 *event = keyEvent;
587 break;
588 }
589
590 case INPUT_EVENT_TYPE_MOTION: {
591 MotionEvent* motionEvent = factory->createMotionEvent();
592 if (! motionEvent) return NO_MEMORY;
593
594 populateMotionEvent(motionEvent);
595
596 *event = motionEvent;
597 break;
598 }
599
600 default:
601 LOGE("channel '%s' consumer ~ Received message of unknown type %d",
602 mChannel->getName().string(), mSharedMessage->type);
603 return UNKNOWN_ERROR;
604 }
605
606 return OK;
607}
608
609status_t InputConsumer::sendFinishedSignal() {
610#if DEBUG_TRANSPORT_ACTIONS
611 LOGD("channel '%s' consumer ~ sendFinishedSignal",
612 mChannel->getName().string());
613#endif
614
615 return mChannel->sendSignal(INPUT_SIGNAL_FINISHED);
616}
617
618status_t InputConsumer::receiveDispatchSignal() {
619#if DEBUG_TRANSPORT_ACTIONS
620 LOGD("channel '%s' consumer ~ receiveDispatchSignal",
621 mChannel->getName().string());
622#endif
623
624 char signal;
625 status_t result = mChannel->receiveSignal(& signal);
626 if (result) {
627 return result;
628 }
629 if (signal != INPUT_SIGNAL_DISPATCH) {
630 LOGE("channel '%s' consumer ~ Received unexpected signal '%c' from publisher",
631 mChannel->getName().string(), signal);
632 return UNKNOWN_ERROR;
633 }
634 return OK;
635}
636
637void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const {
638 keyEvent->initialize(
639 mSharedMessage->deviceId,
640 mSharedMessage->nature,
641 mSharedMessage->key.action,
642 mSharedMessage->key.flags,
643 mSharedMessage->key.keyCode,
644 mSharedMessage->key.scanCode,
645 mSharedMessage->key.metaState,
646 mSharedMessage->key.repeatCount,
647 mSharedMessage->key.downTime,
648 mSharedMessage->key.eventTime);
649}
650
651void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
652 motionEvent->initialize(
653 mSharedMessage->deviceId,
654 mSharedMessage->nature,
655 mSharedMessage->motion.action,
656 mSharedMessage->motion.edgeFlags,
657 mSharedMessage->motion.metaState,
658 mSharedMessage->motion.sampleData[0].coords[0].x,
659 mSharedMessage->motion.sampleData[0].coords[0].y,
660 mSharedMessage->motion.xPrecision,
661 mSharedMessage->motion.yPrecision,
662 mSharedMessage->motion.downTime,
663 mSharedMessage->motion.sampleData[0].eventTime,
664 mSharedMessage->motion.pointerCount,
665 mSharedMessage->motion.pointerIds,
666 mSharedMessage->motion.sampleData[0].coords);
667
668 size_t sampleCount = mSharedMessage->motion.sampleCount;
669 if (sampleCount > 1) {
670 InputMessage::SampleData* sampleData = mSharedMessage->motion.sampleData;
671 size_t sampleDataStride = InputMessage::sampleDataStride(
672 mSharedMessage->motion.pointerCount);
673
674 while (--sampleCount > 0) {
675 sampleData = InputMessage::sampleDataPtrIncrement(sampleData, sampleDataStride);
676 motionEvent->addSample(sampleData->eventTime, sampleData->coords);
677 }
678 }
679
680 motionEvent->offsetLocation(mSharedMessage->motion.xOffset,
681 mSharedMessage->motion.yOffset);
682}
683
684} // namespace android