blob: 4c402dc0202e329bef21e9894362c0f096e88c14 [file] [log] [blame]
Jeff Brown46b9ac02010-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)
Jeff Brown5c225b12010-06-16 01:53:36 -070011#define DEBUG_CHANNEL_SIGNALS 0
Jeff Brown46b9ac02010-04-22 18:58:52 -070012
13// Log debug messages whenever InputChannel objects are created/destroyed
Jeff Brown5c225b12010-06-16 01:53:36 -070014#define DEBUG_CHANNEL_LIFECYCLE 0
Jeff Brown46b9ac02010-04-22 18:58:52 -070015
16// Log debug messages about transport actions (initialize, reset, publish, ...)
Jeff Brown5c225b12010-06-16 01:53:36 -070017#define DEBUG_TRANSPORT_ACTIONS 0
Jeff Brown46b9ac02010-04-22 18:58:52 -070018
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,
Jeff Brown5c225b12010-06-16 01:53:36 -070073 sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
Jeff Brown46b9ac02010-04-22 18:58:52 -070074 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)");
Jeff Brown5c225b12010-06-16 01:53:36 -0700110 outServerChannel = new InputChannel(serverChannelName,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700111 serverAshmemFd, reverse[0], forward[1]);
112
113 String8 clientChannelName = name;
114 clientChannelName.append(" (client)");
Jeff Brown5c225b12010-06-16 01:53:36 -0700115 outClientChannel = new InputChannel(clientChannelName,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700116 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
Jeff Brown5c225b12010-06-16 01:53:36 -0700128 outServerChannel.clear();
129 outClientChannel.clear();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700130 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
Jeff Brown5c225b12010-06-16 01:53:36 -0700158 if (nRead == 0) { // check for EOF
159#if DEBUG_CHANNEL_SIGNALS
160 LOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string());
161#endif
162 return DEAD_OBJECT;
163 }
164
Jeff Brown46b9ac02010-04-22 18:58:52 -0700165 if (errno == EAGAIN) {
166#if DEBUG_CHANNEL_SIGNALS
167 LOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
168#endif
169 return WOULD_BLOCK;
170 }
171
172#if DEBUG_CHANNEL_SIGNALS
173 LOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno);
174#endif
175 return -errno;
176}
177
178
179// --- InputPublisher ---
180
181InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
182 mChannel(channel), mSharedMessage(NULL),
183 mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
184 mMotionEventSampleDataTail(NULL) {
185}
186
187InputPublisher::~InputPublisher() {
188 reset();
189
190 if (mSharedMessage) {
191 munmap(mSharedMessage, mAshmemSize);
192 }
193}
194
195status_t InputPublisher::initialize() {
196#if DEBUG_TRANSPORT_ACTIONS
197 LOGD("channel '%s' publisher ~ initialize",
198 mChannel->getName().string());
199#endif
200
201 int ashmemFd = mChannel->getAshmemFd();
202 int result = ashmem_get_size_region(ashmemFd);
203 if (result < 0) {
204 LOGE("channel '%s' publisher ~ Error %d getting size of ashmem fd %d.",
205 mChannel->getName().string(), result, ashmemFd);
206 return UNKNOWN_ERROR;
207 }
208 mAshmemSize = (size_t) result;
209
210 mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
211 PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
212 if (! mSharedMessage) {
213 LOGE("channel '%s' publisher ~ mmap failed on ashmem fd %d.",
214 mChannel->getName().string(), ashmemFd);
215 return NO_MEMORY;
216 }
217
218 mPinned = true;
219 mSharedMessage->consumed = false;
220
221 return reset();
222}
223
224status_t InputPublisher::reset() {
225#if DEBUG_TRANSPORT_ACTIONS
226 LOGD("channel '%s' publisher ~ reset",
227 mChannel->getName().string());
228#endif
229
230 if (mPinned) {
231 // Destroy the semaphore since we are about to unpin the memory region that contains it.
232 int result;
233 if (mSemaphoreInitialized) {
234 if (mSharedMessage->consumed) {
235 result = sem_post(& mSharedMessage->semaphore);
236 if (result < 0) {
237 LOGE("channel '%s' publisher ~ Error %d in sem_post.",
238 mChannel->getName().string(), errno);
239 return UNKNOWN_ERROR;
240 }
241 }
242
243 result = sem_destroy(& mSharedMessage->semaphore);
244 if (result < 0) {
245 LOGE("channel '%s' publisher ~ Error %d in sem_destroy.",
246 mChannel->getName().string(), errno);
247 return UNKNOWN_ERROR;
248 }
249
250 mSemaphoreInitialized = false;
251 }
252
253 // Unpin the region since we no longer care about its contents.
254 int ashmemFd = mChannel->getAshmemFd();
255 result = ashmem_unpin_region(ashmemFd, 0, 0);
256 if (result < 0) {
257 LOGE("channel '%s' publisher ~ Error %d unpinning ashmem fd %d.",
258 mChannel->getName().string(), result, ashmemFd);
259 return UNKNOWN_ERROR;
260 }
261
262 mPinned = false;
263 }
264
265 mMotionEventSampleDataTail = NULL;
266 mWasDispatched = false;
267 return OK;
268}
269
270status_t InputPublisher::publishInputEvent(
271 int32_t type,
272 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700273 int32_t source) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700274 if (mPinned) {
275 LOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has "
276 "not yet been reset.", mChannel->getName().string());
277 return INVALID_OPERATION;
278 }
279
280 // Pin the region.
281 // We do not check for ASHMEM_NOT_PURGED because we don't care about the previous
282 // contents of the buffer so it does not matter whether it was purged in the meantime.
283 int ashmemFd = mChannel->getAshmemFd();
284 int result = ashmem_pin_region(ashmemFd, 0, 0);
285 if (result < 0) {
286 LOGE("channel '%s' publisher ~ Error %d pinning ashmem fd %d.",
287 mChannel->getName().string(), result, ashmemFd);
288 return UNKNOWN_ERROR;
289 }
290
291 mPinned = true;
292
293 result = sem_init(& mSharedMessage->semaphore, 1, 1);
294 if (result < 0) {
295 LOGE("channel '%s' publisher ~ Error %d in sem_init.",
296 mChannel->getName().string(), errno);
297 return UNKNOWN_ERROR;
298 }
299
300 mSemaphoreInitialized = true;
301
302 mSharedMessage->consumed = false;
303 mSharedMessage->type = type;
304 mSharedMessage->deviceId = deviceId;
Jeff Brownc5ed5912010-07-14 18:48:53 -0700305 mSharedMessage->source = source;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700306 return OK;
307}
308
309status_t InputPublisher::publishKeyEvent(
310 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700311 int32_t source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700312 int32_t action,
313 int32_t flags,
314 int32_t keyCode,
315 int32_t scanCode,
316 int32_t metaState,
317 int32_t repeatCount,
318 nsecs_t downTime,
319 nsecs_t eventTime) {
320#if DEBUG_TRANSPORT_ACTIONS
Jeff Brown85a31762010-09-01 17:01:00 -0700321 LOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=0x%x, "
322 "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
Jeff Brown46b9ac02010-04-22 18:58:52 -0700323 "downTime=%lld, eventTime=%lld",
324 mChannel->getName().string(),
Jeff Brownc5ed5912010-07-14 18:48:53 -0700325 deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700326 downTime, eventTime);
327#endif
328
Jeff Brownc5ed5912010-07-14 18:48:53 -0700329 status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700330 if (result < 0) {
331 return result;
332 }
333
334 mSharedMessage->key.action = action;
335 mSharedMessage->key.flags = flags;
336 mSharedMessage->key.keyCode = keyCode;
337 mSharedMessage->key.scanCode = scanCode;
338 mSharedMessage->key.metaState = metaState;
339 mSharedMessage->key.repeatCount = repeatCount;
340 mSharedMessage->key.downTime = downTime;
341 mSharedMessage->key.eventTime = eventTime;
342 return OK;
343}
344
345status_t InputPublisher::publishMotionEvent(
346 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700347 int32_t source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700348 int32_t action,
Jeff Brown85a31762010-09-01 17:01:00 -0700349 int32_t flags,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700350 int32_t edgeFlags,
351 int32_t metaState,
352 float xOffset,
353 float yOffset,
354 float xPrecision,
355 float yPrecision,
356 nsecs_t downTime,
357 nsecs_t eventTime,
358 size_t pointerCount,
359 const int32_t* pointerIds,
360 const PointerCoords* pointerCoords) {
361#if DEBUG_TRANSPORT_ACTIONS
Jeff Brown85a31762010-09-01 17:01:00 -0700362 LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
363 "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, xOffset=%f, yOffset=%f, "
Jeff Brown46b9ac02010-04-22 18:58:52 -0700364 "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
365 "pointerCount=%d",
366 mChannel->getName().string(),
Jeff Brown85a31762010-09-01 17:01:00 -0700367 deviceId, source, action, flags, edgeFlags, metaState, xOffset, yOffset,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700368 xPrecision, yPrecision, downTime, eventTime, pointerCount);
369#endif
370
371 if (pointerCount > MAX_POINTERS || pointerCount < 1) {
372 LOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
373 mChannel->getName().string(), pointerCount);
374 return BAD_VALUE;
375 }
376
Jeff Brownc5ed5912010-07-14 18:48:53 -0700377 status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700378 if (result < 0) {
379 return result;
380 }
381
382 mSharedMessage->motion.action = action;
Jeff Brown85a31762010-09-01 17:01:00 -0700383 mSharedMessage->motion.flags = flags;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700384 mSharedMessage->motion.edgeFlags = edgeFlags;
385 mSharedMessage->motion.metaState = metaState;
386 mSharedMessage->motion.xOffset = xOffset;
387 mSharedMessage->motion.yOffset = yOffset;
388 mSharedMessage->motion.xPrecision = xPrecision;
389 mSharedMessage->motion.yPrecision = yPrecision;
390 mSharedMessage->motion.downTime = downTime;
391 mSharedMessage->motion.pointerCount = pointerCount;
392
393 mSharedMessage->motion.sampleCount = 1;
394 mSharedMessage->motion.sampleData[0].eventTime = eventTime;
395
396 for (size_t i = 0; i < pointerCount; i++) {
397 mSharedMessage->motion.pointerIds[i] = pointerIds[i];
398 mSharedMessage->motion.sampleData[0].coords[i] = pointerCoords[i];
399 }
400
401 // Cache essential information about the motion event to ensure that a malicious consumer
402 // cannot confuse the publisher by modifying the contents of the shared memory buffer while
403 // it is being updated.
Jeff Brownc5ed5912010-07-14 18:48:53 -0700404 if (action == AMOTION_EVENT_ACTION_MOVE) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700405 mMotionEventPointerCount = pointerCount;
406 mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
407 mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
408 mSharedMessage->motion.sampleData, mMotionEventSampleDataStride);
409 } else {
410 mMotionEventSampleDataTail = NULL;
411 }
412 return OK;
413}
414
415status_t InputPublisher::appendMotionSample(
416 nsecs_t eventTime,
417 const PointerCoords* pointerCoords) {
418#if DEBUG_TRANSPORT_ACTIONS
419 LOGD("channel '%s' publisher ~ appendMotionSample: eventTime=%lld",
420 mChannel->getName().string(), eventTime);
421#endif
422
423 if (! mPinned || ! mMotionEventSampleDataTail) {
424 LOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
Jeff Brownc5ed5912010-07-14 18:48:53 -0700425 "AMOTION_EVENT_ACTION_MOVE event.", mChannel->getName().string());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700426 return INVALID_OPERATION;
427 }
428
429 InputMessage::SampleData* newTail = InputMessage::sampleDataPtrIncrement(
430 mMotionEventSampleDataTail, mMotionEventSampleDataStride);
431 size_t newBytesUsed = reinterpret_cast<char*>(newTail) -
432 reinterpret_cast<char*>(mSharedMessage);
433
434 if (newBytesUsed > mAshmemSize) {
Jeff Brown349703e2010-06-22 01:27:15 -0700435#if DEBUG_TRANSPORT_ACTIONS
Jeff Brown46b9ac02010-04-22 18:58:52 -0700436 LOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory "
437 "buffer is full. Buffer size: %d bytes, pointers: %d, samples: %d",
438 mChannel->getName().string(),
439 mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount);
Jeff Brown349703e2010-06-22 01:27:15 -0700440#endif
Jeff Brown46b9ac02010-04-22 18:58:52 -0700441 return NO_MEMORY;
442 }
443
444 int result;
445 if (mWasDispatched) {
446 result = sem_trywait(& mSharedMessage->semaphore);
447 if (result < 0) {
448 if (errno == EAGAIN) {
449 // Only possible source of contention is the consumer having consumed (or being in the
450 // process of consuming) the message and left the semaphore count at 0.
Jeff Brown349703e2010-06-22 01:27:15 -0700451#if DEBUG_TRANSPORT_ACTIONS
Jeff Brown46b9ac02010-04-22 18:58:52 -0700452 LOGD("channel '%s' publisher ~ Cannot append motion sample because the message has "
453 "already been consumed.", mChannel->getName().string());
Jeff Brown349703e2010-06-22 01:27:15 -0700454#endif
Jeff Brown46b9ac02010-04-22 18:58:52 -0700455 return FAILED_TRANSACTION;
456 } else {
457 LOGE("channel '%s' publisher ~ Error %d in sem_trywait.",
458 mChannel->getName().string(), errno);
459 return UNKNOWN_ERROR;
460 }
461 }
462 }
463
464 mMotionEventSampleDataTail->eventTime = eventTime;
465 for (size_t i = 0; i < mMotionEventPointerCount; i++) {
466 mMotionEventSampleDataTail->coords[i] = pointerCoords[i];
467 }
468 mMotionEventSampleDataTail = newTail;
469
470 mSharedMessage->motion.sampleCount += 1;
471
472 if (mWasDispatched) {
473 result = sem_post(& mSharedMessage->semaphore);
474 if (result < 0) {
475 LOGE("channel '%s' publisher ~ Error %d in sem_post.",
476 mChannel->getName().string(), errno);
477 return UNKNOWN_ERROR;
478 }
479 }
480 return OK;
481}
482
483status_t InputPublisher::sendDispatchSignal() {
484#if DEBUG_TRANSPORT_ACTIONS
485 LOGD("channel '%s' publisher ~ sendDispatchSignal",
486 mChannel->getName().string());
487#endif
488
489 mWasDispatched = true;
490 return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
491}
492
493status_t InputPublisher::receiveFinishedSignal() {
494#if DEBUG_TRANSPORT_ACTIONS
495 LOGD("channel '%s' publisher ~ receiveFinishedSignal",
496 mChannel->getName().string());
497#endif
498
499 char signal;
500 status_t result = mChannel->receiveSignal(& signal);
501 if (result) {
502 return result;
503 }
504 if (signal != INPUT_SIGNAL_FINISHED) {
505 LOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
506 mChannel->getName().string(), signal);
507 return UNKNOWN_ERROR;
508 }
509 return OK;
510}
511
512// --- InputConsumer ---
513
514InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
515 mChannel(channel), mSharedMessage(NULL) {
516}
517
518InputConsumer::~InputConsumer() {
519 if (mSharedMessage) {
520 munmap(mSharedMessage, mAshmemSize);
521 }
522}
523
524status_t InputConsumer::initialize() {
525#if DEBUG_TRANSPORT_ACTIONS
526 LOGD("channel '%s' consumer ~ initialize",
527 mChannel->getName().string());
528#endif
529
530 int ashmemFd = mChannel->getAshmemFd();
531 int result = ashmem_get_size_region(ashmemFd);
532 if (result < 0) {
533 LOGE("channel '%s' consumer ~ Error %d getting size of ashmem fd %d.",
534 mChannel->getName().string(), result, ashmemFd);
535 return UNKNOWN_ERROR;
536 }
537
538 mAshmemSize = (size_t) result;
539
540 mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
541 PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
542 if (! mSharedMessage) {
543 LOGE("channel '%s' consumer ~ mmap failed on ashmem fd %d.",
544 mChannel->getName().string(), ashmemFd);
545 return NO_MEMORY;
546 }
547
548 return OK;
549}
550
Jeff Brown5c225b12010-06-16 01:53:36 -0700551status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700552#if DEBUG_TRANSPORT_ACTIONS
553 LOGD("channel '%s' consumer ~ consume",
554 mChannel->getName().string());
555#endif
556
Jeff Brown5c225b12010-06-16 01:53:36 -0700557 *outEvent = NULL;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700558
559 int ashmemFd = mChannel->getAshmemFd();
560 int result = ashmem_pin_region(ashmemFd, 0, 0);
561 if (result != ASHMEM_NOT_PURGED) {
562 if (result == ASHMEM_WAS_PURGED) {
563 LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "
564 "which probably indicates that the publisher and consumer are out of sync.",
565 mChannel->getName().string(), result, ashmemFd);
566 return INVALID_OPERATION;
567 }
568
569 LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
570 mChannel->getName().string(), result, ashmemFd);
571 return UNKNOWN_ERROR;
572 }
573
574 if (mSharedMessage->consumed) {
575 LOGE("channel '%s' consumer ~ The current message has already been consumed.",
576 mChannel->getName().string());
577 return INVALID_OPERATION;
578 }
579
580 // Acquire but *never release* the semaphore. Contention on the semaphore is used to signal
581 // to the publisher that the message has been consumed (or is in the process of being
582 // consumed). Eventually the publisher will reinitialize the semaphore for the next message.
583 result = sem_wait(& mSharedMessage->semaphore);
584 if (result < 0) {
585 LOGE("channel '%s' consumer ~ Error %d in sem_wait.",
586 mChannel->getName().string(), errno);
587 return UNKNOWN_ERROR;
588 }
589
590 mSharedMessage->consumed = true;
591
592 switch (mSharedMessage->type) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700593 case AINPUT_EVENT_TYPE_KEY: {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700594 KeyEvent* keyEvent = factory->createKeyEvent();
595 if (! keyEvent) return NO_MEMORY;
596
597 populateKeyEvent(keyEvent);
598
Jeff Brown5c225b12010-06-16 01:53:36 -0700599 *outEvent = keyEvent;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700600 break;
601 }
602
Jeff Brownc5ed5912010-07-14 18:48:53 -0700603 case AINPUT_EVENT_TYPE_MOTION: {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700604 MotionEvent* motionEvent = factory->createMotionEvent();
605 if (! motionEvent) return NO_MEMORY;
606
607 populateMotionEvent(motionEvent);
608
Jeff Brown5c225b12010-06-16 01:53:36 -0700609 *outEvent = motionEvent;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700610 break;
611 }
612
613 default:
614 LOGE("channel '%s' consumer ~ Received message of unknown type %d",
615 mChannel->getName().string(), mSharedMessage->type);
616 return UNKNOWN_ERROR;
617 }
618
619 return OK;
620}
621
622status_t InputConsumer::sendFinishedSignal() {
623#if DEBUG_TRANSPORT_ACTIONS
624 LOGD("channel '%s' consumer ~ sendFinishedSignal",
625 mChannel->getName().string());
626#endif
627
628 return mChannel->sendSignal(INPUT_SIGNAL_FINISHED);
629}
630
631status_t InputConsumer::receiveDispatchSignal() {
632#if DEBUG_TRANSPORT_ACTIONS
633 LOGD("channel '%s' consumer ~ receiveDispatchSignal",
634 mChannel->getName().string());
635#endif
636
637 char signal;
638 status_t result = mChannel->receiveSignal(& signal);
639 if (result) {
640 return result;
641 }
642 if (signal != INPUT_SIGNAL_DISPATCH) {
643 LOGE("channel '%s' consumer ~ Received unexpected signal '%c' from publisher",
644 mChannel->getName().string(), signal);
645 return UNKNOWN_ERROR;
646 }
647 return OK;
648}
649
650void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const {
651 keyEvent->initialize(
652 mSharedMessage->deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700653 mSharedMessage->source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700654 mSharedMessage->key.action,
655 mSharedMessage->key.flags,
656 mSharedMessage->key.keyCode,
657 mSharedMessage->key.scanCode,
658 mSharedMessage->key.metaState,
659 mSharedMessage->key.repeatCount,
660 mSharedMessage->key.downTime,
661 mSharedMessage->key.eventTime);
662}
663
664void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
665 motionEvent->initialize(
666 mSharedMessage->deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700667 mSharedMessage->source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700668 mSharedMessage->motion.action,
Jeff Brown85a31762010-09-01 17:01:00 -0700669 mSharedMessage->motion.flags,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700670 mSharedMessage->motion.edgeFlags,
671 mSharedMessage->motion.metaState,
Jeff Brown5c225b12010-06-16 01:53:36 -0700672 mSharedMessage->motion.xOffset,
673 mSharedMessage->motion.yOffset,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700674 mSharedMessage->motion.xPrecision,
675 mSharedMessage->motion.yPrecision,
676 mSharedMessage->motion.downTime,
677 mSharedMessage->motion.sampleData[0].eventTime,
678 mSharedMessage->motion.pointerCount,
679 mSharedMessage->motion.pointerIds,
680 mSharedMessage->motion.sampleData[0].coords);
681
682 size_t sampleCount = mSharedMessage->motion.sampleCount;
683 if (sampleCount > 1) {
684 InputMessage::SampleData* sampleData = mSharedMessage->motion.sampleData;
685 size_t sampleDataStride = InputMessage::sampleDataStride(
686 mSharedMessage->motion.pointerCount);
687
688 while (--sampleCount > 0) {
689 sampleData = InputMessage::sampleDataPtrIncrement(sampleData, sampleDataStride);
690 motionEvent->addSample(sampleData->eventTime, sampleData->coords);
691 }
692 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700693}
694
695} // namespace android