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