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 26 namespace android { 27 28 static struct { 29 jfieldID mPtr; // native object attached to the DVM MessageQueue 30 } gMessageQueueClassInfo; 31 32 33 class NativeMessageQueue : public MessageQueue { 34 public: 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 44 private: 45 bool mInCallback; 46 jthrowable mExceptionObj; 47 }; 48 49 50 MessageQueue::MessageQueue() { 51 } 52 53 MessageQueue::~MessageQueue() { 54 } 55 56 bool 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 67 NativeMessageQueue::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 75 NativeMessageQueue::~NativeMessageQueue() { 76 } 77 78 void 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 95 void 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 106 void NativeMessageQueue::wake() { 107 mLooper->wake(); 108 } 109 110 // ---------------------------------------------------------------------------- 111 112 sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) { 113 jint intPtr = env->GetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr); 114 return reinterpret_cast<NativeMessageQueue*>(intPtr); 115 } 116 117 static jint 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<jint>(nativeMessageQueue); 126 } 127 128 static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jint ptr) { 129 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 130 nativeMessageQueue->decStrong(env); 131 } 132 133 static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz, 134 jint ptr, jint timeoutMillis) { 135 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 136 nativeMessageQueue->pollOnce(env, timeoutMillis); 137 } 138 139 static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jint ptr) { 140 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 141 return nativeMessageQueue->wake(); 142 } 143 144 static jboolean android_os_MessageQueue_nativeIsIdling(JNIEnv* env, jclass clazz, jint ptr) { 145 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 146 return nativeMessageQueue->getLooper()->isIdling(); 147 } 148 149 // ---------------------------------------------------------------------------- 150 151 static JNINativeMethod gMessageQueueMethods[] = { 152 /* name, signature, funcPtr */ 153 { "nativeInit", "()I", (void*)android_os_MessageQueue_nativeInit }, 154 { "nativeDestroy", "(I)V", (void*)android_os_MessageQueue_nativeDestroy }, 155 { "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce }, 156 { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake }, 157 { "nativeIsIdling", "(I)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 168 int 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", "I"); 178 179 return 0; 180 } 181 182 } // namespace android 183