blob: 5c57a76f40f496d1d985e50c7a1cba2d16b50f52 [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
Jeff Brown3915bb82010-11-05 15:02:16 -070038// consuming the most recent message and it handled it.
39static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f';
40
41// Signal sent by the consumer to the producer to inform it that it has finished
42// consuming the most recent message but it did not handle it.
43static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u';
Jeff Brown46b9ac02010-04-22 18:58:52 -070044
45
46// --- InputChannel ---
47
48InputChannel::InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
49 int32_t sendPipeFd) :
50 mName(name), mAshmemFd(ashmemFd), mReceivePipeFd(receivePipeFd), mSendPipeFd(sendPipeFd) {
51#if DEBUG_CHANNEL_LIFECYCLE
52 LOGD("Input channel constructed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
53 mName.string(), ashmemFd, receivePipeFd, sendPipeFd);
54#endif
55
56 int result = fcntl(mReceivePipeFd, F_SETFL, O_NONBLOCK);
57 LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make receive pipe "
58 "non-blocking. errno=%d", mName.string(), errno);
59
60 result = fcntl(mSendPipeFd, F_SETFL, O_NONBLOCK);
61 LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make send pipe "
62 "non-blocking. errno=%d", mName.string(), errno);
63}
64
65InputChannel::~InputChannel() {
66#if DEBUG_CHANNEL_LIFECYCLE
67 LOGD("Input channel destroyed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
68 mName.string(), mAshmemFd, mReceivePipeFd, mSendPipeFd);
69#endif
70
71 ::close(mAshmemFd);
72 ::close(mReceivePipeFd);
73 ::close(mSendPipeFd);
74}
75
76status_t InputChannel::openInputChannelPair(const String8& name,
Jeff Brown5c225b12010-06-16 01:53:36 -070077 sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
Jeff Brown46b9ac02010-04-22 18:58:52 -070078 status_t result;
79
80 int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
81 if (serverAshmemFd < 0) {
82 result = -errno;
83 LOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
84 name.string(), errno);
85 } else {
86 result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE);
87 if (result < 0) {
88 LOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.",
89 name.string(), result, serverAshmemFd);
90 } else {
91 // Dup the file descriptor because the server and client input channel objects that
92 // are returned may have different lifetimes but they share the same shared memory region.
93 int clientAshmemFd;
94 clientAshmemFd = dup(serverAshmemFd);
95 if (clientAshmemFd < 0) {
96 result = -errno;
97 LOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d",
98 name.string(), errno);
99 } else {
100 int forward[2];
101 if (pipe(forward)) {
102 result = -errno;
103 LOGE("channel '%s' ~ Could not create forward pipe. errno=%d",
104 name.string(), errno);
105 } else {
106 int reverse[2];
107 if (pipe(reverse)) {
108 result = -errno;
109 LOGE("channel '%s' ~ Could not create reverse pipe. errno=%d",
110 name.string(), errno);
111 } else {
112 String8 serverChannelName = name;
113 serverChannelName.append(" (server)");
Jeff Brown5c225b12010-06-16 01:53:36 -0700114 outServerChannel = new InputChannel(serverChannelName,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700115 serverAshmemFd, reverse[0], forward[1]);
116
117 String8 clientChannelName = name;
118 clientChannelName.append(" (client)");
Jeff Brown5c225b12010-06-16 01:53:36 -0700119 outClientChannel = new InputChannel(clientChannelName,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700120 clientAshmemFd, forward[0], reverse[1]);
121 return OK;
122 }
123 ::close(forward[0]);
124 ::close(forward[1]);
125 }
126 ::close(clientAshmemFd);
127 }
128 }
129 ::close(serverAshmemFd);
130 }
131
Jeff Brown5c225b12010-06-16 01:53:36 -0700132 outServerChannel.clear();
133 outClientChannel.clear();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700134 return result;
135}
136
137status_t InputChannel::sendSignal(char signal) {
Jeff Brown7dae0e42010-09-16 17:04:52 -0700138 ssize_t nWrite;
139 do {
140 nWrite = ::write(mSendPipeFd, & signal, 1);
141 } while (nWrite == -1 && errno == EINTR);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700142
143 if (nWrite == 1) {
144#if DEBUG_CHANNEL_SIGNALS
145 LOGD("channel '%s' ~ sent signal '%c'", mName.string(), signal);
146#endif
147 return OK;
148 }
149
150#if DEBUG_CHANNEL_SIGNALS
151 LOGD("channel '%s' ~ error sending signal '%c', errno=%d", mName.string(), signal, errno);
152#endif
153 return -errno;
154}
155
156status_t InputChannel::receiveSignal(char* outSignal) {
Jeff Brown7dae0e42010-09-16 17:04:52 -0700157 ssize_t nRead;
158 do {
159 nRead = ::read(mReceivePipeFd, outSignal, 1);
160 } while (nRead == -1 && errno == EINTR);
161
Jeff Brown46b9ac02010-04-22 18:58:52 -0700162 if (nRead == 1) {
163#if DEBUG_CHANNEL_SIGNALS
164 LOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal);
165#endif
166 return OK;
167 }
168
Jeff Brown5c225b12010-06-16 01:53:36 -0700169 if (nRead == 0) { // check for EOF
170#if DEBUG_CHANNEL_SIGNALS
171 LOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string());
172#endif
173 return DEAD_OBJECT;
174 }
175
Jeff Brown46b9ac02010-04-22 18:58:52 -0700176 if (errno == EAGAIN) {
177#if DEBUG_CHANNEL_SIGNALS
178 LOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
179#endif
180 return WOULD_BLOCK;
181 }
182
183#if DEBUG_CHANNEL_SIGNALS
184 LOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno);
185#endif
186 return -errno;
187}
188
189
190// --- InputPublisher ---
191
192InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
193 mChannel(channel), mSharedMessage(NULL),
194 mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
195 mMotionEventSampleDataTail(NULL) {
196}
197
198InputPublisher::~InputPublisher() {
199 reset();
200
201 if (mSharedMessage) {
202 munmap(mSharedMessage, mAshmemSize);
203 }
204}
205
206status_t InputPublisher::initialize() {
207#if DEBUG_TRANSPORT_ACTIONS
208 LOGD("channel '%s' publisher ~ initialize",
209 mChannel->getName().string());
210#endif
211
212 int ashmemFd = mChannel->getAshmemFd();
213 int result = ashmem_get_size_region(ashmemFd);
214 if (result < 0) {
215 LOGE("channel '%s' publisher ~ Error %d getting size of ashmem fd %d.",
216 mChannel->getName().string(), result, ashmemFd);
217 return UNKNOWN_ERROR;
218 }
219 mAshmemSize = (size_t) result;
220
221 mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
222 PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
223 if (! mSharedMessage) {
224 LOGE("channel '%s' publisher ~ mmap failed on ashmem fd %d.",
225 mChannel->getName().string(), ashmemFd);
226 return NO_MEMORY;
227 }
228
229 mPinned = true;
230 mSharedMessage->consumed = false;
231
232 return reset();
233}
234
235status_t InputPublisher::reset() {
236#if DEBUG_TRANSPORT_ACTIONS
237 LOGD("channel '%s' publisher ~ reset",
238 mChannel->getName().string());
239#endif
240
241 if (mPinned) {
242 // Destroy the semaphore since we are about to unpin the memory region that contains it.
243 int result;
244 if (mSemaphoreInitialized) {
245 if (mSharedMessage->consumed) {
246 result = sem_post(& mSharedMessage->semaphore);
247 if (result < 0) {
248 LOGE("channel '%s' publisher ~ Error %d in sem_post.",
249 mChannel->getName().string(), errno);
250 return UNKNOWN_ERROR;
251 }
252 }
253
254 result = sem_destroy(& mSharedMessage->semaphore);
255 if (result < 0) {
256 LOGE("channel '%s' publisher ~ Error %d in sem_destroy.",
257 mChannel->getName().string(), errno);
258 return UNKNOWN_ERROR;
259 }
260
261 mSemaphoreInitialized = false;
262 }
263
264 // Unpin the region since we no longer care about its contents.
265 int ashmemFd = mChannel->getAshmemFd();
266 result = ashmem_unpin_region(ashmemFd, 0, 0);
267 if (result < 0) {
268 LOGE("channel '%s' publisher ~ Error %d unpinning ashmem fd %d.",
269 mChannel->getName().string(), result, ashmemFd);
270 return UNKNOWN_ERROR;
271 }
272
273 mPinned = false;
274 }
275
276 mMotionEventSampleDataTail = NULL;
277 mWasDispatched = false;
278 return OK;
279}
280
281status_t InputPublisher::publishInputEvent(
282 int32_t type,
283 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700284 int32_t source) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700285 if (mPinned) {
286 LOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has "
287 "not yet been reset.", mChannel->getName().string());
288 return INVALID_OPERATION;
289 }
290
291 // Pin the region.
292 // We do not check for ASHMEM_NOT_PURGED because we don't care about the previous
293 // contents of the buffer so it does not matter whether it was purged in the meantime.
294 int ashmemFd = mChannel->getAshmemFd();
295 int result = ashmem_pin_region(ashmemFd, 0, 0);
296 if (result < 0) {
297 LOGE("channel '%s' publisher ~ Error %d pinning ashmem fd %d.",
298 mChannel->getName().string(), result, ashmemFd);
299 return UNKNOWN_ERROR;
300 }
301
302 mPinned = true;
303
304 result = sem_init(& mSharedMessage->semaphore, 1, 1);
305 if (result < 0) {
306 LOGE("channel '%s' publisher ~ Error %d in sem_init.",
307 mChannel->getName().string(), errno);
308 return UNKNOWN_ERROR;
309 }
310
311 mSemaphoreInitialized = true;
312
313 mSharedMessage->consumed = false;
314 mSharedMessage->type = type;
315 mSharedMessage->deviceId = deviceId;
Jeff Brownc5ed5912010-07-14 18:48:53 -0700316 mSharedMessage->source = source;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700317 return OK;
318}
319
320status_t InputPublisher::publishKeyEvent(
321 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700322 int32_t source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700323 int32_t action,
324 int32_t flags,
325 int32_t keyCode,
326 int32_t scanCode,
327 int32_t metaState,
328 int32_t repeatCount,
329 nsecs_t downTime,
330 nsecs_t eventTime) {
331#if DEBUG_TRANSPORT_ACTIONS
Jeff Brown85a31762010-09-01 17:01:00 -0700332 LOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=0x%x, "
333 "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
Jeff Brown46b9ac02010-04-22 18:58:52 -0700334 "downTime=%lld, eventTime=%lld",
335 mChannel->getName().string(),
Jeff Brownc5ed5912010-07-14 18:48:53 -0700336 deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700337 downTime, eventTime);
338#endif
339
Jeff Brownc5ed5912010-07-14 18:48:53 -0700340 status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700341 if (result < 0) {
342 return result;
343 }
344
345 mSharedMessage->key.action = action;
346 mSharedMessage->key.flags = flags;
347 mSharedMessage->key.keyCode = keyCode;
348 mSharedMessage->key.scanCode = scanCode;
349 mSharedMessage->key.metaState = metaState;
350 mSharedMessage->key.repeatCount = repeatCount;
351 mSharedMessage->key.downTime = downTime;
352 mSharedMessage->key.eventTime = eventTime;
353 return OK;
354}
355
356status_t InputPublisher::publishMotionEvent(
357 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700358 int32_t source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700359 int32_t action,
Jeff Brown85a31762010-09-01 17:01:00 -0700360 int32_t flags,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700361 int32_t edgeFlags,
362 int32_t metaState,
363 float xOffset,
364 float yOffset,
365 float xPrecision,
366 float yPrecision,
367 nsecs_t downTime,
368 nsecs_t eventTime,
369 size_t pointerCount,
370 const int32_t* pointerIds,
371 const PointerCoords* pointerCoords) {
372#if DEBUG_TRANSPORT_ACTIONS
Jeff Brown85a31762010-09-01 17:01:00 -0700373 LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
374 "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, xOffset=%f, yOffset=%f, "
Jeff Brown46b9ac02010-04-22 18:58:52 -0700375 "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
376 "pointerCount=%d",
377 mChannel->getName().string(),
Jeff Brown85a31762010-09-01 17:01:00 -0700378 deviceId, source, action, flags, edgeFlags, metaState, xOffset, yOffset,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700379 xPrecision, yPrecision, downTime, eventTime, pointerCount);
380#endif
381
382 if (pointerCount > MAX_POINTERS || pointerCount < 1) {
383 LOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
384 mChannel->getName().string(), pointerCount);
385 return BAD_VALUE;
386 }
387
Jeff Brownc5ed5912010-07-14 18:48:53 -0700388 status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700389 if (result < 0) {
390 return result;
391 }
392
393 mSharedMessage->motion.action = action;
Jeff Brown85a31762010-09-01 17:01:00 -0700394 mSharedMessage->motion.flags = flags;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700395 mSharedMessage->motion.edgeFlags = edgeFlags;
396 mSharedMessage->motion.metaState = metaState;
397 mSharedMessage->motion.xOffset = xOffset;
398 mSharedMessage->motion.yOffset = yOffset;
399 mSharedMessage->motion.xPrecision = xPrecision;
400 mSharedMessage->motion.yPrecision = yPrecision;
401 mSharedMessage->motion.downTime = downTime;
402 mSharedMessage->motion.pointerCount = pointerCount;
403
404 mSharedMessage->motion.sampleCount = 1;
405 mSharedMessage->motion.sampleData[0].eventTime = eventTime;
406
407 for (size_t i = 0; i < pointerCount; i++) {
408 mSharedMessage->motion.pointerIds[i] = pointerIds[i];
409 mSharedMessage->motion.sampleData[0].coords[i] = pointerCoords[i];
410 }
411
412 // Cache essential information about the motion event to ensure that a malicious consumer
413 // cannot confuse the publisher by modifying the contents of the shared memory buffer while
414 // it is being updated.
Jeff Browncc0c1592011-02-19 05:07:28 -0800415 if (action == AMOTION_EVENT_ACTION_MOVE
416 || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700417 mMotionEventPointerCount = pointerCount;
418 mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
419 mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
420 mSharedMessage->motion.sampleData, mMotionEventSampleDataStride);
421 } else {
422 mMotionEventSampleDataTail = NULL;
423 }
424 return OK;
425}
426
427status_t InputPublisher::appendMotionSample(
428 nsecs_t eventTime,
429 const PointerCoords* pointerCoords) {
430#if DEBUG_TRANSPORT_ACTIONS
431 LOGD("channel '%s' publisher ~ appendMotionSample: eventTime=%lld",
432 mChannel->getName().string(), eventTime);
433#endif
434
435 if (! mPinned || ! mMotionEventSampleDataTail) {
436 LOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
Jeff Brownc5ed5912010-07-14 18:48:53 -0700437 "AMOTION_EVENT_ACTION_MOVE event.", mChannel->getName().string());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700438 return INVALID_OPERATION;
439 }
440
441 InputMessage::SampleData* newTail = InputMessage::sampleDataPtrIncrement(
442 mMotionEventSampleDataTail, mMotionEventSampleDataStride);
443 size_t newBytesUsed = reinterpret_cast<char*>(newTail) -
444 reinterpret_cast<char*>(mSharedMessage);
445
446 if (newBytesUsed > mAshmemSize) {
Jeff Brown349703e2010-06-22 01:27:15 -0700447#if DEBUG_TRANSPORT_ACTIONS
Jeff Brown46b9ac02010-04-22 18:58:52 -0700448 LOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory "
449 "buffer is full. Buffer size: %d bytes, pointers: %d, samples: %d",
450 mChannel->getName().string(),
451 mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount);
Jeff Brown349703e2010-06-22 01:27:15 -0700452#endif
Jeff Brown46b9ac02010-04-22 18:58:52 -0700453 return NO_MEMORY;
454 }
455
456 int result;
457 if (mWasDispatched) {
458 result = sem_trywait(& mSharedMessage->semaphore);
459 if (result < 0) {
460 if (errno == EAGAIN) {
461 // Only possible source of contention is the consumer having consumed (or being in the
462 // process of consuming) the message and left the semaphore count at 0.
Jeff Brown349703e2010-06-22 01:27:15 -0700463#if DEBUG_TRANSPORT_ACTIONS
Jeff Brown46b9ac02010-04-22 18:58:52 -0700464 LOGD("channel '%s' publisher ~ Cannot append motion sample because the message has "
465 "already been consumed.", mChannel->getName().string());
Jeff Brown349703e2010-06-22 01:27:15 -0700466#endif
Jeff Brown46b9ac02010-04-22 18:58:52 -0700467 return FAILED_TRANSACTION;
468 } else {
469 LOGE("channel '%s' publisher ~ Error %d in sem_trywait.",
470 mChannel->getName().string(), errno);
471 return UNKNOWN_ERROR;
472 }
473 }
474 }
475
476 mMotionEventSampleDataTail->eventTime = eventTime;
477 for (size_t i = 0; i < mMotionEventPointerCount; i++) {
478 mMotionEventSampleDataTail->coords[i] = pointerCoords[i];
479 }
480 mMotionEventSampleDataTail = newTail;
481
482 mSharedMessage->motion.sampleCount += 1;
483
484 if (mWasDispatched) {
485 result = sem_post(& mSharedMessage->semaphore);
486 if (result < 0) {
487 LOGE("channel '%s' publisher ~ Error %d in sem_post.",
488 mChannel->getName().string(), errno);
489 return UNKNOWN_ERROR;
490 }
491 }
492 return OK;
493}
494
495status_t InputPublisher::sendDispatchSignal() {
496#if DEBUG_TRANSPORT_ACTIONS
497 LOGD("channel '%s' publisher ~ sendDispatchSignal",
498 mChannel->getName().string());
499#endif
500
501 mWasDispatched = true;
502 return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
503}
504
Jeff Brown49ed71d2010-12-06 17:13:33 -0800505status_t InputPublisher::receiveFinishedSignal(bool* outHandled) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700506#if DEBUG_TRANSPORT_ACTIONS
507 LOGD("channel '%s' publisher ~ receiveFinishedSignal",
508 mChannel->getName().string());
509#endif
510
511 char signal;
512 status_t result = mChannel->receiveSignal(& signal);
513 if (result) {
Jeff Brown49ed71d2010-12-06 17:13:33 -0800514 *outHandled = false;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700515 return result;
516 }
Jeff Brown3915bb82010-11-05 15:02:16 -0700517 if (signal == INPUT_SIGNAL_FINISHED_HANDLED) {
Jeff Brown49ed71d2010-12-06 17:13:33 -0800518 *outHandled = true;
Jeff Brown3915bb82010-11-05 15:02:16 -0700519 } else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) {
Jeff Brown49ed71d2010-12-06 17:13:33 -0800520 *outHandled = false;
Jeff Brown3915bb82010-11-05 15:02:16 -0700521 } else {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700522 LOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
523 mChannel->getName().string(), signal);
524 return UNKNOWN_ERROR;
525 }
526 return OK;
527}
528
529// --- InputConsumer ---
530
531InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
532 mChannel(channel), mSharedMessage(NULL) {
533}
534
535InputConsumer::~InputConsumer() {
536 if (mSharedMessage) {
537 munmap(mSharedMessage, mAshmemSize);
538 }
539}
540
541status_t InputConsumer::initialize() {
542#if DEBUG_TRANSPORT_ACTIONS
543 LOGD("channel '%s' consumer ~ initialize",
544 mChannel->getName().string());
545#endif
546
547 int ashmemFd = mChannel->getAshmemFd();
548 int result = ashmem_get_size_region(ashmemFd);
549 if (result < 0) {
550 LOGE("channel '%s' consumer ~ Error %d getting size of ashmem fd %d.",
551 mChannel->getName().string(), result, ashmemFd);
552 return UNKNOWN_ERROR;
553 }
554
555 mAshmemSize = (size_t) result;
556
557 mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
558 PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
559 if (! mSharedMessage) {
560 LOGE("channel '%s' consumer ~ mmap failed on ashmem fd %d.",
561 mChannel->getName().string(), ashmemFd);
562 return NO_MEMORY;
563 }
564
565 return OK;
566}
567
Jeff Brown5c225b12010-06-16 01:53:36 -0700568status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700569#if DEBUG_TRANSPORT_ACTIONS
570 LOGD("channel '%s' consumer ~ consume",
571 mChannel->getName().string());
572#endif
573
Jeff Brown5c225b12010-06-16 01:53:36 -0700574 *outEvent = NULL;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700575
576 int ashmemFd = mChannel->getAshmemFd();
577 int result = ashmem_pin_region(ashmemFd, 0, 0);
578 if (result != ASHMEM_NOT_PURGED) {
579 if (result == ASHMEM_WAS_PURGED) {
580 LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "
581 "which probably indicates that the publisher and consumer are out of sync.",
582 mChannel->getName().string(), result, ashmemFd);
583 return INVALID_OPERATION;
584 }
585
586 LOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
587 mChannel->getName().string(), result, ashmemFd);
588 return UNKNOWN_ERROR;
589 }
590
591 if (mSharedMessage->consumed) {
592 LOGE("channel '%s' consumer ~ The current message has already been consumed.",
593 mChannel->getName().string());
594 return INVALID_OPERATION;
595 }
596
597 // Acquire but *never release* the semaphore. Contention on the semaphore is used to signal
598 // to the publisher that the message has been consumed (or is in the process of being
599 // consumed). Eventually the publisher will reinitialize the semaphore for the next message.
600 result = sem_wait(& mSharedMessage->semaphore);
601 if (result < 0) {
602 LOGE("channel '%s' consumer ~ Error %d in sem_wait.",
603 mChannel->getName().string(), errno);
604 return UNKNOWN_ERROR;
605 }
606
607 mSharedMessage->consumed = true;
608
609 switch (mSharedMessage->type) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700610 case AINPUT_EVENT_TYPE_KEY: {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700611 KeyEvent* keyEvent = factory->createKeyEvent();
612 if (! keyEvent) return NO_MEMORY;
613
614 populateKeyEvent(keyEvent);
615
Jeff Brown5c225b12010-06-16 01:53:36 -0700616 *outEvent = keyEvent;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700617 break;
618 }
619
Jeff Brownc5ed5912010-07-14 18:48:53 -0700620 case AINPUT_EVENT_TYPE_MOTION: {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700621 MotionEvent* motionEvent = factory->createMotionEvent();
622 if (! motionEvent) return NO_MEMORY;
623
624 populateMotionEvent(motionEvent);
625
Jeff Brown5c225b12010-06-16 01:53:36 -0700626 *outEvent = motionEvent;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700627 break;
628 }
629
630 default:
631 LOGE("channel '%s' consumer ~ Received message of unknown type %d",
632 mChannel->getName().string(), mSharedMessage->type);
633 return UNKNOWN_ERROR;
634 }
635
636 return OK;
637}
638
Jeff Brown3915bb82010-11-05 15:02:16 -0700639status_t InputConsumer::sendFinishedSignal(bool handled) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700640#if DEBUG_TRANSPORT_ACTIONS
Jeff Brown3915bb82010-11-05 15:02:16 -0700641 LOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d",
642 mChannel->getName().string(), handled);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700643#endif
644
Jeff Brown3915bb82010-11-05 15:02:16 -0700645 return mChannel->sendSignal(handled
646 ? INPUT_SIGNAL_FINISHED_HANDLED
647 : INPUT_SIGNAL_FINISHED_UNHANDLED);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700648}
649
650status_t InputConsumer::receiveDispatchSignal() {
651#if DEBUG_TRANSPORT_ACTIONS
652 LOGD("channel '%s' consumer ~ receiveDispatchSignal",
653 mChannel->getName().string());
654#endif
655
656 char signal;
657 status_t result = mChannel->receiveSignal(& signal);
658 if (result) {
659 return result;
660 }
661 if (signal != INPUT_SIGNAL_DISPATCH) {
662 LOGE("channel '%s' consumer ~ Received unexpected signal '%c' from publisher",
663 mChannel->getName().string(), signal);
664 return UNKNOWN_ERROR;
665 }
666 return OK;
667}
668
669void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const {
670 keyEvent->initialize(
671 mSharedMessage->deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700672 mSharedMessage->source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700673 mSharedMessage->key.action,
674 mSharedMessage->key.flags,
675 mSharedMessage->key.keyCode,
676 mSharedMessage->key.scanCode,
677 mSharedMessage->key.metaState,
678 mSharedMessage->key.repeatCount,
679 mSharedMessage->key.downTime,
680 mSharedMessage->key.eventTime);
681}
682
683void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
684 motionEvent->initialize(
685 mSharedMessage->deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700686 mSharedMessage->source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700687 mSharedMessage->motion.action,
Jeff Brown85a31762010-09-01 17:01:00 -0700688 mSharedMessage->motion.flags,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700689 mSharedMessage->motion.edgeFlags,
690 mSharedMessage->motion.metaState,
Jeff Brown5c225b12010-06-16 01:53:36 -0700691 mSharedMessage->motion.xOffset,
692 mSharedMessage->motion.yOffset,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700693 mSharedMessage->motion.xPrecision,
694 mSharedMessage->motion.yPrecision,
695 mSharedMessage->motion.downTime,
696 mSharedMessage->motion.sampleData[0].eventTime,
697 mSharedMessage->motion.pointerCount,
698 mSharedMessage->motion.pointerIds,
699 mSharedMessage->motion.sampleData[0].coords);
700
701 size_t sampleCount = mSharedMessage->motion.sampleCount;
702 if (sampleCount > 1) {
703 InputMessage::SampleData* sampleData = mSharedMessage->motion.sampleData;
704 size_t sampleDataStride = InputMessage::sampleDataStride(
705 mSharedMessage->motion.pointerCount);
706
707 while (--sampleCount > 0) {
708 sampleData = InputMessage::sampleDataPtrIncrement(sampleData, sampleDataStride);
709 motionEvent->addSample(sampleData->eventTime, sampleData->coords);
710 }
711 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700712}
713
714} // namespace android