diff options
author | Jeff Brown <jeffbrown@google.com> | 2012-09-20 18:30:13 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2012-09-21 15:34:32 -0700 |
commit | e87bf030766198bf5e1fe846167dba766e27fb3f (patch) | |
tree | b0f379481622310b6afd5e8002c16930e6ed91b6 | |
parent | f98db0de2248ad286b207eed6a826373cc60b786 (diff) | |
download | frameworks_base-e87bf030766198bf5e1fe846167dba766e27fb3f.zip frameworks_base-e87bf030766198bf5e1fe846167dba766e27fb3f.tar.gz frameworks_base-e87bf030766198bf5e1fe846167dba766e27fb3f.tar.bz2 |
Support HDMI hotplug.
Bug: 7206678
Change-Id: Ia5212b16658a5f5a2ccf8528eca7bebd45ca857a
5 files changed, 112 insertions, 24 deletions
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 6848606..b661748 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -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; @@ -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 diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index 0b138c2..a919ffc 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -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) { } /** @@ -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); } } diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 89058a7..3d9d005 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -39,6 +39,7 @@ static struct { jclass clazz; jmethodID dispatchVsync; + jmethodID dispatchHotplug; } gDisplayEventReceiverClassInfo; @@ -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); }; @@ -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) { @@ -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) { @@ -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) { @@ -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; } diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java index b109f2a..85f3b56 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -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(); @@ -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(); @@ -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(); diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java index eab4c9a..9c51463 100644 --- a/services/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/java/com/android/server/display/LocalDisplayAdapter.java @@ -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; @@ -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 @@ -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 |