diff options
-rw-r--r-- | core/java/android/app/NativeActivity.java | 11 | ||||
-rw-r--r-- | core/jni/android_app_NativeActivity.cpp | 22 | ||||
-rw-r--r-- | core/jni/android_os_MessageQueue.cpp | 6 | ||||
-rw-r--r-- | include/ui/InputTransport.h | 5 | ||||
-rw-r--r-- | include/utils/PollLoop.h | 34 | ||||
-rw-r--r-- | libs/utils/PollLoop.cpp | 68 | ||||
-rw-r--r-- | native/android/Android.mk | 1 | ||||
-rw-r--r-- | native/android/input.cpp | 13 | ||||
-rw-r--r-- | native/android/looper.cpp | 63 | ||||
-rw-r--r-- | native/include/android/input.h | 14 | ||||
-rw-r--r-- | native/include/android/looper.h | 51 | ||||
-rw-r--r-- | native/include/android/native_activity.h | 15 |
12 files changed, 286 insertions, 17 deletions
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java index 161161c7d8fe..d72dda7842fe 100644 --- a/core/java/android/app/NativeActivity.java +++ b/core/java/android/app/NativeActivity.java @@ -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); } diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index dab1dba811cb..af61b805b794 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -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 }, diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp index 030d6c755143..961f806ea3f5 100644 --- a/core/jni/android_os_MessageQueue.cpp +++ b/core/jni/android_os_MessageQueue.cpp @@ -51,7 +51,11 @@ private: // ---------------------------------------------------------------------------- NativeMessageQueue::NativeMessageQueue() { - mPollLoop = new PollLoop(); + mPollLoop = PollLoop::getForThread(); + if (mPollLoop == NULL) { + mPollLoop = new PollLoop(); + PollLoop::setForThread(mPollLoop); + } } NativeMessageQueue::~NativeMessageQueue() { diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h index 2dfe2a866ef1..11714d536285 100644 --- a/include/ui/InputTransport.h +++ b/include/ui/InputTransport.h @@ -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 diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h index a95fb171cf56..b3651caeacb9 100644 --- a/include/utils/PollLoop.h +++ b/include/utils/PollLoop.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(); @@ -83,6 +93,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. * * When this method returns, it is safe to close the file descriptor since the poll loop @@ -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 diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp index 20a4d1385bd1..58fe1411d99a 100644 --- a/libs/utils/PollLoop.cpp +++ b/libs/utils/PollLoop.cpp @@ -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, - pendingCallback.data); + 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); diff --git a/native/android/Android.mk b/native/android/Android.mk index fe8ed0003a0a..376c64f2bf60 100644 --- a/native/android/Android.mk +++ b/native/android/Android.mk @@ -8,6 +8,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ activity.cpp \ input.cpp \ + looper.cpp \ native_window.cpp LOCAL_SHARED_LIBRARIES := \ diff --git a/native/android/input.cpp b/native/android/input.cpp index 84988403e301..015a1ced432b 100644 --- a/native/android/input.cpp +++ b/native/android/input.cpp @@ -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) { diff --git a/native/android/looper.cpp b/native/android/looper.cpp new file mode 100644 index 000000000000..6e78bbd03d12 --- /dev/null +++ b/native/android/looper.cpp @@ -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; +} diff --git a/native/include/android/input.h b/native/include/android/input.h index 76176624a9ae..75be85abb95c 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -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 diff --git a/native/include/android/looper.h b/native/include/android/looper.h new file mode 100644 index 000000000000..90a89838a57e --- /dev/null +++ b/native/include/android/looper.h @@ -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 diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h index bf5c641fc162..a31c5af74f08 100644 --- a/native/include/android/native_activity.h +++ b/native/include/android/native_activity.h @@ -64,6 +64,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 * state. |