Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efa10850 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

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
parent bf83375c
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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
+33 −1
Original line number Diff line number Diff line
@@ -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
+64 −4
Original line number Diff line number Diff line
@@ -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,
            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);