Add new native Looper API.
This allows us to avoid exposing the file descriptor of the event queue; instead, you attach an event queue to a looper. This will also should allow native apps to be written without the need for a separate thread, by attaching the event queue to the main thread's looper and scheduling their own messages there. Change-Id: I38489282635895ae2cbfacb88599c1b1cad9b239
This commit is contained in:
parent
bf83375c73
commit
efa1085066
@ -33,6 +33,7 @@
|
||||
#include <semaphore.h>
|
||||
#include <ui/Input.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/PollLoop.h>
|
||||
#include <utils/Timers.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/String8.h>
|
||||
@ -345,11 +346,15 @@ public:
|
||||
|
||||
android::status_t consume(android::InputEvent** event);
|
||||
|
||||
void setPollLoop(const android::sp<android::PollLoop>& pollLoop) { mPollLoop = pollLoop; }
|
||||
const android::sp<android::PollLoop> getPollLoop() const { return mPollLoop; }
|
||||
|
||||
virtual void doDefaultKey(android::KeyEvent* keyEvent) = 0;
|
||||
|
||||
private:
|
||||
android::InputConsumer mConsumer;
|
||||
android::PreallocatedInputEventFactory mInputEventFactory;
|
||||
android::sp<android::PollLoop> mPollLoop;
|
||||
};
|
||||
|
||||
#endif // _UI_INPUT_TRANSPORT_H
|
||||
|
@ -22,12 +22,22 @@
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include <android/looper.h>
|
||||
|
||||
struct ALooper : public android::RefBase {
|
||||
protected:
|
||||
virtual ~ALooper() { }
|
||||
|
||||
public:
|
||||
ALooper() { }
|
||||
};
|
||||
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* A basic file descriptor polling loop based on poll() with callbacks.
|
||||
*/
|
||||
class PollLoop : public RefBase {
|
||||
class PollLoop : public ALooper {
|
||||
protected:
|
||||
virtual ~PollLoop();
|
||||
|
||||
@ -82,6 +92,11 @@ public:
|
||||
*/
|
||||
void setCallback(int fd, int events, Callback callback, void* data = NULL);
|
||||
|
||||
/**
|
||||
* Like setCallback(), but for the NDK callback function.
|
||||
*/
|
||||
void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback, void* data);
|
||||
|
||||
/**
|
||||
* Removes the callback for a file descriptor, if one exists.
|
||||
*
|
||||
@ -100,9 +115,22 @@ public:
|
||||
*/
|
||||
bool removeCallback(int fd);
|
||||
|
||||
/**
|
||||
* Set the given PollLoop to be associated with the
|
||||
* calling thread. There must be a 1:1 relationship between
|
||||
* PollLoop and thread.
|
||||
*/
|
||||
static void setForThread(const sp<PollLoop>& pollLoop);
|
||||
|
||||
/**
|
||||
* Return the PollLoop associated with the calling thread.
|
||||
*/
|
||||
static sp<PollLoop> getForThread();
|
||||
|
||||
private:
|
||||
struct RequestedCallback {
|
||||
Callback callback;
|
||||
ALooper_callbackFunc* looperCallback;
|
||||
void* data;
|
||||
};
|
||||
|
||||
@ -110,6 +138,7 @@ private:
|
||||
int fd;
|
||||
int events;
|
||||
Callback callback;
|
||||
ALooper_callbackFunc* looperCallback;
|
||||
void* data;
|
||||
};
|
||||
|
||||
@ -130,8 +159,11 @@ private:
|
||||
void openWakePipe();
|
||||
void closeWakePipe();
|
||||
|
||||
void setCallbackCommon(int fd, int events, Callback callback,
|
||||
ALooper_callbackFunc* looperCallback, void* data);
|
||||
ssize_t getRequestIndexLocked(int fd);
|
||||
void wakeAndLock();
|
||||
static void threadDestructor(void *st);
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
@ -21,6 +21,10 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static bool gHaveTLS = false;
|
||||
static pthread_key_t gTLS = 0;
|
||||
|
||||
PollLoop::PollLoop() :
|
||||
mPolling(false), mWaiters(0) {
|
||||
openWakePipe();
|
||||
@ -30,6 +34,41 @@ PollLoop::~PollLoop() {
|
||||
closeWakePipe();
|
||||
}
|
||||
|
||||
void PollLoop::threadDestructor(void *st) {
|
||||
PollLoop* const self = static_cast<PollLoop*>(st);
|
||||
if (self != NULL) {
|
||||
self->decStrong((void*)threadDestructor);
|
||||
}
|
||||
}
|
||||
|
||||
void PollLoop::setForThread(const sp<PollLoop>& pollLoop) {
|
||||
sp<PollLoop> old = getForThread();
|
||||
|
||||
if (pollLoop != NULL) {
|
||||
pollLoop->incStrong((void*)threadDestructor);
|
||||
}
|
||||
|
||||
pthread_setspecific(gTLS, pollLoop.get());
|
||||
|
||||
if (old != NULL) {
|
||||
old->decStrong((void*)threadDestructor);
|
||||
}
|
||||
}
|
||||
|
||||
sp<PollLoop> PollLoop::getForThread() {
|
||||
if (!gHaveTLS) {
|
||||
pthread_mutex_lock(&gTLSMutex);
|
||||
if (pthread_key_create(&gTLS, threadDestructor) != 0) {
|
||||
pthread_mutex_unlock(&gTLSMutex);
|
||||
return NULL;
|
||||
}
|
||||
gHaveTLS = true;
|
||||
pthread_mutex_unlock(&gTLSMutex);
|
||||
}
|
||||
|
||||
return (PollLoop*)pthread_getspecific(gTLS);
|
||||
}
|
||||
|
||||
void PollLoop::openWakePipe() {
|
||||
int wakeFds[2];
|
||||
int result = pipe(wakeFds);
|
||||
@ -54,6 +93,7 @@ void PollLoop::openWakePipe() {
|
||||
|
||||
RequestedCallback requestedCallback;
|
||||
requestedCallback.callback = NULL;
|
||||
requestedCallback.looperCallback = NULL;
|
||||
requestedCallback.data = NULL;
|
||||
mRequestedCallbacks.insertAt(requestedCallback, 0);
|
||||
}
|
||||
@ -123,12 +163,14 @@ bool PollLoop::pollOnce(int timeoutMillis) {
|
||||
if (revents) {
|
||||
const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
|
||||
Callback callback = requestedCallback.callback;
|
||||
ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback;
|
||||
|
||||
if (callback) {
|
||||
if (callback || looperCallback) {
|
||||
PendingCallback pendingCallback;
|
||||
pendingCallback.fd = requestedFd.fd;
|
||||
pendingCallback.events = requestedFd.revents;
|
||||
pendingCallback.callback = callback;
|
||||
pendingCallback.looperCallback = looperCallback;
|
||||
pendingCallback.data = requestedCallback.data;
|
||||
mPendingCallbacks.push(pendingCallback);
|
||||
} else {
|
||||
@ -172,8 +214,14 @@ Done:
|
||||
LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
|
||||
#endif
|
||||
|
||||
bool keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
|
||||
pendingCallback.data);
|
||||
bool keep = true;
|
||||
if (pendingCallback.callback != NULL) {
|
||||
keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
|
||||
pendingCallback.data);
|
||||
} else {
|
||||
keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
|
||||
pendingCallback.data) != 0;
|
||||
}
|
||||
if (! keep) {
|
||||
removeCallback(pendingCallback.fd);
|
||||
}
|
||||
@ -200,11 +248,22 @@ void PollLoop::wake() {
|
||||
}
|
||||
|
||||
void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
|
||||
setCallbackCommon(fd, events, callback, NULL, data);
|
||||
}
|
||||
|
||||
void PollLoop::setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
|
||||
void* data) {
|
||||
setCallbackCommon(fd, events, NULL, callback, data);
|
||||
}
|
||||
|
||||
void PollLoop::setCallbackCommon(int fd, int events, Callback callback,
|
||||
ALooper_callbackFunc* looperCallback, void* data) {
|
||||
|
||||
#if DEBUG_CALLBACKS
|
||||
LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
|
||||
#endif
|
||||
|
||||
if (! events || ! callback) {
|
||||
if (! events || (! callback && ! looperCallback)) {
|
||||
LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
|
||||
removeCallback(fd);
|
||||
return;
|
||||
@ -218,6 +277,7 @@ void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
|
||||
|
||||
RequestedCallback requestedCallback;
|
||||
requestedCallback.callback = callback;
|
||||
requestedCallback.looperCallback = looperCallback;
|
||||
requestedCallback.data = data;
|
||||
|
||||
ssize_t index = getRequestIndexLocked(fd);
|
||||
|
Loading…
Reference in New Issue
Block a user