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