Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2011 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 "DisplayEventReceiver"
     18 
     19 //#define LOG_NDEBUG 0
     20 
     21 #include "JNIHelp.h"
     22 
     23 #include <inttypes.h>
     24 
     25 #include <android_runtime/AndroidRuntime.h>
     26 #include <androidfw/DisplayEventDispatcher.h>
     27 #include <utils/Log.h>
     28 #include <utils/Looper.h>
     29 #include <utils/threads.h>
     30 #include <gui/DisplayEventReceiver.h>
     31 #include "android_os_MessageQueue.h"
     32 
     33 #include <ScopedLocalRef.h>
     34 
     35 #include "core_jni_helpers.h"
     36 
     37 namespace android {
     38 
     39 // Number of events to read at a time from the DisplayEventReceiver pipe.
     40 // The value should be large enough that we can quickly drain the pipe
     41 // using just a few large reads.
     42 static const size_t EVENT_BUFFER_SIZE = 100;
     43 
     44 static struct {
     45     jclass clazz;
     46 
     47     jmethodID dispatchVsync;
     48     jmethodID dispatchHotplug;
     49 } gDisplayEventReceiverClassInfo;
     50 
     51 
     52 class NativeDisplayEventReceiver : public DisplayEventDispatcher {
     53 public:
     54     NativeDisplayEventReceiver(JNIEnv* env,
     55             jobject receiverWeak, const sp<MessageQueue>& messageQueue);
     56 
     57     void dispose();
     58 
     59 protected:
     60     virtual ~NativeDisplayEventReceiver();
     61 
     62 private:
     63     jobject mReceiverWeakGlobal;
     64     sp<MessageQueue> mMessageQueue;
     65     DisplayEventReceiver mReceiver;
     66     bool mWaitingForVsync;
     67 
     68     virtual void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
     69     virtual void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
     70 };
     71 
     72 
     73 NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
     74         jobject receiverWeak, const sp<MessageQueue>& messageQueue) :
     75         DisplayEventDispatcher(messageQueue->getLooper()),
     76         mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
     77         mMessageQueue(messageQueue), mWaitingForVsync(false) {
     78     ALOGV("receiver %p ~ Initializing display event receiver.", this);
     79 }
     80 
     81 NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
     82     JNIEnv* env = AndroidRuntime::getJNIEnv();
     83     env->DeleteGlobalRef(mReceiverWeakGlobal);
     84     ALOGV("receiver %p ~ dtor display event receiver.", this);
     85 }
     86 
     87 void NativeDisplayEventReceiver::dispose() {
     88     ALOGV("receiver %p ~ Disposing display event receiver.", this);
     89     DisplayEventDispatcher::dispose();
     90 }
     91 
     92 void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
     93     JNIEnv* env = AndroidRuntime::getJNIEnv();
     94 
     95     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
     96     if (receiverObj.get()) {
     97         ALOGV("receiver %p ~ Invoking vsync handler.", this);
     98         env->CallVoidMethod(receiverObj.get(),
     99                 gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
    100         ALOGV("receiver %p ~ Returned from vsync handler.", this);
    101     }
    102 
    103     mMessageQueue->raiseAndClearException(env, "dispatchVsync");
    104 }
    105 
    106 void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
    107     JNIEnv* env = AndroidRuntime::getJNIEnv();
    108 
    109     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
    110     if (receiverObj.get()) {
    111         ALOGV("receiver %p ~ Invoking hotplug handler.", this);
    112         env->CallVoidMethod(receiverObj.get(),
    113                 gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
    114         ALOGV("receiver %p ~ Returned from hotplug handler.", this);
    115     }
    116 
    117     mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
    118 }
    119 
    120 
    121 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
    122         jobject messageQueueObj) {
    123     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    124     if (messageQueue == NULL) {
    125         jniThrowRuntimeException(env, "MessageQueue is not initialized.");
    126         return 0;
    127     }
    128 
    129     sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
    130             receiverWeak, messageQueue);
    131     status_t status = receiver->initialize();
    132     if (status) {
    133         String8 message;
    134         message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
    135         jniThrowRuntimeException(env, message.string());
    136         return 0;
    137     }
    138 
    139     receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
    140     return reinterpret_cast<jlong>(receiver.get());
    141 }
    142 
    143 static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    144     NativeDisplayEventReceiver* receiver =
    145             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
    146     receiver->dispose();
    147     receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
    148 }
    149 
    150 static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    151     sp<NativeDisplayEventReceiver> receiver =
    152             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
    153     status_t status = receiver->scheduleVsync();
    154     if (status) {
    155         String8 message;
    156         message.appendFormat("Failed to schedule next vertical sync pulse.  status=%d", status);
    157         jniThrowRuntimeException(env, message.string());
    158     }
    159 }
    160 
    161 
    162 static const JNINativeMethod gMethods[] = {
    163     /* name, signature, funcPtr */
    164     { "nativeInit",
    165             "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J",
    166             (void*)nativeInit },
    167     { "nativeDispose",
    168             "(J)V",
    169             (void*)nativeDispose },
    170     { "nativeScheduleVsync", "!(J)V",
    171             (void*)nativeScheduleVsync }
    172 };
    173 
    174 int register_android_view_DisplayEventReceiver(JNIEnv* env) {
    175     int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods,
    176                                    NELEM(gMethods));
    177 
    178     jclass clazz = FindClassOrDie(env, "android/view/DisplayEventReceiver");
    179     gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
    180 
    181     gDisplayEventReceiverClassInfo.dispatchVsync = GetMethodIDOrDie(env,
    182             gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JII)V");
    183     gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
    184             gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JIZ)V");
    185 
    186     return res;
    187 }
    188 
    189 } // namespace android
    190