android_os_MessageQueue.cpp revision 63a37153238d95cf8897939e6d6e8fbc56e9ec7f
1fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate/*
2fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * Copyright (C) 2010 The Android Open Source Project
3fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate *
4fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * Licensed under the Apache License, Version 2.0 (the "License");
5fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * you may not use this file except in compliance with the License.
6fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * You may obtain a copy of the License at
7fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate *
8fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate *      http://www.apache.org/licenses/LICENSE-2.0
9fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate *
10fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * Unless required by applicable law or agreed to in writing, software
11fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * distributed under the License is distributed on an "AS IS" BASIS,
12fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * See the License for the specific language governing permissions and
14fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate * limitations under the License.
15fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate */
16fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
1746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define LOG_TAG "MessageQueue-JNI"
18fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
19fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate#include "JNIHelp.h"
20603b44589682db3ff33ade172facb0c5e309f1beJeff Brown#include <android_runtime/AndroidRuntime.h>
21fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
224fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown#include <utils/Looper.h>
23fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate#include <utils/Log.h>
2446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include "android_os_MessageQueue.h"
25fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
2646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownnamespace android {
27fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
28fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tatestatic struct {
2946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    jfieldID mPtr;   // native object attached to the DVM MessageQueue
3046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown} gMessageQueueClassInfo;
31fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
32fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
33603b44589682db3ff33ade172facb0c5e309f1beJeff Brownclass NativeMessageQueue : public MessageQueue {
34fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tatepublic:
3546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    NativeMessageQueue();
36603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    virtual ~NativeMessageQueue();
37603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
38603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
39fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
40603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    void pollOnce(JNIEnv* env, int timeoutMillis);
41fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
4246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    void wake();
43fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
44fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tateprivate:
45603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    bool mInCallback;
46603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    jthrowable mExceptionObj;
47fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate};
48fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
49fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
50603b44589682db3ff33ade172facb0c5e309f1beJeff BrownMessageQueue::MessageQueue() {
51603b44589682db3ff33ade172facb0c5e309f1beJeff Brown}
52603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
53603b44589682db3ff33ade172facb0c5e309f1beJeff BrownMessageQueue::~MessageQueue() {
54603b44589682db3ff33ade172facb0c5e309f1beJeff Brown}
55603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
56603b44589682db3ff33ade172facb0c5e309f1beJeff Brownbool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) {
57603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    jthrowable exceptionObj = env->ExceptionOccurred();
58603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (exceptionObj) {
59603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        env->ExceptionClear();
60603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        raiseException(env, msg, exceptionObj);
61603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        env->DeleteLocalRef(exceptionObj);
62603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        return true;
63603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    }
64603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    return false;
65603b44589682db3ff33ade172facb0c5e309f1beJeff Brown}
66603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
67603b44589682db3ff33ade172facb0c5e309f1beJeff BrownNativeMessageQueue::NativeMessageQueue() : mInCallback(false), mExceptionObj(NULL) {
684fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown    mLooper = Looper::getForThread();
694fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown    if (mLooper == NULL) {
704fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown        mLooper = new Looper(false);
714fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown        Looper::setForThread(mLooper);
72682674154e3fe88f6061245145f934f25f1a2eb8Dianne Hackborn    }
73fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
74fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
7546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff BrownNativeMessageQueue::~NativeMessageQueue() {
76fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
77fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
78603b44589682db3ff33ade172facb0c5e309f1beJeff Brownvoid NativeMessageQueue::raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) {
79603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (exceptionObj) {
80603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        if (mInCallback) {
81603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            if (mExceptionObj) {
82603b44589682db3ff33ade172facb0c5e309f1beJeff Brown                env->DeleteLocalRef(mExceptionObj);
83603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            }
84603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            mExceptionObj = jthrowable(env->NewLocalRef(exceptionObj));
85603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            ALOGE("Exception in MessageQueue callback: %s", msg);
86603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
87603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        } else {
88603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            ALOGE("Exception: %s", msg);
89603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
90603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            LOG_ALWAYS_FATAL("raiseException() was called when not in a callback, exiting.");
91603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        }
92603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    }
93603b44589682db3ff33ade172facb0c5e309f1beJeff Brown}
94603b44589682db3ff33ade172facb0c5e309f1beJeff Brown
95603b44589682db3ff33ade172facb0c5e309f1beJeff Brownvoid NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) {
96603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    mInCallback = true;
97415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    mLooper->pollOnce(timeoutMillis);
98603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    mInCallback = false;
99603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (mExceptionObj) {
100603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        env->Throw(mExceptionObj);
101603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        env->DeleteLocalRef(mExceptionObj);
102603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        mExceptionObj = NULL;
103603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    }
104fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
105fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
10646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownvoid NativeMessageQueue::wake() {
1074fe6c3e51be77e35f40872cdbca6c80f8f8b7ecbJeff Brown    mLooper->wake();
108fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
109fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
11046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown// ----------------------------------------------------------------------------
111fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
112864693461b6223a995038847591b17abe2de647eJeff Brownsp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) {
11363a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat    jlong ptr = env->GetLongField(messageQueueObj, gMessageQueueClassInfo.mPtr);
11463a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat    return reinterpret_cast<NativeMessageQueue*>(ptr);
115fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
116fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
11763a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhatstatic jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
11846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
119603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (!nativeMessageQueue) {
12046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        jniThrowRuntimeException(env, "Unable to allocate native queue");
121864693461b6223a995038847591b17abe2de647eJeff Brown        return 0;
122fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate    }
123fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
124603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    nativeMessageQueue->incStrong(env);
12563a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat    return reinterpret_cast<jlong>(nativeMessageQueue);
126fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
127fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
12863a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhatstatic void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
129864693461b6223a995038847591b17abe2de647eJeff Brown    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
130864693461b6223a995038847591b17abe2de647eJeff Brown    nativeMessageQueue->decStrong(env);
131fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
132fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
133864693461b6223a995038847591b17abe2de647eJeff Brownstatic void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz,
13463a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat        jlong ptr, jint timeoutMillis) {
135415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
136603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    nativeMessageQueue->pollOnce(env, timeoutMillis);
137fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
138fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
13963a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhatstatic void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
140415d8c38199e258dfce92cdb0c69e056b3b51ef8Jeff Brown    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
14146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    return nativeMessageQueue->wake();
142fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
143fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
14463a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhatstatic jboolean android_os_MessageQueue_nativeIsIdling(JNIEnv* env, jclass clazz, jlong ptr) {
145efa92b2182ab581873aa8e75d596e2e363bd5e6dDianne Hackborn    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
146efa92b2182ab581873aa8e75d596e2e363bd5e6dDianne Hackborn    return nativeMessageQueue->getLooper()->isIdling();
147efa92b2182ab581873aa8e75d596e2e363bd5e6dDianne Hackborn}
148efa92b2182ab581873aa8e75d596e2e363bd5e6dDianne Hackborn
149fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate// ----------------------------------------------------------------------------
150fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
151fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tatestatic JNINativeMethod gMessageQueueMethods[] = {
152fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate    /* name, signature, funcPtr */
15363a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat    { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
15463a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat    { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
15563a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat    { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce },
15663a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat    { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake },
15763a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat    { "nativeIsIdling", "(J)Z", (void*)android_os_MessageQueue_nativeIsIdling }
158fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate};
159fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
16046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define FIND_CLASS(var, className) \
16146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = env->FindClass(className); \
16217cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro        LOG_FATAL_IF(! var, "Unable to find class " className);
16346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
16446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
16546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
16646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
16746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
168fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tateint register_android_os_MessageQueue(JNIEnv* env) {
16946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    int res = jniRegisterNativeMethods(env, "android/os/MessageQueue",
17046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown            gMessageQueueMethods, NELEM(gMessageQueueMethods));
17146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
17246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
17317cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    jclass clazz;
17417cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    FIND_CLASS(clazz, "android/os/MessageQueue");
175fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
17617cc33a35729733aaa0a7706f38b1c45f0b1590aCarl Shapiro    GET_FIELD_ID(gMessageQueueClassInfo.mPtr, clazz,
17763a37153238d95cf8897939e6d6e8fbc56e9ec7fAshok Bhat            "mPtr", "J");
178fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
17946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    return 0;
180fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate}
181fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate
18246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown} // namespace android
183