am 68267415: Add new native Looper API.

Merge commit '682674154e3fe88f6061245145f934f25f1a2eb8' into gingerbread-plus-aosp

* commit '682674154e3fe88f6061245145f934f25f1a2eb8':
  Add new native Looper API.
This commit is contained in:
Dianne Hackborn
2010-07-07 09:04:19 -07:00
committed by Android Git Automerger
12 changed files with 286 additions and 17 deletions

View File

@ -6,7 +6,9 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment;
import android.os.Looper; import android.os.Looper;
import android.os.MessageQueue; import android.os.MessageQueue;
import android.view.InputChannel; import android.view.InputChannel;
@ -33,7 +35,8 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
private boolean mDestroyed; 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 unloadNativeCode(int handle);
private native void onStartNative(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); 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) { if (mNativeHandle == 0) {
throw new IllegalArgumentException("Unable to load native library: " + path); throw new IllegalArgumentException("Unable to load native library: " + path);
} }

View File

@ -166,6 +166,9 @@ struct NativeCode {
void* dlhandle; void* dlhandle;
ANativeActivity_createFunc* createActivityFunc; ANativeActivity_createFunc* createActivityFunc;
String8 internalDataPath;
String8 externalDataPath;
sp<ANativeWindow> nativeWindow; sp<ANativeWindow> nativeWindow;
jobject inputChannel; jobject inputChannel;
struct MyInputQueue* nativeInputQueue; struct MyInputQueue* nativeInputQueue;
@ -204,7 +207,8 @@ static bool mainWorkCallback(int fd, int events, void* data) {
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static jint 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); const char* pathStr = env->GetStringUTFChars(path, NULL);
NativeCode* code = NULL; NativeCode* code = NULL;
@ -247,6 +251,19 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ
} }
code->activity.env = env; code->activity.env = env;
code->activity.clazz = env->NewGlobalRef(clazz); 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); code->createActivityFunc(&code->activity, NULL, 0);
} }
@ -420,7 +437,8 @@ onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject
} }
static const JNINativeMethod g_methods[] = { 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 }, { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
{ "onStartNative", "(I)V", (void*)onStart_native }, { "onStartNative", "(I)V", (void*)onStart_native },
{ "onResumeNative", "(I)V", (void*)onResume_native }, { "onResumeNative", "(I)V", (void*)onResume_native },

View File

@ -51,7 +51,11 @@ private:
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
NativeMessageQueue::NativeMessageQueue() { NativeMessageQueue::NativeMessageQueue() {
mPollLoop = PollLoop::getForThread();
if (mPollLoop == NULL) {
mPollLoop = new PollLoop(); mPollLoop = new PollLoop();
PollLoop::setForThread(mPollLoop);
}
} }
NativeMessageQueue::~NativeMessageQueue() { NativeMessageQueue::~NativeMessageQueue() {

View File

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

View File

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

View File

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

View File

@ -8,6 +8,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES:= \
activity.cpp \ activity.cpp \
input.cpp \ input.cpp \
looper.cpp \
native_window.cpp native_window.cpp
LOCAL_SHARED_LIBRARIES := \ LOCAL_SHARED_LIBRARIES := \

View File

@ -20,6 +20,7 @@
#include <android/input.h> #include <android/input.h>
#include <ui/Input.h> #include <ui/Input.h>
#include <ui/InputTransport.h> #include <ui/InputTransport.h>
#include <utils/PollLoop.h>
#include <poll.h> #include <poll.h>
@ -184,8 +185,16 @@ float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_i
pointer_index, history_index); pointer_index, history_index);
} }
int AInputQueue_getFd(AInputQueue* queue) { void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
return queue->getConsumer().getChannel()->getReceivePipeFd(); ALooper_callbackFunc callback, void* data) {
queue->setPollLoop(static_cast<android::PollLoop*>(looper));
ALooper_setCallback(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
POLLIN, callback, data);
}
void AInputQueue_detachLooper(AInputQueue* queue) {
queue->getPollLoop()->removeCallback(
queue->getConsumer().getChannel()->getReceivePipeFd());
} }
int AInputQueue_hasEvents(AInputQueue* queue) { int AInputQueue_hasEvents(AInputQueue* queue) {

63
native/android/looper.cpp Normal file
View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "ALooper"
#include <utils/Log.h>
#include <android/looper.h>
#include <utils/PollLoop.h>
using android::PollLoop;
using android::sp;
ALooper* ALooper_forThread() {
return PollLoop::getForThread().get();
}
ALooper* ALooper_prepare() {
sp<PollLoop> loop = PollLoop::getForThread();
if (loop == NULL) {
loop = new PollLoop();
PollLoop::setForThread(loop);
}
return loop.get();
}
int32_t ALooper_pollOnce(int timeoutMillis) {
sp<PollLoop> loop = PollLoop::getForThread();
if (loop == NULL) {
LOGW("ALooper_pollOnce: No looper for this thread!");
return -1;
}
return loop->pollOnce(timeoutMillis) ? 1 : 0;
}
void ALooper_acquire(ALooper* looper) {
static_cast<PollLoop*>(looper)->incStrong((void*)ALooper_acquire);
}
void ALooper_release(ALooper* looper) {
static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
}
void ALooper_setCallback(ALooper* looper, int fd, int events,
ALooper_callbackFunc* callback, void* data) {
static_cast<PollLoop*>(looper)->setLooperCallback(fd, events, callback, data);
}
int32_t ALooper_removeCallback(ALooper* looper, int fd) {
return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0;
}

View File

@ -42,6 +42,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <android/keycodes.h> #include <android/keycodes.h>
#include <android/looper.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -533,12 +534,15 @@ struct AInputQueue;
typedef struct AInputQueue AInputQueue; typedef struct AInputQueue AInputQueue;
/* /*
* Return a file descriptor for the queue, which you * Add this input queue to a looper for processing.
* can use to determine if there are events available. This
* is typically used with select() or poll() to multiplex
* with other kinds of events.
*/ */
int AInputQueue_getFd(AInputQueue* queue); void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
ALooper_callbackFunc callback, void* data);
/*
* Remove the input queue from the looper it is currently attached to.
*/
void AInputQueue_detachLooper(AInputQueue* queue);
/* /*
* Returns true if there are one or more events available in the * Returns true if there are one or more events available in the

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_LOOPER_H
#define ANDROID_LOOPER_H
#include <poll.h>
#ifdef __cplusplus
extern "C" {
#endif
struct ALooper;
typedef struct ALooper ALooper;
typedef int ALooper_callbackFunc(int fd, int events, void* data);
ALooper* ALooper_forThread();
ALooper* ALooper_prepare();
int32_t ALooper_pollOnce(int timeoutMillis);
void ALooper_acquire(ALooper* looper);
void ALooper_release(ALooper* looper);
void ALooper_setCallback(ALooper* looper, int fd, int events,
ALooper_callbackFunc* callback, void* data);
int32_t ALooper_removeCallback(ALooper* looper, int fd);
#ifdef __cplusplus
};
#endif
#endif // ANDROID_NATIVE_WINDOW_H

View File

@ -63,6 +63,21 @@ typedef struct ANativeActivity {
*/ */
jobject clazz; jobject clazz;
/**
* Path to this application's internal data directory.
*/
const char* internalDataPath;
/**
* Path to this application's external (removable/mountable) data directory.
*/
const char* externalDataPath;
/**
* The platform's SDK version code.
*/
int32_t sdkVersion;
/** /**
* This is the native instance of the application. It is not used by * This is the native instance of the application. It is not used by
* the framework, but can be set by the application to its own instance * the framework, but can be set by the application to its own instance