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 #include "core_jni_helpers.h" 27 28 namespace android { 29 30 static struct { 31 jfieldID mPtr; // native object attached to the DVM MessageQueue 32 jmethodID dispatchEvents; 33 } gMessageQueueClassInfo; 34 35 // Must be kept in sync with the constants in Looper.FileDescriptorCallback 36 static const int CALLBACK_EVENT_INPUT = 1 << 0; 37 static const int CALLBACK_EVENT_OUTPUT = 1 << 1; 38 static const int CALLBACK_EVENT_ERROR = 1 << 2; 39 40 41 class NativeMessageQueue : public MessageQueue, public LooperCallback { 42 public: 43 NativeMessageQueue(); 44 virtual ~NativeMessageQueue(); 45 46 virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj); 47 48 void pollOnce(JNIEnv* env, jobject obj, int timeoutMillis); 49 void wake(); 50 void setFileDescriptorEvents(int fd, int events); 51 52 virtual int handleEvent(int fd, int events, void* data); 53 54 private: 55 JNIEnv* mPollEnv; 56 jobject mPollObj; 57 jthrowable mExceptionObj; 58 }; 59 60 61 MessageQueue::MessageQueue() { 62 } 63 64 MessageQueue::~MessageQueue() { 65 } 66 67 bool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) { 68 if (env->ExceptionCheck()) { 69 jthrowable exceptionObj = env->ExceptionOccurred(); 70 env->ExceptionClear(); 71 raiseException(env, msg, exceptionObj); 72 env->DeleteLocalRef(exceptionObj); 73 return true; 74 } 75 return false; 76 } 77 78 NativeMessageQueue::NativeMessageQueue() : 79 mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) { 80 mLooper = Looper::getForThread(); 81 if (mLooper == NULL) { 82 mLooper = new Looper(false); 83 Looper::setForThread(mLooper); 84 } 85 } 86 87 NativeMessageQueue::~NativeMessageQueue() { 88 } 89 90 void NativeMessageQueue::raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) { 91 if (exceptionObj) { 92 if (mPollEnv == env) { 93 if (mExceptionObj) { 94 env->DeleteLocalRef(mExceptionObj); 95 } 96 mExceptionObj = jthrowable(env->NewLocalRef(exceptionObj)); 97 ALOGE("Exception in MessageQueue callback: %s", msg); 98 jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj); 99 } else { 100 ALOGE("Exception: %s", msg); 101 jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj); 102 LOG_ALWAYS_FATAL("raiseException() was called when not in a callback, exiting."); 103 } 104 } 105 } 106 107 void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) { 108 mPollEnv = env; 109 mPollObj = pollObj; 110 mLooper->pollOnce(timeoutMillis); 111 mPollObj = NULL; 112 mPollEnv = NULL; 113 114 if (mExceptionObj) { 115 env->Throw(mExceptionObj); 116 env->DeleteLocalRef(mExceptionObj); 117 mExceptionObj = NULL; 118 } 119 } 120 121 void NativeMessageQueue::wake() { 122 mLooper->wake(); 123 } 124 125 void NativeMessageQueue::setFileDescriptorEvents(int fd, int events) { 126 if (events) { 127 int looperEvents = 0; 128 if (events & CALLBACK_EVENT_INPUT) { 129 looperEvents |= Looper::EVENT_INPUT; 130 } 131 if (events & CALLBACK_EVENT_OUTPUT) { 132 looperEvents |= Looper::EVENT_OUTPUT; 133 } 134 mLooper->addFd(fd, Looper::POLL_CALLBACK, looperEvents, this, 135 reinterpret_cast<void*>(events)); 136 } else { 137 mLooper->removeFd(fd); 138 } 139 } 140 141 int NativeMessageQueue::handleEvent(int fd, int looperEvents, void* data) { 142 int events = 0; 143 if (looperEvents & Looper::EVENT_INPUT) { 144 events |= CALLBACK_EVENT_INPUT; 145 } 146 if (looperEvents & Looper::EVENT_OUTPUT) { 147 events |= CALLBACK_EVENT_OUTPUT; 148 } 149 if (looperEvents & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP | Looper::EVENT_INVALID)) { 150 events |= CALLBACK_EVENT_ERROR; 151 } 152 int oldWatchedEvents = reinterpret_cast<intptr_t>(data); 153 int newWatchedEvents = mPollEnv->CallIntMethod(mPollObj, 154 gMessageQueueClassInfo.dispatchEvents, fd, events); 155 if (!newWatchedEvents) { 156 return 0; // unregister the fd 157 } 158 if (newWatchedEvents != oldWatchedEvents) { 159 setFileDescriptorEvents(fd, newWatchedEvents); 160 } 161 return 1; 162 } 163 164 165 // ---------------------------------------------------------------------------- 166 167 sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) { 168 jlong ptr = env->GetLongField(messageQueueObj, gMessageQueueClassInfo.mPtr); 169 return reinterpret_cast<NativeMessageQueue*>(ptr); 170 } 171 172 static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) { 173 NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); 174 if (!nativeMessageQueue) { 175 jniThrowRuntimeException(env, "Unable to allocate native queue"); 176 return 0; 177 } 178 179 nativeMessageQueue->incStrong(env); 180 return reinterpret_cast<jlong>(nativeMessageQueue); 181 } 182 183 static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { 184 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 185 nativeMessageQueue->decStrong(env); 186 } 187 188 static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, 189 jlong ptr, jint timeoutMillis) { 190 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 191 nativeMessageQueue->pollOnce(env, obj, timeoutMillis); 192 } 193 194 static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) { 195 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 196 nativeMessageQueue->wake(); 197 } 198 199 static jboolean android_os_MessageQueue_nativeIsPolling(JNIEnv* env, jclass clazz, jlong ptr) { 200 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 201 return nativeMessageQueue->getLooper()->isPolling(); 202 } 203 204 static void android_os_MessageQueue_nativeSetFileDescriptorEvents(JNIEnv* env, jclass clazz, 205 jlong ptr, jint fd, jint events) { 206 NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr); 207 nativeMessageQueue->setFileDescriptorEvents(fd, events); 208 } 209 210 // ---------------------------------------------------------------------------- 211 212 static const JNINativeMethod gMessageQueueMethods[] = { 213 /* name, signature, funcPtr */ 214 { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit }, 215 { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy }, 216 { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce }, 217 { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake }, 218 { "nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling }, 219 { "nativeSetFileDescriptorEvents", "(JII)V", 220 (void*)android_os_MessageQueue_nativeSetFileDescriptorEvents }, 221 }; 222 223 int register_android_os_MessageQueue(JNIEnv* env) { 224 int res = RegisterMethodsOrDie(env, "android/os/MessageQueue", gMessageQueueMethods, 225 NELEM(gMessageQueueMethods)); 226 227 jclass clazz = FindClassOrDie(env, "android/os/MessageQueue"); 228 gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J"); 229 gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(env, clazz, 230 "dispatchEvents", "(II)I"); 231 232 return res; 233 } 234 235 } // namespace android 236