@@ -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