android_os_MessageQueue.cpp revision 603b44589682db3ff33ade172facb0c5e309f1be
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 112static NativeMessageQueue* android_os_MessageQueue_getNativeMessageQueue(JNIEnv* env, 113 jobject messageQueueObj) { 114 jint intPtr = env->GetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr); 115 return reinterpret_cast<NativeMessageQueue*>(intPtr); 116} 117 118static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject messageQueueObj, 119 NativeMessageQueue* nativeMessageQueue) { 120 env->SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr, 121 reinterpret_cast<jint>(nativeMessageQueue)); 122} 123 124sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) { 125 NativeMessageQueue* nativeMessageQueue = 126 android_os_MessageQueue_getNativeMessageQueue(env, messageQueueObj); 127 return nativeMessageQueue; 128} 129 130static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) { 131 NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); 132 if (!nativeMessageQueue) { 133 jniThrowRuntimeException(env, "Unable to allocate native queue"); 134 return; 135 } 136 137 nativeMessageQueue->incStrong(env); 138 android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue); 139} 140 141static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jobject obj) { 142 NativeMessageQueue* nativeMessageQueue = 143 android_os_MessageQueue_getNativeMessageQueue(env, obj); 144 if (nativeMessageQueue) { 145 android_os_MessageQueue_setNativeMessageQueue(env, obj, NULL); 146 nativeMessageQueue->decStrong(env); 147 } 148} 149 150static void throwQueueNotInitialized(JNIEnv* env) { 151 jniThrowException(env, "java/lang/IllegalStateException", "Message queue not initialized"); 152} 153 154static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, 155 jint ptr, jint timeoutMillis) { 156 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 157 nativeMessageQueue->pollOnce(env, timeoutMillis); 158} 159 160static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) { 161 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 162 return nativeMessageQueue->wake(); 163} 164 165// ---------------------------------------------------------------------------- 166 167static JNINativeMethod gMessageQueueMethods[] = { 168 /* name, signature, funcPtr */ 169 { "nativeInit", "()V", (void*)android_os_MessageQueue_nativeInit }, 170 { "nativeDestroy", "()V", (void*)android_os_MessageQueue_nativeDestroy }, 171 { "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce }, 172 { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake } 173}; 174 175#define FIND_CLASS(var, className) \ 176 var = env->FindClass(className); \ 177 LOG_FATAL_IF(! var, "Unable to find class " className); 178 179#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 180 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 181 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 182 183int register_android_os_MessageQueue(JNIEnv* env) { 184 int res = jniRegisterNativeMethods(env, "android/os/MessageQueue", 185 gMessageQueueMethods, NELEM(gMessageQueueMethods)); 186 LOG_FATAL_IF(res < 0, "Unable to register native methods."); 187 188 jclass clazz; 189 FIND_CLASS(clazz, "android/os/MessageQueue"); 190 191 GET_FIELD_ID(gMessageQueueClassInfo.mPtr, clazz, 192 "mPtr", "I"); 193 194 return 0; 195} 196 197} // namespace android 198