Skip to content

Commit 5c74bca

Browse files
Jeff BrownAndroid (Google) Code Review
authored andcommitted
Merge "Synthesize fake vsyncs when the screen is off." into jb-dev
2 parents 839734b + 858491b commit 5c74bca

File tree

1 file changed

+36
-6
lines changed

1 file changed

+36
-6
lines changed

core/java/android/view/Choreographer.java

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ public final class Choreographer {
7979
// be dequeued.
8080
private static final long DEFAULT_FRAME_DELAY = 10;
8181

82+
// The fake vsync delay in milliseconds.
83+
// When the screen is off, we might not receive real vsync pulses from the hardware
84+
// which would cause posted Choreographer callbacks to not run. This is bad because
85+
// messages in the Looper might be blocked behind a barrier that is scheduled to be
86+
// removed by one of those Choreographer callback (see ViewRootImpl.doTraversals).
87+
// Until the barrier is removed, those messages will not run. To prevent starvation
88+
// of the Looper, we synthesize fake vsync pulses at a reduced rate whenever the
89+
// display hardware stops generating them.
90+
private static final long FAKE_VSYNC_DELAY = 100;
91+
8292
// The number of milliseconds between animation frames.
8393
private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
8494

@@ -113,6 +123,7 @@ protected Choreographer initialValue() {
113123
private static final int MSG_DO_FRAME = 0;
114124
private static final int MSG_DO_SCHEDULE_VSYNC = 1;
115125
private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
126+
private static final int MSG_FAKE_VSYNC = 3;
116127

117128
// All frame callbacks posted by applications have this token.
118129
private static final Object FRAME_CALLBACK_TOKEN = new Object() {
@@ -587,6 +598,13 @@ void doScheduleCallback(int callbackType) {
587598

588599
private void scheduleVsyncLocked() {
589600
mDisplayEventReceiver.scheduleVsync();
601+
602+
// Post a message to simulate a fake vsync pulse at a reduced rate in case the
603+
// display hardware stops generating them. This ensures that Choreographer
604+
// callbacks can continue to run even if the screen is off.
605+
Message msg = mHandler.obtainMessage(MSG_FAKE_VSYNC);
606+
msg.setAsynchronous(true);
607+
mHandler.sendMessageDelayed(msg, FAKE_VSYNC_DELAY);
590608
}
591609

592610
private boolean isRunningOnLooperThreadLocked() {
@@ -662,6 +680,12 @@ public void handleMessage(Message msg) {
662680
case MSG_DO_SCHEDULE_CALLBACK:
663681
doScheduleCallback(msg.arg1);
664682
break;
683+
case MSG_FAKE_VSYNC:
684+
if (DEBUG) {
685+
Log.d(TAG, "Handling fake vsync while screen is off.");
686+
}
687+
doFrame(System.nanoTime(), 0);
688+
break;
665689
}
666690
}
667691
}
@@ -683,6 +707,17 @@ public void onVsync(long timestampNanos, int frame) {
683707
// the message queue. If there are no messages in the queue with timestamps
684708
// earlier than the frame time, then the vsync event will be processed immediately.
685709
// Otherwise, messages that predate the vsync event will be handled first.
710+
if (mHavePendingVsync) {
711+
if (DEBUG) {
712+
Log.d(TAG, "Already have a pending vsync event. There should only be "
713+
+ "one at a time but they can double up when a fake vsync "
714+
+ "is handled in place of a real one.");
715+
}
716+
mHandler.removeCallbacks(this);
717+
} else {
718+
mHavePendingVsync = true;
719+
}
720+
686721
long now = System.nanoTime();
687722
if (timestampNanos > now) {
688723
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
@@ -691,12 +726,7 @@ public void onVsync(long timestampNanos, int frame) {
691726
timestampNanos = now;
692727
}
693728

694-
if (mHavePendingVsync) {
695-
Log.w(TAG, "Already have a pending vsync event. There should only be "
696-
+ "one at a time.");
697-
} else {
698-
mHavePendingVsync = true;
699-
}
729+
mHandler.removeMessages(MSG_FAKE_VSYNC);
700730

701731
mTimestampNanos = timestampNanos;
702732
mFrame = frame;

0 commit comments

Comments
 (0)