• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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