Loading core/jni/android_app_NativeActivity.cpp +16 −24 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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. */ Loading @@ -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."); Loading @@ -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."); Loading @@ -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); Loading Loading @@ -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; } Loading @@ -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) { Loading core/jni/android_os_MessageQueue.cpp +57 −16 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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(); inline sp<Looper> getLooper() { return mLooper; } virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj); 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); Loading @@ -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() { Loading @@ -81,10 +121,10 @@ 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) { Loading @@ -94,6 +134,7 @@ static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) { return; } nativeMessageQueue->incStrong(env); android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue); } Loading @@ -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); } } Loading @@ -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) { Loading core/jni/android_os_MessageQueue.h +43 −2 Original line number Diff line number Diff line Loading @@ -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 Loading core/jni/android_view_DisplayEventReceiver.cpp +10 −15 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -55,7 +55,7 @@ protected: private: jobject mReceiverObjGlobal; sp<Looper> mLooper; sp<MessageQueue> mMessageQueue; DisplayEventReceiver mReceiver; bool mWaitingForVsync; Loading @@ -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); } Loading @@ -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(); Loading @@ -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; Loading Loading @@ -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 } Loading @@ -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; Loading core/jni/android_view_InputEventReceiver.cpp +17 −23 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -61,7 +61,7 @@ protected: private: jobject mReceiverObjGlobal; InputConsumer mInputConsumer; sp<Looper> mLooper; sp<MessageQueue> mMessageQueue; PreallocatedInputEventFactory mInputEventFactory; bool mBatchedInputEventPending; Loading @@ -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()); Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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 } } Loading @@ -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: Loading @@ -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: Loading @@ -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 Loading @@ -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; } } } Loading @@ -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; Loading Loading
core/jni/android_app_NativeActivity.cpp +16 −24 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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. */ Loading @@ -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."); Loading @@ -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."); Loading @@ -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); Loading Loading @@ -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; } Loading @@ -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) { Loading
core/jni/android_os_MessageQueue.cpp +57 −16 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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(); inline sp<Looper> getLooper() { return mLooper; } virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj); 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); Loading @@ -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() { Loading @@ -81,10 +121,10 @@ 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) { Loading @@ -94,6 +134,7 @@ static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) { return; } nativeMessageQueue->incStrong(env); android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue); } Loading @@ -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); } } Loading @@ -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) { Loading
core/jni/android_os_MessageQueue.h +43 −2 Original line number Diff line number Diff line Loading @@ -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 Loading
core/jni/android_view_DisplayEventReceiver.cpp +10 −15 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -55,7 +55,7 @@ protected: private: jobject mReceiverObjGlobal; sp<Looper> mLooper; sp<MessageQueue> mMessageQueue; DisplayEventReceiver mReceiver; bool mWaitingForVsync; Loading @@ -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); } Loading @@ -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(); Loading @@ -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; Loading Loading @@ -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 } Loading @@ -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; Loading
core/jni/android_view_InputEventReceiver.cpp +17 −23 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -61,7 +61,7 @@ protected: private: jobject mReceiverObjGlobal; InputConsumer mInputConsumer; sp<Looper> mLooper; sp<MessageQueue> mMessageQueue; PreallocatedInputEventFactory mInputEventFactory; bool mBatchedInputEventPending; Loading @@ -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()); Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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 } } Loading @@ -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: Loading @@ -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: Loading @@ -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 Loading @@ -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; } } } Loading @@ -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; Loading