Merge "gltrace: Patch up all glUniform*() calls."
diff --git a/cmds/keystore/keystore.cpp b/cmds/keystore/keystore.cpp
index 05f77e5..2c9cb35 100644
--- a/cmds/keystore/keystore.cpp
+++ b/cmds/keystore/keystore.cpp
@@ -581,7 +581,7 @@
static ResponseCode insert(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* val) {
char filename[NAME_MAX];
encode_key(filename, uid, keyName);
- Blob keyBlob(val->value, val->length, 0, NULL);
+ Blob keyBlob(val->value, val->length, NULL, 0);
return keyStore->put(filename, &keyBlob);
}
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 991a181..ae99160 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -60,6 +60,8 @@
BufferQueue(bool allowSynchronousMode = true);
virtual ~BufferQueue();
+ virtual int query(int what, int* value);
+
// setBufferCount updates the number of available buffer slots. After
// calling this all buffer slots are both unallocated and owned by the
// BufferQueue object (i.e. they are not owned by the client).
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 4318f0f..dcab049 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -55,7 +55,7 @@
virtual ~SurfaceTexture();
- virtual int query(int what, int* value);
+
// updateTexImage sets the image contents of the target texture to that of
// the most recently queued buffer.
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 95e4447..1f738cd 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,88 +36,26 @@
namespace android {
/*
- * An input channel consists of a shared memory buffer and a pair of pipes
- * used to send input messages from an InputPublisher to an InputConsumer
- * across processes. Each channel has a descriptive name for debugging purposes.
- *
- * Each endpoint has its own InputChannel object that specifies its own file descriptors.
- *
- * The input channel is closed when all references to it are released.
- */
-class InputChannel : public RefBase {
-protected:
- virtual ~InputChannel();
-
-public:
- InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
- int32_t sendPipeFd);
-
- /* Creates a pair of input channels and their underlying shared memory buffers
- * and pipes.
- *
- * Returns OK on success.
- */
- static status_t openInputChannelPair(const String8& name,
- sp<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.
+ * Intermediate representation used to send input events and related signals.
*/
struct InputMessage {
- /* Semaphore count is set to 1 when the message is published.
- * It becomes 0 transiently while the publisher updates the message.
- * It becomes 0 permanently when the consumer consumes the message.
- */
- sem_t semaphore;
-
- /* Initialized to false by the publisher.
- * Set to true by the consumer when it consumes the message.
- */
- bool consumed;
-
- int32_t type;
-
- struct SampleData {
- nsecs_t eventTime;
- PointerCoords coords[0]; // variable length
+ enum {
+ TYPE_KEY = 1,
+ TYPE_MOTION = 2,
+ TYPE_FINISHED = 3,
};
- int32_t deviceId;
- int32_t source;
+ struct Header {
+ uint32_t type;
+ uint32_t padding; // 8 byte alignment for the body that follows
+ } header;
- union {
- struct {
+ union Body {
+ struct Key {
+ uint32_t seq;
+ nsecs_t eventTime;
+ int32_t deviceId;
+ int32_t source;
int32_t action;
int32_t flags;
int32_t keyCode;
@@ -129,10 +63,17 @@
int32_t metaState;
int32_t repeatCount;
nsecs_t downTime;
- nsecs_t eventTime;
+
+ inline size_t size() const {
+ return sizeof(Key);
+ }
} key;
- struct {
+ struct Motion {
+ uint32_t seq;
+ nsecs_t eventTime;
+ int32_t deviceId;
+ int32_t source;
int32_t action;
int32_t flags;
int32_t metaState;
@@ -144,28 +85,88 @@
float xPrecision;
float yPrecision;
size_t pointerCount;
- PointerProperties pointerProperties[MAX_POINTERS];
- size_t sampleCount;
- SampleData sampleData[0]; // variable length
+ struct Pointer {
+ PointerProperties properties;
+ PointerCoords coords;
+ } pointers[MAX_POINTERS];
+
+ inline size_t size() const {
+ return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS
+ + sizeof(Pointer) * pointerCount;
+ }
} motion;
- };
- /* Gets the number of bytes to add to step to the next SampleData object in a motion
- * event message for a given number of pointers.
- */
- static inline size_t sampleDataStride(size_t pointerCount) {
- return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords);
- }
+ struct Finished {
+ uint32_t seq;
+ bool handled;
- /* 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);
- }
+ inline size_t size() const {
+ return sizeof(Finished);
+ }
+ } finished;
+ } body;
+
+ bool isValid(size_t actualSize) const;
+ size_t size() const;
};
/*
- * Publishes input events to an anonymous shared memory buffer.
- * Uses atomic operations to coordinate shared access with a single concurrent consumer.
+ * An input channel consists of a local unix domain socket used to send and receive
+ * input messages across processes. Each channel has a descriptive name for debugging purposes.
+ *
+ * Each endpoint has its own InputChannel object that specifies its file descriptor.
+ *
+ * The input channel is closed when all references to it are released.
+ */
+class InputChannel : public RefBase {
+protected:
+ virtual ~InputChannel();
+
+public:
+ InputChannel(const String8& name, int32_t fd);
+
+ /* Creates a pair of input channels.
+ *
+ * Returns OK on success.
+ */
+ static status_t openInputChannelPair(const String8& name,
+ sp<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 {
public:
@@ -178,26 +179,16 @@
/* 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 @@
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 @@
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,76 @@
/* 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.
+ *
+ * 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.
- * 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.
- */
- 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.
- *
- * Returns OK on success.
- * Errors probably indicate that the channel is broken.
- */
- status_t sendFinishedSignal(bool handled);
-
- /* Receives the dispatched signal from the publisher.
- *
- * Returns OK on success.
- * Returns WOULD_BLOCK if there is no signal present.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveDispatchSignal();
+ status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
+ uint32_t* outSeq, InputEvent** outEvent);
+
+ /* 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 BAD_VALUE if seq is 0.
+ * Other errors probably indicate that the channel is broken.
+ */
+ 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;
+ // The current input message.
+ InputMessage mMsg;
- void populateKeyEvent(KeyEvent* keyEvent) const;
- void populateMotionEvent(MotionEvent* motionEvent) const;
+ // True if mMsg contains a valid input message that was deferred from the previous
+ // call to consume and that still needs to be handled.
+ bool mMsgDeferred;
+
+ // Batched motion events per device and source.
+ struct Batch {
+ uint32_t seq; // sequence number of last input message batched in the event
+ MotionEvent event;
+ };
+ Vector<Batch> mBatches;
+
+ // Chain of batched sequence numbers. When multiple input messages are combined into
+ // a batch, we append a record here that associates the last sequence number in the
+ // batch with the previous one. When the finished signal is sent, we traverse the
+ // chain to individually finish all input messages that were part of the batch.
+ struct SeqChain {
+ uint32_t seq; // sequence number of batched input message
+ uint32_t chain; // sequence number of previous batched input message
+ };
+ Vector<SeqChain> mSeqChains;
+
+ ssize_t findBatch(int32_t deviceId, int32_t source) const;
+ status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
+
+ 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/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index 6bcdea4..fcc3bcf 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -66,7 +66,7 @@
ssize_t indexOfKey(const KEY& key) const;
/*!
- * modifing the array
+ * modifying the array
*/
VALUE& editValueFor(const KEY& key);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index c7e2c0f..0791de2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -166,6 +166,37 @@
return OK;
}
+int BufferQueue::query(int what, int* outValue)
+{
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("query: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
+ int value;
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ value = mDefaultWidth;
+ break;
+ case NATIVE_WINDOW_HEIGHT:
+ value = mDefaultHeight;
+ break;
+ case NATIVE_WINDOW_FORMAT:
+ value = mPixelFormat;
+ break;
+ case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+ value = mSynchronousMode ?
+ (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ outValue[0] = value;
+ return NO_ERROR;
+}
+
status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ST_LOGV("requestBuffer: slot=%d", slot);
Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index be1bcd1..a7bfc61 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -416,36 +416,7 @@
return mSynchronousMode;
}
-int SurfaceTexture::query(int what, int* outValue)
-{
- Mutex::Autolock lock(mMutex);
- if (mAbandoned) {
- ST_LOGE("query: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
-
- int value;
- switch (what) {
- case NATIVE_WINDOW_WIDTH:
- value = mDefaultWidth;
- break;
- case NATIVE_WINDOW_HEIGHT:
- value = mDefaultHeight;
- break;
- case NATIVE_WINDOW_FORMAT:
- value = mPixelFormat;
- break;
- case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- value = mSynchronousMode ?
- (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
- break;
- default:
- return BAD_VALUE;
- }
- outValue[0] = value;
- return NO_ERROR;
-}
void SurfaceTexture::abandon() {
Mutex::Autolock lock(mMutex);
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 09cbb31..ecb3fb5 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
+// 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;
-// 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';
+// --- InputMessage ---
-// 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';
+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);
-#endif
- return -errno;
-}
-
-status_t InputChannel::receiveSignal(char* outSignal) {
- ssize_t nRead;
- do {
- nRead = ::read(mReceivePipeFd, outSignal, 1);
- } while (nRead == -1 && errno == EINTR);
-
- if (nRead == 1) {
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal);
-#endif
- return OK;
- }
-
- if (nRead == 0) { // check for EOF
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string());
+ if (size_t(nWrite) != msgLength) {
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
+ mName.string(), msg->header.type);
#endif
return DEAD_OBJECT;
}
- if (errno == EAGAIN) {
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
#endif
- return WOULD_BLOCK;
+ return OK;
+}
+
+status_t InputChannel::receiveMessage(InputMessage* msg) {
+ ssize_t nRead;
+ do {
+ nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
+ } while (nRead == -1 && errno == EINTR);
+
+ if (nRead < 0) {
+ int error = errno;
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);
+#endif
+ if (error == EAGAIN || error == EWOULDBLOCK) {
+ return WOULD_BLOCK;
+ }
+ if (error == EPIPE || error == ENOTCONN) {
+ return DEAD_OBJECT;
+ }
+ return -error;
}
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno);
+ if (nRead == 0) { // check for EOF
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
#endif
- return -errno;
+ return DEAD_OBJECT;
+ }
+
+ if (!msg->isValid(nRead)) {
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ received invalid message", mName.string());
+#endif
+ return BAD_VALUE;
+ }
+
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);
+#endif
+ return OK;
}
// --- InputPublisher ---
InputPublisher::InputPublisher(const sp<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 @@
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,349 @@
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), mMsgDeferred(false) {
}
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;
- }
-
- 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) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ consume",
- mChannel->getName().string());
-#endif
-
+ *outSeq = 0;
*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;
+ // Fetch the next input message.
+ // Loop until an event can be returned or no additional events are received.
+ while (!*outEvent) {
+ if (mMsgDeferred) {
+ // mMsg contains a valid input message from the previous call to consume
+ // that has not yet been processed.
+ mMsgDeferred = false;
+ } else {
+ // Receive a fresh message.
+ status_t result = mChannel->receiveMessage(&mMsg);
+ 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 ~ consumed batch event, seq=%u",
+ mChannel->getName().string(), *outSeq);
+#endif
+ break;
+ }
+ return result;
+ }
}
- ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
+ switch (mMsg.header.type) {
+ case InputMessage::TYPE_KEY: {
+ KeyEvent* keyEvent = factory->createKeyEvent();
+ if (!keyEvent) return NO_MEMORY;
- if (mSharedMessage->consumed) {
- ALOGE("channel '%s' consumer ~ The current message has already been consumed.",
- mChannel->getName().string());
- return INVALID_OPERATION;
- }
-
- // Acquire but *never release* the semaphore. Contention on the semaphore is used to signal
- // to the publisher that the message has been consumed (or is in the process of being
- // consumed). Eventually the publisher will reinitialize the semaphore for the next message.
- result = sem_wait(& mSharedMessage->semaphore);
- if (result < 0) {
- ALOGE("channel '%s' consumer ~ Error %d in sem_wait.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
-
- mSharedMessage->consumed = true;
-
- switch (mSharedMessage->type) {
- case AINPUT_EVENT_TYPE_KEY: {
- KeyEvent* keyEvent = factory->createKeyEvent();
- if (! keyEvent) return NO_MEMORY;
-
- populateKeyEvent(keyEvent);
-
- *outEvent = keyEvent;
- break;
- }
-
- case AINPUT_EVENT_TYPE_MOTION: {
- MotionEvent* motionEvent = factory->createMotionEvent();
- if (! motionEvent) return NO_MEMORY;
-
- populateMotionEvent(motionEvent);
-
- *outEvent = motionEvent;
- break;
- }
-
- default:
- ALOGE("channel '%s' consumer ~ Received message of unknown type %d",
- mChannel->getName().string(), mSharedMessage->type);
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t InputConsumer::sendFinishedSignal(bool handled) {
+ initializeKeyEvent(keyEvent, &mMsg);
+ *outSeq = mMsg.body.key.seq;
+ *outEvent = keyEvent;
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d",
- mChannel->getName().string(), handled);
+ ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
+ mChannel->getName().string(), *outSeq);
#endif
+ break;
+ }
- return mChannel->sendSignal(handled
- ? INPUT_SIGNAL_FINISHED_HANDLED
- : INPUT_SIGNAL_FINISHED_UNHANDLED);
-}
+ case AINPUT_EVENT_TYPE_MOTION: {
+ ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
+ if (batchIndex >= 0) {
+ Batch& batch = mBatches.editItemAt(batchIndex);
+ if (canAppendSamples(&batch.event, &mMsg)) {
+ // Append to the batch and save the new sequence number for the tail end.
+ uint32_t chain = batch.seq;
+ appendSamples(&batch.event, &mMsg);
+ batch.seq = mMsg.body.motion.seq;
-status_t InputConsumer::receiveDispatchSignal() {
+ // Update the sequence number chain.
+ SeqChain seqChain;
+ seqChain.seq = batch.seq;
+ seqChain.chain = chain;
+ mSeqChains.push(seqChain);
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ receiveDispatchSignal",
- mChannel->getName().string());
+ ALOGD("channel '%s' consumer ~ appended to batch event",
+ mChannel->getName().string());
#endif
+ break;
+ } else {
+ MotionEvent* motionEvent = factory->createMotionEvent();
+ if (! motionEvent) return NO_MEMORY;
- 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;
+ // We cannot append to the batch in progress, so we need to consume
+ // the previous batch right now and defer the new message until later.
+ mMsgDeferred = true;
+
+ // 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;
+ }
+ }
+
+ // Start a new batch if needed.
+ if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
+ || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ mBatches.push();
+ Batch& batch = mBatches.editTop();
+ batch.seq = mMsg.body.motion.seq;
+ initializeMotionEvent(&batch.event, &mMsg);
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ started batch event",
+ mChannel->getName().string());
+#endif
+ break;
+ }
+
+ MotionEvent* motionEvent = factory->createMotionEvent();
+ if (! motionEvent) return NO_MEMORY;
+
+ initializeMotionEvent(motionEvent, &mMsg);
+ *outSeq = mMsg.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 unexpected message of type %d",
+ mChannel->getName().string(), mMsg.header.type);
+ 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);
-}
+status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
+ mChannel->getName().string(), seq, handled ? "true" : "false");
+#endif
-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);
+ if (!seq) {
+ ALOGE("Attempted to send a finished signal with sequence number 0.");
+ return BAD_VALUE;
+ }
- 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);
+ // Send finished signals for the batch sequence chain first.
+ size_t seqChainCount = mSeqChains.size();
+ if (seqChainCount) {
+ uint32_t currentSeq = seq;
+ uint32_t chainSeqs[seqChainCount];
+ size_t chainIndex = 0;
+ for (size_t i = seqChainCount; i-- > 0; ) {
+ const SeqChain& seqChain = mSeqChains.itemAt(i);
+ if (seqChain.seq == currentSeq) {
+ currentSeq = seqChain.chain;
+ chainSeqs[chainIndex++] = currentSeq;
+ mSeqChains.removeAt(i);
+ }
+ }
+ status_t status = OK;
+ while (!status && chainIndex-- > 0) {
+ status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
+ }
+ if (status) {
+ // An error occurred so at least one signal was not sent, reconstruct the chain.
+ do {
+ SeqChain seqChain;
+ seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
+ seqChain.chain = chainSeqs[chainIndex];
+ mSeqChains.push(seqChain);
+ } while (chainIndex-- > 0);
+ return status;
}
}
+
+ // Send finished signal for the last message in the batch.
+ return sendUnchainedFinishedSignal(seq, handled);
+}
+
+status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
+ InputMessage msg;
+ msg.header.type = InputMessage::TYPE_FINISHED;
+ msg.body.finished.seq = seq;
+ msg.body.finished.handled = handled;
+ return mChannel->sendMessage(&msg);
+}
+
+bool InputConsumer::hasPendingBatch() const {
+ return !mBatches.isEmpty();
+}
+
+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 -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::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);
+}
+
+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 eff22ee..ee422fe 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 @@
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 @@
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 @@
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 @@
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 @@
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 fcc4cad..3303053 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -57,11 +57,8 @@
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 @@
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 @@
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 @@
<< "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 @@
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 @@
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;
+
+ 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);
}
- 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);
- }
- }
-
- 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 @@
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 @@
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_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 @@
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 @@
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
}
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledBeforeDispatchSignal_AppendsSamples) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(3, 0));
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledAfterDispatchSignalAndNotConsumed_AppendsSamples) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(0, 4));
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenNoMotionEventPublished_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- PointerCoords pointerCoords[1];
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher appendMotionSample should return INVALID_OPERATION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEventIsNotAMove_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = MAX_POINTERS;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status);
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher appendMotionSample should return INVALID_OPERATION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = MAX_POINTERS;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status);
-
- status = mPublisher->sendDispatchSignal();
- ASSERT_EQ(OK, status);
-
- status = mConsumer->receiveDispatchSignal();
- ASSERT_EQ(OK, status);
-
- InputEvent* event;
- status = mConsumer->consume(& mEventFactory, & event);
- ASSERT_EQ(OK, status);
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(status_t(FAILED_TRANSACTION), status)
- << "publisher appendMotionSample should return FAILED_TRANSACTION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = MAX_POINTERS;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status);
-
- for (int count = 1;; count++) {
- ASSERT_LT(count, 100000) << "should eventually reach OOM";
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- if (status != OK) {
- ASSERT_GT(count, 12) << "should be able to add at least a dozen samples";
- ASSERT_EQ(NO_MEMORY, status)
- << "publisher appendMotionSample should return NO_MEMORY when buffer is full";
- break;
- }
- }
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(NO_MEMORY, status)
- << "publisher appendMotionSample should return NO_MEMORY persistently until reset";
-}
-
} // namespace android
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 06be2ef..0b1016c 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -118,12 +118,6 @@
// ----------------------------------------------------------------------------
-Loader::entry_t::entry_t(int dpy, int impl, const char* tag)
- : dpy(dpy), impl(impl), tag(tag) {
-}
-
-// ----------------------------------------------------------------------------
-
Loader::Loader()
{
char line[256];
@@ -131,8 +125,9 @@
/* Special case for GLES emulation */
if (checkGlesEmulationStatus() == 0) {
- ALOGD("Emulator without GPU support detected. Fallback to software renderer.");
- gConfig.add( entry_t(0, 0, "android") );
+ ALOGD("Emulator without GPU support detected. "
+ "Fallback to software renderer.");
+ mDriverTag.setTo("android");
return;
}
@@ -141,14 +136,16 @@
if (cfg == NULL) {
// default config
ALOGD("egl.cfg not found, using default config");
- gConfig.add( entry_t(0, 0, "android") );
+ mDriverTag.setTo("android");
} else {
while (fgets(line, 256, cfg)) {
- int dpy;
- int impl;
+ int dpy, impl;
if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) {
//ALOGD(">>> %u %u %s", dpy, impl, tag);
- gConfig.add( entry_t(dpy, impl, tag) );
+ // We only load the h/w accelerated implementation
+ if (tag != String8("android")) {
+ mDriverTag = tag;
+ }
}
}
fclose(cfg);
@@ -160,30 +157,12 @@
GLTrace_stop();
}
-const char* Loader::getTag(int dpy, int impl)
+void* Loader::open(egl_connection_t* cnx)
{
- const Vector<entry_t>& cfgs(gConfig);
- const size_t c = cfgs.size();
- for (size_t i=0 ; i<c ; i++) {
- if (dpy == cfgs[i].dpy)
- if (impl == cfgs[i].impl)
- return cfgs[i].tag.string();
- }
- return 0;
-}
-
-void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx)
-{
- /*
- * TODO: if we don't find display/0, then use 0/0
- * (0/0 should always work)
- */
-
void* dso;
- int index = int(display);
driver_t* hnd = 0;
- char const* tag = getTag(index, impl);
+ char const* tag = mDriverTag.string();
if (tag) {
dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2);
if (dso) {
@@ -193,16 +172,14 @@
dso = load_driver("EGL", tag, cnx, EGL);
if (dso) {
hnd = new driver_t(dso);
-
// TODO: make this more automated
hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM );
-
- hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 );
+ hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 );
}
}
}
- LOG_FATAL_IF(!index && !impl && !hnd,
+ LOG_FATAL_IF(!index && !hnd,
"couldn't find the default OpenGL ES implementation "
"for default display");
@@ -221,7 +198,7 @@
__eglMustCastToProperFunctionPointerType* curr,
getProcAddressType getProcAddress)
{
- const size_t SIZE = 256;
+ const ssize_t SIZE = 256;
char scrap[SIZE];
while (*api) {
char const * name = *api;
@@ -326,14 +303,14 @@
if (mask & GLESv1_CM) {
init_api(dso, gl_names,
(__eglMustCastToProperFunctionPointerType*)
- &cnx->hooks[GLESv1_INDEX]->gl,
+ &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl,
getProcAddress);
}
if (mask & GLESv2) {
init_api(dso, gl_names,
(__eglMustCastToProperFunctionPointerType*)
- &cnx->hooks[GLESv2_INDEX]->gl,
+ &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
getProcAddress);
}
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 580d6e4..30773cb 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -24,7 +24,6 @@
#include <utils/Errors.h>
#include <utils/Singleton.h>
#include <utils/String8.h>
-#include <utils/Vector.h>
#include <EGL/egl.h>
@@ -53,23 +52,13 @@
void* dso[3];
};
- struct entry_t {
- entry_t() { }
- entry_t(int dpy, int impl, const char* tag);
- int dpy;
- int impl;
- String8 tag;
- };
-
- Vector<entry_t> gConfig;
+ String8 mDriverTag;
getProcAddressType getProcAddress;
- const char* getTag(int dpy, int impl);
-
public:
~Loader();
- void* open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx);
+ void* open(egl_connection_t* cnx);
status_t close(void* driver);
private:
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 83933e5..4a56dcf 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -48,8 +48,8 @@
namespace android {
// ----------------------------------------------------------------------------
-egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
-gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+egl_connection_t gEGLImpl;
+gl_hooks_t gHooks[2];
gl_hooks_t gHooksNoContext;
pthread_key_t gGLWrapperKey = -1;
@@ -187,16 +187,13 @@
return dp;
}
-egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig config,
+egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig,
egl_display_t const*& dp) {
dp = validate_display(dpy);
if (!dp)
return (egl_connection_t*) NULL;
- if (intptr_t(config) >= dp->numTotalConfigs) {
- return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
- }
- egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(config)].impl];
+ egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso == 0) {
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
}
@@ -228,7 +225,7 @@
// EGL.
egl_image_t const * const i = get_image(image);
- return i->images[c->impl];
+ return i->image;
}
// ----------------------------------------------------------------------------
@@ -266,34 +263,17 @@
// get our driver loader
Loader& loader(Loader::getInstance());
- // dynamically load all our EGL implementations
- egl_connection_t* cnx;
-
- cnx = &gEGLImpl[IMPL_SOFTWARE];
+ // dynamically load our EGL implementation
+ egl_connection_t* cnx = &gEGLImpl;
if (cnx->dso == 0) {
- cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
- cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
- cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
+ cnx->hooks[egl_connection_t::GLESv1_INDEX] =
+ &gHooks[egl_connection_t::GLESv1_INDEX];
+ cnx->hooks[egl_connection_t::GLESv2_INDEX] =
+ &gHooks[egl_connection_t::GLESv2_INDEX];
+ cnx->dso = loader.open(cnx);
}
- cnx = &gEGLImpl[IMPL_HARDWARE];
- if (cnx->dso == 0) {
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.hw", value, "1");
- if (atoi(value) != 0) {
- cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
- cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
- cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
- } else {
- ALOGD("3D hardware acceleration is disabled");
- }
- }
-
- if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
- return EGL_FALSE;
- }
-
- return EGL_TRUE;
+ return cnx->dso ? EGL_TRUE : EGL_FALSE;
}
static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 73aab26..bb2783d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -44,6 +44,7 @@
#include "egl_impl.h"
#include "egl_object.h"
#include "egl_tls.h"
+#include "egldefs.h"
using namespace android;
@@ -88,24 +89,6 @@
// ----------------------------------------------------------------------------
-template<typename T>
-static __attribute__((noinline))
-int binarySearch(T const sortedArray[], int first, int last, T key) {
- while (first <= last) {
- int mid = (first + last) / 2;
- if (sortedArray[mid] < key) {
- first = mid + 1;
- } else if (key < sortedArray[mid]) {
- last = mid - 1;
- } else {
- return mid;
- }
- }
- return -1;
-}
-
-// ----------------------------------------------------------------------------
-
namespace android {
extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
extern EGLBoolean egl_init_drivers();
@@ -183,21 +166,20 @@
egl_display_t const * const dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- GLint numConfigs = dp->numTotalConfigs;
- if (!configs) {
- *num_config = numConfigs;
- return EGL_TRUE;
+ if (num_config==0) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
- GLint n = 0;
- for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
- *configs++ = EGLConfig(i);
- config_size--;
- n++;
+ EGLBoolean res = EGL_FALSE;
+ *num_config = 0;
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso) {
+ res = cnx->egl.eglGetConfigs(
+ dp->disp.dpy, configs, config_size, num_config);
}
-
- *num_config = n;
- return EGL_TRUE;
+
+ return res;
}
EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
@@ -213,105 +195,13 @@
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
- EGLint n;
EGLBoolean res = EGL_FALSE;
*num_config = 0;
-
- // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
- // to do this, we have to go through the attrib_list array once
- // to figure out both its size and if it contains an EGL_CONFIG_ID
- // key. If so, the full array is copied and patched.
- // NOTE: we assume that there can be only one occurrence
- // of EGL_CONFIG_ID.
-
- EGLint patch_index = -1;
- GLint attr;
- size_t size = 0;
- if (attrib_list) {
- while ((attr=attrib_list[size]) != EGL_NONE) {
- if (attr == EGL_CONFIG_ID)
- patch_index = size;
- size += 2;
- }
- }
- if (patch_index >= 0) {
- size += 2; // we need copy the sentinel as well
- EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
- if (new_list == 0)
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- memcpy(new_list, attrib_list, size*sizeof(EGLint));
-
- // patch the requested EGL_CONFIG_ID
- bool found = false;
- EGLConfig ourConfig(0);
- EGLint& configId(new_list[patch_index+1]);
- for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
- if (dp->configs[i].configId == configId) {
- ourConfig = EGLConfig(i);
- configId = dp->configs[i].implConfigId;
- found = true;
- break;
- }
- }
-
- egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
- if (found && cnx->dso) {
- // and switch to the new list
- attrib_list = const_cast<const EGLint *>(new_list);
-
- // At this point, the only configuration that can match is
- // dp->configs[i][index], however, we don't know if it would be
- // rejected because of the other attributes, so we do have to call
- // cnx->egl.eglChooseConfig() -- but we don't have to loop
- // through all the EGLimpl[].
- // We also know we can only get a single config back, and we know
- // which one.
-
- res = cnx->egl.eglChooseConfig(
- dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
- attrib_list, configs, config_size, &n);
- if (res && n>0) {
- // n has to be 0 or 1, by construction, and we already know
- // which config it will return (since there can be only one).
- if (configs) {
- configs[0] = ourConfig;
- }
- *num_config = 1;
- }
- }
-
- free(const_cast<EGLint *>(attrib_list));
- return res;
- }
-
-
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglChooseConfig(
- dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
- if (configs) {
- // now we need to convert these client EGLConfig to our
- // internal EGLConfig format.
- // This is done in O(n Log(n)) time.
- for (int j=0 ; j<n ; j++) {
- egl_config_t key(i, configs[j]);
- intptr_t index = binarySearch<egl_config_t>(
- dp->configs, 0, dp->numTotalConfigs, key);
- if (index >= 0) {
- configs[j] = EGLConfig(index);
- } else {
- return setError(EGL_BAD_CONFIG, EGL_FALSE);
- }
- }
- configs += n;
- config_size -= n;
- }
- *num_config += n;
- res = EGL_TRUE;
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso) {
+ res = cnx->egl.eglChooseConfig(
+ dp->disp.dpy, attrib_list, configs, config_size, num_config);
}
return res;
}
@@ -325,13 +215,8 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (!cnx) return EGL_FALSE;
- if (attribute == EGL_CONFIG_ID) {
- *value = dp->configs[intptr_t(config)].configId;
- return EGL_TRUE;
- }
return cnx->egl.eglGetConfigAttrib(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config, attribute, value);
+ dp->disp.dpy, config, attribute, value);
}
// ----------------------------------------------------------------------------
@@ -347,8 +232,7 @@
egl_display_t const* dp = 0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
- EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy;
- EGLConfig iConfig = dp->configs[intptr_t(config)].config;
+ EGLDisplay iDpy = dp->disp.dpy;
EGLint format;
if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
@@ -359,7 +243,7 @@
// set the native window's buffers format to match this config
if (cnx->egl.eglGetConfigAttrib(iDpy,
- iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
+ config, EGL_NATIVE_VISUAL_ID, &format)) {
if (format != 0) {
int err = native_window_set_buffers_format(window, format);
if (err != 0) {
@@ -377,10 +261,9 @@
anw->setSwapInterval(anw, 1);
EGLSurface surface = cnx->egl.eglCreateWindowSurface(
- iDpy, iConfig, window, attrib_list);
+ iDpy, config, window, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
- dp->configs[intptr_t(config)].impl, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, cnx);
return s;
}
@@ -401,11 +284,9 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config, pixmap, attrib_list);
+ dp->disp.dpy, config, pixmap, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
- dp->configs[intptr_t(config)].impl, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
return s;
}
}
@@ -421,11 +302,9 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config, attrib_list);
+ dp->disp.dpy, config, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
- dp->configs[intptr_t(config)].impl, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
return s;
}
}
@@ -444,8 +323,7 @@
return setError(EGL_BAD_SURFACE, EGL_FALSE);
egl_surface_t * const s = get_surface(surface);
- EGLBoolean result = s->cnx->egl.eglDestroySurface(
- dp->disp[s->impl].dpy, s->surface);
+ EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
if (result == EGL_TRUE) {
_s.terminate();
}
@@ -465,16 +343,8 @@
return setError(EGL_BAD_SURFACE, EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
- EGLBoolean result(EGL_TRUE);
- if (attribute == EGL_CONFIG_ID) {
- // We need to remap EGL_CONFIG_IDs
- *value = dp->configs[intptr_t(s->config)].configId;
- } else {
- result = s->cnx->egl.eglQuerySurface(
- dp->disp[s->impl].dpy, s->surface, attribute, value);
- }
-
- return result;
+ return s->cnx->egl.eglQuerySurface(
+ dp->disp.dpy, s->surface, attribute, value);
}
void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
@@ -514,9 +384,7 @@
share_list = c->context;
}
EGLContext context = cnx->egl.eglCreateContext(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config,
- share_list, attrib_list);
+ dp->disp.dpy, config, share_list, attrib_list);
if (context != EGL_NO_CONTEXT) {
// figure out if it's a GLESv1 or GLESv2
int version = 0;
@@ -526,15 +394,14 @@
GLint value = *attrib_list++;
if (attr == EGL_CONTEXT_CLIENT_VERSION) {
if (value == 1) {
- version = GLESv1_INDEX;
+ version = egl_connection_t::GLESv1_INDEX;
} else if (value == 2) {
- version = GLESv2_INDEX;
+ version = egl_connection_t::GLESv2_INDEX;
}
}
};
}
- egl_context_t* c = new egl_context_t(dpy, context, config,
- dp->configs[intptr_t(config)].impl, cnx, version);
+ egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version);
#if EGL_TRACE
if (gEGLDebugLevel > 0)
GLTrace_eglCreateContext(version, c);
@@ -558,8 +425,7 @@
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
egl_context_t * const c = get_context(ctx);
- EGLBoolean result = c->cnx->egl.eglDestroyContext(
- dp->disp[c->impl].dpy, c->context);
+ EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
if (result == EGL_TRUE) {
_c.terminate();
}
@@ -625,20 +491,12 @@
// retrieve the underlying implementation's draw EGLSurface
if (draw != EGL_NO_SURFACE) {
d = get_surface(draw);
- // make sure the EGLContext and EGLSurface passed in are for
- // the same driver
- if (c && d->impl != c->impl)
- return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_draw = d->surface;
}
// retrieve the underlying implementation's read EGLSurface
if (read != EGL_NO_SURFACE) {
r = get_surface(read);
- // make sure the EGLContext and EGLSurface passed in are for
- // the same driver
- if (c && r->impl != c->impl)
- return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_read = r->surface;
}
@@ -682,17 +540,9 @@
if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
egl_context_t * const c = get_context(ctx);
+ return c->cnx->egl.eglQueryContext(
+ dp->disp.dpy, c->context, attribute, value);
- EGLBoolean result(EGL_TRUE);
- if (attribute == EGL_CONFIG_ID) {
- *value = dp->configs[intptr_t(c->config)].configId;
- } else {
- // We need to remap EGL_CONFIG_IDs
- result = c->cnx->egl.eglQueryContext(
- dp->disp[c->impl].dpy, c->context, attribute, value);
- }
-
- return result;
}
EGLContext eglGetCurrentContext(void)
@@ -744,64 +594,37 @@
EGLBoolean eglWaitGL(void)
{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would return GL_TRUE, which isn't wrong.
-
clearError();
- EGLBoolean res = EGL_TRUE;
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (uint32_t(c->impl)>=2)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- egl_connection_t* const cnx = &gEGLImpl[c->impl];
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- res = cnx->egl.eglWaitGL();
- }
- return res;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ return cnx->egl.eglWaitGL();
}
EGLBoolean eglWaitNative(EGLint engine)
{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would return GL_TRUE, which isn't wrong.
-
clearError();
- EGLBoolean res = EGL_TRUE;
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (uint32_t(c->impl)>=2)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- egl_connection_t* const cnx = &gEGLImpl[c->impl];
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- res = cnx->egl.eglWaitNative(engine);
- }
- return res;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ return cnx->egl.eglWaitNative(engine);
}
EGLint eglGetError(void)
{
- EGLint result = EGL_SUCCESS;
- EGLint err;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- err = EGL_SUCCESS;
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso)
- err = cnx->egl.eglGetError();
- if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
- result = err;
+ EGLint err = EGL_SUCCESS;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso) {
+ err = cnx->egl.eglGetError();
}
- err = egl_tls_t::getError();
- if (result == EGL_SUCCESS)
- result = err;
- return result;
+ if (err == EGL_SUCCESS) {
+ err = egl_tls_t::getError();
+ }
+ return err;
}
// Note: Similar implementations of these functions also exist in
@@ -885,20 +708,20 @@
if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
bool found = false;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->egl.eglGetProcAddress) {
- found = true;
- // Extensions are independent of the bound context
- cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
- cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglGetProcAddress) {
+ found = true;
+ // Extensions are independent of the bound context
+ cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
+ cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
#if EGL_TRACE
- debugHooks->ext.extensions[slot] =
- gHooksTrace.ext.extensions[slot] =
+ debugHooks->ext.extensions[slot] =
+ gHooksTrace.ext.extensions[slot] =
#endif
- cnx->egl.eglGetProcAddress(procname);
- }
+ cnx->egl.eglGetProcAddress(procname);
}
+
if (found) {
addr = gExtensionForwarders[slot];
@@ -937,7 +760,7 @@
#endif
egl_surface_t const * const s = get_surface(draw);
- return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
+ return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
}
EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
@@ -953,8 +776,7 @@
return setError(EGL_BAD_SURFACE, EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
- return s->cnx->egl.eglCopyBuffers(
- dp->disp[s->impl].dpy, s->surface, target);
+ return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
}
const char* eglQueryString(EGLDisplay dpy, EGLint name)
@@ -973,12 +795,8 @@
return dp->getExtensionString();
case EGL_CLIENT_APIS:
return dp->getClientApiString();
- case EGL_VERSION_HW_ANDROID: {
- if (gEGLImpl[IMPL_HARDWARE].dso) {
- return dp->disp[IMPL_HARDWARE].queryString.version;
- }
- return dp->disp[IMPL_SOFTWARE].queryString.version;
- }
+ case EGL_VERSION_HW_ANDROID:
+ return dp->disp.queryString.version;
}
return setError(EGL_BAD_PARAMETER, (const char *)0);
}
@@ -1003,7 +821,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglSurfaceAttrib) {
return s->cnx->egl.eglSurfaceAttrib(
- dp->disp[s->impl].dpy, s->surface, attribute, value);
+ dp->disp.dpy, s->surface, attribute, value);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1023,7 +841,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglBindTexImage) {
return s->cnx->egl.eglBindTexImage(
- dp->disp[s->impl].dpy, s->surface, buffer);
+ dp->disp.dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1043,7 +861,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglReleaseTexImage) {
return s->cnx->egl.eglReleaseTexImage(
- dp->disp[s->impl].dpy, s->surface, buffer);
+ dp->disp.dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1056,17 +874,11 @@
if (!dp) return EGL_FALSE;
EGLBoolean res = EGL_TRUE;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglSwapInterval) {
- if (cnx->egl.eglSwapInterval(
- dp->disp[i].dpy, interval) == EGL_FALSE) {
- res = EGL_FALSE;
- }
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglSwapInterval) {
+ res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
}
+
return res;
}
@@ -1079,23 +891,15 @@
{
clearError();
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would return GL_TRUE, which isn't wrong.
- EGLBoolean res = EGL_TRUE;
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (uint32_t(c->impl)>=2)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- egl_connection_t* const cnx = &gEGLImpl[c->impl];
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (cnx->egl.eglWaitClient) {
- res = cnx->egl.eglWaitClient();
- } else {
- res = cnx->egl.eglWaitGL();
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ EGLBoolean res;
+ if (cnx->egl.eglWaitClient) {
+ res = cnx->egl.eglWaitClient();
+ } else {
+ res = cnx->egl.eglWaitGL();
}
return res;
}
@@ -1110,15 +914,9 @@
// bind this API on all EGLs
EGLBoolean res = EGL_TRUE;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglBindAPI) {
- if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
- res = EGL_FALSE;
- }
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglBindAPI) {
+ res = cnx->egl.eglBindAPI(api);
}
return res;
}
@@ -1131,16 +929,11 @@
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglQueryAPI) {
- // the first one we find is okay, because they all
- // should be the same
- return cnx->egl.eglQueryAPI();
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglQueryAPI) {
+ return cnx->egl.eglQueryAPI();
}
+
// or, it can only be OpenGL ES
return EGL_OPENGL_ES_API;
}
@@ -1152,14 +945,11 @@
// If there is context bound to the thread, release it
egl_display_t::loseCurrent(get_context(getContext()));
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglReleaseThread) {
- cnx->egl.eglReleaseThread();
- }
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglReleaseThread) {
+ cnx->egl.eglReleaseThread();
}
+
egl_tls_t::clearTLS();
#if EGL_TRACE
if (gEGLDebugLevel > 0)
@@ -1179,9 +969,7 @@
if (!cnx) return EGL_FALSE;
if (cnx->egl.eglCreatePbufferFromClientBuffer) {
return cnx->egl.eglCreatePbufferFromClientBuffer(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- buftype, buffer,
- dp->configs[intptr_t(config)].config, attrib_list);
+ dp->disp.dpy, buftype, buffer, config, attrib_list);
}
return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
}
@@ -1205,7 +993,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglLockSurfaceKHR) {
return s->cnx->egl.eglLockSurfaceKHR(
- dp->disp[s->impl].dpy, s->surface, attrib_list);
+ dp->disp.dpy, s->surface, attrib_list);
}
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
@@ -1223,8 +1011,7 @@
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglUnlockSurfaceKHR) {
- return s->cnx->egl.eglUnlockSurfaceKHR(
- dp->disp[s->impl].dpy, s->surface);
+ return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
}
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
@@ -1244,12 +1031,12 @@
egl_context_t * const c = get_context(ctx);
// since we have an EGLContext, we know which implementation to use
EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
- dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
+ dp->disp.dpy, c->context, target, buffer, attrib_list);
if (image == EGL_NO_IMAGE_KHR)
return image;
egl_image_t* result = new egl_image_t(dpy, ctx);
- result->images[c->impl] = image;
+ result->image = image;
return (EGLImageKHR)result;
} else {
// EGL_NO_CONTEXT is a valid parameter
@@ -1261,23 +1048,14 @@
EGLint currentError = eglGetError();
- EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
- bool success = false;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- implImages[i] = EGL_NO_IMAGE_KHR;
- if (cnx->dso) {
- if (cnx->egl.eglCreateImageKHR) {
- implImages[i] = cnx->egl.eglCreateImageKHR(
- dp->disp[i].dpy, ctx, target, buffer, attrib_list);
- if (implImages[i] != EGL_NO_IMAGE_KHR) {
- success = true;
- }
- }
- }
+ EGLImageKHR implImage = EGL_NO_IMAGE_KHR;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglCreateImageKHR) {
+ implImage = cnx->egl.eglCreateImageKHR(
+ dp->disp.dpy, ctx, target, buffer, attrib_list);
}
- if (!success) {
+ if (implImage == EGL_NO_IMAGE_KHR) {
// failure, if there was an error when we entered this function,
// the error flag must not be updated.
// Otherwise, the error is whatever happened in the implementation
@@ -1289,13 +1067,12 @@
} else {
// In case of success, we need to clear all error flags
// (especially those caused by the implementation that didn't
- // succeed). TODO: we could avoid this if we knew this was
- // a "full" success (all implementation succeeded).
+ // succeed).
eglGetError();
}
egl_image_t* result = new egl_image_t(dpy, ctx);
- memcpy(result->images, implImages, sizeof(implImages));
+ result->image = implImage;
return (EGLImageKHR)result;
}
}
@@ -1312,19 +1089,17 @@
egl_image_t* image = get_image(img);
bool success = false;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (image->images[i] != EGL_NO_IMAGE_KHR) {
- if (cnx->dso) {
- if (cnx->egl.eglDestroyImageKHR) {
- if (cnx->egl.eglDestroyImageKHR(
- dp->disp[i].dpy, image->images[i])) {
- success = true;
- }
- }
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (image->image != EGL_NO_IMAGE_KHR) {
+ if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
+ if (cnx->egl.eglDestroyImageKHR(
+ dp->disp.dpy, image->image)) {
+ success = true;
}
}
}
+
if (!success)
return EGL_FALSE;
@@ -1354,7 +1129,7 @@
EGLSyncKHR result = EGL_NO_SYNC_KHR;
if (c->cnx->egl.eglCreateSyncKHR) {
EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
- dp->disp[c->impl].dpy, type, attrib_list);
+ dp->disp.dpy, type, attrib_list);
if (sync == EGL_NO_SYNC_KHR)
return sync;
result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
@@ -1382,7 +1157,7 @@
egl_context_t * const c = get_context(ctx);
if (c->cnx->egl.eglDestroySyncKHR) {
result = c->cnx->egl.eglDestroySyncKHR(
- dp->disp[c->impl].dpy, syncObject->sync);
+ dp->disp.dpy, syncObject->sync);
if (result)
_s.terminate();
}
@@ -1408,7 +1183,7 @@
egl_context_t * const c = get_context(ctx);
if (c->cnx->egl.eglClientWaitSyncKHR) {
return c->cnx->egl.eglClientWaitSyncKHR(
- dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
+ dp->disp.dpy, syncObject->sync, flags, timeout);
}
return EGL_FALSE;
@@ -1434,7 +1209,7 @@
egl_context_t * const c = get_context(ctx);
if (c->cnx->egl.eglGetSyncAttribKHR) {
return c->cnx->egl.eglGetSyncAttribKHR(
- dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
+ dp->disp.dpy, syncObject->sync, attribute, value);
}
return EGL_FALSE;
@@ -1458,12 +1233,10 @@
}
EGLuint64NV ret = 0;
- egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
+ egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso) {
- if (cnx->egl.eglGetSystemTimeFrequencyNV) {
- return cnx->egl.eglGetSystemTimeFrequencyNV();
- }
+ if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
+ return cnx->egl.eglGetSystemTimeFrequencyNV();
}
return setErrorQuiet(EGL_BAD_DISPLAY, 0);
@@ -1478,12 +1251,10 @@
}
EGLuint64NV ret = 0;
- egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
+ egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso) {
- if (cnx->egl.eglGetSystemTimeNV) {
- return cnx->egl.eglGetSystemTimeNV();
- }
+ if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
+ return cnx->egl.eglGetSystemTimeNV();
}
return setErrorQuiet(EGL_BAD_DISPLAY, 0);
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 7fd6519..c79fb5f 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -83,39 +83,39 @@
void egl_cache_t::initialize(egl_display_t *display) {
Mutex::Autolock lock(mMutex);
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
- const char* exts = display->disp[i].queryString.extensions;
- size_t bcExtLen = strlen(BC_EXT_STR);
- size_t extsLen = strlen(exts);
- bool equal = !strcmp(BC_EXT_STR, exts);
- bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1);
- bool atEnd = (bcExtLen+1) < extsLen &&
- !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1));
- bool inMiddle = strstr(exts, " " BC_EXT_STR " ");
- if (equal || atStart || atEnd || inMiddle) {
- PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
- eglSetBlobCacheFuncsANDROID =
- reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
+ const char* exts = display->disp.queryString.extensions;
+ size_t bcExtLen = strlen(BC_EXT_STR);
+ size_t extsLen = strlen(exts);
+ bool equal = !strcmp(BC_EXT_STR, exts);
+ bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1);
+ bool atEnd = (bcExtLen+1) < extsLen &&
+ !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1));
+ bool inMiddle = strstr(exts, " " BC_EXT_STR " ");
+ if (equal || atStart || atEnd || inMiddle) {
+ PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
+ eglSetBlobCacheFuncsANDROID =
+ reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
cnx->egl.eglGetProcAddress(
"eglSetBlobCacheFuncsANDROID"));
- if (eglSetBlobCacheFuncsANDROID == NULL) {
- ALOGE("EGL_ANDROID_blob_cache advertised by display %d, "
- "but unable to get eglSetBlobCacheFuncsANDROID", i);
- continue;
- }
+ if (eglSetBlobCacheFuncsANDROID == NULL) {
+ ALOGE("EGL_ANDROID_blob_cache advertised, "
+ "but unable to get eglSetBlobCacheFuncsANDROID");
+ return;
+ }
- eglSetBlobCacheFuncsANDROID(display->disp[i].dpy,
- android::setBlob, android::getBlob);
- EGLint err = cnx->egl.eglGetError();
- if (err != EGL_SUCCESS) {
- ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: "
- "%#x", err);
- }
+ eglSetBlobCacheFuncsANDROID(display->disp.dpy,
+ android::setBlob, android::getBlob);
+ EGLint err = cnx->egl.eglGetError();
+ if (err != EGL_SUCCESS) {
+ ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: "
+ "%#x", err);
}
}
}
+
mInitialized = true;
}
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 6b2ae51..c85b4ce 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -60,18 +60,12 @@
extern void initEglTraceLevel();
extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
-static int cmp_configs(const void* a, const void *b) {
- const egl_config_t& c0 = *(egl_config_t const *)a;
- const egl_config_t& c1 = *(egl_config_t const *)b;
- return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
-}
-
// ----------------------------------------------------------------------------
egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
egl_display_t::egl_display_t() :
- magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) {
+ magic('_dpy'), refs(0) {
}
egl_display_t::~egl_display_t() {
@@ -119,15 +113,13 @@
// get our driver loader
Loader& loader(Loader::getInstance());
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) {
- EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
- disp[i].dpy = dpy;
- if (dpy == EGL_NO_DISPLAY) {
- loader.close(cnx->dso);
- cnx->dso = NULL;
- }
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
+ EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
+ disp.dpy = dpy;
+ if (dpy == EGL_NO_DISPLAY) {
+ loader.close(cnx->dso);
+ cnx->dso = NULL;
}
}
@@ -160,12 +152,11 @@
// initialize each EGL and
// build our own extension string first, based on the extension we know
// and the extension supported by our client implementation
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- cnx->major = -1;
- cnx->minor = -1;
- if (!cnx->dso)
- continue;
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ cnx->major = -1;
+ cnx->minor = -1;
+ if (cnx->dso) {
#if defined(ADRENO130)
#warning "Adreno-130 eglInitialize() workaround"
@@ -177,31 +168,30 @@
* eglGetDisplay() before calling eglInitialize();
*/
if (i == IMPL_HARDWARE) {
- disp[i].dpy =
- cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
}
#endif
- EGLDisplay idpy = disp[i].dpy;
+ EGLDisplay idpy = disp.dpy;
if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
- //ALOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
- // i, idpy, cnx->major, cnx->minor, cnx);
+ //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p",
+ // idpy, cnx->major, cnx->minor, cnx);
// display is now initialized
- disp[i].state = egl_display_t::INITIALIZED;
+ disp.state = egl_display_t::INITIALIZED;
// get the query-strings for this display for each implementation
- disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy,
+ disp.queryString.vendor = cnx->egl.eglQueryString(idpy,
EGL_VENDOR);
- disp[i].queryString.version = cnx->egl.eglQueryString(idpy,
+ disp.queryString.version = cnx->egl.eglQueryString(idpy,
EGL_VERSION);
- disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy,
+ disp.queryString.extensions = cnx->egl.eglQueryString(idpy,
EGL_EXTENSIONS);
- disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy,
+ disp.queryString.clientApi = cnx->egl.eglQueryString(idpy,
EGL_CLIENT_APIS);
} else {
- ALOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
+ ALOGW("eglInitialize(%p) failed (%s)", idpy,
egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
}
}
@@ -211,7 +201,7 @@
mVersionString.setTo(sVersionString);
mClientApiString.setTo(sClientApiString);
- // we only add extensions that exist in at least one implementation
+ // we only add extensions that exist in the implementation
char const* start = sExtensionString;
char const* end;
do {
@@ -223,15 +213,13 @@
if (len) {
// NOTE: we could avoid the copy if we had strnstr.
const String8 ext(start, len);
- // now go through all implementations and look for this extension
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- if (disp[i].queryString.extensions) {
- // if we find it, add this extension string to our list
- // (and don't forget the space)
- const char* match = strstr(disp[i].queryString.extensions, ext.string());
- if (match && (match[len] == ' ' || match[len] == 0)) {
- mExtensionString.append(start, len+1);
- }
+ // now look for this extension
+ if (disp.queryString.extensions) {
+ // if we find it, add this extension string to our list
+ // (and don't forget the space)
+ const char* match = strstr(disp.queryString.extensions, ext.string());
+ if (match && (match[len] == ' ' || match[len] == 0)) {
+ mExtensionString.append(start, len+1);
}
}
}
@@ -242,52 +230,12 @@
egl_cache_t::get()->initialize(this);
- EGLBoolean res = EGL_FALSE;
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
- EGLint n;
- if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) {
- disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n);
- if (disp[i].config) {
- if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n,
- &disp[i].numConfigs)) {
- numTotalConfigs += n;
- res = EGL_TRUE;
- }
- }
- }
- }
- }
-
- if (res == EGL_TRUE) {
- configs = new egl_config_t[numTotalConfigs];
- for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
- for (int j = 0; j < disp[i].numConfigs; j++) {
- configs[k].impl = i;
- configs[k].config = disp[i].config[j];
- configs[k].configId = k + 1; // CONFIG_ID start at 1
- // store the implementation's CONFIG_ID
- cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j],
- EGL_CONFIG_ID, &configs[k].implConfigId);
- k++;
- }
- }
- }
-
- // sort our configurations so we can do binary-searches
- qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs);
-
- refs++;
- if (major != NULL)
- *major = VERSION_MAJOR;
- if (minor != NULL)
- *minor = VERSION_MINOR;
- return EGL_TRUE;
- }
- return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ refs++;
+ if (major != NULL)
+ *major = VERSION_MAJOR;
+ if (minor != NULL)
+ *minor = VERSION_MINOR;
+ return EGL_TRUE;
}
EGLBoolean egl_display_t::terminate() {
@@ -305,22 +253,15 @@
}
EGLBoolean res = EGL_FALSE;
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) {
- if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) {
- ALOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy,
- egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
- }
- // REVISIT: it's unclear what to do if eglTerminate() fails
- free(disp[i].config);
-
- disp[i].numConfigs = 0;
- disp[i].config = 0;
- disp[i].state = egl_display_t::TERMINATED;
-
- res = EGL_TRUE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
+ if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
+ ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
+ egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
}
+ // REVISIT: it's unclear what to do if eglTerminate() fails
+ disp.state = egl_display_t::TERMINATED;
+ res = EGL_TRUE;
}
// Mark all objects remaining in the list as terminated, unless
@@ -337,8 +278,6 @@
objects.clear();
refs--;
- numTotalConfigs = 0;
- delete[] configs;
return res;
}
@@ -390,13 +329,13 @@
Mutex::Autolock _l(lock);
if (c) {
result = c->cnx->egl.eglMakeCurrent(
- disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ disp.dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
c->onMakeCurrent(draw, read);
}
} else {
result = cur_c->cnx->egl.eglMakeCurrent(
- disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ disp.dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
cur_c->onLooseCurrent();
}
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index f3c4ddf..6348228 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -44,23 +44,6 @@
// ----------------------------------------------------------------------------
-struct egl_config_t {
- egl_config_t() {}
- egl_config_t(int impl, EGLConfig config)
- : impl(impl), config(config), configId(0), implConfigId(0) { }
- int impl; // the implementation this config is for
- EGLConfig config; // the implementation's EGLConfig
- EGLint configId; // our CONFIG_ID
- EGLint implConfigId; // the implementation's CONFIG_ID
- inline bool operator < (const egl_config_t& rhs) const {
- if (impl < rhs.impl) return true;
- if (impl > rhs.impl) return false;
- return config < rhs.config;
- }
-};
-
-// ----------------------------------------------------------------------------
-
class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
static egl_display_t sDisplay[NUM_DISPLAYS];
EGLDisplay getDisplay(EGLNativeDisplayType display);
@@ -113,12 +96,9 @@
};
struct DisplayImpl {
- DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
- state(NOT_INITIALIZED), numConfigs(0) { }
+ DisplayImpl() : dpy(EGL_NO_DISPLAY), state(NOT_INITIALIZED) { }
EGLDisplay dpy;
- EGLConfig* config;
EGLint state;
- EGLint numConfigs;
strings_t queryString;
};
@@ -126,9 +106,7 @@
uint32_t magic;
public:
- DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
- EGLint numTotalConfigs;
- egl_config_t* configs;
+ DisplayImpl disp;
private:
uint32_t refs;
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index b660c53..d0cbb31 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -64,9 +64,9 @@
// ----------------------------------------------------------------------------
egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
- int impl, egl_connection_t const* cnx, int version) :
+ egl_connection_t const* cnx, int version) :
egl_object_t(get_display(dpy)), dpy(dpy), context(context),
- config(config), read(0), draw(0), impl(impl), cnx(cnx),
+ config(config), read(0), draw(0), cnx(cnx),
version(version)
{
}
@@ -87,7 +87,7 @@
if (gl_extensions.isEmpty()) {
// call the implementation's glGetString(GL_EXTENSIONS)
- const char* exts = (const char *)gEGLImpl[impl].hooks[version]->gl.glGetString(GL_EXTENSIONS);
+ const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
gl_extensions.setTo(exts);
if (gl_extensions.find("GL_EXT_debug_marker") < 0) {
String8 temp("GL_EXT_debug_marker ");
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index abd4cbb..f137bad 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -125,7 +125,7 @@
// ----------------------------------------------------------------------------
-class egl_surface_t: public egl_object_t {
+class egl_surface_t : public egl_object_t {
protected:
~egl_surface_t() {
ANativeWindow* const window = win.get();
@@ -140,15 +140,14 @@
typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
- EGLSurface surface, int impl, egl_connection_t const* cnx) :
+ EGLSurface surface, egl_connection_t const* cnx) :
egl_object_t(get_display(dpy)), dpy(dpy), surface(surface),
- config(config), win(win), impl(impl), cnx(cnx) {
+ config(config), win(win), cnx(cnx) {
}
EGLDisplay dpy;
EGLSurface surface;
EGLConfig config;
sp<ANativeWindow> win;
- int impl;
egl_connection_t const* cnx;
};
@@ -159,7 +158,7 @@
typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
- int impl, egl_connection_t const* cnx, int version);
+ egl_connection_t const* cnx, int version);
void onLooseCurrent();
void onMakeCurrent(EGLSurface draw, EGLSurface read);
@@ -169,7 +168,6 @@
EGLConfig config;
EGLSurface read;
EGLSurface draw;
- int impl;
egl_connection_t const* cnx;
int version;
String8 gl_extensions;
@@ -182,12 +180,11 @@
typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
egl_image_t(EGLDisplay dpy, EGLContext context) :
- egl_object_t(get_display(dpy)), dpy(dpy), context(context) {
- memset(images, 0, sizeof(images));
- }
+ egl_object_t(get_display(dpy)),
+ dpy(dpy), context(context), image(EGL_NO_IMAGE_KHR) { }
EGLDisplay dpy;
EGLContext context;
- EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
+ EGLImageKHR image;
};
class egl_sync_t: public egl_object_t {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index ff20957..c900c1c 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -19,31 +19,24 @@
#include "hooks.h"
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 4
-
// EGLDisplay are global, not attached to a given thread
const unsigned int NUM_DISPLAYS = 1;
-enum {
- IMPL_HARDWARE = 0,
- IMPL_SOFTWARE,
- IMPL_NUM_IMPLEMENTATIONS
-};
-
-enum {
- GLESv1_INDEX = 0,
- GLESv2_INDEX = 1,
-};
-
// ----------------------------------------------------------------------------
-struct egl_connection_t
-{
+struct egl_connection_t {
+ enum {
+ GLESv1_INDEX = 0,
+ GLESv2_INDEX = 1
+ };
+
inline egl_connection_t() : dso(0) { }
void * dso;
gl_hooks_t * hooks[2];
@@ -54,7 +47,7 @@
// ----------------------------------------------------------------------------
-extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+extern gl_hooks_t gHooks[2];
extern gl_hooks_t gHooksNoContext;
extern pthread_key_t gGLWrapperKey;
extern "C" void gl_unimplemented();
@@ -63,7 +56,7 @@
extern char const * const gl_names[];
extern char const * const egl_names[];
-extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
+extern egl_connection_t gEGLImpl;
// ----------------------------------------------------------------------------
}; // namespace android