diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index ac4fe5b1c6be3..f383c5d52561b 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -130,21 +130,21 @@ AInputQueue::~AInputQueue() { void AInputQueue::attachLooper(ALooper* looper, int ident, ALooper_callbackFunc callback, void* data) { mLooper = static_cast(looper); - mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(), + mLooper->addFd(mConsumer.getChannel()->getFd(), ident, ALOOPER_EVENT_INPUT, callback, data); mLooper->addFd(mDispatchKeyRead, ident, ALOOPER_EVENT_INPUT, callback, data); } void AInputQueue::detachLooper() { - mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd()); + mLooper->removeFd(mConsumer.getChannel()->getFd()); mLooper->removeFd(mDispatchKeyRead); } int32_t AInputQueue::hasEvents() { struct pollfd pfd[2]; - pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd(); + pfd[0].fd = mConsumer.getChannel()->getFd(); pfd[0].events = POLLIN; pfd[0].revents = 0; pfd[1].fd = mDispatchKeyRead; @@ -200,16 +200,9 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { return 0; } } - - int32_t res = mConsumer.receiveDispatchSignal(); - if (res != android::OK) { - ALOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d", - mConsumer.getChannel()->getName().string(), res); - return -1; - } InputEvent* myEvent = NULL; - res = mConsumer.consume(this, &myEvent); + status_t res = mConsumer.consume(this, &myEvent); if (res != android::OK) { ALOGW("channel '%s' ~ Failed to consume input event. status=%d", mConsumer.getChannel()->getName().string(), res); @@ -481,11 +474,6 @@ struct NativeCode : public ANativeActivity { android_view_InputChannel_getInputChannel(env, _channel); if (ic != NULL) { nativeInputQueue = new AInputQueue(ic, mainWorkWrite); - if (nativeInputQueue->getConsumer().initialize() != android::OK) { - delete nativeInputQueue; - nativeInputQueue = NULL; - return UNKNOWN_ERROR; - } } else { return UNKNOWN_ERROR; } diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index fce432bf5d0d3..53774251a43ee 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -199,32 +199,16 @@ static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject bool isInitialized = parcel->readInt32(); if (isInitialized) { String8 name = parcel->readString8(); - int32_t parcelAshmemFd = parcel->readFileDescriptor(); - int32_t ashmemFd = dup(parcelAshmemFd); - if (ashmemFd < 0) { - ALOGE("Error %d dup ashmem fd %d.", errno, parcelAshmemFd); - } - int32_t parcelReceivePipeFd = parcel->readFileDescriptor(); - int32_t receivePipeFd = dup(parcelReceivePipeFd); - if (receivePipeFd < 0) { - ALOGE("Error %d dup receive pipe fd %d.", errno, parcelReceivePipeFd); - } - int32_t parcelSendPipeFd = parcel->readFileDescriptor(); - int32_t sendPipeFd = dup(parcelSendPipeFd); - if (sendPipeFd < 0) { - ALOGE("Error %d dup send pipe fd %d.", errno, parcelSendPipeFd); - } - if (ashmemFd < 0 || receivePipeFd < 0 || sendPipeFd < 0) { - if (ashmemFd >= 0) ::close(ashmemFd); - if (receivePipeFd >= 0) ::close(receivePipeFd); - if (sendPipeFd >= 0) ::close(sendPipeFd); + int32_t rawFd = parcel->readFileDescriptor(); + int32_t dupFd = dup(rawFd); + if (rawFd < 0) { + ALOGE("Error %d dup channel fd %d.", errno, rawFd); jniThrowRuntimeException(env, "Could not read input channel file descriptors from parcel."); return; } - InputChannel* inputChannel = new InputChannel(name, ashmemFd, - receivePipeFd, sendPipeFd); + InputChannel* inputChannel = new InputChannel(name, dupFd); NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel); android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel); @@ -243,9 +227,7 @@ static void android_view_InputChannel_nativeWriteToParcel(JNIEnv* env, jobject o parcel->writeInt32(1); parcel->writeString8(inputChannel->getName()); - parcel->writeDupFileDescriptor(inputChannel->getAshmemFd()); - parcel->writeDupFileDescriptor(inputChannel->getReceivePipeFd()); - parcel->writeDupFileDescriptor(inputChannel->getSendPipeFd()); + parcel->writeDupFileDescriptor(inputChannel->getFd()); } else { parcel->writeInt32(0); } diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index ed0acce699b9d..23e1590555d04 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -83,7 +83,7 @@ NativeInputEventReceiver::~NativeInputEventReceiver() { ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName()); #endif - mLooper->removeFd(mInputConsumer.getChannel()->getReceivePipeFd()); + mLooper->removeFd(mInputConsumer.getChannel()->getFd()); if (mEventInProgress) { mInputConsumer.sendFinishedSignal(false); // ignoring result } @@ -93,14 +93,7 @@ NativeInputEventReceiver::~NativeInputEventReceiver() { } status_t NativeInputEventReceiver::initialize() { - status_t result = mInputConsumer.initialize(); - if (result) { - ALOGW("Failed to initialize input consumer for input channel '%s', status=%d", - getInputChannelName(), result); - return result; - } - - int32_t receiveFd = mInputConsumer.getChannel()->getReceivePipeFd(); + int32_t receiveFd = mInputConsumer.getChannel()->getFd(); mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); return OK; } @@ -139,13 +132,6 @@ int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, v return 1; } - status_t status = r->mInputConsumer.receiveDispatchSignal(); - if (status) { - ALOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d", - r->getInputChannelName(), status); - return 0; // remove the callback - } - if (r->mEventInProgress) { ALOGW("channel '%s' ~ Publisher sent spurious dispatch signal.", r->getInputChannelName()); @@ -153,7 +139,7 @@ int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, v } InputEvent* inputEvent; - status = r->mInputConsumer.consume(&r->mInputEventFactory, &inputEvent); + status_t status = r->mInputConsumer.consume(&r->mInputEventFactory, &inputEvent); if (status) { ALOGW("channel '%s' ~ Failed to consume input event. status=%d", r->getInputChannelName(), status); diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h index 95e4447c6a888..f3a39c31a31eb 100644 --- a/include/ui/InputTransport.h +++ b/include/ui/InputTransport.h @@ -20,17 +20,13 @@ /** * Native input transport. * - * Uses anonymous shared memory as a whiteboard for sending input events from an - * InputPublisher to an InputConsumer and ensuring appropriate synchronization. - * One interesting feature is that published events can be updated in place as long as they - * have not yet been consumed. + * The InputChannel provides a mechanism for exchanging InputMessage structures across processes. * - * The InputPublisher and InputConsumer only take care of transferring event data - * over an InputChannel and sending synchronization signals. The InputDispatcher and InputQueue - * build on these abstractions to add multiplexing and queueing. + * The InputPublisher and InputConsumer each handle one end-point of an input channel. + * The InputPublisher is used by the input dispatcher to send events to the application. + * The InputConsumer is used by the application to receive events from the input dispatcher. */ -#include #include #include #include @@ -40,88 +36,25 @@ namespace android { /* - * An input channel consists of a shared memory buffer and a pair of pipes - * used to send input messages from an InputPublisher to an InputConsumer - * across processes. Each channel has a descriptive name for debugging purposes. - * - * Each endpoint has its own InputChannel object that specifies its own file descriptors. - * - * The input channel is closed when all references to it are released. - */ -class InputChannel : public RefBase { -protected: - virtual ~InputChannel(); - -public: - InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd, - int32_t sendPipeFd); - - /* Creates a pair of input channels and their underlying shared memory buffers - * and pipes. - * - * Returns OK on success. - */ - static status_t openInputChannelPair(const String8& name, - sp& outServerChannel, sp& outClientChannel); - - inline String8 getName() const { return mName; } - inline int32_t getAshmemFd() const { return mAshmemFd; } - inline int32_t getReceivePipeFd() const { return mReceivePipeFd; } - inline int32_t getSendPipeFd() const { return mSendPipeFd; } - - /* Sends a signal to the other endpoint. - * - * Returns OK on success. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Other errors probably indicate that the channel is broken. - */ - status_t sendSignal(char signal); - - /* Receives a signal send by the other endpoint. - * (Should only call this after poll() indicates that the receivePipeFd has available input.) - * - * Returns OK on success. - * Returns WOULD_BLOCK if there is no signal present. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Other errors probably indicate that the channel is broken. - */ - status_t receiveSignal(char* outSignal); - -private: - String8 mName; - int32_t mAshmemFd; - int32_t mReceivePipeFd; - int32_t mSendPipeFd; -}; - -/* - * Private intermediate representation of input events as messages written into an - * ashmem buffer. + * Intermediate representation used to send input events and related signals. */ struct InputMessage { - /* Semaphore count is set to 1 when the message is published. - * It becomes 0 transiently while the publisher updates the message. - * It becomes 0 permanently when the consumer consumes the message. - */ - sem_t semaphore; - - /* Initialized to false by the publisher. - * Set to true by the consumer when it consumes the message. - */ - bool consumed; - - int32_t type; - - struct SampleData { - nsecs_t eventTime; - PointerCoords coords[0]; // variable length + enum { + TYPE_KEY = 1, + TYPE_MOTION = 2, + TYPE_FINISHED = 3, }; - int32_t deviceId; - int32_t source; + struct Header { + uint32_t type; + uint32_t padding; // 8 byte alignment for the body that follows + } header; - union { - struct { + union Body { + struct Key { + nsecs_t eventTime; + int32_t deviceId; + int32_t source; int32_t action; int32_t flags; int32_t keyCode; @@ -129,10 +62,16 @@ struct InputMessage { int32_t metaState; int32_t repeatCount; nsecs_t downTime; - nsecs_t eventTime; + + inline size_t size() const { + return sizeof(Key); + } } key; - struct { + struct Motion { + nsecs_t eventTime; + int32_t deviceId; + int32_t source; int32_t action; int32_t flags; int32_t metaState; @@ -144,28 +83,87 @@ struct InputMessage { float xPrecision; float yPrecision; size_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - size_t sampleCount; - SampleData sampleData[0]; // variable length + struct Pointer { + PointerProperties properties; + PointerCoords coords; + } pointers[MAX_POINTERS]; + + inline size_t size() const { + return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS + + sizeof(Pointer) * pointerCount; + } } motion; - }; - /* Gets the number of bytes to add to step to the next SampleData object in a motion - * event message for a given number of pointers. - */ - static inline size_t sampleDataStride(size_t pointerCount) { - return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords); - } + struct Finished { + bool handled; - /* Adds the SampleData stride to the given pointer. */ - static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) { - return reinterpret_cast(reinterpret_cast(ptr) + stride); - } + inline size_t size() const { + return sizeof(Finished); + } + } finished; + } body; + + bool isValid(size_t actualSize) const; + size_t size() const; }; /* - * Publishes input events to an anonymous shared memory buffer. - * Uses atomic operations to coordinate shared access with a single concurrent consumer. + * An input channel consists of a local unix domain socket used to send and receive + * input messages across processes. Each channel has a descriptive name for debugging purposes. + * + * Each endpoint has its own InputChannel object that specifies its file descriptor. + * + * The input channel is closed when all references to it are released. + */ +class InputChannel : public RefBase { +protected: + virtual ~InputChannel(); + +public: + InputChannel(const String8& name, int32_t fd); + + /* Creates a pair of input channels. + * + * Returns OK on success. + */ + static status_t openInputChannelPair(const String8& name, + sp& outServerChannel, sp& outClientChannel); + + inline String8 getName() const { return mName; } + inline int32_t getFd() const { return mFd; } + + /* Sends a message to the other endpoint. + * + * If the channel is full then the message is guaranteed not to have been sent at all. + * Try again after the consumer has sent a finished signal indicating that it has + * consumed some of the pending messages from the channel. + * + * Returns OK on success. + * Returns WOULD_BLOCK if the channel is full. + * Returns DEAD_OBJECT if the channel's peer has been closed. + * Other errors probably indicate that the channel is broken. + */ + status_t sendMessage(const InputMessage* msg); + + /* Receives a message sent by the other endpoint. + * + * If there is no message present, try again after poll() indicates that the fd + * is readable. + * + * Returns OK on success. + * Returns WOULD_BLOCK if there is no message present. + * Returns DEAD_OBJECT if the channel's peer has been closed. + * Other errors probably indicate that the channel is broken. + */ + status_t receiveMessage(InputMessage* msg); + +private: + String8 mName; + int32_t mFd; +}; + +/* + * Publishes input events to an input channel. */ class InputPublisher { public: @@ -178,24 +176,12 @@ public: /* Gets the underlying input channel. */ inline sp getChannel() { return mChannel; } - /* Prepares the publisher for use. Must be called before it is used. - * Returns OK on success. - * - * This method implicitly calls reset(). */ - status_t initialize(); - - /* Resets the publisher to its initial state and unpins its ashmem buffer. - * Returns OK on success. - * - * Should be called after an event has been consumed to release resources used by the - * publisher until the next event is ready to be published. - */ - status_t reset(); - - /* Publishes a key event to the ashmem buffer. + /* Publishes a key event to the input channel. * * Returns OK on success. - * Returns INVALID_OPERATION if the publisher has not been reset. + * Returns WOULD_BLOCK if the channel is full. + * Returns DEAD_OBJECT if the channel's peer has been closed. + * Other errors probably indicate that the channel is broken. */ status_t publishKeyEvent( int32_t deviceId, @@ -209,11 +195,13 @@ public: nsecs_t downTime, nsecs_t eventTime); - /* Publishes a motion event to the ashmem buffer. + /* Publishes a motion event to the input channel. * * Returns OK on success. - * Returns INVALID_OPERATION if the publisher has not been reset. + * Returns WOULD_BLOCK if the channel is full. + * Returns DEAD_OBJECT if the channel's peer has been closed. * Returns BAD_VALUE if pointerCount is less than 1 or greater than MAX_POINTERS. + * Other errors probably indicate that the channel is broken. */ status_t publishMotionEvent( int32_t deviceId, @@ -233,55 +221,22 @@ public: const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); - /* Appends a motion sample to a motion event unless already consumed. - * - * Returns OK on success. - * Returns INVALID_OPERATION if the current event is not a AMOTION_EVENT_ACTION_MOVE event. - * Returns FAILED_TRANSACTION if the current event has already been consumed. - * Returns NO_MEMORY if the buffer is full and no additional samples can be added. - */ - status_t appendMotionSample( - nsecs_t eventTime, - const PointerCoords* pointerCoords); - - /* Sends a dispatch signal to the consumer to inform it that a new message is available. - * - * Returns OK on success. - * Errors probably indicate that the channel is broken. - */ - status_t sendDispatchSignal(); - /* Receives the finished signal from the consumer in reply to the original dispatch signal. * Returns whether the consumer handled the message. * * Returns OK on success. * Returns WOULD_BLOCK if there is no signal present. + * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ status_t receiveFinishedSignal(bool* outHandled); private: sp mChannel; - - size_t mAshmemSize; - InputMessage* mSharedMessage; - bool mPinned; - bool mSemaphoreInitialized; - bool mWasDispatched; - - size_t mMotionEventPointerCount; - InputMessage::SampleData* mMotionEventSampleDataTail; - size_t mMotionEventSampleDataStride; - - status_t publishInputEvent( - int32_t type, - int32_t deviceId, - int32_t source); }; /* - * Consumes input events from an anonymous shared memory buffer. - * Uses atomic operations to coordinate shared access with a single concurrent publisher. + * Consumes input events from an input channel. */ class InputConsumer { public: @@ -294,16 +249,14 @@ public: /* Gets the underlying input channel. */ inline sp getChannel() { return mChannel; } - /* Prepares the consumer for use. Must be called before it is used. */ - status_t initialize(); - - /* Consumes the input event in the buffer and copies its contents into + /* Consumes an input event from the input channel and copies its contents into * an InputEvent object created using the specified factory. - * This operation will block if the publisher is updating the event. * * Returns OK on success. - * Returns INVALID_OPERATION if there is no currently published event. + * Returns WOULD_BLOCK if there is no event present. + * Returns DEAD_OBJECT if the channel's peer has been closed. * Returns NO_MEMORY if the event could not be created. + * Other errors probably indicate that the channel is broken. */ status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent); @@ -311,26 +264,12 @@ public: * finished processing and specifies whether the message was handled by the consumer. * * Returns OK on success. - * Errors probably indicate that the channel is broken. + * Other errors probably indicate that the channel is broken. */ status_t sendFinishedSignal(bool handled); - /* Receives the dispatched signal from the publisher. - * - * Returns OK on success. - * Returns WOULD_BLOCK if there is no signal present. - * Other errors probably indicate that the channel is broken. - */ - status_t receiveDispatchSignal(); - private: sp mChannel; - - size_t mAshmemSize; - InputMessage* mSharedMessage; - - void populateKeyEvent(KeyEvent* keyEvent) const; - void populateMotionEvent(MotionEvent* motionEvent) const; }; } // namespace android diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 09cbb318cd930..70473226fd844 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -7,322 +7,186 @@ //#define LOG_NDEBUG 0 -// Log debug messages about channel signalling (send signal, receive signal) -#define DEBUG_CHANNEL_SIGNALS 0 +// Log debug messages about channel messages (send message, receive message) +#define DEBUG_CHANNEL_MESSAGES 0 // Log debug messages whenever InputChannel objects are created/destroyed #define DEBUG_CHANNEL_LIFECYCLE 0 -// Log debug messages about transport actions (initialize, reset, publish, ...) #define DEBUG_TRANSPORT_ACTIONS 0 +// Log debug messages about transport actions -#include #include #include #include -#include #include #include +#include +#include + namespace android { -#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1)) -#define MIN_HISTORY_DEPTH 20 +// --- InputMessage --- -// Must be at least sizeof(InputMessage) + sufficient space for pointer data -static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP( - sizeof(InputMessage) + MIN_HISTORY_DEPTH - * (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)), - 4096); +bool InputMessage::isValid(size_t actualSize) const { + if (size() == actualSize) { + switch (header.type) { + case TYPE_KEY: + return true; + case TYPE_MOTION: + return body.motion.pointerCount > 0 + && body.motion.pointerCount <= MAX_POINTERS; + case TYPE_FINISHED: + return true; + } + } + return false; +} -// Signal sent by the producer to the consumer to inform it that a new message is -// available to be consumed in the shared memory buffer. -static const char INPUT_SIGNAL_DISPATCH = 'D'; - -// Signal sent by the consumer to the producer to inform it that it has finished -// consuming the most recent message and it handled it. -static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f'; - -// Signal sent by the consumer to the producer to inform it that it has finished -// consuming the most recent message but it did not handle it. -static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u'; +size_t InputMessage::size() const { + switch (header.type) { + case TYPE_KEY: + return sizeof(Header) + body.key.size(); + case TYPE_MOTION: + return sizeof(Header) + body.motion.size(); + case TYPE_FINISHED: + return sizeof(Header) + body.finished.size(); + } + return sizeof(Header); +} // --- InputChannel --- -InputChannel::InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd, - int32_t sendPipeFd) : - mName(name), mAshmemFd(ashmemFd), mReceivePipeFd(receivePipeFd), mSendPipeFd(sendPipeFd) { +InputChannel::InputChannel(const String8& name, int fd) : + mName(name), mFd(fd) { #if DEBUG_CHANNEL_LIFECYCLE - ALOGD("Input channel constructed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d", - mName.string(), ashmemFd, receivePipeFd, sendPipeFd); + ALOGD("Input channel constructed: name='%s', fd=%d", + mName.string(), fd); #endif - int result = fcntl(mReceivePipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make receive pipe " - "non-blocking. errno=%d", mName.string(), errno); - - result = fcntl(mSendPipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make send pipe " + int result = fcntl(mFd, F_SETFL, O_NONBLOCK); + LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket " "non-blocking. errno=%d", mName.string(), errno); } InputChannel::~InputChannel() { #if DEBUG_CHANNEL_LIFECYCLE - ALOGD("Input channel destroyed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d", - mName.string(), mAshmemFd, mReceivePipeFd, mSendPipeFd); + ALOGD("Input channel destroyed: name='%s', fd=%d", + mName.string(), mFd); #endif - ::close(mAshmemFd); - ::close(mReceivePipeFd); - ::close(mSendPipeFd); + ::close(mFd); } status_t InputChannel::openInputChannelPair(const String8& name, sp& outServerChannel, sp& outClientChannel) { - status_t result; - - String8 ashmemName("InputChannel "); - ashmemName.append(name); - int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE); - if (serverAshmemFd < 0) { - result = -errno; - ALOGE("channel '%s' ~ Could not create shared memory region. errno=%d", + int sockets[2]; + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { + status_t result = -errno; + ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", name.string(), errno); - } else { - result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE); - if (result < 0) { - ALOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.", - name.string(), result, serverAshmemFd); - } else { - // Dup the file descriptor because the server and client input channel objects that - // are returned may have different lifetimes but they share the same shared memory region. - int clientAshmemFd; - clientAshmemFd = dup(serverAshmemFd); - if (clientAshmemFd < 0) { - result = -errno; - ALOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d", - name.string(), errno); - } else { - int forward[2]; - if (pipe(forward)) { - result = -errno; - ALOGE("channel '%s' ~ Could not create forward pipe. errno=%d", - name.string(), errno); - } else { - int reverse[2]; - if (pipe(reverse)) { - result = -errno; - ALOGE("channel '%s' ~ Could not create reverse pipe. errno=%d", - name.string(), errno); - } else { - String8 serverChannelName = name; - serverChannelName.append(" (server)"); - outServerChannel = new InputChannel(serverChannelName, - serverAshmemFd, reverse[0], forward[1]); - - String8 clientChannelName = name; - clientChannelName.append(" (client)"); - outClientChannel = new InputChannel(clientChannelName, - clientAshmemFd, forward[0], reverse[1]); - return OK; - } - ::close(forward[0]); - ::close(forward[1]); - } - ::close(clientAshmemFd); - } - } - ::close(serverAshmemFd); + outServerChannel.clear(); + outClientChannel.clear(); + return result; } - outServerChannel.clear(); - outClientChannel.clear(); - return result; + String8 serverChannelName = name; + serverChannelName.append(" (server)"); + outServerChannel = new InputChannel(serverChannelName, sockets[0]); + + String8 clientChannelName = name; + clientChannelName.append(" (client)"); + outClientChannel = new InputChannel(clientChannelName, sockets[1]); + return OK; } -status_t InputChannel::sendSignal(char signal) { +status_t InputChannel::sendMessage(const InputMessage* msg) { + size_t msgLength = msg->size(); ssize_t nWrite; do { - nWrite = ::write(mSendPipeFd, & signal, 1); + nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 && errno == EINTR); - if (nWrite == 1) { -#if DEBUG_CHANNEL_SIGNALS - ALOGD("channel '%s' ~ sent signal '%c'", mName.string(), signal); + if (nWrite < 0) { + int error = errno; +#if DEBUG_CHANNEL_MESSAGES + ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(), + msg->header.type, error); #endif - return OK; + if (error == EAGAIN || error == EWOULDBLOCK) { + return WOULD_BLOCK; + } + if (error == EPIPE || error == ENOTCONN) { + return DEAD_OBJECT; + } + return -error; } -#if DEBUG_CHANNEL_SIGNALS - ALOGD("channel '%s' ~ error sending signal '%c', errno=%d", mName.string(), signal, errno); -#endif - return -errno; -} - -status_t InputChannel::receiveSignal(char* outSignal) { - ssize_t nRead; - do { - nRead = ::read(mReceivePipeFd, outSignal, 1); - } while (nRead == -1 && errno == EINTR); - - if (nRead == 1) { -#if DEBUG_CHANNEL_SIGNALS - ALOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal); -#endif - return OK; - } - - if (nRead == 0) { // check for EOF -#if DEBUG_CHANNEL_SIGNALS - ALOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string()); + if (size_t(nWrite) != msgLength) { +#if DEBUG_CHANNEL_MESSAGES + ALOGD("channel '%s' ~ error sending message type %d, send was incomplete", + mName.string(), msg->header.type); #endif return DEAD_OBJECT; } - if (errno == EAGAIN) { -#if DEBUG_CHANNEL_SIGNALS - ALOGD("channel '%s' ~ receive signal failed because no signal available", mName.string()); +#if DEBUG_CHANNEL_MESSAGES + ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type); #endif - return WOULD_BLOCK; + return OK; +} + +status_t InputChannel::receiveMessage(InputMessage* msg) { + ssize_t nRead; + do { + nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT); + } while (nRead == -1 && errno == EINTR); + + if (nRead < 0) { + int error = errno; +#if DEBUG_CHANNEL_MESSAGES + ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno); +#endif + if (error == EAGAIN || error == EWOULDBLOCK) { + return WOULD_BLOCK; + } + if (error == EPIPE || error == ENOTCONN) { + return DEAD_OBJECT; + } + return -error; } -#if DEBUG_CHANNEL_SIGNALS - ALOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno); + if (nRead == 0) { // check for EOF +#if DEBUG_CHANNEL_MESSAGES + ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string()); #endif - return -errno; + return DEAD_OBJECT; + } + + if (!msg->isValid(nRead)) { +#if DEBUG_CHANNEL_MESSAGES + ALOGD("channel '%s' ~ received invalid message", mName.string()); +#endif + return BAD_VALUE; + } + +#if DEBUG_CHANNEL_MESSAGES + ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type); +#endif + return OK; } // --- InputPublisher --- InputPublisher::InputPublisher(const sp& channel) : - mChannel(channel), mSharedMessage(NULL), - mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false), - mMotionEventSampleDataTail(NULL) { + mChannel(channel) { } InputPublisher::~InputPublisher() { - reset(); - - if (mSharedMessage) { - munmap(mSharedMessage, mAshmemSize); - } -} - -status_t InputPublisher::initialize() { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ initialize", - mChannel->getName().string()); -#endif - - int ashmemFd = mChannel->getAshmemFd(); - int result = ashmem_get_size_region(ashmemFd); - if (result < 0) { - ALOGE("channel '%s' publisher ~ Error %d getting size of ashmem fd %d.", - mChannel->getName().string(), result, ashmemFd); - return UNKNOWN_ERROR; - } - mAshmemSize = (size_t) result; - - mSharedMessage = static_cast(mmap(NULL, mAshmemSize, - PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0)); - if (! mSharedMessage) { - ALOGE("channel '%s' publisher ~ mmap failed on ashmem fd %d.", - mChannel->getName().string(), ashmemFd); - return NO_MEMORY; - } - - mPinned = true; - mSharedMessage->consumed = false; - - return reset(); -} - -status_t InputPublisher::reset() { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ reset", - mChannel->getName().string()); -#endif - - if (mPinned) { - // Destroy the semaphore since we are about to unpin the memory region that contains it. - int result; - if (mSemaphoreInitialized) { - if (mSharedMessage->consumed) { - result = sem_post(& mSharedMessage->semaphore); - if (result < 0) { - ALOGE("channel '%s' publisher ~ Error %d in sem_post.", - mChannel->getName().string(), errno); - return UNKNOWN_ERROR; - } - } - - result = sem_destroy(& mSharedMessage->semaphore); - if (result < 0) { - ALOGE("channel '%s' publisher ~ Error %d in sem_destroy.", - mChannel->getName().string(), errno); - return UNKNOWN_ERROR; - } - - mSemaphoreInitialized = false; - } - - // Unpin the region since we no longer care about its contents. - int ashmemFd = mChannel->getAshmemFd(); - result = ashmem_unpin_region(ashmemFd, 0, 0); - if (result < 0) { - ALOGE("channel '%s' publisher ~ Error %d unpinning ashmem fd %d.", - mChannel->getName().string(), result, ashmemFd); - return UNKNOWN_ERROR; - } - - mPinned = false; - } - - mMotionEventSampleDataTail = NULL; - mWasDispatched = false; - return OK; -} - -status_t InputPublisher::publishInputEvent( - int32_t type, - int32_t deviceId, - int32_t source) { - if (mPinned) { - ALOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has " - "not yet been reset.", mChannel->getName().string()); - return INVALID_OPERATION; - } - - // Pin the region. - // We do not check for ASHMEM_NOT_PURGED because we don't care about the previous - // contents of the buffer so it does not matter whether it was purged in the meantime. - int ashmemFd = mChannel->getAshmemFd(); - int result = ashmem_pin_region(ashmemFd, 0, 0); - if (result < 0) { - ALOGE("channel '%s' publisher ~ Error %d pinning ashmem fd %d.", - mChannel->getName().string(), result, ashmemFd); - return UNKNOWN_ERROR; - } - - mPinned = true; - - result = sem_init(& mSharedMessage->semaphore, 1, 1); - if (result < 0) { - ALOGE("channel '%s' publisher ~ Error %d in sem_init.", - mChannel->getName().string(), errno); - return UNKNOWN_ERROR; - } - - mSemaphoreInitialized = true; - - mSharedMessage->consumed = false; - mSharedMessage->type = type; - mSharedMessage->deviceId = deviceId; - mSharedMessage->source = source; - return OK; } status_t InputPublisher::publishKeyEvent( @@ -345,20 +209,19 @@ status_t InputPublisher::publishKeyEvent( downTime, eventTime); #endif - status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source); - if (result < 0) { - return result; - } - - mSharedMessage->key.action = action; - mSharedMessage->key.flags = flags; - mSharedMessage->key.keyCode = keyCode; - mSharedMessage->key.scanCode = scanCode; - mSharedMessage->key.metaState = metaState; - mSharedMessage->key.repeatCount = repeatCount; - mSharedMessage->key.downTime = downTime; - mSharedMessage->key.eventTime = eventTime; - return OK; + InputMessage msg; + msg.header.type = InputMessage::TYPE_KEY; + msg.body.key.deviceId = deviceId; + msg.body.key.source = source; + msg.body.key.action = action; + msg.body.key.flags = flags; + msg.body.key.keyCode = keyCode; + msg.body.key.scanCode = scanCode; + msg.body.key.metaState = metaState; + msg.body.key.repeatCount = repeatCount; + msg.body.key.downTime = downTime; + msg.body.key.eventTime = eventTime; + return mChannel->sendMessage(&msg); } status_t InputPublisher::publishMotionEvent( @@ -395,123 +258,27 @@ status_t InputPublisher::publishMotionEvent( return BAD_VALUE; } - status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source); - if (result < 0) { - return result; - } - - mSharedMessage->motion.action = action; - mSharedMessage->motion.flags = flags; - mSharedMessage->motion.edgeFlags = edgeFlags; - mSharedMessage->motion.metaState = metaState; - mSharedMessage->motion.buttonState = buttonState; - mSharedMessage->motion.xOffset = xOffset; - mSharedMessage->motion.yOffset = yOffset; - mSharedMessage->motion.xPrecision = xPrecision; - mSharedMessage->motion.yPrecision = yPrecision; - mSharedMessage->motion.downTime = downTime; - mSharedMessage->motion.pointerCount = pointerCount; - - mSharedMessage->motion.sampleCount = 1; - mSharedMessage->motion.sampleData[0].eventTime = eventTime; - + InputMessage msg; + msg.header.type = InputMessage::TYPE_MOTION; + msg.body.motion.deviceId = deviceId; + msg.body.motion.source = source; + msg.body.motion.action = action; + msg.body.motion.flags = flags; + msg.body.motion.edgeFlags = edgeFlags; + msg.body.motion.metaState = metaState; + msg.body.motion.buttonState = buttonState; + msg.body.motion.xOffset = xOffset; + msg.body.motion.yOffset = yOffset; + msg.body.motion.xPrecision = xPrecision; + msg.body.motion.yPrecision = yPrecision; + msg.body.motion.downTime = downTime; + msg.body.motion.eventTime = eventTime; + msg.body.motion.pointerCount = pointerCount; for (size_t i = 0; i < pointerCount; i++) { - mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]); - mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]); + msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]); + msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]); } - - // Cache essential information about the motion event to ensure that a malicious consumer - // cannot confuse the publisher by modifying the contents of the shared memory buffer while - // it is being updated. - if (action == AMOTION_EVENT_ACTION_MOVE - || action == AMOTION_EVENT_ACTION_HOVER_MOVE) { - mMotionEventPointerCount = pointerCount; - mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount); - mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement( - mSharedMessage->motion.sampleData, mMotionEventSampleDataStride); - } else { - mMotionEventSampleDataTail = NULL; - } - return OK; -} - -status_t InputPublisher::appendMotionSample( - nsecs_t eventTime, - const PointerCoords* pointerCoords) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ appendMotionSample: eventTime=%lld", - mChannel->getName().string(), eventTime); -#endif - - if (! mPinned || ! mMotionEventSampleDataTail) { - ALOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current " - "AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.", - mChannel->getName().string()); - return INVALID_OPERATION; - } - - InputMessage::SampleData* newTail = InputMessage::sampleDataPtrIncrement( - mMotionEventSampleDataTail, mMotionEventSampleDataStride); - size_t newBytesUsed = reinterpret_cast(newTail) - - reinterpret_cast(mSharedMessage); - - if (newBytesUsed > mAshmemSize) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory " - "buffer is full. Buffer size: %d bytes, pointers: %d, samples: %d", - mChannel->getName().string(), - mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount); -#endif - return NO_MEMORY; - } - - int result; - if (mWasDispatched) { - result = sem_trywait(& mSharedMessage->semaphore); - if (result < 0) { - if (errno == EAGAIN) { - // Only possible source of contention is the consumer having consumed (or being in the - // process of consuming) the message and left the semaphore count at 0. -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ Cannot append motion sample because the message has " - "already been consumed.", mChannel->getName().string()); -#endif - return FAILED_TRANSACTION; - } else { - ALOGE("channel '%s' publisher ~ Error %d in sem_trywait.", - mChannel->getName().string(), errno); - return UNKNOWN_ERROR; - } - } - } - - mMotionEventSampleDataTail->eventTime = eventTime; - for (size_t i = 0; i < mMotionEventPointerCount; i++) { - mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]); - } - mMotionEventSampleDataTail = newTail; - - mSharedMessage->motion.sampleCount += 1; - - if (mWasDispatched) { - result = sem_post(& mSharedMessage->semaphore); - if (result < 0) { - ALOGE("channel '%s' publisher ~ Error %d in sem_post.", - mChannel->getName().string(), errno); - return UNKNOWN_ERROR; - } - } - return OK; -} - -status_t InputPublisher::sendDispatchSignal() { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ sendDispatchSignal", - mChannel->getName().string()); -#endif - - mWasDispatched = true; - return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH); + return mChannel->sendMessage(&msg); } status_t InputPublisher::receiveFinishedSignal(bool* outHandled) { @@ -520,61 +287,28 @@ status_t InputPublisher::receiveFinishedSignal(bool* outHandled) { mChannel->getName().string()); #endif - char signal; - status_t result = mChannel->receiveSignal(& signal); + InputMessage msg; + status_t result = mChannel->receiveMessage(&msg); if (result) { *outHandled = false; return result; } - if (signal == INPUT_SIGNAL_FINISHED_HANDLED) { - *outHandled = true; - } else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) { - *outHandled = false; - } else { - ALOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer", - mChannel->getName().string(), signal); + if (msg.header.type != InputMessage::TYPE_FINISHED) { + ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer", + mChannel->getName().string(), msg.header.type); return UNKNOWN_ERROR; } + *outHandled = msg.body.finished.handled; return OK; } // --- InputConsumer --- InputConsumer::InputConsumer(const sp& channel) : - mChannel(channel), mSharedMessage(NULL) { + mChannel(channel) { } InputConsumer::~InputConsumer() { - if (mSharedMessage) { - munmap(mSharedMessage, mAshmemSize); - } -} - -status_t InputConsumer::initialize() { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ initialize", - mChannel->getName().string()); -#endif - - int ashmemFd = mChannel->getAshmemFd(); - int result = ashmem_get_size_region(ashmemFd); - if (result < 0) { - ALOGE("channel '%s' consumer ~ Error %d getting size of ashmem fd %d.", - mChannel->getName().string(), result, ashmemFd); - return UNKNOWN_ERROR; - } - - mAshmemSize = (size_t) result; - - mSharedMessage = static_cast(mmap(NULL, mAshmemSize, - PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0)); - if (! mSharedMessage) { - ALOGE("channel '%s' consumer ~ mmap failed on ashmem fd %d.", - mChannel->getName().string(), ashmemFd); - return NO_MEMORY; - } - - return OK; } status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) { @@ -585,46 +319,28 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent* *outEvent = NULL; - int ashmemFd = mChannel->getAshmemFd(); - int result = ashmem_pin_region(ashmemFd, 0, 0); - if (result != ASHMEM_NOT_PURGED) { - if (result == ASHMEM_WAS_PURGED) { - ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged " - "which probably indicates that the publisher and consumer are out of sync.", - mChannel->getName().string(), result, ashmemFd); - return INVALID_OPERATION; - } - - ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.", - mChannel->getName().string(), result, ashmemFd); - return UNKNOWN_ERROR; + InputMessage msg; + status_t result = mChannel->receiveMessage(&msg); + if (result) { + return result; } - if (mSharedMessage->consumed) { - ALOGE("channel '%s' consumer ~ The current message has already been consumed.", - mChannel->getName().string()); - return INVALID_OPERATION; - } - - // Acquire but *never release* the semaphore. Contention on the semaphore is used to signal - // to the publisher that the message has been consumed (or is in the process of being - // consumed). Eventually the publisher will reinitialize the semaphore for the next message. - result = sem_wait(& mSharedMessage->semaphore); - if (result < 0) { - ALOGE("channel '%s' consumer ~ Error %d in sem_wait.", - mChannel->getName().string(), errno); - return UNKNOWN_ERROR; - } - - mSharedMessage->consumed = true; - - switch (mSharedMessage->type) { - case AINPUT_EVENT_TYPE_KEY: { + switch (msg.header.type) { + case InputMessage::TYPE_KEY: { KeyEvent* keyEvent = factory->createKeyEvent(); - if (! keyEvent) return NO_MEMORY; - - populateKeyEvent(keyEvent); + if (!keyEvent) return NO_MEMORY; + keyEvent->initialize( + msg.body.key.deviceId, + msg.body.key.source, + msg.body.key.action, + msg.body.key.flags, + msg.body.key.keyCode, + msg.body.key.scanCode, + msg.body.key.metaState, + msg.body.key.repeatCount, + msg.body.key.downTime, + msg.body.key.eventTime); *outEvent = keyEvent; break; } @@ -633,15 +349,38 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent* MotionEvent* motionEvent = factory->createMotionEvent(); if (! motionEvent) return NO_MEMORY; - populateMotionEvent(motionEvent); + size_t pointerCount = msg.body.motion.pointerCount; + PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].copyFrom(msg.body.motion.pointers[i].properties); + pointerCoords[i].copyFrom(msg.body.motion.pointers[i].coords); + } + motionEvent->initialize( + msg.body.motion.deviceId, + msg.body.motion.source, + msg.body.motion.action, + msg.body.motion.flags, + msg.body.motion.edgeFlags, + msg.body.motion.metaState, + msg.body.motion.buttonState, + msg.body.motion.xOffset, + msg.body.motion.yOffset, + msg.body.motion.xPrecision, + msg.body.motion.yPrecision, + msg.body.motion.downTime, + msg.body.motion.eventTime, + pointerCount, + pointerProperties, + pointerCoords); *outEvent = motionEvent; break; } default: - ALOGE("channel '%s' consumer ~ Received message of unknown type %d", - mChannel->getName().string(), mSharedMessage->type); + ALOGE("channel '%s' consumer ~ Received unexpected message of type %d", + mChannel->getName().string(), msg.header.type); return UNKNOWN_ERROR; } @@ -654,74 +393,10 @@ status_t InputConsumer::sendFinishedSignal(bool handled) { mChannel->getName().string(), handled); #endif - return mChannel->sendSignal(handled - ? INPUT_SIGNAL_FINISHED_HANDLED - : INPUT_SIGNAL_FINISHED_UNHANDLED); -} - -status_t InputConsumer::receiveDispatchSignal() { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ receiveDispatchSignal", - mChannel->getName().string()); -#endif - - char signal; - status_t result = mChannel->receiveSignal(& signal); - if (result) { - return result; - } - if (signal != INPUT_SIGNAL_DISPATCH) { - ALOGE("channel '%s' consumer ~ Received unexpected signal '%c' from publisher", - mChannel->getName().string(), signal); - return UNKNOWN_ERROR; - } - return OK; -} - -void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const { - keyEvent->initialize( - mSharedMessage->deviceId, - mSharedMessage->source, - mSharedMessage->key.action, - mSharedMessage->key.flags, - mSharedMessage->key.keyCode, - mSharedMessage->key.scanCode, - mSharedMessage->key.metaState, - mSharedMessage->key.repeatCount, - mSharedMessage->key.downTime, - mSharedMessage->key.eventTime); -} - -void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const { - motionEvent->initialize( - mSharedMessage->deviceId, - mSharedMessage->source, - mSharedMessage->motion.action, - mSharedMessage->motion.flags, - mSharedMessage->motion.edgeFlags, - mSharedMessage->motion.metaState, - mSharedMessage->motion.buttonState, - mSharedMessage->motion.xOffset, - mSharedMessage->motion.yOffset, - mSharedMessage->motion.xPrecision, - mSharedMessage->motion.yPrecision, - mSharedMessage->motion.downTime, - mSharedMessage->motion.sampleData[0].eventTime, - mSharedMessage->motion.pointerCount, - mSharedMessage->motion.pointerProperties, - mSharedMessage->motion.sampleData[0].coords); - - size_t sampleCount = mSharedMessage->motion.sampleCount; - if (sampleCount > 1) { - InputMessage::SampleData* sampleData = mSharedMessage->motion.sampleData; - size_t sampleDataStride = InputMessage::sampleDataStride( - mSharedMessage->motion.pointerCount); - - while (--sampleCount > 0) { - sampleData = InputMessage::sampleDataPtrIncrement(sampleData, sampleDataStride); - motionEvent->addSample(sampleData->eventTime, sampleData->coords); - } - } + InputMessage msg; + msg.header.type = InputMessage::TYPE_FINISHED; + msg.body.finished.handled = handled; + return mChannel->sendMessage(&msg); } } // namespace android diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/ui/tests/InputChannel_test.cpp index eff22ee5f0eb4..c73dc2fc52d2f 100644 --- a/libs/ui/tests/InputChannel_test.cpp +++ b/libs/ui/tests/InputChannel_test.cpp @@ -20,8 +20,7 @@ #include #include #include -#include -#include +#include #include "../../utils/tests/TestHelpers.h" @@ -36,35 +35,24 @@ protected: TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) { // Our purpose here is to verify that the input channel destructor closes the - // file descriptors provided to it. One easy way is to provide it with one end + // file descriptor provided to it. One easy way is to provide it with one end // of a pipe and to check for EPIPE on the other end after the channel is destroyed. - Pipe fakeAshmem, sendPipe, receivePipe; + Pipe pipe; - sp inputChannel = new InputChannel(String8("channel name"), - fakeAshmem.sendFd, receivePipe.receiveFd, sendPipe.sendFd); + sp inputChannel = new InputChannel(String8("channel name"), pipe.sendFd); EXPECT_STREQ("channel name", inputChannel->getName().string()) << "channel should have provided name"; - EXPECT_EQ(fakeAshmem.sendFd, inputChannel->getAshmemFd()) - << "channel should have provided ashmem fd"; - EXPECT_EQ(receivePipe.receiveFd, inputChannel->getReceivePipeFd()) - << "channel should have provided receive pipe fd"; - EXPECT_EQ(sendPipe.sendFd, inputChannel->getSendPipeFd()) - << "channel should have provided send pipe fd"; + EXPECT_EQ(pipe.sendFd, inputChannel->getFd()) + << "channel should have provided fd"; inputChannel.clear(); // destroys input channel - EXPECT_EQ(-EPIPE, fakeAshmem.readSignal()) - << "channel should have closed ashmem fd when destroyed"; - EXPECT_EQ(-EPIPE, receivePipe.writeSignal()) - << "channel should have closed receive pipe fd when destroyed"; - EXPECT_EQ(-EPIPE, sendPipe.readSignal()) - << "channel should have closed send pipe fd when destroyed"; + EXPECT_EQ(-EPIPE, pipe.readSignal()) + << "channel should have closed fd when destroyed"; // clean up fds of Pipe endpoints that were closed so we don't try to close them again - fakeAshmem.sendFd = -1; - receivePipe.receiveFd = -1; - sendPipe.sendFd = -1; + pipe.sendFd = -1; } TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { @@ -82,43 +70,37 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { EXPECT_STREQ("channel name (client)", clientChannel->getName().string()) << "client channel should have suffixed name"; - // Ashmem uniqueness - EXPECT_NE(serverChannel->getAshmemFd(), clientChannel->getAshmemFd()) - << "server and client channel should have different ashmem fds because it was dup'd"; - - // Ashmem usability - ssize_t serverAshmemSize = ashmem_get_size_region(serverChannel->getAshmemFd()); - ssize_t clientAshmemSize = ashmem_get_size_region(clientChannel->getAshmemFd()); - uint32_t* serverAshmem = static_cast(mmap(NULL, serverAshmemSize, - PROT_READ | PROT_WRITE, MAP_SHARED, serverChannel->getAshmemFd(), 0)); - uint32_t* clientAshmem = static_cast(mmap(NULL, clientAshmemSize, - PROT_READ | PROT_WRITE, MAP_SHARED, clientChannel->getAshmemFd(), 0)); - ASSERT_TRUE(serverAshmem != NULL) - << "server channel ashmem should be mappable"; - ASSERT_TRUE(clientAshmem != NULL) - << "client channel ashmem should be mappable"; - *serverAshmem = 0xf00dd00d; - EXPECT_EQ(0xf00dd00d, *clientAshmem) - << "ashmem buffer should be shared by client and server"; - munmap(serverAshmem, serverAshmemSize); - munmap(clientAshmem, clientAshmemSize); - // Server->Client communication - EXPECT_EQ(OK, serverChannel->sendSignal('S')) - << "server channel should be able to send signal to client channel"; - char signal; - EXPECT_EQ(OK, clientChannel->receiveSignal(& signal)) - << "client channel should be able to receive signal from server channel"; - EXPECT_EQ('S', signal) - << "client channel should receive the correct signal from server channel"; + InputMessage serverMsg; + memset(&serverMsg, 0, sizeof(InputMessage)); + serverMsg.header.type = InputMessage::TYPE_KEY; + serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN; + EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg)) + << "server channel should be able to send message to client channel"; + + InputMessage clientMsg; + EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg)) + << "client channel should be able to receive message from server channel"; + EXPECT_EQ(serverMsg.header.type, clientMsg.header.type) + << "client channel should receive the correct message from server channel"; + EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action) + << "client channel should receive the correct message from server channel"; // Client->Server communication - EXPECT_EQ(OK, clientChannel->sendSignal('c')) - << "client channel should be able to send signal to server channel"; - EXPECT_EQ(OK, serverChannel->receiveSignal(& signal)) - << "server channel should be able to receive signal from client channel"; - EXPECT_EQ('c', signal) - << "server channel should receive the correct signal from client channel"; + InputMessage clientReply; + memset(&clientReply, 0, sizeof(InputMessage)); + clientReply.header.type = InputMessage::TYPE_FINISHED; + clientReply.body.finished.handled = true; + EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply)) + << "client channel should be able to send message to server channel"; + + InputMessage serverReply; + EXPECT_EQ(OK, serverChannel->receiveMessage(&serverReply)) + << "server channel should be able to receive message from client channel"; + EXPECT_EQ(clientReply.header.type, serverReply.header.type) + << "server channel should receive the correct message from client channel"; + EXPECT_EQ(clientReply.body.finished.handled, serverReply.body.finished.handled) + << "server channel should receive the correct message from client channel"; } TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) { @@ -130,9 +112,9 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) { ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; - char signal; - EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveSignal(& signal)) - << "receiveSignal should have returned WOULD_BLOCK"; + InputMessage msg; + EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveMessage(&msg)) + << "receiveMessage should have returned WOULD_BLOCK"; } TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { @@ -146,9 +128,9 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { serverChannel.clear(); // close server channel - char signal; - EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveSignal(& signal)) - << "receiveSignal should have returned DEAD_OBJECT"; + InputMessage msg; + EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg)) + << "receiveMessage should have returned DEAD_OBJECT"; } TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) { @@ -162,8 +144,10 @@ TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) { serverChannel.clear(); // close server channel - EXPECT_EQ(DEAD_OBJECT, clientChannel->sendSignal('S')) - << "sendSignal should have returned DEAD_OBJECT"; + InputMessage msg; + msg.header.type = InputMessage::TYPE_KEY; + EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg)) + << "sendMessage should have returned DEAD_OBJECT"; } diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp index fcc4cadb71ce2..a0ee94b63463e 100644 --- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp @@ -57,11 +57,8 @@ protected: clientChannel.clear(); } - void Initialize(); void PublishAndConsumeKeyEvent(); - void PublishAndConsumeMotionEvent( - size_t samplesToAppendBeforeDispatch = 0, - size_t samplesToAppendAfterDispatch = 0); + void PublishAndConsumeMotionEvent(); }; TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) { @@ -69,18 +66,6 @@ TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) { EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get()); } -void InputPublisherAndConsumerTest::Initialize() { - status_t status; - - status = mPublisher->initialize(); - ASSERT_EQ(OK, status) - << "publisher initialize should return OK"; - - status = mConsumer->initialize(); - ASSERT_EQ(OK, status) - << "consumer initialize should return OK"; -} - void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { status_t status; @@ -100,14 +85,6 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK"; - status = mPublisher->sendDispatchSignal(); - ASSERT_EQ(OK, status) - << "publisher sendDispatchSignal should return OK"; - - status = mConsumer->receiveDispatchSignal(); - ASSERT_EQ(OK, status) - << "consumer receiveDispatchSignal should return OK"; - InputEvent* event; status = mConsumer->consume(& mEventFactory, & event); ASSERT_EQ(OK, status) @@ -140,14 +117,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { << "publisher receiveFinishedSignal should return OK"; ASSERT_TRUE(handled) << "publisher receiveFinishedSignal should have set handled to consumer's reply"; - - status = mPublisher->reset(); - ASSERT_EQ(OK, status) - << "publisher reset should return OK"; } -void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( - size_t samplesToAppendBeforeDispatch, size_t samplesToAppendAfterDispatch) { +void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { status_t status; const int32_t deviceId = 1; @@ -163,65 +135,33 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( const float yPrecision = 0.5; const nsecs_t downTime = 3; const size_t pointerCount = 3; + const nsecs_t eventTime = 4; PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; for (size_t i = 0; i < pointerCount; i++) { pointerProperties[i].clear(); pointerProperties[i].id = (i + 2) % pointerCount; pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - Vector sampleEventTimes; - Vector samplePointerCoords; - - for (size_t i = 0; i <= samplesToAppendAfterDispatch + samplesToAppendBeforeDispatch; i++) { - sampleEventTimes.push(i + 10); - for (size_t j = 0; j < pointerCount; j++) { - samplePointerCoords.push(); - PointerCoords& pc = samplePointerCoords.editTop(); - pc.clear(); - pc.setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i + j); - pc.setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i + j); - pc.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i + j); - pc.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i + j); - pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i + j); - pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i + j); - pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i + j); - pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i + j); - pc.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i + j); - } + pointerCoords[i].clear(); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i); } status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, - downTime, sampleEventTimes[0], pointerCount, - pointerProperties, samplePointerCoords.array()); + downTime, eventTime, pointerCount, + pointerProperties, pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; - for (size_t i = 0; i < samplesToAppendBeforeDispatch; i++) { - size_t sampleIndex = i + 1; - status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex], - samplePointerCoords.array() + sampleIndex * pointerCount); - ASSERT_EQ(OK, status) - << "publisher appendMotionEvent should return OK"; - } - - status = mPublisher->sendDispatchSignal(); - ASSERT_EQ(OK, status) - << "publisher sendDispatchSignal should return OK"; - - for (size_t i = 0; i < samplesToAppendAfterDispatch; i++) { - size_t sampleIndex = i + 1 + samplesToAppendBeforeDispatch; - status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex], - samplePointerCoords.array() + sampleIndex * pointerCount); - ASSERT_EQ(OK, status) - << "publisher appendMotionEvent should return OK"; - } - - status = mConsumer->receiveDispatchSignal(); - ASSERT_EQ(OK, status) - << "consumer receiveDispatchSignal should return OK"; - InputEvent* event; status = mConsumer->consume(& mEventFactory, & event); ASSERT_EQ(OK, status) @@ -232,8 +172,6 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType()) << "consumer should have returned a motion event"; - size_t lastSampleIndex = samplesToAppendBeforeDispatch + samplesToAppendAfterDispatch; - MotionEvent* motionEvent = static_cast(event); EXPECT_EQ(deviceId, motionEvent->getDeviceId()); EXPECT_EQ(source, motionEvent->getSource()); @@ -245,74 +183,36 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( EXPECT_EQ(xPrecision, motionEvent->getXPrecision()); EXPECT_EQ(yPrecision, motionEvent->getYPrecision()); EXPECT_EQ(downTime, motionEvent->getDownTime()); - EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime()); + EXPECT_EQ(eventTime, motionEvent->getEventTime()); EXPECT_EQ(pointerCount, motionEvent->getPointerCount()); - EXPECT_EQ(lastSampleIndex, motionEvent->getHistorySize()); + EXPECT_EQ(0U, motionEvent->getHistorySize()); for (size_t i = 0; i < pointerCount; i++) { SCOPED_TRACE(i); EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i)); EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i)); - } - for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) { - SCOPED_TRACE(sampleIndex); - EXPECT_EQ(sampleEventTimes[sampleIndex], - motionEvent->getHistoricalEventTime(sampleIndex)); - for (size_t i = 0; i < pointerCount; i++) { - SCOPED_TRACE(i); - size_t offset = sampleIndex * pointerCount + i; - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X), - motionEvent->getHistoricalRawX(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y), - motionEvent->getHistoricalRawY(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset, - motionEvent->getHistoricalX(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset, - motionEvent->getHistoricalY(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - motionEvent->getHistoricalPressure(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - motionEvent->getHistoricalSize(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - motionEvent->getHistoricalTouchMajor(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - motionEvent->getHistoricalTouchMinor(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - motionEvent->getHistoricalToolMajor(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - motionEvent->getHistoricalToolMinor(i, sampleIndex)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), - motionEvent->getHistoricalOrientation(i, sampleIndex)); - } - } - - SCOPED_TRACE(lastSampleIndex); - EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime()); - for (size_t i = 0; i < pointerCount; i++) { - SCOPED_TRACE(i); - size_t offset = lastSampleIndex * pointerCount + i; - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X), + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), motionEvent->getRawX(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y), + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), motionEvent->getRawY(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset, + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset, motionEvent->getX(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset, + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset, motionEvent->getY(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent->getPressure(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE), + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent->getSize(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent->getTouchMajor(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i)); - EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), + EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), motionEvent->getOrientation(i)); } @@ -326,64 +226,18 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( << "publisher receiveFinishedSignal should return OK"; ASSERT_FALSE(handled) << "publisher receiveFinishedSignal should have set handled to consumer's reply"; - - status = mPublisher->reset(); - ASSERT_EQ(OK, status) - << "publisher reset should return OK"; } TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(Initialize()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); } -TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_WhenNotReset_ReturnsError) { - status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - - status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - ASSERT_EQ(OK, status) - << "publisher publishKeyEvent should return OK first time"; - - status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - ASSERT_EQ(INVALID_OPERATION, status) - << "publisher publishKeyEvent should return INVALID_OPERATION because " - "the publisher was not reset"; -} - TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(Initialize()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); } -TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsError) { - status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - - const size_t pointerCount = 1; - PointerProperties pointerProperties[pointerCount]; - PointerCoords pointerCoords[pointerCount]; - for (size_t i = 0; i < pointerCount; i++) { - pointerProperties[i].clear(); - pointerCoords[i].clear(); - } - - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); - ASSERT_EQ(OK, status) - << "publisher publishMotionEvent should return OK"; - - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); - ASSERT_EQ(INVALID_OPERATION, status) - << "publisher publishMotionEvent should return INVALID_OPERATION because "; - "the publisher was not reset"; -} - TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) { status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - const size_t pointerCount = 0; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; @@ -396,8 +250,6 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) { status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - const size_t pointerCount = MAX_POINTERS + 1; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; @@ -413,7 +265,6 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater } TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(Initialize()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); @@ -421,111 +272,4 @@ TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) { ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); } -TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledBeforeDispatchSignal_AppendsSamples) { - status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(3, 0)); -} - -TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledAfterDispatchSignalAndNotConsumed_AppendsSamples) { - status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(0, 4)); -} - -TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenNoMotionEventPublished_ReturnsError) { - status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - - PointerCoords pointerCoords[1]; - status = mPublisher->appendMotionSample(0, pointerCoords); - ASSERT_EQ(INVALID_OPERATION, status) - << "publisher appendMotionSample should return INVALID_OPERATION"; -} - -TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEventIsNotAMove_ReturnsError) { - status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - - const size_t pointerCount = MAX_POINTERS; - PointerProperties pointerProperties[pointerCount]; - PointerCoords pointerCoords[pointerCount]; - for (size_t i = 0; i < pointerCount; i++) { - pointerProperties[i].clear(); - pointerCoords[i].clear(); - } - - status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); - ASSERT_EQ(OK, status); - - status = mPublisher->appendMotionSample(0, pointerCoords); - ASSERT_EQ(INVALID_OPERATION, status) - << "publisher appendMotionSample should return INVALID_OPERATION"; -} - -TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_ReturnsError) { - status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - - const size_t pointerCount = MAX_POINTERS; - PointerProperties pointerProperties[pointerCount]; - PointerCoords pointerCoords[pointerCount]; - for (size_t i = 0; i < pointerCount; i++) { - pointerProperties[i].clear(); - pointerCoords[i].clear(); - } - - status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); - ASSERT_EQ(OK, status); - - status = mPublisher->sendDispatchSignal(); - ASSERT_EQ(OK, status); - - status = mConsumer->receiveDispatchSignal(); - ASSERT_EQ(OK, status); - - InputEvent* event; - status = mConsumer->consume(& mEventFactory, & event); - ASSERT_EQ(OK, status); - - status = mPublisher->appendMotionSample(0, pointerCoords); - ASSERT_EQ(status_t(FAILED_TRANSACTION), status) - << "publisher appendMotionSample should return FAILED_TRANSACTION"; -} - -TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsError) { - status_t status; - ASSERT_NO_FATAL_FAILURE(Initialize()); - - const size_t pointerCount = MAX_POINTERS; - PointerProperties pointerProperties[pointerCount]; - PointerCoords pointerCoords[pointerCount]; - for (size_t i = 0; i < pointerCount; i++) { - pointerProperties[i].clear(); - pointerCoords[i].clear(); - } - - status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); - ASSERT_EQ(OK, status); - - for (int count = 1;; count++) { - ASSERT_LT(count, 100000) << "should eventually reach OOM"; - - status = mPublisher->appendMotionSample(0, pointerCoords); - if (status != OK) { - ASSERT_GT(count, 12) << "should be able to add at least a dozen samples"; - ASSERT_EQ(NO_MEMORY, status) - << "publisher appendMotionSample should return NO_MEMORY when buffer is full"; - break; - } - } - - status = mPublisher->appendMotionSample(0, pointerCoords); - ASSERT_EQ(NO_MEMORY, status) - << "publisher appendMotionSample should return NO_MEMORY persistently until reset"; -} - } // namespace android diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 1953aa80fd5f0..87cf0dea9248b 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -196,8 +196,8 @@ InputDispatcher::~InputDispatcher() { drainInboundQueueLocked(); } - while (mConnectionsByReceiveFd.size() != 0) { - unregisterInputChannel(mConnectionsByReceiveFd.valueAt(0)->inputChannel); + while (mConnectionsByFd.size() != 0) { + unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel); } } @@ -888,7 +888,7 @@ void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTi ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { - sp connection = mConnectionsByReceiveFd.valueAt(connectionIndex); + sp connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } else { #if DEBUG_FOCUS @@ -994,7 +994,7 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout if (inputChannel.get()) { ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex >= 0) { - sp connection = mConnectionsByReceiveFd.valueAt(connectionIndex); + sp connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->status == Connection::STATUS_NORMAL) { CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "application not responding"); @@ -1643,7 +1643,7 @@ bool InputDispatcher::isWindowFinishedWithPreviousInputLocked( const sp& windowHandle) { ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel()); if (connectionIndex >= 0) { - sp connection = mConnectionsByReceiveFd.valueAt(connectionIndex); + sp connection = mConnectionsByFd.valueAt(connectionIndex); return connection->outboundQueue.isEmpty(); } else { return true; @@ -1957,15 +1957,6 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } } - // Send the dispatch signal. - status = connection->inputPublisher.sendDispatchSignal(); - if (status) { - ALOGE("channel '%s' ~ Could not send dispatch signal, status=%d", - connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); - return; - } - // Record information about the newly started dispatch cycle. connection->lastEventTime = eventEntry->eventTime; connection->lastDispatchTime = currentTime; @@ -1990,17 +1981,6 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, return; } - // Reset the publisher since the event has been consumed. - // We do this now so that the publisher can release some of its internal resources - // while waiting for the next dispatch cycle to begin. - status_t status = connection->inputPublisher.reset(); - if (status) { - ALOGE("channel '%s' ~ Could not reset publisher, status=%d", - connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); - return; - } - // Notify other system components and prepare to start the next dispatch cycle. onDispatchCycleFinishedLocked(currentTime, connection, handled); } @@ -2064,21 +2044,21 @@ void InputDispatcher::drainOutboundQueueLocked(Connection* connection) { deactivateConnectionLocked(connection); } -int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) { +int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { InputDispatcher* d = static_cast(data); { // acquire lock AutoMutex _l(d->mLock); - ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd); + ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); if (connectionIndex < 0) { ALOGE("Received spurious receive callback for unknown input channel. " - "fd=%d, events=0x%x", receiveFd, events); + "fd=%d, events=0x%x", fd, events); return 0; // remove the callback } bool notify; - sp connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex); + sp connection = d->mConnectionsByFd.valueAt(connectionIndex); if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { if (!(events & ALOOPER_EVENT_INPUT)) { ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " @@ -2117,9 +2097,9 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options) { - for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) { + for (size_t i = 0; i < mConnectionsByFd.size(); i++) { synthesizeCancelationEventsForConnectionLocked( - mConnectionsByReceiveFd.valueAt(i), options); + mConnectionsByFd.valueAt(i), options); } } @@ -2128,7 +2108,7 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( ssize_t index = getConnectionIndexLocked(channel); if (index >= 0) { synthesizeCancelationEventsForConnectionLocked( - mConnectionsByReceiveFd.valueAt(index), options); + mConnectionsByFd.valueAt(index), options); } } @@ -2968,8 +2948,8 @@ bool InputDispatcher::transferTouchFocus(const sp& fromChannel, ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { - sp fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex); - sp toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex); + sp fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex); + sp toConnection = mConnectionsByFd.valueAt(toConnectionIndex); fromConnection->inputState.copyPointerStateTo(toConnection->inputState); CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, @@ -3134,21 +3114,15 @@ status_t InputDispatcher::registerInputChannel(const sp& inputChan } sp connection = new Connection(inputChannel, inputWindowHandle, monitor); - status_t status = connection->initialize(); - if (status) { - ALOGE("Failed to initialize input publisher for input channel '%s', status=%d", - inputChannel->getName().string(), status); - return status; - } - int32_t receiveFd = inputChannel->getReceivePipeFd(); - mConnectionsByReceiveFd.add(receiveFd, connection); + int32_t fd = inputChannel->getFd(); + mConnectionsByFd.add(fd, connection); if (monitor) { mMonitoringChannels.push(inputChannel); } - mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); + mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); runCommandsLockedInterruptible(); } // release lock @@ -3184,14 +3158,14 @@ status_t InputDispatcher::unregisterInputChannelLocked(const sp& i return BAD_VALUE; } - sp connection = mConnectionsByReceiveFd.valueAt(connectionIndex); - mConnectionsByReceiveFd.removeItemsAt(connectionIndex); + sp connection = mConnectionsByFd.valueAt(connectionIndex); + mConnectionsByFd.removeItemsAt(connectionIndex); if (connection->monitor) { removeMonitorChannelLocked(inputChannel); } - mLooper->removeFd(inputChannel->getReceivePipeFd()); + mLooper->removeFd(inputChannel->getFd()); nsecs_t currentTime = now(); abortBrokenDispatchCycleLocked(currentTime, connection, notify); @@ -3212,9 +3186,9 @@ void InputDispatcher::removeMonitorChannelLocked(const sp& inputCh } ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputChannel) { - ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd()); + ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd()); if (connectionIndex >= 0) { - sp connection = mConnectionsByReceiveFd.valueAt(connectionIndex); + sp connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->inputChannel.get() == inputChannel.get()) { return connectionIndex; } @@ -4052,10 +4026,6 @@ InputDispatcher::Connection::Connection(const sp& inputChannel, InputDispatcher::Connection::~Connection() { } -status_t InputDispatcher::Connection::initialize() { - return inputPublisher.initialize(); -} - const char* InputDispatcher::Connection::getStatusLabel() const { switch (status) { case STATUS_NORMAL: diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 7a2839fbbd389..e593c25f567ac 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -807,8 +807,6 @@ private: inline double getDispatchLatencyMillis(nsecs_t currentTime) const { return (currentTime - lastDispatchTime) / 1000000.0; } - - status_t initialize(); }; enum DropReason { @@ -862,8 +860,8 @@ private: sp findTouchedWindowAtLocked(int32_t x, int32_t y); - // All registered connections mapped by receive pipe file descriptor. - KeyedVector > mConnectionsByReceiveFd; + // All registered connections mapped by channel file descriptor. + KeyedVector > mConnectionsByFd; ssize_t getConnectionIndexLocked(const sp& inputChannel); @@ -1027,7 +1025,7 @@ private: void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp& connection, bool notify); void drainOutboundQueueLocked(Connection* connection); - static int handleReceiveCallback(int receiveFd, int events, void* data); + static int handleReceiveCallback(int fd, int events, void* data); void synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options);