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

Commit 68267415 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 8ecfb60a
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -6,7 +6,9 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Looper;
import android.os.MessageQueue;
import android.view.InputChannel;
@@ -33,7 +35,8 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
    
    private boolean mDestroyed;
    
    private native int loadNativeCode(String path, MessageQueue queue);
    private native int loadNativeCode(String path, MessageQueue queue,
            String internalDataPath, String externalDataPath, int sdkVersion);
    private native void unloadNativeCode(int handle);
    
    private native void onStartNative(int handle);
@@ -90,7 +93,11 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
            throw new IllegalArgumentException("Unable to find native library: " + libname);
        }
        
        mNativeHandle = loadNativeCode(path, Looper.myQueue());
        mNativeHandle = loadNativeCode(path, Looper.myQueue(),
                 getFilesDir().toString(),
                 Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(),
                 Build.VERSION.SDK_INT);
        
        if (mNativeHandle == 0) {
            throw new IllegalArgumentException("Unable to load native library: " + path);
        }
+20 −2
Original line number Diff line number Diff line
@@ -166,6 +166,9 @@ struct NativeCode {
    void* dlhandle;
    ANativeActivity_createFunc* createActivityFunc;
    
    String8 internalDataPath;
    String8 externalDataPath;
    
    sp<ANativeWindow> nativeWindow;
    jobject inputChannel;
    struct MyInputQueue* nativeInputQueue;
@@ -204,7 +207,8 @@ static bool mainWorkCallback(int fd, int events, void* data) {
// ------------------------------------------------------------------------

static jint
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue)
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue,
        jstring internalDataDir, jstring externalDataDir, int sdkVersion)
{
    const char* pathStr = env->GetStringUTFChars(path, NULL);
    NativeCode* code = NULL;
@@ -247,6 +251,19 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ
        }
        code->activity.env = env;
        code->activity.clazz = env->NewGlobalRef(clazz);
        
        const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
        code->internalDataPath = dirStr;
        code->activity.internalDataPath = code->internalDataPath.string();
        env->ReleaseStringUTFChars(path, dirStr);
    
        dirStr = env->GetStringUTFChars(externalDataDir, NULL);
        code->externalDataPath = dirStr;
        code->activity.externalDataPath = code->externalDataPath.string();
        env->ReleaseStringUTFChars(path, dirStr);
    
        code->activity.sdkVersion = sdkVersion;
        
        code->createActivityFunc(&code->activity, NULL, 0);
    }
    
@@ -420,7 +437,8 @@ onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject
}

static const JNINativeMethod g_methods[] = {
    { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;)I", (void*)loadNativeCode_native },
    { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;I)I",
            (void*)loadNativeCode_native },
    { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
    { "onStartNative", "(I)V", (void*)onStart_native },
    { "onResumeNative", "(I)V", (void*)onResume_native },
+5 −1
Original line number Diff line number Diff line
@@ -51,7 +51,11 @@ private:
// ----------------------------------------------------------------------------

NativeMessageQueue::NativeMessageQueue() {
    mPollLoop = PollLoop::getForThread();
    if (mPollLoop == NULL) {
        mPollLoop = new PollLoop();
        PollLoop::setForThread(mPollLoop);
    }
}

NativeMessageQueue::~NativeMessageQueue() {
+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
Loading