/* * 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 "MessageQueue-JNI" #include "JNIHelp.h" #include #include #include #include "android_os_MessageQueue.h" #include "core_jni_helpers.h" namespace android { static struct { jfieldID mPtr; // native object attached to the DVM MessageQueue } gMessageQueueClassInfo; class NativeMessageQueue : public MessageQueue { public: NativeMessageQueue(); virtual ~NativeMessageQueue(); virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj); void pollOnce(JNIEnv* env, int timeoutMillis); void wake(); private: bool mInCallback; jthrowable mExceptionObj; }; MessageQueue::MessageQueue() { } MessageQueue::~MessageQueue() { } bool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) { if (env->ExceptionCheck()) { jthrowable exceptionObj = env->ExceptionOccurred(); 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); Looper::setForThread(mLooper); } } NativeMessageQueue::~NativeMessageQueue() { } 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() { mLooper->wake(); } // ---------------------------------------------------------------------------- sp android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) { jlong ptr = env->GetLongField(messageQueueObj, gMessageQueueClassInfo.mPtr); return reinterpret_cast(ptr); } static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) { NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); if (!nativeMessageQueue) { jniThrowRuntimeException(env, "Unable to allocate native queue"); return 0; } nativeMessageQueue->incStrong(env); return reinterpret_cast(nativeMessageQueue); } static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr); nativeMessageQueue->decStrong(env); } static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz, jlong ptr, jint timeoutMillis) { NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr); nativeMessageQueue->pollOnce(env, timeoutMillis); } static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) { NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr); return nativeMessageQueue->wake(); } static jboolean android_os_MessageQueue_nativeIsIdling(JNIEnv* env, jclass clazz, jlong ptr) { NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr); return nativeMessageQueue->getLooper()->isIdling(); } // ---------------------------------------------------------------------------- static JNINativeMethod gMessageQueueMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit }, { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy }, { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce }, { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake }, { "nativeIsIdling", "(J)Z", (void*)android_os_MessageQueue_nativeIsIdling } }; int register_android_os_MessageQueue(JNIEnv* env) { int res = RegisterMethodsOrDie(env, "android/os/MessageQueue", gMessageQueueMethods, NELEM(gMessageQueueMethods)); jclass clazz = FindClassOrDie(env, "android/os/MessageQueue"); gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J"); return res; } } // namespace android