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:
Dianne Hackborn 2010-07-02 18:52:01 -07:00
parent bf83375c73
commit efa1085066
3 changed files with 102 additions and 5 deletions

View File

@ -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

View File

@ -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

View File

@ -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);