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:
@ -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);
|
||||
}
|
||||
|
@ -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 },
|
||||
|
@ -51,7 +51,11 @@ private:
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
NativeMessageQueue::NativeMessageQueue() {
|
||||
mPollLoop = PollLoop::getForThread();
|
||||
if (mPollLoop == NULL) {
|
||||
mPollLoop = new PollLoop();
|
||||
PollLoop::setForThread(mPollLoop);
|
||||
}
|
||||
}
|
||||
|
||||
NativeMessageQueue::~NativeMessageQueue() {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -8,6 +8,7 @@ include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES:= \
|
||||
activity.cpp \
|
||||
input.cpp \
|
||||
looper.cpp \
|
||||
native_window.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <android/input.h>
|
||||
#include <ui/Input.h>
|
||||
#include <ui/InputTransport.h>
|
||||
#include <utils/PollLoop.h>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
@ -184,8 +185,16 @@ float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_i
|
||||
pointer_index, history_index);
|
||||
}
|
||||
|
||||
int AInputQueue_getFd(AInputQueue* queue) {
|
||||
return queue->getConsumer().getChannel()->getReceivePipeFd();
|
||||
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
|
||||
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) {
|
||||
|
63
native/android/looper.cpp
Normal file
63
native/android/looper.cpp
Normal 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;
|
||||
}
|
@ -42,6 +42,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <android/keycodes.h>
|
||||
#include <android/looper.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -533,12 +534,15 @@ struct AInputQueue;
|
||||
typedef struct AInputQueue AInputQueue;
|
||||
|
||||
/*
|
||||
* Return a file descriptor for the queue, which you
|
||||
* can use to determine if there are events available. This
|
||||
* is typically used with select() or poll() to multiplex
|
||||
* with other kinds of events.
|
||||
* Add this input queue to a looper for processing.
|
||||
*/
|
||||
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
|
||||
|
51
native/include/android/looper.h
Normal file
51
native/include/android/looper.h
Normal 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
|
@ -63,6 +63,21 @@ typedef struct ANativeActivity {
|
||||
*/
|
||||
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
|
||||
* the framework, but can be set by the application to its own instance
|
||||
|
Reference in New Issue
Block a user