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 Original line Diff line number Diff line
@@ -33,6 +33,7 @@
#include <semaphore.h>
#include <semaphore.h>
#include <ui/Input.h>
#include <ui/Input.h>
#include <utils/Errors.h>
#include <utils/Errors.h>
#include <utils/PollLoop.h>
#include <utils/Timers.h>
#include <utils/Timers.h>
#include <utils/RefBase.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/String8.h>
@@ -345,11 +346,15 @@ public:
    
    
    android::status_t consume(android::InputEvent** event);
    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;
    virtual void doDefaultKey(android::KeyEvent* keyEvent) = 0;
    
    
private:
private:
    android::InputConsumer mConsumer;
    android::InputConsumer mConsumer;
    android::PreallocatedInputEventFactory mInputEventFactory;
    android::PreallocatedInputEventFactory mInputEventFactory;
    android::sp<android::PollLoop> mPollLoop;
};
};


#endif // _UI_INPUT_TRANSPORT_H
#endif // _UI_INPUT_TRANSPORT_H
+33 −1
Original line number Original line Diff line number Diff line
@@ -22,12 +22,22 @@


#include <sys/poll.h>
#include <sys/poll.h>


#include <android/looper.h>

struct ALooper : public android::RefBase {
protected:
    virtual ~ALooper() { }

public:
    ALooper() { }
};

namespace android {
namespace android {


/**
/**
 * A basic file descriptor polling loop based on poll() with callbacks.
 * A basic file descriptor polling loop based on poll() with callbacks.
 */
 */
class PollLoop : public RefBase {
class PollLoop : public ALooper {
protected:
protected:
    virtual ~PollLoop();
    virtual ~PollLoop();


@@ -82,6 +92,11 @@ public:
     */
     */
    void setCallback(int fd, int events, Callback callback, void* data = NULL);
    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.
     * Removes the callback for a file descriptor, if one exists.
     *
     *
@@ -100,9 +115,22 @@ public:
     */
     */
    bool removeCallback(int fd);
    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:
private:
    struct RequestedCallback {
    struct RequestedCallback {
        Callback callback;
        Callback callback;
        ALooper_callbackFunc* looperCallback;
        void* data;
        void* data;
    };
    };


@@ -110,6 +138,7 @@ private:
        int fd;
        int fd;
        int events;
        int events;
        Callback callback;
        Callback callback;
        ALooper_callbackFunc* looperCallback;
        void* data;
        void* data;
    };
    };


@@ -130,8 +159,11 @@ private:
    void openWakePipe();
    void openWakePipe();
    void closeWakePipe();
    void closeWakePipe();


    void setCallbackCommon(int fd, int events, Callback callback,
            ALooper_callbackFunc* looperCallback, void* data);
    ssize_t getRequestIndexLocked(int fd);
    ssize_t getRequestIndexLocked(int fd);
    void wakeAndLock();
    void wakeAndLock();
    static void threadDestructor(void *st);
};
};


} // namespace android
} // namespace android
+64 −4
Original line number Original line Diff line number Diff line
@@ -21,6 +21,10 @@


namespace android {
namespace android {


static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static pthread_key_t gTLS = 0;

PollLoop::PollLoop() :
PollLoop::PollLoop() :
        mPolling(false), mWaiters(0) {
        mPolling(false), mWaiters(0) {
    openWakePipe();
    openWakePipe();
@@ -30,6 +34,41 @@ PollLoop::~PollLoop() {
    closeWakePipe();
    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() {
void PollLoop::openWakePipe() {
    int wakeFds[2];
    int wakeFds[2];
    int result = pipe(wakeFds);
    int result = pipe(wakeFds);
@@ -54,6 +93,7 @@ void PollLoop::openWakePipe() {


    RequestedCallback requestedCallback;
    RequestedCallback requestedCallback;
    requestedCallback.callback = NULL;
    requestedCallback.callback = NULL;
    requestedCallback.looperCallback = NULL;
    requestedCallback.data = NULL;
    requestedCallback.data = NULL;
    mRequestedCallbacks.insertAt(requestedCallback, 0);
    mRequestedCallbacks.insertAt(requestedCallback, 0);
}
}
@@ -123,12 +163,14 @@ bool PollLoop::pollOnce(int timeoutMillis) {
        if (revents) {
        if (revents) {
            const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
            const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
            Callback callback = requestedCallback.callback;
            Callback callback = requestedCallback.callback;
            ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback;


            if (callback) {
            if (callback || looperCallback) {
                PendingCallback pendingCallback;
                PendingCallback pendingCallback;
                pendingCallback.fd = requestedFd.fd;
                pendingCallback.fd = requestedFd.fd;
                pendingCallback.events = requestedFd.revents;
                pendingCallback.events = requestedFd.revents;
                pendingCallback.callback = callback;
                pendingCallback.callback = callback;
                pendingCallback.looperCallback = looperCallback;
                pendingCallback.data = requestedCallback.data;
                pendingCallback.data = requestedCallback.data;
                mPendingCallbacks.push(pendingCallback);
                mPendingCallbacks.push(pendingCallback);
            } else {
            } else {
@@ -172,8 +214,14 @@ Done:
            LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
            LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
#endif
#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);
                        pendingCallback.data);
            } else {
                keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
                        pendingCallback.data) != 0;
            }
            if (! keep) {
            if (! keep) {
                removeCallback(pendingCallback.fd);
                removeCallback(pendingCallback.fd);
            }
            }
@@ -200,11 +248,22 @@ void PollLoop::wake() {
}
}


void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
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
#if DEBUG_CALLBACKS
    LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
    LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
#endif
#endif


    if (! events || ! callback) {
    if (! events || (! callback && ! looperCallback)) {
        LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
        LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
        removeCallback(fd);
        removeCallback(fd);
        return;
        return;
@@ -218,6 +277,7 @@ void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {


    RequestedCallback requestedCallback;
    RequestedCallback requestedCallback;
    requestedCallback.callback = callback;
    requestedCallback.callback = callback;
    requestedCallback.looperCallback = looperCallback;
    requestedCallback.data = data;
    requestedCallback.data = data;


    ssize_t index = getRequestIndexLocked(fd);
    ssize_t index = getRequestIndexLocked(fd);