diff options
| -rw-r--r-- | include/ui/InputTransport.h | 338 | ||||
| -rw-r--r-- | libs/ui/InputTransport.cpp | 910 | ||||
| -rw-r--r-- | libs/ui/tests/InputChannel_test.cpp | 113 | ||||
| -rw-r--r-- | libs/ui/tests/InputPublisherAndConsumer_test.cpp | 346 | 
4 files changed, 648 insertions, 1059 deletions
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h index 95e4447c6a..bdd2fb9aa3 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 <semaphore.h>  #include <ui/Input.h>  #include <utils/Errors.h>  #include <utils/Timers.h> @@ -40,11 +36,85 @@  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. + * Intermediate representation used to send input events and related signals. + */ +struct InputMessage { +    enum { +        TYPE_KEY = 1, +        TYPE_MOTION = 2, +        TYPE_FINISHED = 3, +    }; + +    struct Header { +        uint32_t type; +        uint32_t padding; // 8 byte alignment for the body that follows +    } header; + +    union Body { +        struct Key { +            uint32_t seq; +            nsecs_t eventTime; +            int32_t deviceId; +            int32_t source; +            int32_t action; +            int32_t flags; +            int32_t keyCode; +            int32_t scanCode; +            int32_t metaState; +            int32_t repeatCount; +            nsecs_t downTime; + +            inline size_t size() const { +                return sizeof(Key); +            } +        } key; + +        struct Motion { +            uint32_t seq; +            nsecs_t eventTime; +            int32_t deviceId; +            int32_t source; +            int32_t action; +            int32_t flags; +            int32_t metaState; +            int32_t buttonState; +            int32_t edgeFlags; +            nsecs_t downTime; +            float xOffset; +            float yOffset; +            float xPrecision; +            float yPrecision; +            size_t pointerCount; +            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; + +        struct Finished { +            uint32_t seq; +            bool handled; + +            inline size_t size() const { +                return sizeof(Finished); +            } +        } finished; +    } body; + +    bool isValid(size_t actualSize) const; +    size_t size() const; +}; + +/* + * 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 own file descriptors. + * Each endpoint has its own InputChannel object that specifies its file descriptor.   *   * The input channel is closed when all references to it are released.   */ @@ -53,11 +123,9 @@ protected:      virtual ~InputChannel();  public: -    InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd, -            int32_t sendPipeFd); +    InputChannel(const String8& name, int32_t fd); -    /* Creates a pair of input channels and their underlying shared memory buffers -     * and pipes. +    /* Creates a pair of input channels.       *       * Returns OK on success.       */ @@ -65,107 +133,40 @@ public:              sp<InputChannel>& outServerChannel, sp<InputChannel>& 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; } +    inline int32_t getFd() const { return mFd; } -    /* Sends a signal to the other endpoint. +    /* 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 sendSignal(char signal); +    status_t sendMessage(const InputMessage* msg); -    /* Receives a signal send by the other endpoint. -     * (Should only call this after poll() indicates that the receivePipeFd has available input.) +    /* 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 signal present. +     * 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 receiveSignal(char* outSignal); +    status_t receiveMessage(InputMessage* msg);  private:      String8 mName; -    int32_t mAshmemFd; -    int32_t mReceivePipeFd; -    int32_t mSendPipeFd; +    int32_t mFd;  };  /* - * Private intermediate representation of input events as messages written into an - * ashmem buffer. - */ -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 -    }; - -    int32_t deviceId; -    int32_t source; - -    union { -        struct { -            int32_t action; -            int32_t flags; -            int32_t keyCode; -            int32_t scanCode; -            int32_t metaState; -            int32_t repeatCount; -            nsecs_t downTime; -            nsecs_t eventTime; -        } key; - -        struct { -            int32_t action; -            int32_t flags; -            int32_t metaState; -            int32_t buttonState; -            int32_t edgeFlags; -            nsecs_t downTime; -            float xOffset; -            float yOffset; -            float xPrecision; -            float yPrecision; -            size_t pointerCount; -            PointerProperties pointerProperties[MAX_POINTERS]; -            size_t sampleCount; -            SampleData sampleData[0]; // variable length -        } 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); -    } - -    /* Adds the SampleData stride to the given pointer. */ -    static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) { -        return reinterpret_cast<InputMessage::SampleData*>(reinterpret_cast<char*>(ptr) + stride); -    } -}; - -/* - * Publishes input events to an anonymous shared memory buffer. - * Uses atomic operations to coordinate shared access with a single concurrent consumer. + * Publishes input events to an input channel.   */  class InputPublisher {  public: @@ -178,26 +179,16 @@ public:      /* Gets the underlying input channel. */      inline sp<InputChannel> 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. +     * Returns BAD_VALUE if seq is 0. +     * Other errors probably indicate that the channel is broken.       */      status_t publishKeyEvent( +            uint32_t seq,              int32_t deviceId,              int32_t source,              int32_t action, @@ -209,13 +200,16 @@ 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 BAD_VALUE if pointerCount is less than 1 or greater than MAX_POINTERS. +     * Returns WOULD_BLOCK if the channel is full. +     * Returns DEAD_OBJECT if the channel's peer has been closed. +     * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS. +     * Other errors probably indicate that the channel is broken.       */      status_t publishMotionEvent( +            uint32_t seq,              int32_t deviceId,              int32_t source,              int32_t action, @@ -233,55 +227,25 @@ 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. +     * If a signal was received, returns the message sequence number, +     * and whether the consumer handled the message. +     * +     * The returned sequence number is never 0 unless the operation failed.       *       * 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); +    status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);  private:      sp<InputChannel> 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,43 +258,63 @@ public:      /* Gets the underlying input channel. */      inline sp<InputChannel> 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 NO_MEMORY if the event could not be created. -     */ -    status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent); - -    /* Sends a finished signal to the publisher to inform it that the current message is -     * finished processing and specifies whether the message was handled by the consumer. +     * Tries to combine a series of move events into larger batches whenever possible. +     * +     * If consumeBatches is false, then defers consuming pending batched events if it +     * is possible for additional samples to be added to them later.  Call hasPendingBatch() +     * to determine whether a pending batch is available to be consumed. +     * +     * If consumeBatches is true, then events are still batched but they are consumed +     * immediately as soon as the input channel is exhausted. +     * +     * The returned sequence number is never 0 unless the operation failed.       *       * Returns OK on success. -     * Errors probably indicate that the channel is broken. +     * 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 sendFinishedSignal(bool handled); +    status_t consume(InputEventFactoryInterface* factory, bool consumeBatches, +            uint32_t* outSeq, InputEvent** outEvent); -    /* Receives the dispatched signal from the publisher. +    /* Sends a finished signal to the publisher to inform it that the message +     * with the specified sequence number has finished being process and whether +     * the message was handled by the consumer.       *       * Returns OK on success. -     * Returns WOULD_BLOCK if there is no signal present. +     * Returns BAD_VALUE if seq is 0.       * Other errors probably indicate that the channel is broken.       */ -    status_t receiveDispatchSignal(); +    status_t sendFinishedSignal(uint32_t seq, bool handled); + +    /* Returns true if there is a pending batch. */ +    bool hasPendingBatch() const;  private:      sp<InputChannel> mChannel; -    size_t mAshmemSize; -    InputMessage* mSharedMessage; +    // State about an event that consume would have returned except that it had to +    // return a completed batch first.  Sequence number is non-zero if an event was deferred. +    uint32_t mDeferredEventSeq; +    MotionEvent mDeferredEvent; + +    // Batched motion events per device and source. +    struct Batch { +        uint32_t seq; +        MotionEvent event; +    }; +    Vector<Batch> mBatches; + +    ssize_t findBatch(int32_t deviceId, int32_t source) const; -    void populateKeyEvent(KeyEvent* keyEvent) const; -    void populateMotionEvent(MotionEvent* motionEvent) const; +    static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg); +    static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg); +    static bool canAppendSamples(const MotionEvent* event, const InputMessage* msg); +    static void appendSamples(MotionEvent* event, const InputMessage* msg);  };  } // namespace android diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 09cbb318cd..98c4bddc8d 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -7,325 +7,203 @@  //#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, ...) +// Log debug messages about transport actions  #define DEBUG_TRANSPORT_ACTIONS 0 -#include <cutils/ashmem.h>  #include <cutils/log.h>  #include <errno.h>  #include <fcntl.h> -#include <sys/mman.h>  #include <ui/InputTransport.h>  #include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> -namespace android { - -#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1)) -#define MIN_HISTORY_DEPTH 20 -// 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); - -// 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'; +namespace android { -// 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'; +// Socket buffer size.  The default is typically about 128KB, which is much larger than +// we really need.  So we make it smaller.  It just needs to be big enough to hold +// a few dozen large multi-finger motion events in the case where an application gets +// behind processing touches. +static const size_t SOCKET_BUFFER_SIZE = 32 * 1024; + + +// --- InputMessage --- + +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 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<InputChannel>& outServerChannel, sp<InputChannel>& 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; +    int bufferSize = SOCKET_BUFFER_SIZE; +    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); +    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); +    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); +    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); + +    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); +    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 -errno; +        return DEAD_OBJECT; +    } + +#if DEBUG_CHANNEL_MESSAGES +    ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type); +#endif +    return OK;  } -status_t InputChannel::receiveSignal(char* outSignal) { +status_t InputChannel::receiveMessage(InputMessage* msg) {      ssize_t nRead;      do { -        nRead = ::read(mReceivePipeFd, outSignal, 1); +        nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);      } while (nRead == -1 && errno == EINTR); -    if (nRead == 1) { -#if DEBUG_CHANNEL_SIGNALS -        ALOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal); +    if (nRead < 0) { +        int error = errno; +#if DEBUG_CHANNEL_MESSAGES +        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);  #endif -        return OK; +        if (error == EAGAIN || error == EWOULDBLOCK) { +            return WOULD_BLOCK; +        } +        if (error == EPIPE || error == ENOTCONN) { +            return DEAD_OBJECT; +        } +        return -error;      }      if (nRead == 0) { // check for EOF -#if DEBUG_CHANNEL_SIGNALS -        ALOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string()); +#if DEBUG_CHANNEL_MESSAGES +        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());  #endif          return DEAD_OBJECT;      } -    if (errno == EAGAIN) { -#if DEBUG_CHANNEL_SIGNALS -        ALOGD("channel '%s' ~ receive signal failed because no signal available", mName.string()); +    if (!msg->isValid(nRead)) { +#if DEBUG_CHANNEL_MESSAGES +        ALOGD("channel '%s' ~ received invalid message", mName.string());  #endif -        return WOULD_BLOCK; +        return BAD_VALUE;      } -#if DEBUG_CHANNEL_SIGNALS -    ALOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno); +#if DEBUG_CHANNEL_MESSAGES +    ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);  #endif -    return -errno; +    return OK;  }  // --- InputPublisher ---  InputPublisher::InputPublisher(const sp<InputChannel>& 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<InputMessage*>(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( +        uint32_t seq,          int32_t deviceId,          int32_t source,          int32_t action, @@ -337,31 +215,37 @@ status_t InputPublisher::publishKeyEvent(          nsecs_t downTime,          nsecs_t eventTime) {  #if DEBUG_TRANSPORT_ACTIONS -    ALOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=0x%x, " +    ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "              "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"              "downTime=%lld, eventTime=%lld", -            mChannel->getName().string(), +            mChannel->getName().string(), seq,              deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,              downTime, eventTime);  #endif -    status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source); -    if (result < 0) { -        return result; +    if (!seq) { +        ALOGE("Attempted to publish a key event with sequence number 0."); +        return BAD_VALUE;      } -    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.seq = seq; +    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( +        uint32_t seq,          int32_t deviceId,          int32_t source,          int32_t action, @@ -379,349 +263,327 @@ status_t InputPublisher::publishMotionEvent(          const PointerProperties* pointerProperties,          const PointerCoords* pointerCoords) {  #if DEBUG_TRANSPORT_ACTIONS -    ALOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, " +    ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "              "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "              "xOffset=%f, yOffset=%f, "              "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "              "pointerCount=%d", -            mChannel->getName().string(), +            mChannel->getName().string(), seq,              deviceId, source, action, flags, edgeFlags, metaState, buttonState,              xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);  #endif +    if (!seq) { +        ALOGE("Attempted to publish a motion event with sequence number 0."); +        return BAD_VALUE; +    } +      if (pointerCount > MAX_POINTERS || pointerCount < 1) {          ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",                  mChannel->getName().string(), pointerCount);          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.seq = seq; +    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; +    return mChannel->sendMessage(&msg);  } -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<char*>(newTail) - -            reinterpret_cast<char*>(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); -} - -status_t InputPublisher::receiveFinishedSignal(bool* outHandled) { +status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {  #if DEBUG_TRANSPORT_ACTIONS      ALOGD("channel '%s' publisher ~ receiveFinishedSignal",              mChannel->getName().string());  #endif -    char signal; -    status_t result = mChannel->receiveSignal(& signal); +    InputMessage msg; +    status_t result = mChannel->receiveMessage(&msg);      if (result) { +        *outSeq = 0;          *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;      } +    *outSeq = msg.body.finished.seq; +    *outHandled = msg.body.finished.handled;      return OK;  }  // --- InputConsumer ---  InputConsumer::InputConsumer(const sp<InputChannel>& channel) : -        mChannel(channel), mSharedMessage(NULL) { +        mChannel(channel), mDeferredEventSeq(0) {  }  InputConsumer::~InputConsumer() { -    if (mSharedMessage) { -        munmap(mSharedMessage, mAshmemSize); -    }  } -status_t InputConsumer::initialize() { +status_t InputConsumer::consume(InputEventFactoryInterface* factory, +        bool consumeBatches, uint32_t* outSeq, InputEvent** outEvent) {  #if DEBUG_TRANSPORT_ACTIONS -    ALOGD("channel '%s' consumer ~ initialize", -            mChannel->getName().string()); +    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s", +            mChannel->getName().string(), consumeBatches ? "true" : "false");  #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; -    } +    *outSeq = 0; +    *outEvent = NULL; -    mAshmemSize = (size_t) result; +    // Report deferred event first, if we had to end a batch earlier than we expected +    // during the previous time consume was called. +    if (mDeferredEventSeq) { +        MotionEvent* motionEvent = factory->createMotionEvent(); +        if (! motionEvent) return NO_MEMORY; -    mSharedMessage = static_cast<InputMessage*>(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; +        motionEvent->copyFrom(&mDeferredEvent, true /*keepHistory*/); +        *outSeq = mDeferredEventSeq; +        *outEvent = motionEvent; +        mDeferredEventSeq = 0; +#if DEBUG_TRANSPORT_ACTIONS +        ALOGD("channel '%s' consumer ~ consumed deferred event, seq=%u", +                mChannel->getName().string(), *outSeq); +#endif +        return OK;      } -    return OK; -} - -status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) { +    // Fetch the next input message. +    // Loop until an event can be returned or no additional events are received. +    while (!*outEvent) { +        InputMessage msg; +        status_t result = mChannel->receiveMessage(&msg); +        if (result) { +            // Consume the next batched event unless batches are being held for later. +            if (!mBatches.isEmpty() && (consumeBatches || result != WOULD_BLOCK)) { +                MotionEvent* motionEvent = factory->createMotionEvent(); +                if (! motionEvent) return NO_MEMORY; + +                const Batch& batch = mBatches.top(); +                motionEvent->copyFrom(&batch.event, true /*keepHistory*/); +                *outSeq = batch.seq; +                *outEvent = motionEvent; +                mBatches.pop();  #if DEBUG_TRANSPORT_ACTIONS -    ALOGD("channel '%s' consumer ~ consume", -            mChannel->getName().string()); +                ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u", +                        mChannel->getName().string(), *outSeq);  #endif - -    *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; +                break; +            } +            return result;          } -        ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.", -                mChannel->getName().string(), result, ashmemFd); -        return UNKNOWN_ERROR; -    } - -    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 (msg.header.type) { +        case InputMessage::TYPE_KEY: { +            KeyEvent* keyEvent = factory->createKeyEvent(); +            if (!keyEvent) return NO_MEMORY; -    switch (mSharedMessage->type) { -    case AINPUT_EVENT_TYPE_KEY: { -        KeyEvent* keyEvent = factory->createKeyEvent(); -        if (! keyEvent) return NO_MEMORY; +            initializeKeyEvent(keyEvent, &msg); +            *outSeq = msg.body.key.seq; +            *outEvent = keyEvent; +#if DEBUG_TRANSPORT_ACTIONS +            ALOGD("channel '%s' consumer ~ consumed key event, seq=%u", +                    mChannel->getName().string(), *outSeq); +#endif +            break; +        } -        populateKeyEvent(keyEvent); +        case AINPUT_EVENT_TYPE_MOTION: { +            ssize_t batchIndex = findBatch(msg.body.motion.deviceId, msg.body.motion.source); +            if (batchIndex >= 0) { +                Batch& batch = mBatches.editItemAt(batchIndex); +                if (canAppendSamples(&batch.event, &msg)) { +                    // Send finished message for the earlier part of the batch. +                    // Claim that we handled the event.  (The dispatcher doesn't care either +                    // way at the moment.) +                    status_t status = sendFinishedSignal(batch.seq, true); +                    if (status) { +                        return status; +                    } -        *outEvent = keyEvent; -        break; -    } +                    // Append to the batch and save the new sequence number for the tail end. +                    appendSamples(&batch.event, &msg); +                    batch.seq = msg.body.motion.seq; +#if DEBUG_TRANSPORT_ACTIONS +                    ALOGD("channel '%s' consumer ~ appended to batch event", +                            mChannel->getName().string()); +#endif +                    break; +                } else { +                    MotionEvent* motionEvent = factory->createMotionEvent(); +                    if (! motionEvent) return NO_MEMORY; + +                    // We cannot append to the batch in progress, so we need to consume +                    // the previous batch right now and defer the new event until later. +                    mDeferredEventSeq = msg.body.motion.seq; +                    initializeMotionEvent(&mDeferredEvent, &msg); + +                    // Return the end of the previous batch. +                    motionEvent->copyFrom(&batch.event, true /*keepHistory*/); +                    *outSeq = batch.seq; +                    *outEvent = motionEvent; +                    mBatches.removeAt(batchIndex); +#if DEBUG_TRANSPORT_ACTIONS +                    ALOGD("channel '%s' consumer ~ consumed batch event and " +                            "deferred current event, seq=%u", +                            mChannel->getName().string(), *outSeq); +#endif +                    break; +                } +            } -    case AINPUT_EVENT_TYPE_MOTION: { -        MotionEvent* motionEvent = factory->createMotionEvent(); -        if (! motionEvent) return NO_MEMORY; +            // Start a new batch if needed. +            if (msg.body.motion.action == AMOTION_EVENT_ACTION_MOVE +                    || msg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) { +                mBatches.push(); +                Batch& batch = mBatches.editTop(); +                batch.seq = msg.body.motion.seq; +                initializeMotionEvent(&batch.event, &msg); +#if DEBUG_TRANSPORT_ACTIONS +                ALOGD("channel '%s' consumer ~ started batch event", +                        mChannel->getName().string()); +#endif +                break; +            } -        populateMotionEvent(motionEvent); +            MotionEvent* motionEvent = factory->createMotionEvent(); +            if (! motionEvent) return NO_MEMORY; -        *outEvent = motionEvent; -        break; -    } +            initializeMotionEvent(motionEvent, &msg); +            *outSeq = msg.body.motion.seq; +            *outEvent = motionEvent; +#if DEBUG_TRANSPORT_ACTIONS +            ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u", +                    mChannel->getName().string(), *outSeq); +#endif +            break; +        } -    default: -        ALOGE("channel '%s' consumer ~ Received message of unknown type %d", -                mChannel->getName().string(), mSharedMessage->type); -        return UNKNOWN_ERROR; +        default: +            ALOGE("channel '%s' consumer ~ Received unexpected message of type %d", +                    mChannel->getName().string(), msg.header.type); +            return UNKNOWN_ERROR; +        }      } -      return OK;  } -status_t InputConsumer::sendFinishedSignal(bool handled) { +status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {  #if DEBUG_TRANSPORT_ACTIONS -    ALOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d", -            mChannel->getName().string(), handled); +    ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s", +            mChannel->getName().string(), seq, handled ? "true" : "false");  #endif -    return mChannel->sendSignal(handled -            ? INPUT_SIGNAL_FINISHED_HANDLED -            : INPUT_SIGNAL_FINISHED_UNHANDLED); +    if (!seq) { +        ALOGE("Attempted to send a finished signal with sequence number 0."); +        return BAD_VALUE; +    } + +    InputMessage msg; +    msg.header.type = InputMessage::TYPE_FINISHED; +    msg.body.finished.seq = seq; +    msg.body.finished.handled = handled; +    return mChannel->sendMessage(&msg);  } -status_t InputConsumer::receiveDispatchSignal() { -#if DEBUG_TRANSPORT_ACTIONS -    ALOGD("channel '%s' consumer ~ receiveDispatchSignal", -            mChannel->getName().string()); -#endif +bool InputConsumer::hasPendingBatch() const { +    return !mBatches.isEmpty(); +} -    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; +ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const { +    for (size_t i = 0; i < mBatches.size(); i++) { +        const Batch& batch = mBatches.itemAt(i); +        if (batch.event.getDeviceId() == deviceId && batch.event.getSource() == source) { +            return i; +        }      } -    return OK; +    return -1; +} + +void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) { +    event->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);  } -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::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) { +    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); +    } + +    event->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);  } -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); +bool InputConsumer::canAppendSamples(const MotionEvent* event, const InputMessage *msg) { +    size_t pointerCount = msg->body.motion.pointerCount; +    if (event->getPointerCount() != pointerCount +            || event->getAction() != msg->body.motion.action) { +        return false; +    } +    for (size_t i = 0; i < pointerCount; i++) { +        if (*event->getPointerProperties(i) != msg->body.motion.pointers[i].properties) { +            return false;          }      } +    return true; +} + +void InputConsumer::appendSamples(MotionEvent* event, const InputMessage* msg) { +    size_t pointerCount = msg->body.motion.pointerCount; +    PointerCoords pointerCoords[pointerCount]; +    for (size_t i = 0; i < pointerCount; i++) { +        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); +    } + +    event->setMetaState(event->getMetaState() | msg->body.motion.metaState); +    event->addSample(msg->body.motion.eventTime, pointerCoords);  }  } // namespace android diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/ui/tests/InputChannel_test.cpp index eff22ee5f0..ee422fe7d8 100644 --- a/libs/ui/tests/InputChannel_test.cpp +++ b/libs/ui/tests/InputChannel_test.cpp @@ -20,8 +20,7 @@  #include <gtest/gtest.h>  #include <unistd.h>  #include <time.h> -#include <sys/mman.h> -#include <cutils/ashmem.h> +#include <errno.h>  #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> inputChannel = new InputChannel(String8("channel name"), -            fakeAshmem.sendFd, receivePipe.receiveFd, sendPipe.sendFd); +    sp<InputChannel> 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,40 @@ 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<uint32_t*>(mmap(NULL, serverAshmemSize, -            PROT_READ | PROT_WRITE, MAP_SHARED, serverChannel->getAshmemFd(), 0)); -    uint32_t* clientAshmem = static_cast<uint32_t*>(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.seq = 0x11223344; +    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.seq, serverReply.body.finished.seq) +            << "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 +115,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 +131,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 +147,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 fcc4cadb71..3303053132 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,21 +66,10 @@ 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; +    const uint32_t seq = 15;      const int32_t deviceId = 1;      const int32_t source = AINPUT_SOURCE_KEYBOARD;      const int32_t action = AKEY_EVENT_ACTION_DOWN; @@ -95,21 +81,14 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {      const nsecs_t downTime = 3;      const nsecs_t eventTime = 4; -    status = mPublisher->publishKeyEvent(deviceId, source, action, flags, +    status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags,              keyCode, scanCode, metaState, repeatCount, downTime, eventTime);      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"; - +    uint32_t consumeSeq;      InputEvent* event; -    status = mConsumer->consume(& mEventFactory, & event); +    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, &consumeSeq, &event);      ASSERT_EQ(OK, status)              << "consumer consume should return OK"; @@ -119,6 +98,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {              << "consumer should have returned a key event";      KeyEvent* keyEvent = static_cast<KeyEvent*>(event); +    EXPECT_EQ(seq, consumeSeq);      EXPECT_EQ(deviceId, keyEvent->getDeviceId());      EXPECT_EQ(source, keyEvent->getSource());      EXPECT_EQ(action, keyEvent->getAction()); @@ -130,26 +110,25 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {      EXPECT_EQ(downTime, keyEvent->getDownTime());      EXPECT_EQ(eventTime, keyEvent->getEventTime()); -    status = mConsumer->sendFinishedSignal(true); +    status = mConsumer->sendFinishedSignal(seq, true);      ASSERT_EQ(OK, status)              << "consumer sendFinishedSignal should return OK"; +    uint32_t finishedSeq = 0;      bool handled = false; -    status = mPublisher->receiveFinishedSignal(&handled); +    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);      ASSERT_EQ(OK, status)              << "publisher receiveFinishedSignal should return OK"; +    ASSERT_EQ(seq, finishedSeq) +            << "publisher receiveFinishedSignal should have returned the original sequence number";      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 uint32_t seq = 15;      const int32_t deviceId = 1;      const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;      const int32_t action = AMOTION_EVENT_ACTION_MOVE; @@ -163,67 +142,36 @@ 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<nsecs_t> sampleEventTimes; -    Vector<PointerCoords> 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, +    status = mPublisher->publishMotionEvent(seq, 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"; - +    uint32_t consumeSeq;      InputEvent* event; -    status = mConsumer->consume(& mEventFactory, & event); +    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, &consumeSeq, &event);      ASSERT_EQ(OK, status)              << "consumer consume should return OK"; @@ -232,9 +180,8 @@ 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<MotionEvent*>(event); +    EXPECT_EQ(seq, consumeSeq);      EXPECT_EQ(deviceId, motionEvent->getDeviceId());      EXPECT_EQ(source, motionEvent->getSource());      EXPECT_EQ(action, motionEvent->getAction()); @@ -245,150 +192,69 @@ 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));      } -    status = mConsumer->sendFinishedSignal(false); +    status = mConsumer->sendFinishedSignal(seq, false);      ASSERT_EQ(OK, status)              << "consumer sendFinishedSignal should return OK"; +    uint32_t finishedSeq = 0;      bool handled = true; -    status = mPublisher->receiveFinishedSignal(&handled); +    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);      ASSERT_EQ(OK, status)              << "publisher receiveFinishedSignal should return OK"; +    ASSERT_EQ(seq, finishedSeq) +            << "publisher receiveFinishedSignal should have returned the original sequence number";      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]; -    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,              pointerCount, pointerProperties, pointerCoords);      ASSERT_EQ(BAD_VALUE, status)              << "publisher publishMotionEvent should return BAD_VALUE"; @@ -396,8 +262,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]; @@ -406,14 +270,13 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater          pointerCoords[i].clear();      } -    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,              pointerCount, pointerProperties, pointerCoords);      ASSERT_EQ(BAD_VALUE, status)              << "publisher publishMotionEvent should return BAD_VALUE";  }  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 +284,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  |