summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/jni/android_app_NativeActivity.cpp40
-rw-r--r--core/jni/android_os_MessageQueue.cpp73
-rw-r--r--core/jni/android_os_MessageQueue.h45
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp25
-rw-r--r--core/jni/android_view_InputEventReceiver.cpp40
-rw-r--r--services/jni/com_android_server_input_InputManagerService.cpp5
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);
}