Rewrite input transport using sockets.

Since we will not longer be modifying events in place, we don't need
to use an ashmem region for input.  Simplified the code to instead
use a socket of type SOCK_SEQPACKET.

This is part of a series of changes to improve input system pipelining.

Bug: 5963420

Change-Id: I05909075ed8b61b93900913e44c6db84857340d8
This commit is contained in:
Jeff Brown
2012-02-03 20:11:27 -08:00
parent 3241b6b7bd
commit cbee6d6ede
9 changed files with 433 additions and 1167 deletions

View File

@@ -130,21 +130,21 @@ AInputQueue::~AInputQueue() {
void AInputQueue::attachLooper(ALooper* looper, int ident, void AInputQueue::attachLooper(ALooper* looper, int ident,
ALooper_callbackFunc callback, void* data) { ALooper_callbackFunc callback, void* data) {
mLooper = static_cast<android::Looper*>(looper); mLooper = static_cast<android::Looper*>(looper);
mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(), mLooper->addFd(mConsumer.getChannel()->getFd(),
ident, ALOOPER_EVENT_INPUT, callback, data); ident, ALOOPER_EVENT_INPUT, callback, data);
mLooper->addFd(mDispatchKeyRead, mLooper->addFd(mDispatchKeyRead,
ident, ALOOPER_EVENT_INPUT, callback, data); ident, ALOOPER_EVENT_INPUT, callback, data);
} }
void AInputQueue::detachLooper() { void AInputQueue::detachLooper() {
mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd()); mLooper->removeFd(mConsumer.getChannel()->getFd());
mLooper->removeFd(mDispatchKeyRead); mLooper->removeFd(mDispatchKeyRead);
} }
int32_t AInputQueue::hasEvents() { int32_t AInputQueue::hasEvents() {
struct pollfd pfd[2]; struct pollfd pfd[2];
pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd(); pfd[0].fd = mConsumer.getChannel()->getFd();
pfd[0].events = POLLIN; pfd[0].events = POLLIN;
pfd[0].revents = 0; pfd[0].revents = 0;
pfd[1].fd = mDispatchKeyRead; pfd[1].fd = mDispatchKeyRead;
@@ -201,15 +201,8 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
} }
} }
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; InputEvent* myEvent = NULL;
res = mConsumer.consume(this, &myEvent); status_t res = mConsumer.consume(this, &myEvent);
if (res != android::OK) { if (res != android::OK) {
ALOGW("channel '%s' ~ Failed to consume input event. status=%d", ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
mConsumer.getChannel()->getName().string(), res); mConsumer.getChannel()->getName().string(), res);
@@ -481,11 +474,6 @@ struct NativeCode : public ANativeActivity {
android_view_InputChannel_getInputChannel(env, _channel); android_view_InputChannel_getInputChannel(env, _channel);
if (ic != NULL) { if (ic != NULL) {
nativeInputQueue = new AInputQueue(ic, mainWorkWrite); nativeInputQueue = new AInputQueue(ic, mainWorkWrite);
if (nativeInputQueue->getConsumer().initialize() != android::OK) {
delete nativeInputQueue;
nativeInputQueue = NULL;
return UNKNOWN_ERROR;
}
} else { } else {
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }

View File

@@ -199,32 +199,16 @@ static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject
bool isInitialized = parcel->readInt32(); bool isInitialized = parcel->readInt32();
if (isInitialized) { if (isInitialized) {
String8 name = parcel->readString8(); String8 name = parcel->readString8();
int32_t parcelAshmemFd = parcel->readFileDescriptor(); int32_t rawFd = parcel->readFileDescriptor();
int32_t ashmemFd = dup(parcelAshmemFd); int32_t dupFd = dup(rawFd);
if (ashmemFd < 0) { if (rawFd < 0) {
ALOGE("Error %d dup ashmem fd %d.", errno, parcelAshmemFd); ALOGE("Error %d dup channel fd %d.", errno, rawFd);
}
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);
jniThrowRuntimeException(env, jniThrowRuntimeException(env,
"Could not read input channel file descriptors from parcel."); "Could not read input channel file descriptors from parcel.");
return; return;
} }
InputChannel* inputChannel = new InputChannel(name, ashmemFd, InputChannel* inputChannel = new InputChannel(name, dupFd);
receivePipeFd, sendPipeFd);
NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel); NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel);
android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel); 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->writeInt32(1);
parcel->writeString8(inputChannel->getName()); parcel->writeString8(inputChannel->getName());
parcel->writeDupFileDescriptor(inputChannel->getAshmemFd()); parcel->writeDupFileDescriptor(inputChannel->getFd());
parcel->writeDupFileDescriptor(inputChannel->getReceivePipeFd());
parcel->writeDupFileDescriptor(inputChannel->getSendPipeFd());
} else { } else {
parcel->writeInt32(0); parcel->writeInt32(0);
} }

View File

@@ -83,7 +83,7 @@ NativeInputEventReceiver::~NativeInputEventReceiver() {
ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName()); ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
#endif #endif
mLooper->removeFd(mInputConsumer.getChannel()->getReceivePipeFd()); mLooper->removeFd(mInputConsumer.getChannel()->getFd());
if (mEventInProgress) { if (mEventInProgress) {
mInputConsumer.sendFinishedSignal(false); // ignoring result mInputConsumer.sendFinishedSignal(false); // ignoring result
} }
@@ -93,14 +93,7 @@ NativeInputEventReceiver::~NativeInputEventReceiver() {
} }
status_t NativeInputEventReceiver::initialize() { status_t NativeInputEventReceiver::initialize() {
status_t result = mInputConsumer.initialize(); int32_t receiveFd = mInputConsumer.getChannel()->getFd();
if (result) {
ALOGW("Failed to initialize input consumer for input channel '%s', status=%d",
getInputChannelName(), result);
return result;
}
int32_t receiveFd = mInputConsumer.getChannel()->getReceivePipeFd();
mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
return OK; return OK;
} }
@@ -139,13 +132,6 @@ int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, v
return 1; 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) { if (r->mEventInProgress) {
ALOGW("channel '%s' ~ Publisher sent spurious dispatch signal.", ALOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
r->getInputChannelName()); r->getInputChannelName());
@@ -153,7 +139,7 @@ int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, v
} }
InputEvent* inputEvent; InputEvent* inputEvent;
status = r->mInputConsumer.consume(&r->mInputEventFactory, &inputEvent); status_t status = r->mInputConsumer.consume(&r->mInputEventFactory, &inputEvent);
if (status) { if (status) {
ALOGW("channel '%s' ~ Failed to consume input event. status=%d", ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
r->getInputChannelName(), status); r->getInputChannelName(), status);

View File

@@ -20,17 +20,13 @@
/** /**
* Native input transport. * Native input transport.
* *
* Uses anonymous shared memory as a whiteboard for sending input events from an * The InputChannel provides a mechanism for exchanging InputMessage structures across processes.
* 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 InputPublisher and InputConsumer only take care of transferring event data * The InputPublisher and InputConsumer each handle one end-point of an input channel.
* over an InputChannel and sending synchronization signals. The InputDispatcher and InputQueue * The InputPublisher is used by the input dispatcher to send events to the application.
* build on these abstractions to add multiplexing and queueing. * The InputConsumer is used by the application to receive events from the input dispatcher.
*/ */
#include <semaphore.h>
#include <ui/Input.h> #include <ui/Input.h>
#include <utils/Errors.h> #include <utils/Errors.h>
#include <utils/Timers.h> #include <utils/Timers.h>
@@ -40,88 +36,25 @@
namespace android { namespace android {
/* /*
* An input channel consists of a shared memory buffer and a pair of pipes * Intermediate representation used to send input events and related signals.
* 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<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; }
/* 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.
*/ */
struct InputMessage { struct InputMessage {
/* Semaphore count is set to 1 when the message is published. enum {
* It becomes 0 transiently while the publisher updates the message. TYPE_KEY = 1,
* It becomes 0 permanently when the consumer consumes the message. TYPE_MOTION = 2,
*/ TYPE_FINISHED = 3,
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; struct Header {
int32_t source; uint32_t type;
uint32_t padding; // 8 byte alignment for the body that follows
} header;
union { union Body {
struct { struct Key {
nsecs_t eventTime;
int32_t deviceId;
int32_t source;
int32_t action; int32_t action;
int32_t flags; int32_t flags;
int32_t keyCode; int32_t keyCode;
@@ -129,10 +62,16 @@ struct InputMessage {
int32_t metaState; int32_t metaState;
int32_t repeatCount; int32_t repeatCount;
nsecs_t downTime; nsecs_t downTime;
nsecs_t eventTime;
inline size_t size() const {
return sizeof(Key);
}
} key; } key;
struct { struct Motion {
nsecs_t eventTime;
int32_t deviceId;
int32_t source;
int32_t action; int32_t action;
int32_t flags; int32_t flags;
int32_t metaState; int32_t metaState;
@@ -144,28 +83,87 @@ struct InputMessage {
float xPrecision; float xPrecision;
float yPrecision; float yPrecision;
size_t pointerCount; size_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS]; struct Pointer {
size_t sampleCount; PointerProperties properties;
SampleData sampleData[0]; // variable length PointerCoords coords;
} pointers[MAX_POINTERS];
inline size_t size() const {
return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS
+ sizeof(Pointer) * pointerCount;
}
} motion; } motion;
};
/* Gets the number of bytes to add to step to the next SampleData object in a motion struct Finished {
* event message for a given number of pointers. bool handled;
*/
static inline size_t sampleDataStride(size_t pointerCount) {
return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords);
}
/* Adds the SampleData stride to the given pointer. */ inline size_t size() const {
static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) { return sizeof(Finished);
return reinterpret_cast<InputMessage::SampleData*>(reinterpret_cast<char*>(ptr) + stride); }
} } finished;
} body;
bool isValid(size_t actualSize) const;
size_t size() const;
}; };
/* /*
* Publishes input events to an anonymous shared memory buffer. * An input channel consists of a local unix domain socket used to send and receive
* Uses atomic operations to coordinate shared access with a single concurrent consumer. * 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<InputChannel>& outServerChannel, sp<InputChannel>& 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 { class InputPublisher {
public: public:
@@ -178,24 +176,12 @@ public:
/* Gets the underlying input channel. */ /* Gets the underlying input channel. */
inline sp<InputChannel> getChannel() { return mChannel; } inline sp<InputChannel> getChannel() { return mChannel; }
/* Prepares the publisher for use. Must be called before it is used. /* Publishes a key event to the input channel.
* 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.
* *
* Returns OK on success. * 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( status_t publishKeyEvent(
int32_t deviceId, int32_t deviceId,
@@ -209,11 +195,13 @@ public:
nsecs_t downTime, nsecs_t downTime,
nsecs_t eventTime); nsecs_t eventTime);
/* Publishes a motion event to the ashmem buffer. /* Publishes a motion event to the input channel.
* *
* Returns OK on success. * 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. * 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( status_t publishMotionEvent(
int32_t deviceId, int32_t deviceId,
@@ -233,55 +221,22 @@ public:
const PointerProperties* pointerProperties, const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords); 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. /* Receives the finished signal from the consumer in reply to the original dispatch signal.
* Returns whether the consumer handled the message. * Returns whether the consumer handled the message.
* *
* Returns OK on success. * Returns OK on success.
* Returns WOULD_BLOCK if there is no signal present. * 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. * Other errors probably indicate that the channel is broken.
*/ */
status_t receiveFinishedSignal(bool* outHandled); status_t receiveFinishedSignal(bool* outHandled);
private: private:
sp<InputChannel> mChannel; 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. * Consumes input events from an input channel.
* Uses atomic operations to coordinate shared access with a single concurrent publisher.
*/ */
class InputConsumer { class InputConsumer {
public: public:
@@ -294,16 +249,14 @@ public:
/* Gets the underlying input channel. */ /* Gets the underlying input channel. */
inline sp<InputChannel> getChannel() { return mChannel; } inline sp<InputChannel> getChannel() { return mChannel; }
/* Prepares the consumer for use. Must be called before it is used. */ /* Consumes an input event from the input channel and copies its contents into
status_t initialize();
/* Consumes the input event in the buffer and copies its contents into
* an InputEvent object created using the specified factory. * an InputEvent object created using the specified factory.
* This operation will block if the publisher is updating the event.
* *
* Returns OK on success. * 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. * 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); status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent);
@@ -311,26 +264,12 @@ public:
* finished processing and specifies whether the message was handled by the consumer. * finished processing and specifies whether the message was handled by the consumer.
* *
* Returns OK on success. * 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); 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: private:
sp<InputChannel> mChannel; sp<InputChannel> mChannel;
size_t mAshmemSize;
InputMessage* mSharedMessage;
void populateKeyEvent(KeyEvent* keyEvent) const;
void populateMotionEvent(MotionEvent* motionEvent) const;
}; };
} // namespace android } // namespace android

View File

@@ -7,322 +7,186 @@
//#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0
// Log debug messages about channel signalling (send signal, receive signal) // Log debug messages about channel messages (send message, receive message)
#define DEBUG_CHANNEL_SIGNALS 0 #define DEBUG_CHANNEL_MESSAGES 0
// Log debug messages whenever InputChannel objects are created/destroyed // Log debug messages whenever InputChannel objects are created/destroyed
#define DEBUG_CHANNEL_LIFECYCLE 0 #define DEBUG_CHANNEL_LIFECYCLE 0
// Log debug messages about transport actions (initialize, reset, publish, ...)
#define DEBUG_TRANSPORT_ACTIONS 0 #define DEBUG_TRANSPORT_ACTIONS 0
// Log debug messages about transport actions
#include <cutils/ashmem.h>
#include <cutils/log.h> #include <cutils/log.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/mman.h>
#include <ui/InputTransport.h> #include <ui/InputTransport.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
namespace android { namespace android {
#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1)) // --- InputMessage ---
#define MIN_HISTORY_DEPTH 20
// Must be at least sizeof(InputMessage) + sufficient space for pointer data bool InputMessage::isValid(size_t actualSize) const {
static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP( if (size() == actualSize) {
sizeof(InputMessage) + MIN_HISTORY_DEPTH switch (header.type) {
* (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)), case TYPE_KEY:
4096); 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 size_t InputMessage::size() const {
// available to be consumed in the shared memory buffer. switch (header.type) {
static const char INPUT_SIGNAL_DISPATCH = 'D'; case TYPE_KEY:
return sizeof(Header) + body.key.size();
// Signal sent by the consumer to the producer to inform it that it has finished case TYPE_MOTION:
// consuming the most recent message and it handled it. return sizeof(Header) + body.motion.size();
static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f'; case TYPE_FINISHED:
return sizeof(Header) + body.finished.size();
// 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. return sizeof(Header);
static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u'; }
// --- InputChannel --- // --- InputChannel ---
InputChannel::InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd, InputChannel::InputChannel(const String8& name, int fd) :
int32_t sendPipeFd) : mName(name), mFd(fd) {
mName(name), mAshmemFd(ashmemFd), mReceivePipeFd(receivePipeFd), mSendPipeFd(sendPipeFd) {
#if DEBUG_CHANNEL_LIFECYCLE #if DEBUG_CHANNEL_LIFECYCLE
ALOGD("Input channel constructed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d", ALOGD("Input channel constructed: name='%s', fd=%d",
mName.string(), ashmemFd, receivePipeFd, sendPipeFd); mName.string(), fd);
#endif #endif
int result = fcntl(mReceivePipeFd, F_SETFL, O_NONBLOCK); int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make receive pipe " LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
"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 "
"non-blocking. errno=%d", mName.string(), errno); "non-blocking. errno=%d", mName.string(), errno);
} }
InputChannel::~InputChannel() { InputChannel::~InputChannel() {
#if DEBUG_CHANNEL_LIFECYCLE #if DEBUG_CHANNEL_LIFECYCLE
ALOGD("Input channel destroyed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d", ALOGD("Input channel destroyed: name='%s', fd=%d",
mName.string(), mAshmemFd, mReceivePipeFd, mSendPipeFd); mName.string(), mFd);
#endif #endif
::close(mAshmemFd); ::close(mFd);
::close(mReceivePipeFd);
::close(mSendPipeFd);
} }
status_t InputChannel::openInputChannelPair(const String8& name, status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) { sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
status_t result; int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
String8 ashmemName("InputChannel "); status_t result = -errno;
ashmemName.append(name); ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
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",
name.string(), errno); name.string(), errno);
} else { outServerChannel.clear();
result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE); outClientChannel.clear();
if (result < 0) { return result;
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(); String8 serverChannelName = name;
outClientChannel.clear(); serverChannelName.append(" (server)");
return result; 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; ssize_t nWrite;
do { do {
nWrite = ::write(mSendPipeFd, & signal, 1); nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR); } while (nWrite == -1 && errno == EINTR);
if (nWrite == 1) { if (nWrite < 0) {
#if DEBUG_CHANNEL_SIGNALS int error = errno;
ALOGD("channel '%s' ~ sent signal '%c'", mName.string(), signal); #if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
msg->header.type, error);
#endif #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 if (size_t(nWrite) != msgLength) {
ALOGD("channel '%s' ~ error sending signal '%c', errno=%d", mName.string(), signal, errno); #if DEBUG_CHANNEL_MESSAGES
#endif ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
return -errno; mName.string(), msg->header.type);
}
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());
#endif #endif
return DEAD_OBJECT; return DEAD_OBJECT;
} }
if (errno == EAGAIN) { #if DEBUG_CHANNEL_MESSAGES
#if DEBUG_CHANNEL_SIGNALS ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
ALOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
#endif #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 if (nRead == 0) { // check for EOF
ALOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno); #if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
#endif #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::InputPublisher(const sp<InputChannel>& channel) : InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
mChannel(channel), mSharedMessage(NULL), mChannel(channel) {
mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
mMotionEventSampleDataTail(NULL) {
} }
InputPublisher::~InputPublisher() { 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( status_t InputPublisher::publishKeyEvent(
@@ -345,20 +209,19 @@ status_t InputPublisher::publishKeyEvent(
downTime, eventTime); downTime, eventTime);
#endif #endif
status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source); InputMessage msg;
if (result < 0) { msg.header.type = InputMessage::TYPE_KEY;
return result; msg.body.key.deviceId = deviceId;
} msg.body.key.source = source;
msg.body.key.action = action;
mSharedMessage->key.action = action; msg.body.key.flags = flags;
mSharedMessage->key.flags = flags; msg.body.key.keyCode = keyCode;
mSharedMessage->key.keyCode = keyCode; msg.body.key.scanCode = scanCode;
mSharedMessage->key.scanCode = scanCode; msg.body.key.metaState = metaState;
mSharedMessage->key.metaState = metaState; msg.body.key.repeatCount = repeatCount;
mSharedMessage->key.repeatCount = repeatCount; msg.body.key.downTime = downTime;
mSharedMessage->key.downTime = downTime; msg.body.key.eventTime = eventTime;
mSharedMessage->key.eventTime = eventTime; return mChannel->sendMessage(&msg);
return OK;
} }
status_t InputPublisher::publishMotionEvent( status_t InputPublisher::publishMotionEvent(
@@ -395,123 +258,27 @@ status_t InputPublisher::publishMotionEvent(
return BAD_VALUE; return BAD_VALUE;
} }
status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source); InputMessage msg;
if (result < 0) { msg.header.type = InputMessage::TYPE_MOTION;
return result; msg.body.motion.deviceId = deviceId;
} msg.body.motion.source = source;
msg.body.motion.action = action;
mSharedMessage->motion.action = action; msg.body.motion.flags = flags;
mSharedMessage->motion.flags = flags; msg.body.motion.edgeFlags = edgeFlags;
mSharedMessage->motion.edgeFlags = edgeFlags; msg.body.motion.metaState = metaState;
mSharedMessage->motion.metaState = metaState; msg.body.motion.buttonState = buttonState;
mSharedMessage->motion.buttonState = buttonState; msg.body.motion.xOffset = xOffset;
mSharedMessage->motion.xOffset = xOffset; msg.body.motion.yOffset = yOffset;
mSharedMessage->motion.yOffset = yOffset; msg.body.motion.xPrecision = xPrecision;
mSharedMessage->motion.xPrecision = xPrecision; msg.body.motion.yPrecision = yPrecision;
mSharedMessage->motion.yPrecision = yPrecision; msg.body.motion.downTime = downTime;
mSharedMessage->motion.downTime = downTime; msg.body.motion.eventTime = eventTime;
mSharedMessage->motion.pointerCount = pointerCount; msg.body.motion.pointerCount = pointerCount;
mSharedMessage->motion.sampleCount = 1;
mSharedMessage->motion.sampleData[0].eventTime = eventTime;
for (size_t i = 0; i < pointerCount; i++) { for (size_t i = 0; i < pointerCount; i++) {
mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]); msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]); msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
} }
return mChannel->sendMessage(&msg);
// 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<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(bool* outHandled) {
@@ -520,61 +287,28 @@ status_t InputPublisher::receiveFinishedSignal(bool* outHandled) {
mChannel->getName().string()); mChannel->getName().string());
#endif #endif
char signal; InputMessage msg;
status_t result = mChannel->receiveSignal(& signal); status_t result = mChannel->receiveMessage(&msg);
if (result) { if (result) {
*outHandled = false; *outHandled = false;
return result; return result;
} }
if (signal == INPUT_SIGNAL_FINISHED_HANDLED) { if (msg.header.type != InputMessage::TYPE_FINISHED) {
*outHandled = true; ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
} else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) { mChannel->getName().string(), msg.header.type);
*outHandled = false;
} else {
ALOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
mChannel->getName().string(), signal);
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
*outHandled = msg.body.finished.handled;
return OK; return OK;
} }
// --- InputConsumer --- // --- InputConsumer ---
InputConsumer::InputConsumer(const sp<InputChannel>& channel) : InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
mChannel(channel), mSharedMessage(NULL) { mChannel(channel) {
} }
InputConsumer::~InputConsumer() { 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<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;
}
return OK;
} }
status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) { status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
@@ -585,46 +319,28 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent*
*outEvent = NULL; *outEvent = NULL;
int ashmemFd = mChannel->getAshmemFd(); InputMessage msg;
int result = ashmem_pin_region(ashmemFd, 0, 0); status_t result = mChannel->receiveMessage(&msg);
if (result != ASHMEM_NOT_PURGED) { if (result) {
if (result == ASHMEM_WAS_PURGED) { return result;
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;
} }
if (mSharedMessage->consumed) { switch (msg.header.type) {
ALOGE("channel '%s' consumer ~ The current message has already been consumed.", case InputMessage::TYPE_KEY: {
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: {
KeyEvent* keyEvent = factory->createKeyEvent(); KeyEvent* keyEvent = factory->createKeyEvent();
if (! keyEvent) return NO_MEMORY; if (!keyEvent) return NO_MEMORY;
populateKeyEvent(keyEvent);
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; *outEvent = keyEvent;
break; break;
} }
@@ -633,15 +349,38 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent*
MotionEvent* motionEvent = factory->createMotionEvent(); MotionEvent* motionEvent = factory->createMotionEvent();
if (! motionEvent) return NO_MEMORY; 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; *outEvent = motionEvent;
break; break;
} }
default: default:
ALOGE("channel '%s' consumer ~ Received message of unknown type %d", ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
mChannel->getName().string(), mSharedMessage->type); mChannel->getName().string(), msg.header.type);
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
@@ -654,74 +393,10 @@ status_t InputConsumer::sendFinishedSignal(bool handled) {
mChannel->getName().string(), handled); mChannel->getName().string(), handled);
#endif #endif
return mChannel->sendSignal(handled InputMessage msg;
? INPUT_SIGNAL_FINISHED_HANDLED msg.header.type = InputMessage::TYPE_FINISHED;
: INPUT_SIGNAL_FINISHED_UNHANDLED); 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
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);
}
}
} }
} // namespace android } // namespace android

View File

@@ -20,8 +20,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include <sys/mman.h> #include <errno.h>
#include <cutils/ashmem.h>
#include "../../utils/tests/TestHelpers.h" #include "../../utils/tests/TestHelpers.h"
@@ -36,35 +35,24 @@ protected:
TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) { TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) {
// Our purpose here is to verify that the input channel destructor closes the // 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. // 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"), sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd);
fakeAshmem.sendFd, receivePipe.receiveFd, sendPipe.sendFd);
EXPECT_STREQ("channel name", inputChannel->getName().string()) EXPECT_STREQ("channel name", inputChannel->getName().string())
<< "channel should have provided name"; << "channel should have provided name";
EXPECT_EQ(fakeAshmem.sendFd, inputChannel->getAshmemFd()) EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
<< "channel should have provided ashmem fd"; << "channel should have provided 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";
inputChannel.clear(); // destroys input channel inputChannel.clear(); // destroys input channel
EXPECT_EQ(-EPIPE, fakeAshmem.readSignal()) EXPECT_EQ(-EPIPE, pipe.readSignal())
<< "channel should have closed ashmem fd when destroyed"; << "channel should have closed 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";
// clean up fds of Pipe endpoints that were closed so we don't try to close them again // clean up fds of Pipe endpoints that were closed so we don't try to close them again
fakeAshmem.sendFd = -1; pipe.sendFd = -1;
receivePipe.receiveFd = -1;
sendPipe.sendFd = -1;
} }
TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
@@ -82,43 +70,37 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
EXPECT_STREQ("channel name (client)", clientChannel->getName().string()) EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
<< "client channel should have suffixed name"; << "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 // Server->Client communication
EXPECT_EQ(OK, serverChannel->sendSignal('S')) InputMessage serverMsg;
<< "server channel should be able to send signal to client channel"; memset(&serverMsg, 0, sizeof(InputMessage));
char signal; serverMsg.header.type = InputMessage::TYPE_KEY;
EXPECT_EQ(OK, clientChannel->receiveSignal(& signal)) serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
<< "client channel should be able to receive signal from server channel"; EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
EXPECT_EQ('S', signal) << "server channel should be able to send message to client channel";
<< "client channel should receive the correct signal from server 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 // Client->Server communication
EXPECT_EQ(OK, clientChannel->sendSignal('c')) InputMessage clientReply;
<< "client channel should be able to send signal to server channel"; memset(&clientReply, 0, sizeof(InputMessage));
EXPECT_EQ(OK, serverChannel->receiveSignal(& signal)) clientReply.header.type = InputMessage::TYPE_FINISHED;
<< "server channel should be able to receive signal from client channel"; clientReply.body.finished.handled = true;
EXPECT_EQ('c', signal) EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply))
<< "server channel should receive the correct signal from client channel"; << "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) { TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
@@ -130,9 +112,9 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
ASSERT_EQ(OK, result) ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair"; << "should have successfully opened a channel pair";
char signal; InputMessage msg;
EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveSignal(& signal)) EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveMessage(&msg))
<< "receiveSignal should have returned WOULD_BLOCK"; << "receiveMessage should have returned WOULD_BLOCK";
} }
TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
@@ -146,9 +128,9 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
serverChannel.clear(); // close server channel serverChannel.clear(); // close server channel
char signal; InputMessage msg;
EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveSignal(& signal)) EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg))
<< "receiveSignal should have returned DEAD_OBJECT"; << "receiveMessage should have returned DEAD_OBJECT";
} }
TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) { TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
@@ -162,8 +144,10 @@ TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
serverChannel.clear(); // close server channel serverChannel.clear(); // close server channel
EXPECT_EQ(DEAD_OBJECT, clientChannel->sendSignal('S')) InputMessage msg;
<< "sendSignal should have returned DEAD_OBJECT"; msg.header.type = InputMessage::TYPE_KEY;
EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg))
<< "sendMessage should have returned DEAD_OBJECT";
} }

View File

@@ -57,11 +57,8 @@ protected:
clientChannel.clear(); clientChannel.clear();
} }
void Initialize();
void PublishAndConsumeKeyEvent(); void PublishAndConsumeKeyEvent();
void PublishAndConsumeMotionEvent( void PublishAndConsumeMotionEvent();
size_t samplesToAppendBeforeDispatch = 0,
size_t samplesToAppendAfterDispatch = 0);
}; };
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) { TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
@@ -69,18 +66,6 @@ TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get()); 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() { void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
status_t status; status_t status;
@@ -100,14 +85,6 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
ASSERT_EQ(OK, status) ASSERT_EQ(OK, status)
<< "publisher publishKeyEvent should return OK"; << "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; InputEvent* event;
status = mConsumer->consume(& mEventFactory, & event); status = mConsumer->consume(& mEventFactory, & event);
ASSERT_EQ(OK, status) ASSERT_EQ(OK, status)
@@ -140,14 +117,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
<< "publisher receiveFinishedSignal should return OK"; << "publisher receiveFinishedSignal should return OK";
ASSERT_TRUE(handled) ASSERT_TRUE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply"; << "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( void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
size_t samplesToAppendBeforeDispatch, size_t samplesToAppendAfterDispatch) {
status_t status; status_t status;
const int32_t deviceId = 1; const int32_t deviceId = 1;
@@ -163,65 +135,33 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
const float yPrecision = 0.5; const float yPrecision = 0.5;
const nsecs_t downTime = 3; const nsecs_t downTime = 3;
const size_t pointerCount = 3; const size_t pointerCount = 3;
const nsecs_t eventTime = 4;
PointerProperties pointerProperties[pointerCount]; PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
for (size_t i = 0; i < pointerCount; i++) { for (size_t i = 0; i < pointerCount; i++) {
pointerProperties[i].clear(); pointerProperties[i].clear();
pointerProperties[i].id = (i + 2) % pointerCount; pointerProperties[i].id = (i + 2) % pointerCount;
pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
}
Vector<nsecs_t> sampleEventTimes; pointerCoords[i].clear();
Vector<PointerCoords> samplePointerCoords; pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i);
pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i);
for (size_t i = 0; i <= samplesToAppendAfterDispatch + samplesToAppendBeforeDispatch; i++) { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i);
sampleEventTimes.push(i + 10); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i);
for (size_t j = 0; j < pointerCount; j++) { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i);
samplePointerCoords.push(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i);
PointerCoords& pc = samplePointerCoords.editTop(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i);
pc.clear(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i);
pc.setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i + j); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
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);
}
} }
status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags, status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags,
metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
downTime, sampleEventTimes[0], pointerCount, downTime, eventTime, pointerCount,
pointerProperties, samplePointerCoords.array()); pointerProperties, pointerCoords);
ASSERT_EQ(OK, status) ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK"; << "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; InputEvent* event;
status = mConsumer->consume(& mEventFactory, & event); status = mConsumer->consume(& mEventFactory, & event);
ASSERT_EQ(OK, status) ASSERT_EQ(OK, status)
@@ -232,8 +172,6 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType()) ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
<< "consumer should have returned a motion event"; << "consumer should have returned a motion event";
size_t lastSampleIndex = samplesToAppendBeforeDispatch + samplesToAppendAfterDispatch;
MotionEvent* motionEvent = static_cast<MotionEvent*>(event); MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
EXPECT_EQ(deviceId, motionEvent->getDeviceId()); EXPECT_EQ(deviceId, motionEvent->getDeviceId());
EXPECT_EQ(source, motionEvent->getSource()); EXPECT_EQ(source, motionEvent->getSource());
@@ -245,74 +183,36 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
EXPECT_EQ(xPrecision, motionEvent->getXPrecision()); EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
EXPECT_EQ(yPrecision, motionEvent->getYPrecision()); EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
EXPECT_EQ(downTime, motionEvent->getDownTime()); EXPECT_EQ(downTime, motionEvent->getDownTime());
EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime()); EXPECT_EQ(eventTime, motionEvent->getEventTime());
EXPECT_EQ(pointerCount, motionEvent->getPointerCount()); EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
EXPECT_EQ(lastSampleIndex, motionEvent->getHistorySize()); EXPECT_EQ(0U, motionEvent->getHistorySize());
for (size_t i = 0; i < pointerCount; i++) { for (size_t i = 0; i < pointerCount; i++) {
SCOPED_TRACE(i); SCOPED_TRACE(i);
EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i)); EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i)); EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
}
for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) { EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
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),
motionEvent->getRawX(i)); motionEvent->getRawX(i));
EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y), EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
motionEvent->getRawY(i)); 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)); 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)); motionEvent->getY(i));
EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
motionEvent->getPressure(i)); motionEvent->getPressure(i));
EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE), EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
motionEvent->getSize(i)); 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)); 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)); 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)); 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)); motionEvent->getToolMinor(i));
EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
motionEvent->getOrientation(i)); motionEvent->getOrientation(i));
} }
@@ -326,64 +226,18 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
<< "publisher receiveFinishedSignal should return OK"; << "publisher receiveFinishedSignal should return OK";
ASSERT_FALSE(handled) ASSERT_FALSE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply"; << "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) { TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); 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) { TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); 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) { TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
status_t status; status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
const size_t pointerCount = 0; const size_t pointerCount = 0;
PointerProperties pointerProperties[pointerCount]; PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount]; PointerCoords pointerCoords[pointerCount];
@@ -396,8 +250,6 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) { TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
status_t status; status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
const size_t pointerCount = MAX_POINTERS + 1; const size_t pointerCount = MAX_POINTERS + 1;
PointerProperties pointerProperties[pointerCount]; PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount]; PointerCoords pointerCoords[pointerCount];
@@ -413,7 +265,6 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater
} }
TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) { TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
@@ -421,111 +272,4 @@ TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); 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 } // namespace android

View File

@@ -196,8 +196,8 @@ InputDispatcher::~InputDispatcher() {
drainInboundQueueLocked(); drainInboundQueueLocked();
} }
while (mConnectionsByReceiveFd.size() != 0) { while (mConnectionsByFd.size() != 0) {
unregisterInputChannel(mConnectionsByReceiveFd.valueAt(0)->inputChannel); unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel);
} }
} }
@@ -888,7 +888,7 @@ void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTi
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) { if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else { } else {
#if DEBUG_FOCUS #if DEBUG_FOCUS
@@ -994,7 +994,7 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout
if (inputChannel.get()) { if (inputChannel.get()) {
ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
if (connectionIndex >= 0) { if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
if (connection->status == Connection::STATUS_NORMAL) { if (connection->status == Connection::STATUS_NORMAL) {
CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
"application not responding"); "application not responding");
@@ -1643,7 +1643,7 @@ bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(
const sp<InputWindowHandle>& windowHandle) { const sp<InputWindowHandle>& windowHandle) {
ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel()); ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
if (connectionIndex >= 0) { if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
return connection->outboundQueue.isEmpty(); return connection->outboundQueue.isEmpty();
} else { } else {
return true; 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. // Record information about the newly started dispatch cycle.
connection->lastEventTime = eventEntry->eventTime; connection->lastEventTime = eventEntry->eventTime;
connection->lastDispatchTime = currentTime; connection->lastDispatchTime = currentTime;
@@ -1990,17 +1981,6 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
return; 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. // Notify other system components and prepare to start the next dispatch cycle.
onDispatchCycleFinishedLocked(currentTime, connection, handled); onDispatchCycleFinishedLocked(currentTime, connection, handled);
} }
@@ -2064,21 +2044,21 @@ void InputDispatcher::drainOutboundQueueLocked(Connection* connection) {
deactivateConnectionLocked(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<InputDispatcher*>(data); InputDispatcher* d = static_cast<InputDispatcher*>(data);
{ // acquire lock { // acquire lock
AutoMutex _l(d->mLock); AutoMutex _l(d->mLock);
ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd); ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
if (connectionIndex < 0) { if (connectionIndex < 0) {
ALOGE("Received spurious receive callback for unknown input channel. " 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 return 0; // remove the callback
} }
bool notify; bool notify;
sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex); sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
if (!(events & ALOOPER_EVENT_INPUT)) { if (!(events & ALOOPER_EVENT_INPUT)) {
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " 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( void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options) { const CancelationOptions& options) {
for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) { for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
synthesizeCancelationEventsForConnectionLocked( synthesizeCancelationEventsForConnectionLocked(
mConnectionsByReceiveFd.valueAt(i), options); mConnectionsByFd.valueAt(i), options);
} }
} }
@@ -2128,7 +2108,7 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
ssize_t index = getConnectionIndexLocked(channel); ssize_t index = getConnectionIndexLocked(channel);
if (index >= 0) { if (index >= 0) {
synthesizeCancelationEventsForConnectionLocked( synthesizeCancelationEventsForConnectionLocked(
mConnectionsByReceiveFd.valueAt(index), options); mConnectionsByFd.valueAt(index), options);
} }
} }
@@ -2968,8 +2948,8 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex); sp<Connection> fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex);
sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex); sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex);
fromConnection->inputState.copyPointerStateTo(toConnection->inputState); fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -3134,21 +3114,15 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan
} }
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); sp<Connection> 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(); int32_t fd = inputChannel->getFd();
mConnectionsByReceiveFd.add(receiveFd, connection); mConnectionsByFd.add(fd, connection);
if (monitor) { if (monitor) {
mMonitoringChannels.push(inputChannel); mMonitoringChannels.push(inputChannel);
} }
mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
runCommandsLockedInterruptible(); runCommandsLockedInterruptible();
} // release lock } // release lock
@@ -3184,14 +3158,14 @@ status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& i
return BAD_VALUE; return BAD_VALUE;
} }
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
mConnectionsByReceiveFd.removeItemsAt(connectionIndex); mConnectionsByFd.removeItemsAt(connectionIndex);
if (connection->monitor) { if (connection->monitor) {
removeMonitorChannelLocked(inputChannel); removeMonitorChannelLocked(inputChannel);
} }
mLooper->removeFd(inputChannel->getReceivePipeFd()); mLooper->removeFd(inputChannel->getFd());
nsecs_t currentTime = now(); nsecs_t currentTime = now();
abortBrokenDispatchCycleLocked(currentTime, connection, notify); abortBrokenDispatchCycleLocked(currentTime, connection, notify);
@@ -3212,9 +3186,9 @@ void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputCh
} }
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) { ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd()); ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
if (connectionIndex >= 0) { if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
if (connection->inputChannel.get() == inputChannel.get()) { if (connection->inputChannel.get() == inputChannel.get()) {
return connectionIndex; return connectionIndex;
} }
@@ -4052,10 +4026,6 @@ InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
InputDispatcher::Connection::~Connection() { InputDispatcher::Connection::~Connection() {
} }
status_t InputDispatcher::Connection::initialize() {
return inputPublisher.initialize();
}
const char* InputDispatcher::Connection::getStatusLabel() const { const char* InputDispatcher::Connection::getStatusLabel() const {
switch (status) { switch (status) {
case STATUS_NORMAL: case STATUS_NORMAL:

View File

@@ -807,8 +807,6 @@ private:
inline double getDispatchLatencyMillis(nsecs_t currentTime) const { inline double getDispatchLatencyMillis(nsecs_t currentTime) const {
return (currentTime - lastDispatchTime) / 1000000.0; return (currentTime - lastDispatchTime) / 1000000.0;
} }
status_t initialize();
}; };
enum DropReason { enum DropReason {
@@ -862,8 +860,8 @@ private:
sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y); sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y);
// All registered connections mapped by receive pipe file descriptor. // All registered connections mapped by channel file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd; KeyedVector<int, sp<Connection> > mConnectionsByFd;
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel); ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
@@ -1027,7 +1025,7 @@ private:
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool notify); bool notify);
void drainOutboundQueueLocked(Connection* connection); void drainOutboundQueueLocked(Connection* connection);
static int handleReceiveCallback(int receiveFd, int events, void* data); static int handleReceiveCallback(int fd, int events, void* data);
void synthesizeCancelationEventsForAllConnectionsLocked( void synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options); const CancelationOptions& options);