Skip to content

Commit e87bf03

Browse files
author
Jeff Brown
committed
Support HDMI hotplug.
Bug: 7206678 Change-Id: Ia5212b16658a5f5a2ccf8528eca7bebd45ca857a
1 parent f98db0d commit e87bf03

File tree

5 files changed

+112
-24
lines changed

5 files changed

+112
-24
lines changed

core/java/android/view/Choreographer.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package android.view;
1818

19-
import android.hardware.display.DisplayManager;
2019
import android.hardware.display.DisplayManagerGlobal;
2120
import android.os.Handler;
2221
import android.os.Looper;
@@ -685,7 +684,24 @@ public FrameDisplayEventReceiver(Looper looper) {
685684
}
686685

687686
@Override
688-
public void onVsync(long timestampNanos, int frame) {
687+
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
688+
// Ignore vsync from secondary display.
689+
// This can be problematic because the call to scheduleVsync() is a one-shot.
690+
// We need to ensure that we will still receive the vsync from the primary
691+
// display which is the one we really care about. Ideally we should schedule
692+
// vsync for a particular display.
693+
// At this time Surface Flinger won't send us vsyncs for secondary displays
694+
// but that could change in the future so let's log a message to help us remember
695+
// that we need to fix this.
696+
if (builtInDisplayId != Surface.BUILT_IN_DISPLAY_ID_MAIN) {
697+
Log.d(TAG, "Received vsync from secondary display, but we don't support "
698+
+ "this case yet. Choreographer needs a way to explicitly request "
699+
+ "vsync for a specific display to ensure it doesn't lose track "
700+
+ "of its scheduled vsync.");
701+
scheduleVsync();
702+
return;
703+
}
704+
689705
// Post the vsync event to the Handler.
690706
// The idea is to prevent incoming vsync events from completely starving
691707
// the message queue. If there are no messages in the queue with timestamps

core/java/android/view/DisplayEventReceiver.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,23 @@ private void dispose(boolean finalized) {
101101
*
102102
* @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}
103103
* timebase.
104+
* @param builtInDisplayId The surface flinger built-in display id such as
105+
* {@link Surface#BUILT_IN_DISPLAY_ID_MAIN}.
104106
* @param frame The frame number. Increases by one for each vertical sync interval.
105107
*/
106-
public void onVsync(long timestampNanos, int frame) {
108+
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
109+
}
110+
111+
/**
112+
* Called when a display hotplug event is received.
113+
*
114+
* @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
115+
* timebase.
116+
* @param builtInDisplayId The surface flinger built-in display id such as
117+
* {@link Surface#BUILT_IN_DISPLAY_ID_HDMI}.
118+
* @param connected True if the display is connected, false if it disconnected.
119+
*/
120+
public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
107121
}
108122

109123
/**
@@ -121,7 +135,13 @@ public void scheduleVsync() {
121135

122136
// Called from native code.
123137
@SuppressWarnings("unused")
124-
private void dispatchVsync(long timestampNanos, int frame) {
125-
onVsync(timestampNanos, frame);
138+
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
139+
onVsync(timestampNanos, builtInDisplayId, frame);
140+
}
141+
142+
// Called from native code.
143+
@SuppressWarnings("unused")
144+
private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
145+
onHotplug(timestampNanos, builtInDisplayId, connected);
126146
}
127147
}

core/jni/android_view_DisplayEventReceiver.cpp

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static struct {
3939
jclass clazz;
4040

4141
jmethodID dispatchVsync;
42+
jmethodID dispatchHotplug;
4243
} gDisplayEventReceiverClassInfo;
4344

4445

@@ -61,7 +62,9 @@ class NativeDisplayEventReceiver : public LooperCallback {
6162
bool mWaitingForVsync;
6263

6364
virtual int handleEvent(int receiveFd, int events, void* data);
64-
bool readLastVsyncMessage(nsecs_t* outTimestamp, uint32_t* outCount);
65+
bool readLastVsyncMessage(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
66+
void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
67+
void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
6568
};
6669

6770

@@ -106,8 +109,9 @@ status_t NativeDisplayEventReceiver::scheduleVsync() {
106109

107110
// Drain all pending events.
108111
nsecs_t vsyncTimestamp;
112+
int32_t vsyncDisplayId;
109113
uint32_t vsyncCount;
110-
readLastVsyncMessage(&vsyncTimestamp, &vsyncCount);
114+
readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
111115

112116
status_t status = mReceiver.requestNextVsync();
113117
if (status) {
@@ -135,39 +139,39 @@ int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* dat
135139

136140
// Drain all pending events, keep the last vsync.
137141
nsecs_t vsyncTimestamp;
142+
int32_t vsyncDisplayId;
138143
uint32_t vsyncCount;
139-
if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncCount)) {
144+
if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
140145
ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this);
141146
return 1; // keep the callback, did not obtain a vsync pulse
142147
}
143148

144-
ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d",
145-
this, vsyncTimestamp, vsyncCount);
149+
ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d",
150+
this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
146151
mWaitingForVsync = false;
147152

148-
JNIEnv* env = AndroidRuntime::getJNIEnv();
149-
150-
ALOGV("receiver %p ~ Invoking vsync handler.", this);
151-
env->CallVoidMethod(mReceiverObjGlobal,
152-
gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
153-
ALOGV("receiver %p ~ Returned from vsync handler.", this);
154-
155-
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
153+
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
156154
return 1; // keep the callback
157155
}
158156

159157
bool NativeDisplayEventReceiver::readLastVsyncMessage(
160-
nsecs_t* outTimestamp, uint32_t* outCount) {
158+
nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
161159
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
162160
ssize_t n;
163161
while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
164162
ALOGV("receiver %p ~ Read %d events.", this, int(n));
165163
while (n-- > 0) {
166-
if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
167-
*outTimestamp = buf[n].header.timestamp;
168-
*outCount = buf[n].vsync.count;
164+
const DisplayEventReceiver::Event& ev = buf[n];
165+
if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
166+
*outTimestamp = ev.header.timestamp;
167+
*outId = ev.header.id;
168+
*outCount = ev.vsync.count;
169169
return true; // stop at last vsync in the buffer
170170
}
171+
172+
if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
173+
dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
174+
}
171175
}
172176
}
173177
if (n < 0) {
@@ -176,6 +180,28 @@ bool NativeDisplayEventReceiver::readLastVsyncMessage(
176180
return false;
177181
}
178182

183+
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
184+
JNIEnv* env = AndroidRuntime::getJNIEnv();
185+
186+
ALOGV("receiver %p ~ Invoking vsync handler.", this);
187+
env->CallVoidMethod(mReceiverObjGlobal,
188+
gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
189+
ALOGV("receiver %p ~ Returned from vsync handler.", this);
190+
191+
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
192+
}
193+
194+
void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
195+
JNIEnv* env = AndroidRuntime::getJNIEnv();
196+
197+
ALOGV("receiver %p ~ Invoking hotplug handler.", this);
198+
env->CallVoidMethod(mReceiverObjGlobal,
199+
gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
200+
ALOGV("receiver %p ~ Returned from hotplug handler.", this);
201+
202+
mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
203+
}
204+
179205

180206
static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
181207
jobject messageQueueObj) {
@@ -248,7 +274,10 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
248274

249275
GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync,
250276
gDisplayEventReceiverClassInfo.clazz,
251-
"dispatchVsync", "(JI)V");
277+
"dispatchVsync", "(JII)V");
278+
GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug,
279+
gDisplayEventReceiverClassInfo.clazz,
280+
"dispatchHotplug", "(JIZ)V");
252281
return 0;
253282
}
254283

services/java/com/android/server/display/DisplayManagerService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,8 @@ private void handleDisplayDeviceAdded(DisplayDevice device) {
536536
return;
537537
}
538538

539+
Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
540+
539541
mDisplayDevices.add(device);
540542
addLogicalDisplayLocked(device);
541543
scheduleTraversalLocked();
@@ -550,6 +552,8 @@ private void handleDisplayDeviceChanged(DisplayDevice device) {
550552
return;
551553
}
552554

555+
Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
556+
553557
device.applyPendingDisplayDeviceInfoChangesLocked();
554558
if (updateLogicalDisplaysLocked()) {
555559
scheduleTraversalLocked();
@@ -565,6 +569,8 @@ private void handleDisplayDeviceRemoved(DisplayDevice device) {
565569
return;
566570
}
567571

572+
Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
573+
568574
mRemovedDisplayDevices.add(device);
569575
updateLogicalDisplaysLocked();
570576
scheduleTraversalLocked();

services/java/com/android/server/display/LocalDisplayAdapter.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import android.content.Context;
2020
import android.os.Handler;
2121
import android.os.IBinder;
22+
import android.os.Looper;
2223
import android.util.SparseArray;
24+
import android.view.DisplayEventReceiver;
2325
import android.view.Surface;
2426
import android.view.Surface.PhysicalDisplayInfo;
2527

@@ -41,12 +43,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
4143

4244
private final SparseArray<LocalDisplayDevice> mDevices =
4345
new SparseArray<LocalDisplayDevice>();
46+
private final HotplugDisplayEventReceiver mHotplugReceiver;
4447

4548
private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo();
4649

4750
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
4851
Context context, Handler handler, Listener listener) {
4952
super(syncRoot, context, handler, listener, TAG);
53+
mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper());
5054
}
5155

5256
@Override
@@ -148,4 +152,17 @@ public void dumpLocked(PrintWriter pw) {
148152
pw.println("mPhys=" + mPhys);
149153
}
150154
}
151-
}
155+
156+
private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
157+
public HotplugDisplayEventReceiver(Looper looper) {
158+
super(looper);
159+
}
160+
161+
@Override
162+
public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
163+
synchronized (getSyncRoot()) {
164+
scanDisplaysLocked();
165+
}
166+
}
167+
}
168+
}

0 commit comments

Comments
 (0)