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 #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 
     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 
     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 
     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 
    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 
    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 
    200 InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
    201         mChannel(channel), mSharedMessage(NULL),
    202         mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
    203         mMotionEventSampleDataTail(NULL) {
    204 }
    205 
    206 InputPublisher::~InputPublisher() {
    207     reset();
    208 
    209     if (mSharedMessage) {
    210         munmap(mSharedMessage, mAshmemSize);
    211     }
    212 }
    213 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    543 InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
    544         mChannel(channel), mSharedMessage(NULL) {
    545 }
    546 
    547 InputConsumer::~InputConsumer() {
    548     if (mSharedMessage) {
    549         munmap(mSharedMessage, mAshmemSize);
    550     }
    551 }
    552 
    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 
    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 
    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 
    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 
    681 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 
    695 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