Code Offer

Code Is Poetry!

Free Code: Andriod – Process all display events in order

blob: 64fb27b3e18a4b4059bdf7ea4276279fba1825f4 [file history]
  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. #define LOG_TAG “DisplayEventReceiver”
  17. //#define LOG_NDEBUG 0
  18. #include “JNIHelp.h”
  19. #include <android_runtime/AndroidRuntime.h>
  20. #include <utils/Log.h>
  21. #include <utils/Looper.h>
  22. #include <utils/threads.h>
  23. #include <gui/DisplayEventReceiver.h>
  24. #include “android_os_MessageQueue.h”
  25. namespace android {
  26. // Number of events to read at a time from the DisplayEventReceiver pipe.
  27. // The value should be large enough that we can quickly drain the pipe
  28. // using just a few large reads.
  29. static const size_t EVENT_BUFFER_SIZE = 100;
  30. static struct {
  31.     jclass clazz;
  32.     jmethodID dispatchVsync;
  33.     jmethodID dispatchHotplug;
  34. } gDisplayEventReceiverClassInfo;
  35. class NativeDisplayEventReceiver : public LooperCallback {
  36. public:
  37.     NativeDisplayEventReceiver(JNIEnv* env,
  38.             jobject receiverObj, const sp<MessageQueue>& messageQueue);
  39.     status_t initialize();
  40.     void dispose();
  41.     status_t scheduleVsync();
  42. protected:
  43.     virtual ~NativeDisplayEventReceiver();
  44. private:
  45.     jobject mReceiverObjGlobal;
  46.     sp<MessageQueue> mMessageQueue;
  47.     DisplayEventReceiver mReceiver;
  48.     bool mWaitingForVsync;
  49.     virtual int handleEvent(int receiveFd, int events, void* data);
  50.     bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
  51.     void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
  52.     void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
  53. };
  54. NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
  55.         jobject receiverObj, const sp<MessageQueue>& messageQueue) :
  56.         mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
  57.         mMessageQueue(messageQueue), mWaitingForVsync(false) {
  58.     ALOGV(“receiver %p ~ Initializing input event receiver.”, this);
  59. }
  60. NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
  61.     JNIEnv* env = AndroidRuntime::getJNIEnv();
  62.     env->DeleteGlobalRef(mReceiverObjGlobal);
  63. }
  64. status_t NativeDisplayEventReceiver::initialize() {
  65.     status_t result = mReceiver.initCheck();
  66.     if (result) {
  67.         ALOGW(“Failed to initialize display event receiver, status=%d”, result);
  68.         return result;
  69.     }
  70.     int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
  71.             this, NULL);
  72.     if (rc < 0) {
  73.         return UNKNOWN_ERROR;
  74.     }
  75.     return OK;
  76. }
  77. void NativeDisplayEventReceiver::dispose() {
  78.     ALOGV(“receiver %p ~ Disposing display event receiver.”, this);
  79.     if (!mReceiver.initCheck()) {
  80.         mMessageQueue->getLooper()->removeFd(mReceiver.getFd());
  81.     }
  82. }
  83. status_t NativeDisplayEventReceiver::scheduleVsync() {
  84.     if (!mWaitingForVsync) {
  85.         ALOGV(“receiver %p ~ Scheduling vsync.”, this);
  86.         // Drain all pending events.
  87.         nsecs_t vsyncTimestamp;
  88.         int32_t vsyncDisplayId;
  89.         uint32_t vsyncCount;
  90.         processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
  91.         status_t status = mReceiver.requestNextVsync();
  92.         if (status) {
  93.             ALOGW(“Failed to request next vsync, status=%d”, status);
  94.             return status;
  95.         }
  96.         mWaitingForVsync = true;
  97.     }
  98.     return OK;
  99. }
  100. int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
  101.     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
  102.         ALOGE(“Display event receiver pipe was closed or an error occurred.  “
  103.                 “events=0x%x”, events);
  104.         return 0; // remove the callback
  105.     }
  106.     if (!(events & ALOOPER_EVENT_INPUT)) {
  107.         ALOGW(“Received spurious callback for unhandled poll event.  “
  108.                 “events=0x%x”, events);
  109.         return 1; // keep the callback
  110.     }
  111.     // Drain all pending events, keep the last vsync.
  112.     nsecs_t vsyncTimestamp;
  113.     int32_t vsyncDisplayId;
  114.     uint32_t vsyncCount;
  115.     if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
  116.         ALOGV(“receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d”,
  117.                 this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
  118.         mWaitingForVsync = false;
  119.         dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
  120.     }
  121.     return 1; // keep the callback
  122. }
  123. bool NativeDisplayEventReceiver::processPendingEvents(
  124.         nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
  125.     bool gotVsync = false;
  126.     DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
  127.     ssize_t n;
  128.     while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
  129.         ALOGV(“receiver %p ~ Read %d events.”, this, int(n));
  130.         for (ssize_t i = 0; i < n; i++) {
  131.             const DisplayEventReceiver::Event& ev = buf[i];
  132.             switch (ev.header.type) {
  133.             case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
  134.                 // Later vsync events will just overwrite the info from earlier
  135.                 // ones. That’s fine, we only care about the most recent.
  136.                 gotVsync = true;
  137.                 *outTimestamp = ev.header.timestamp;
  138.                 *outId = ev.header.id;
  139.                 *outCount = ev.vsync.count;
  140.                 break;
  141.             case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
  142.                 dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
  143.                 break;
  144.             default:
  145.                 ALOGW(“receiver %p ~ ignoring unknown event type %#x”, this, ev.header.type);
  146.                 break;
  147.             }
  148.         }
  149.     }
  150.     if (n < 0) {
  151.         ALOGW(“Failed to get events from display event receiver, status=%d”, status_t(n));
  152.     }
  153.     return gotVsync;
  154. }
  155. void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
  156.     JNIEnv* env = AndroidRuntime::getJNIEnv();
  157.     ALOGV(“receiver %p ~ Invoking vsync handler.”, this);
  158.     env->CallVoidMethod(mReceiverObjGlobal,
  159.             gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
  160.     ALOGV(“receiver %p ~ Returned from vsync handler.”, this);
  161.     mMessageQueue->raiseAndClearException(env, “dispatchVsync”);
  162. }
  163. void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
  164.     JNIEnv* env = AndroidRuntime::getJNIEnv();
  165.     ALOGV(“receiver %p ~ Invoking hotplug handler.”, this);
  166.     env->CallVoidMethod(mReceiverObjGlobal,
  167.             gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
  168.     ALOGV(“receiver %p ~ Returned from hotplug handler.”, this);
  169.     mMessageQueue->raiseAndClearException(env, “dispatchHotplug”);
  170. }
  171. static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
  172.         jobject messageQueueObj) {
  173.     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
  174.     if (messageQueue == NULL) {
  175.         jniThrowRuntimeException(env, “MessageQueue is not initialized.”);
  176.         return 0;
  177.     }
  178.     sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
  179.             receiverObj, messageQueue);
  180.     status_t status = receiver->initialize();
  181.     if (status) {
  182.         String8 message;
  183.         message.appendFormat(“Failed to initialize display event receiver.  status=%d”, status);
  184.         jniThrowRuntimeException(env, message.string());
  185.         return 0;
  186.     }
  187.     receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
  188.     return reinterpret_cast<jint>(receiver.get());
  189. }
  190. static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) {
  191.     sp<NativeDisplayEventReceiver> receiver =
  192.             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
  193.     receiver->dispose();
  194.     receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
  195. }
  196. static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jint receiverPtr) {
  197.     sp<NativeDisplayEventReceiver> receiver =
  198.             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
  199.     status_t status = receiver->scheduleVsync();
  200.     if (status) {
  201.         String8 message;
  202.         message.appendFormat(“Failed to schedule next vertical sync pulse.  status=%d”, status);
  203.         jniThrowRuntimeException(env, message.string());
  204.     }
  205. }
  206. static JNINativeMethod gMethods[] = {
  207.     /* name, signature, funcPtr */
  208.     { “nativeInit”,
  209.             “(Landroid/view/DisplayEventReceiver;Landroid/os/MessageQueue;)I”,
  210.             (void*)nativeInit },
  211.     { “nativeDispose”,
  212.             “(I)V”,
  213.             (void*)nativeDispose },
  214.     { “nativeScheduleVsync”, “(I)V”,
  215.             (void*)nativeScheduleVsync }
  216. };
  217. #define FIND_CLASS(var, className) \
  218.         var = env->FindClass(className); \
  219.         LOG_FATAL_IF(! var, “Unable to find class ” className); \
  220.         var = jclass(env->NewGlobalRef(var));
  221. #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
  222.         var = env->GetMethodID(clazz, methodName, methodDescriptor); \
  223.         LOG_FATAL_IF(! var, “Unable to find method ” methodName);
  224. int register_android_view_DisplayEventReceiver(JNIEnv* env) {
  225.     int res = jniRegisterNativeMethods(env, “android/view/DisplayEventReceiver”,
  226.             gMethods, NELEM(gMethods));
  227.     LOG_FATAL_IF(res < 0, “Unable to register native methods.”);
  228.     FIND_CLASS(gDisplayEventReceiverClassInfo.clazz, “android/view/DisplayEventReceiver”);
  229.     GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync,
  230.             gDisplayEventReceiverClassInfo.clazz,
  231.             “dispatchVsync”, “(JII)V”);
  232.     GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug,
  233.             gDisplayEventReceiverClassInfo.clazz,
  234.             “dispatchHotplug”, “(JIZ)V”);
  235.     return 0;
  236. }
  237. } // namespace android

Leave a comment

Information

This entry was posted on August 12, 2012 by .