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