diff options
| -rw-r--r-- | core/jni/android_app_NativeActivity.cpp | 40 | ||||
| -rw-r--r-- | core/jni/android_os_MessageQueue.cpp | 73 | ||||
| -rw-r--r-- | core/jni/android_os_MessageQueue.h | 45 | ||||
| -rw-r--r-- | core/jni/android_view_DisplayEventReceiver.cpp | 25 | ||||
| -rw-r--r-- | core/jni/android_view_InputEventReceiver.cpp | 40 | ||||
| -rw-r--r-- | services/jni/com_android_server_input_InputManagerService.cpp | 5 |
6 files changed, 146 insertions, 82 deletions
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index 655a8342e08a..19bc154aee1a 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -416,8 +416,8 @@ struct NativeCode : public ANativeActivity { if (env != NULL && clazz != NULL) { env->DeleteGlobalRef(clazz); } - if (looper != NULL && mainWorkRead >= 0) { - looper->removeFd(mainWorkRead); + if (messageQueue != NULL && mainWorkRead >= 0) { + messageQueue->getLooper()->removeFd(mainWorkRead); } if (nativeInputQueue != NULL) { nativeInputQueue->mWorkWrite = -1; @@ -481,7 +481,7 @@ struct NativeCode : public ANativeActivity { // These are used to wake up the main thread to process work. int mainWorkRead; int mainWorkWrite; - sp<Looper> looper; + sp<MessageQueue> messageQueue; }; void android_NativeActivity_finish(ANativeActivity* activity) { @@ -515,16 +515,6 @@ void android_NativeActivity_hideSoftInput( // ------------------------------------------------------------------------ -static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { - if (env->ExceptionCheck()) { - ALOGE("An exception was thrown by callback '%s'.", methodName); - LOGE_EX(env); - env->ExceptionClear(); - return true; - } - return false; -} - /* * Callback for handling native events on the application's main thread. */ @@ -551,7 +541,8 @@ static int mainWorkCallback(int fd, int events, void* data) { if (inputEventObj) { handled = code->env->CallBooleanMethod(code->clazz, gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj); - checkAndClearExceptionFromCallback(code->env, "dispatchUnhandledKeyEvent"); + code->messageQueue->raiseAndClearException( + code->env, "dispatchUnhandledKeyEvent"); code->env->DeleteLocalRef(inputEventObj); } else { ALOGE("Failed to obtain key event for dispatchUnhandledKeyEvent."); @@ -566,7 +557,7 @@ static int mainWorkCallback(int fd, int events, void* data) { if (inputEventObj) { code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq); - checkAndClearExceptionFromCallback(code->env, "preDispatchKeyEvent"); + code->messageQueue->raiseAndClearException(code->env, "preDispatchKeyEvent"); code->env->DeleteLocalRef(inputEventObj); } else { ALOGE("Failed to obtain key event for preDispatchKeyEvent."); @@ -575,27 +566,27 @@ static int mainWorkCallback(int fd, int events, void* data) { } break; case CMD_FINISH: { code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.finish); - checkAndClearExceptionFromCallback(code->env, "finish"); + code->messageQueue->raiseAndClearException(code->env, "finish"); } break; case CMD_SET_WINDOW_FORMAT: { code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.setWindowFormat, work.arg1); - checkAndClearExceptionFromCallback(code->env, "setWindowFormat"); + code->messageQueue->raiseAndClearException(code->env, "setWindowFormat"); } break; case CMD_SET_WINDOW_FLAGS: { code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2); - checkAndClearExceptionFromCallback(code->env, "setWindowFlags"); + code->messageQueue->raiseAndClearException(code->env, "setWindowFlags"); } break; case CMD_SHOW_SOFT_INPUT: { code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.showIme, work.arg1); - checkAndClearExceptionFromCallback(code->env, "showIme"); + code->messageQueue->raiseAndClearException(code->env, "showIme"); } break; case CMD_HIDE_SOFT_INPUT: { code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.hideIme, work.arg1); - checkAndClearExceptionFromCallback(code->env, "hideIme"); + code->messageQueue->raiseAndClearException(code->env, "hideIme"); } break; default: ALOGW("Unknown work command: %d", work.cmd); @@ -634,9 +625,9 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName return 0; } - code->looper = android_os_MessageQueue_getLooper(env, messageQueue); - if (code->looper == NULL) { - ALOGW("Unable to retrieve MessageQueue's Looper"); + code->messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueue); + if (code->messageQueue == NULL) { + ALOGW("Unable to retrieve native MessageQueue"); delete code; return 0; } @@ -655,7 +646,8 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK); SLOGW_IF(result != 0, "Could not make main work write pipe " "non-blocking: %s", strerror(errno)); - code->looper->addFd(code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code); + code->messageQueue->getLooper()->addFd( + code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code); code->ANativeActivity::callbacks = &code->callbacks; if (env->GetJavaVM(&code->vm) < 0) { diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp index 12a77d53db25..a4dcac6d886a 100644 --- a/core/jni/android_os_MessageQueue.cpp +++ b/core/jni/android_os_MessageQueue.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "MessageQueue-JNI" #include "JNIHelp.h" +#include <android_runtime/AndroidRuntime.h> #include <utils/Looper.h> #include <utils/Log.h> @@ -24,31 +25,46 @@ namespace android { -// ---------------------------------------------------------------------------- - static struct { jfieldID mPtr; // native object attached to the DVM MessageQueue } gMessageQueueClassInfo; -// ---------------------------------------------------------------------------- -class NativeMessageQueue { +class NativeMessageQueue : public MessageQueue { public: NativeMessageQueue(); - ~NativeMessageQueue(); + virtual ~NativeMessageQueue(); + + virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj); - inline sp<Looper> getLooper() { return mLooper; } + void pollOnce(JNIEnv* env, int timeoutMillis); - void pollOnce(int timeoutMillis); void wake(); private: - sp<Looper> mLooper; + bool mInCallback; + jthrowable mExceptionObj; }; -// ---------------------------------------------------------------------------- -NativeMessageQueue::NativeMessageQueue() { +MessageQueue::MessageQueue() { +} + +MessageQueue::~MessageQueue() { +} + +bool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) { + jthrowable exceptionObj = env->ExceptionOccurred(); + if (exceptionObj) { + env->ExceptionClear(); + raiseException(env, msg, exceptionObj); + env->DeleteLocalRef(exceptionObj); + return true; + } + return false; +} + +NativeMessageQueue::NativeMessageQueue() : mInCallback(false), mExceptionObj(NULL) { mLooper = Looper::getForThread(); if (mLooper == NULL) { mLooper = new Looper(false); @@ -59,8 +75,32 @@ NativeMessageQueue::NativeMessageQueue() { NativeMessageQueue::~NativeMessageQueue() { } -void NativeMessageQueue::pollOnce(int timeoutMillis) { +void NativeMessageQueue::raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) { + if (exceptionObj) { + if (mInCallback) { + if (mExceptionObj) { + env->DeleteLocalRef(mExceptionObj); + } + mExceptionObj = jthrowable(env->NewLocalRef(exceptionObj)); + ALOGE("Exception in MessageQueue callback: %s", msg); + jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj); + } else { + ALOGE("Exception: %s", msg); + jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj); + LOG_ALWAYS_FATAL("raiseException() was called when not in a callback, exiting."); + } + } +} + +void NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) { + mInCallback = true; mLooper->pollOnce(timeoutMillis); + mInCallback = false; + if (mExceptionObj) { + env->Throw(mExceptionObj); + env->DeleteLocalRef(mExceptionObj); + mExceptionObj = NULL; + } } void NativeMessageQueue::wake() { @@ -81,19 +121,20 @@ static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject m reinterpret_cast<jint>(nativeMessageQueue)); } -sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj) { +sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) { NativeMessageQueue* nativeMessageQueue = android_os_MessageQueue_getNativeMessageQueue(env, messageQueueObj); - return nativeMessageQueue != NULL ? nativeMessageQueue->getLooper() : NULL; + return nativeMessageQueue; } static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) { NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); - if (! nativeMessageQueue) { + if (!nativeMessageQueue) { jniThrowRuntimeException(env, "Unable to allocate native queue"); return; } + nativeMessageQueue->incStrong(env); android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue); } @@ -102,7 +143,7 @@ static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jobject obj) { android_os_MessageQueue_getNativeMessageQueue(env, obj); if (nativeMessageQueue) { android_os_MessageQueue_setNativeMessageQueue(env, obj, NULL); - delete nativeMessageQueue; + nativeMessageQueue->decStrong(env); } } @@ -113,7 +154,7 @@ static void throwQueueNotInitialized(JNIEnv* env) { static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jint ptr, jint timeoutMillis) { NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); - nativeMessageQueue->pollOnce(timeoutMillis); + nativeMessageQueue->pollOnce(env, timeoutMillis); } static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) { diff --git a/core/jni/android_os_MessageQueue.h b/core/jni/android_os_MessageQueue.h index f961d8f2f5da..49d2aa0c283d 100644 --- a/core/jni/android_os_MessageQueue.h +++ b/core/jni/android_os_MessageQueue.h @@ -18,12 +18,53 @@ #define _ANDROID_OS_MESSAGEQUEUE_H #include "jni.h" +#include <utils/Looper.h> namespace android { -class Looper; +class MessageQueue : public RefBase { +public: + /* Gets the message queue's looper. */ + inline sp<Looper> getLooper() const { + return mLooper; + } -extern sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj); + /* Checks whether the JNI environment has a pending exception. + * + * If an exception occurred, logs it together with the specified message, + * and calls raiseException() to ensure the exception will be raised when + * the callback returns, clears the pending exception from the environment, + * then returns true. + * + * If no exception occurred, returns false. + */ + bool raiseAndClearException(JNIEnv* env, const char* msg); + + /* Raises an exception from within a callback function. + * The exception will be rethrown when control returns to the message queue which + * will typically cause the application to crash. + * + * This message can only be called from within a callback function. If it is called + * at any other time, the process will simply be killed. + * + * Does nothing if exception is NULL. + * + * (This method does not take ownership of the exception object reference. + * The caller is responsible for releasing its reference when it is done.) + */ + virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) = 0; + +protected: + MessageQueue(); + virtual ~MessageQueue(); + +protected: + sp<Looper> mLooper; +}; + +/* Gets the native object associated with a MessageQueue. */ +extern sp<MessageQueue> android_os_MessageQueue_getMessageQueue( + JNIEnv* env, jobject messageQueueObj); } // namespace android diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 72c171cf229f..d80bfb339040 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -45,7 +45,7 @@ static struct { class NativeDisplayEventReceiver : public RefBase { public: NativeDisplayEventReceiver(JNIEnv* env, - jobject receiverObj, const sp<Looper>& looper); + jobject receiverObj, const sp<MessageQueue>& messageQueue); status_t initialize(); status_t scheduleVsync(); @@ -55,7 +55,7 @@ protected: private: jobject mReceiverObjGlobal; - sp<Looper> mLooper; + sp<MessageQueue> mMessageQueue; DisplayEventReceiver mReceiver; bool mWaitingForVsync; @@ -65,9 +65,9 @@ private: NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, - jobject receiverObj, const sp<Looper>& looper) : + jobject receiverObj, const sp<MessageQueue>& messageQueue) : mReceiverObjGlobal(env->NewGlobalRef(receiverObj)), - mLooper(looper), mWaitingForVsync(false) { + mMessageQueue(messageQueue), mWaitingForVsync(false) { ALOGV("receiver %p ~ Initializing input event receiver.", this); } @@ -75,7 +75,7 @@ NativeDisplayEventReceiver::~NativeDisplayEventReceiver() { ALOGV("receiver %p ~ Disposing display event receiver.", this); if (!mReceiver.initCheck()) { - mLooper->removeFd(mReceiver.getFd()); + mMessageQueue->getLooper()->removeFd(mReceiver.getFd()); } JNIEnv* env = AndroidRuntime::getJNIEnv(); @@ -89,7 +89,7 @@ status_t NativeDisplayEventReceiver::initialize() { return result; } - int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT, + int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); if (rc < 0) { return UNKNOWN_ERROR; @@ -151,12 +151,7 @@ int NativeDisplayEventReceiver::handleReceiveCallback(int receiveFd, int events, gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount); ALOGV("receiver %p ~ Returned from vsync handler.", data); - if (env->ExceptionCheck()) { - ALOGE("An exception occurred while dispatching a vsync event."); - LOGE_EX(env); - env->ExceptionClear(); - } - + r->mMessageQueue->raiseAndClearException(env, "dispatchVsync"); return 1; // keep the callback } @@ -183,14 +178,14 @@ bool NativeDisplayEventReceiver::readLastVsyncMessage( static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj, jobject messageQueueObj) { - sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj); - if (looper == NULL) { + sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); + if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env, - receiverObj, looper); + receiverObj, messageQueue); status_t status = receiver->initialize(); if (status) { String8 message; diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index e7d424472831..348437d0f34a 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -48,7 +48,7 @@ class NativeInputEventReceiver : public RefBase { public: NativeInputEventReceiver(JNIEnv* env, jobject receiverObj, const sp<InputChannel>& inputChannel, - const sp<Looper>& looper); + const sp<MessageQueue>& messageQueue); status_t initialize(); status_t finishInputEvent(uint32_t seq, bool handled); @@ -61,7 +61,7 @@ protected: private: jobject mReceiverObjGlobal; InputConsumer mInputConsumer; - sp<Looper> mLooper; + sp<MessageQueue> mMessageQueue; PreallocatedInputEventFactory mInputEventFactory; bool mBatchedInputEventPending; @@ -72,9 +72,10 @@ private: NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env, - jobject receiverObj, const sp<InputChannel>& inputChannel, const sp<Looper>& looper) : + jobject receiverObj, const sp<InputChannel>& inputChannel, + const sp<MessageQueue>& messageQueue) : mReceiverObjGlobal(env->NewGlobalRef(receiverObj)), - mInputConsumer(inputChannel), mLooper(looper), + mInputConsumer(inputChannel), mMessageQueue(messageQueue), mBatchedInputEventPending(false) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName()); @@ -86,7 +87,7 @@ NativeInputEventReceiver::~NativeInputEventReceiver() { ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName()); #endif - mLooper->removeFd(mInputConsumer.getChannel()->getFd()); + mMessageQueue->getLooper()->removeFd(mInputConsumer.getChannel()->getFd()); JNIEnv* env = AndroidRuntime::getJNIEnv(); env->DeleteGlobalRef(mReceiverObjGlobal); @@ -94,7 +95,8 @@ NativeInputEventReceiver::~NativeInputEventReceiver() { status_t NativeInputEventReceiver::initialize() { int receiveFd = mInputConsumer.getChannel()->getFd(); - mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); + mMessageQueue->getLooper()->addFd( + receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); return OK; } @@ -157,12 +159,8 @@ status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { #endif env->CallVoidMethod(mReceiverObjGlobal, gInputEventReceiverClassInfo.dispatchBatchedInputEventPending); - - if (env->ExceptionCheck()) { - ALOGE("channel '%s' ~ An exception occurred while dispatching that " - "batched input events are pending.", getInputChannelName()); - LOGE_EX(env); - env->ExceptionClear(); + if (mMessageQueue->raiseAndClearException( + env, "dispatchBatchedInputEventPending")) { mBatchedInputEventPending = false; // try again later } } @@ -182,6 +180,7 @@ status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { #endif inputEventObj = android_view_KeyEvent_fromNative(env, static_cast<KeyEvent*>(inputEvent)); + mMessageQueue->raiseAndClearException(env, "new KeyEvent"); break; case AINPUT_EVENT_TYPE_MOTION: @@ -190,6 +189,7 @@ status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { #endif inputEventObj = android_view_MotionEvent_obtainAsCopy(env, static_cast<MotionEvent*>(inputEvent)); + mMessageQueue->raiseAndClearException(env, "new MotionEvent"); break; default: @@ -200,7 +200,7 @@ status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { if (!inputEventObj) { ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName()); mInputConsumer.sendFinishedSignal(seq, false); - return NO_MEMORY; + continue; } #if DEBUG_DISPATCH_CYCLE @@ -211,14 +211,8 @@ status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { env->DeleteLocalRef(inputEventObj); - if (env->ExceptionCheck()) { - ALOGE("channel '%s' ~ An exception occurred while dispatching an event.", - getInputChannelName()); - LOGE_EX(env); - env->ExceptionClear(); - + if (mMessageQueue->raiseAndClearException(env, "dispatchInputEvent")) { mInputConsumer.sendFinishedSignal(seq, false); - return OK; } } } @@ -233,14 +227,14 @@ static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj, return 0; } - sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj); - if (looper == NULL) { + sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); + if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env, - receiverObj, inputChannel, looper); + receiverObj, inputChannel, messageQueue); status_t status = receiver->initialize(); if (status) { String8 message; diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp index c57402f0932c..75c20f3db5ab 100644 --- a/services/jni/com_android_server_input_InputManagerService.cpp +++ b/services/jni/com_android_server_input_InputManagerService.cpp @@ -950,8 +950,9 @@ void NativeInputManager::loadPointerResources(PointerResources* outResources) { static jint nativeInit(JNIEnv* env, jclass clazz, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { - sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj); - NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, looper); + sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); + NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, + messageQueue->getLooper()); im->incStrong(serviceObj); return reinterpret_cast<jint>(im); } |