@@ -103,6 +103,11 @@ protected Choreographer initialValue() {
103103 private static final boolean USE_FRAME_TIME = SystemProperties .getBoolean (
104104 "debug.choreographer.frametime" , true );
105105
106+ // Set a limit to warn about skipped frames.
107+ // Skipped frames imply jank.
108+ private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties .getInt (
109+ "debug.choreographer.skipwarning" , 30 );
110+
106111 private static final long NANOS_PER_MS = 1000000 ;
107112
108113 private static final int MSG_DO_FRAME = 0 ;
@@ -486,21 +491,26 @@ void doFrame(long frameTimeNanos, int frame) {
486491 startNanos = System .nanoTime ();
487492 final long jitterNanos = startNanos - frameTimeNanos ;
488493 if (jitterNanos >= mFrameIntervalNanos ) {
494+ final long skippedFrames = jitterNanos / mFrameIntervalNanos ;
495+ if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT ) {
496+ Log .w (TAG , "Skipped " + skippedFrames + " frames! "
497+ + "The application may be doing too much work on its main thread." );
498+ }
489499 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos ;
490500 if (DEBUG ) {
491501 Log .d (TAG , "Missed vsync by " + (jitterNanos * 0.000001f ) + " ms "
492502 + "which is more than the frame interval of "
493503 + (mFrameIntervalNanos * 0.000001f ) + " ms! "
494- + "Setting frame time to " + ( lastFrameOffset * 0.000001f )
495- + " ms in the past." );
504+ + "Skipping " + skippedFrames + " frames and setting frame "
505+ + "time to " + ( lastFrameOffset * 0.000001f ) + " ms in the past." );
496506 }
497507 frameTimeNanos = startNanos - lastFrameOffset ;
498508 }
499509
500510 if (frameTimeNanos < mLastFrameTimeNanos ) {
501511 if (DEBUG ) {
502512 Log .d (TAG , "Frame time appears to be going backwards. May be due to a "
503- + "previously skipped frame. Waiting for next vsync" );
513+ + "previously skipped frame. Waiting for next vsync. " );
504514 }
505515 scheduleVsyncLocked ();
506516 return ;
@@ -658,6 +668,7 @@ public void handleMessage(Message msg) {
658668
659669 private final class FrameDisplayEventReceiver extends DisplayEventReceiver
660670 implements Runnable {
671+ private boolean mHavePendingVsync ;
661672 private long mTimestampNanos ;
662673 private int mFrame ;
663674
@@ -672,6 +683,21 @@ public void onVsync(long timestampNanos, int frame) {
672683 // the message queue. If there are no messages in the queue with timestamps
673684 // earlier than the frame time, then the vsync event will be processed immediately.
674685 // Otherwise, messages that predate the vsync event will be handled first.
686+ long now = System .nanoTime ();
687+ if (timestampNanos > now ) {
688+ Log .w (TAG , "Frame time is " + ((timestampNanos - now ) * 0.000001f )
689+ + " ms in the future! Check that graphics HAL is generating vsync "
690+ + "timestamps using the correct timebase." );
691+ timestampNanos = now ;
692+ }
693+
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+ }
700+
675701 mTimestampNanos = timestampNanos ;
676702 mFrame = frame ;
677703 Message msg = Message .obtain (mHandler , this );
@@ -681,6 +707,7 @@ public void onVsync(long timestampNanos, int frame) {
681707
682708 @ Override
683709 public void run () {
710+ mHavePendingVsync = false ;
684711 doFrame (mTimestampNanos , mFrame );
685712 }
686713 }
0 commit comments