Loading core/java/android/view/Choreographer.java +18 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package android.view; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; import android.os.Handler; import android.os.Looper; Loading Loading @@ -685,7 +684,24 @@ public final class Choreographer { } @Override public void onVsync(long timestampNanos, int frame) { public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { // Ignore vsync from secondary display. // This can be problematic because the call to scheduleVsync() is a one-shot. // We need to ensure that we will still receive the vsync from the primary // display which is the one we really care about. Ideally we should schedule // vsync for a particular display. // At this time Surface Flinger won't send us vsyncs for secondary displays // but that could change in the future so let's log a message to help us remember // that we need to fix this. if (builtInDisplayId != Surface.BUILT_IN_DISPLAY_ID_MAIN) { Log.d(TAG, "Received vsync from secondary display, but we don't support " + "this case yet. Choreographer needs a way to explicitly request " + "vsync for a specific display to ensure it doesn't lose track " + "of its scheduled vsync."); scheduleVsync(); return; } // Post the vsync event to the Handler. // The idea is to prevent incoming vsync events from completely starving // the message queue. If there are no messages in the queue with timestamps Loading core/java/android/view/DisplayEventReceiver.java +23 −3 Original line number Diff line number Diff line Loading @@ -101,9 +101,23 @@ public abstract class DisplayEventReceiver { * * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()} * timebase. * @param builtInDisplayId The surface flinger built-in display id such as * {@link Surface#BUILT_IN_DISPLAY_ID_MAIN}. * @param frame The frame number. Increases by one for each vertical sync interval. */ public void onVsync(long timestampNanos, int frame) { public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { } /** * Called when a display hotplug event is received. * * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} * timebase. * @param builtInDisplayId The surface flinger built-in display id such as * {@link Surface#BUILT_IN_DISPLAY_ID_HDMI}. * @param connected True if the display is connected, false if it disconnected. */ public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { } /** Loading @@ -121,7 +135,13 @@ public abstract class DisplayEventReceiver { // Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, int frame) { onVsync(timestampNanos, frame); private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) { onVsync(timestampNanos, builtInDisplayId, frame); } // Called from native code. @SuppressWarnings("unused") private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { onHotplug(timestampNanos, builtInDisplayId, connected); } } core/jni/android_view_DisplayEventReceiver.cpp +47 −18 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ static struct { jclass clazz; jmethodID dispatchVsync; jmethodID dispatchHotplug; } gDisplayEventReceiverClassInfo; Loading @@ -61,7 +62,9 @@ private: bool mWaitingForVsync; virtual int handleEvent(int receiveFd, int events, void* data); bool readLastVsyncMessage(nsecs_t* outTimestamp, uint32_t* outCount); bool readLastVsyncMessage(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount); void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count); void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected); }; Loading Loading @@ -106,8 +109,9 @@ status_t NativeDisplayEventReceiver::scheduleVsync() { // Drain all pending events. nsecs_t vsyncTimestamp; int32_t vsyncDisplayId; uint32_t vsyncCount; readLastVsyncMessage(&vsyncTimestamp, &vsyncCount); readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount); status_t status = mReceiver.requestNextVsync(); if (status) { Loading Loading @@ -135,39 +139,39 @@ int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* dat // Drain all pending events, keep the last vsync. nsecs_t vsyncTimestamp; int32_t vsyncDisplayId; uint32_t vsyncCount; if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncCount)) { if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this); return 1; // keep the callback, did not obtain a vsync pulse } ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d", this, vsyncTimestamp, vsyncCount); ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d", this, vsyncTimestamp, vsyncDisplayId, vsyncCount); mWaitingForVsync = false; JNIEnv* env = AndroidRuntime::getJNIEnv(); ALOGV("receiver %p ~ Invoking vsync handler.", this); env->CallVoidMethod(mReceiverObjGlobal, gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount); ALOGV("receiver %p ~ Returned from vsync handler.", this); mMessageQueue->raiseAndClearException(env, "dispatchVsync"); dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount); return 1; // keep the callback } bool NativeDisplayEventReceiver::readLastVsyncMessage( nsecs_t* outTimestamp, uint32_t* outCount) { nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) { DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; ssize_t n; while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { ALOGV("receiver %p ~ Read %d events.", this, int(n)); while (n-- > 0) { if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { *outTimestamp = buf[n].header.timestamp; *outCount = buf[n].vsync.count; const DisplayEventReceiver::Event& ev = buf[n]; if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { *outTimestamp = ev.header.timestamp; *outId = ev.header.id; *outCount = ev.vsync.count; return true; // stop at last vsync in the buffer } if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) { dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected); } } } if (n < 0) { Loading @@ -176,6 +180,28 @@ bool NativeDisplayEventReceiver::readLastVsyncMessage( return false; } void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ALOGV("receiver %p ~ Invoking vsync handler.", this); env->CallVoidMethod(mReceiverObjGlobal, gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count); ALOGV("receiver %p ~ Returned from vsync handler.", this); mMessageQueue->raiseAndClearException(env, "dispatchVsync"); } void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ALOGV("receiver %p ~ Invoking hotplug handler.", this); env->CallVoidMethod(mReceiverObjGlobal, gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected); ALOGV("receiver %p ~ Returned from hotplug handler.", this); mMessageQueue->raiseAndClearException(env, "dispatchHotplug"); } static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj, jobject messageQueueObj) { Loading Loading @@ -248,7 +274,10 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JI)V"); "dispatchVsync", "(JII)V"); GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug, gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JIZ)V"); return 0; } Loading services/java/com/android/server/display/DisplayManagerService.java +6 −0 Original line number Diff line number Diff line Loading @@ -536,6 +536,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return; } Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked()); mDisplayDevices.add(device); addLogicalDisplayLocked(device); scheduleTraversalLocked(); Loading @@ -550,6 +552,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return; } Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked()); device.applyPendingDisplayDeviceInfoChangesLocked(); if (updateLogicalDisplaysLocked()) { scheduleTraversalLocked(); Loading @@ -565,6 +569,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return; } Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked()); mRemovedDisplayDevices.add(device); updateLogicalDisplaysLocked(); scheduleTraversalLocked(); Loading services/java/com/android/server/display/LocalDisplayAdapter.java +18 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.server.display; import android.content.Context; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.util.SparseArray; import android.view.DisplayEventReceiver; import android.view.Surface; import android.view.Surface.PhysicalDisplayInfo; Loading @@ -41,12 +43,14 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final SparseArray<LocalDisplayDevice> mDevices = new SparseArray<LocalDisplayDevice>(); private final HotplugDisplayEventReceiver mHotplugReceiver; private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo(); public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener) { super(syncRoot, context, handler, listener, TAG); mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper()); } @Override Loading Loading @@ -148,4 +152,17 @@ final class LocalDisplayAdapter extends DisplayAdapter { pw.println("mPhys=" + mPhys); } } private final class HotplugDisplayEventReceiver extends DisplayEventReceiver { public HotplugDisplayEventReceiver(Looper looper) { super(looper); } @Override public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { synchronized (getSyncRoot()) { scanDisplaysLocked(); } } } } No newline at end of file Loading
core/java/android/view/Choreographer.java +18 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package android.view; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; import android.os.Handler; import android.os.Looper; Loading Loading @@ -685,7 +684,24 @@ public final class Choreographer { } @Override public void onVsync(long timestampNanos, int frame) { public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { // Ignore vsync from secondary display. // This can be problematic because the call to scheduleVsync() is a one-shot. // We need to ensure that we will still receive the vsync from the primary // display which is the one we really care about. Ideally we should schedule // vsync for a particular display. // At this time Surface Flinger won't send us vsyncs for secondary displays // but that could change in the future so let's log a message to help us remember // that we need to fix this. if (builtInDisplayId != Surface.BUILT_IN_DISPLAY_ID_MAIN) { Log.d(TAG, "Received vsync from secondary display, but we don't support " + "this case yet. Choreographer needs a way to explicitly request " + "vsync for a specific display to ensure it doesn't lose track " + "of its scheduled vsync."); scheduleVsync(); return; } // Post the vsync event to the Handler. // The idea is to prevent incoming vsync events from completely starving // the message queue. If there are no messages in the queue with timestamps Loading
core/java/android/view/DisplayEventReceiver.java +23 −3 Original line number Diff line number Diff line Loading @@ -101,9 +101,23 @@ public abstract class DisplayEventReceiver { * * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()} * timebase. * @param builtInDisplayId The surface flinger built-in display id such as * {@link Surface#BUILT_IN_DISPLAY_ID_MAIN}. * @param frame The frame number. Increases by one for each vertical sync interval. */ public void onVsync(long timestampNanos, int frame) { public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { } /** * Called when a display hotplug event is received. * * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} * timebase. * @param builtInDisplayId The surface flinger built-in display id such as * {@link Surface#BUILT_IN_DISPLAY_ID_HDMI}. * @param connected True if the display is connected, false if it disconnected. */ public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { } /** Loading @@ -121,7 +135,13 @@ public abstract class DisplayEventReceiver { // Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, int frame) { onVsync(timestampNanos, frame); private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) { onVsync(timestampNanos, builtInDisplayId, frame); } // Called from native code. @SuppressWarnings("unused") private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { onHotplug(timestampNanos, builtInDisplayId, connected); } }
core/jni/android_view_DisplayEventReceiver.cpp +47 −18 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ static struct { jclass clazz; jmethodID dispatchVsync; jmethodID dispatchHotplug; } gDisplayEventReceiverClassInfo; Loading @@ -61,7 +62,9 @@ private: bool mWaitingForVsync; virtual int handleEvent(int receiveFd, int events, void* data); bool readLastVsyncMessage(nsecs_t* outTimestamp, uint32_t* outCount); bool readLastVsyncMessage(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount); void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count); void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected); }; Loading Loading @@ -106,8 +109,9 @@ status_t NativeDisplayEventReceiver::scheduleVsync() { // Drain all pending events. nsecs_t vsyncTimestamp; int32_t vsyncDisplayId; uint32_t vsyncCount; readLastVsyncMessage(&vsyncTimestamp, &vsyncCount); readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount); status_t status = mReceiver.requestNextVsync(); if (status) { Loading Loading @@ -135,39 +139,39 @@ int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* dat // Drain all pending events, keep the last vsync. nsecs_t vsyncTimestamp; int32_t vsyncDisplayId; uint32_t vsyncCount; if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncCount)) { if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this); return 1; // keep the callback, did not obtain a vsync pulse } ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d", this, vsyncTimestamp, vsyncCount); ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d", this, vsyncTimestamp, vsyncDisplayId, vsyncCount); mWaitingForVsync = false; JNIEnv* env = AndroidRuntime::getJNIEnv(); ALOGV("receiver %p ~ Invoking vsync handler.", this); env->CallVoidMethod(mReceiverObjGlobal, gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount); ALOGV("receiver %p ~ Returned from vsync handler.", this); mMessageQueue->raiseAndClearException(env, "dispatchVsync"); dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount); return 1; // keep the callback } bool NativeDisplayEventReceiver::readLastVsyncMessage( nsecs_t* outTimestamp, uint32_t* outCount) { nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) { DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; ssize_t n; while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { ALOGV("receiver %p ~ Read %d events.", this, int(n)); while (n-- > 0) { if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { *outTimestamp = buf[n].header.timestamp; *outCount = buf[n].vsync.count; const DisplayEventReceiver::Event& ev = buf[n]; if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { *outTimestamp = ev.header.timestamp; *outId = ev.header.id; *outCount = ev.vsync.count; return true; // stop at last vsync in the buffer } if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) { dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected); } } } if (n < 0) { Loading @@ -176,6 +180,28 @@ bool NativeDisplayEventReceiver::readLastVsyncMessage( return false; } void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ALOGV("receiver %p ~ Invoking vsync handler.", this); env->CallVoidMethod(mReceiverObjGlobal, gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count); ALOGV("receiver %p ~ Returned from vsync handler.", this); mMessageQueue->raiseAndClearException(env, "dispatchVsync"); } void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ALOGV("receiver %p ~ Invoking hotplug handler.", this); env->CallVoidMethod(mReceiverObjGlobal, gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected); ALOGV("receiver %p ~ Returned from hotplug handler.", this); mMessageQueue->raiseAndClearException(env, "dispatchHotplug"); } static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj, jobject messageQueueObj) { Loading Loading @@ -248,7 +274,10 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JI)V"); "dispatchVsync", "(JII)V"); GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug, gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JIZ)V"); return 0; } Loading
services/java/com/android/server/display/DisplayManagerService.java +6 −0 Original line number Diff line number Diff line Loading @@ -536,6 +536,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return; } Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked()); mDisplayDevices.add(device); addLogicalDisplayLocked(device); scheduleTraversalLocked(); Loading @@ -550,6 +552,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return; } Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked()); device.applyPendingDisplayDeviceInfoChangesLocked(); if (updateLogicalDisplaysLocked()) { scheduleTraversalLocked(); Loading @@ -565,6 +569,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return; } Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked()); mRemovedDisplayDevices.add(device); updateLogicalDisplaysLocked(); scheduleTraversalLocked(); Loading
services/java/com/android/server/display/LocalDisplayAdapter.java +18 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.server.display; import android.content.Context; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.util.SparseArray; import android.view.DisplayEventReceiver; import android.view.Surface; import android.view.Surface.PhysicalDisplayInfo; Loading @@ -41,12 +43,14 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final SparseArray<LocalDisplayDevice> mDevices = new SparseArray<LocalDisplayDevice>(); private final HotplugDisplayEventReceiver mHotplugReceiver; private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo(); public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener) { super(syncRoot, context, handler, listener, TAG); mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper()); } @Override Loading Loading @@ -148,4 +152,17 @@ final class LocalDisplayAdapter extends DisplayAdapter { pw.println("mPhys=" + mPhys); } } private final class HotplugDisplayEventReceiver extends DisplayEventReceiver { public HotplugDisplayEventReceiver(Looper looper) { super(looper); } @Override public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { synchronized (getSyncRoot()) { scanDisplaysLocked(); } } } } No newline at end of file