1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "MessageQueue-JNI" 18 19#include "JNIHelp.h" 20#include <android_runtime/AndroidRuntime.h> 21 22#include <utils/Looper.h> 23#include <utils/Log.h> 24#include "android_os_MessageQueue.h" 25 26namespace android { 27 28static struct { 29 jfieldID mPtr; // native object attached to the DVM MessageQueue 30} gMessageQueueClassInfo; 31 32 33class NativeMessageQueue : public MessageQueue { 34public: 35 NativeMessageQueue(); 36 virtual ~NativeMessageQueue(); 37 38 virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj); 39 40 void pollOnce(JNIEnv* env, int timeoutMillis); 41 42 void wake(); 43 44private: 45 bool mInCallback; 46 jthrowable mExceptionObj; 47}; 48 49 50MessageQueue::MessageQueue() { 51} 52 53MessageQueue::~MessageQueue() { 54} 55 56bool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) { 57 jthrowable exceptionObj = env->ExceptionOccurred(); 58 if (exceptionObj) { 59 env->ExceptionClear(); 60 raiseException(env, msg, exceptionObj); 61 env->DeleteLocalRef(exceptionObj); 62 return true; 63 } 64 return false; 65} 66 67NativeMessageQueue::NativeMessageQueue() : mInCallback(false), mExceptionObj(NULL) { 68 mLooper = Looper::getForThread(); 69 if (mLooper == NULL) { 70 mLooper = new Looper(false); 71 Looper::setForThread(mLooper); 72 } 73} 74 75NativeMessageQueue::~NativeMessageQueue() { 76} 77 78void NativeMessageQueue::raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) { 79 if (exceptionObj) { 80 if (mInCallback) { 81 if (mExceptionObj) { 82 env->DeleteLocalRef(mExceptionObj); 83 } 84 mExceptionObj = jthrowable(env->NewLocalRef(exceptionObj)); 85 ALOGE("Exception in MessageQueue callback: %s", msg); 86 jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj); 87 } else { 88 ALOGE("Exception: %s", msg); 89 jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj); 90 LOG_ALWAYS_FATAL("raiseException() was called when not in a callback, exiting."); 91 } 92 } 93} 94 95void NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) { 96 mInCallback = true; 97 mLooper->pollOnce(timeoutMillis); 98 mInCallback = false; 99 if (mExceptionObj) { 100 env->Throw(mExceptionObj); 101 env->DeleteLocalRef(mExceptionObj); 102 mExceptionObj = NULL; 103 } 104} 105 106void NativeMessageQueue::wake() { 107 mLooper->wake(); 108} 109 110// ---------------------------------------------------------------------------- 111 112sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) { 113 jlong ptr = env->GetLongField(messageQueueObj, gMessageQueueClassInfo.mPtr); 114 return reinterpret_cast<NativeMessageQueue*>(ptr); 115} 116 117static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) { 118 NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); 119 if (!nativeMessageQueue) { 120 jniThrowRuntimeException(env, "Unable to allocate native queue"); 121 return 0; 122 } 123 124 nativeMessageQueue->incStrong(env); 125 return reinterpret_cast<jlong>(nativeMessageQueue); 126} 127 128static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { 129 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 130 nativeMessageQueue->decStrong(env); 131} 132 133static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz, 134 jlong ptr, jint timeoutMillis) { 135 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 136 nativeMessageQueue->pollOnce(env, timeoutMillis); 137} 138 139static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) { 140 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 141 return nativeMessageQueue->wake(); 142} 143 144static jboolean android_os_MessageQueue_nativeIsIdling(JNIEnv* env, jclass clazz, jlong ptr) { 145 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 146 return nativeMessageQueue->getLooper()->isIdling(); 147} 148 149// ---------------------------------------------------------------------------- 150 151static JNINativeMethod gMessageQueueMethods[] = { 152 /* name, signature, funcPtr */ 153 { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit }, 154 { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy }, 155 { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce }, 156 { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake }, 157 { "nativeIsIdling", "(J)Z", (void*)android_os_MessageQueue_nativeIsIdling } 158}; 159 160#define FIND_CLASS(var, className) \ 161 var = env->FindClass(className); \ 162 LOG_FATAL_IF(! var, "Unable to find class " className); 163 164#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 165 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 166 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 167 168int register_android_os_MessageQueue(JNIEnv* env) { 169 int res = jniRegisterNativeMethods(env, "android/os/MessageQueue", 170 gMessageQueueMethods, NELEM(gMessageQueueMethods)); 171 LOG_FATAL_IF(res < 0, "Unable to register native methods."); 172 173 jclass clazz; 174 FIND_CLASS(clazz, "android/os/MessageQueue"); 175 176 GET_FIELD_ID(gMessageQueueClassInfo.mPtr, clazz, 177 "mPtr", "J"); 178 179 return 0; 180} 181 182} // namespace android 183