1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view;
18 
19 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
20 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
21 
22 import android.annotation.TestApi;
23 import android.hardware.display.DisplayManagerGlobal;
24 import android.os.Handler;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.os.SystemClock;
28 import android.os.SystemProperties;
29 import android.os.Trace;
30 import android.util.Log;
31 import android.util.TimeUtils;
32 import android.view.animation.AnimationUtils;
33 
34 import java.io.PrintWriter;
35 
36 /**
37  * Coordinates the timing of animations, input and drawing.
38  * <p>
39  * The choreographer receives timing pulses (such as vertical synchronization)
40  * from the display subsystem then schedules work to occur as part of rendering
41  * the next display frame.
42  * </p><p>
43  * Applications typically interact with the choreographer indirectly using
44  * higher level abstractions in the animation framework or the view hierarchy.
45  * Here are some examples of things you can do using the higher-level APIs.
46  * </p>
47  * <ul>
48  * <li>To post an animation to be processed on a regular time basis synchronized with
49  * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
50  * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
51  * frame, use {@link View#postOnAnimation}.</li>
52  * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
53  * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
54  * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
55  * next display frame, use {@link View#postInvalidateOnAnimation()} or
56  * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
57  * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
58  * sync with display frame rendering, do nothing.  This already happens automatically.
59  * {@link View#onDraw} will be called at the appropriate time.</li>
60  * </ul>
61  * <p>
62  * However, there are a few cases where you might want to use the functions of the
63  * choreographer directly in your application.  Here are some examples.
64  * </p>
65  * <ul>
66  * <li>If your application does its rendering in a different thread, possibly using GL,
67  * or does not use the animation framework or view hierarchy at all
68  * and you want to ensure that it is appropriately synchronized with the display, then use
69  * {@link Choreographer#postFrameCallback}.</li>
70  * <li>... and that's about it.</li>
71  * </ul>
72  * <p>
73  * Each {@link Looper} thread has its own choreographer.  Other threads can
74  * post callbacks to run on the choreographer but they will run on the {@link Looper}
75  * to which the choreographer belongs.
76  * </p>
77  */
78 public final class Choreographer {
79     private static final String TAG = "Choreographer";
80 
81     // Prints debug messages about jank which was detected (low volume).
82     private static final boolean DEBUG_JANK = false;
83 
84     // Prints debug messages about every frame and callback registered (high volume).
85     private static final boolean DEBUG_FRAMES = false;
86 
87     // The default amount of time in ms between animation frames.
88     // When vsync is not enabled, we want to have some idea of how long we should
89     // wait before posting the next animation message.  It is important that the
90     // default value be less than the true inter-frame delay on all devices to avoid
91     // situations where we might skip frames by waiting too long (we must compensate
92     // for jitter and hardware variations).  Regardless of this value, the animation
93     // and display loop is ultimately rate-limited by how fast new graphics buffers can
94     // be dequeued.
95     private static final long DEFAULT_FRAME_DELAY = 10;
96 
97     // The number of milliseconds between animation frames.
98     private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
99 
100     // Thread local storage for the choreographer.
101     private static final ThreadLocal<Choreographer> sThreadInstance =
102             new ThreadLocal<Choreographer>() {
103         @Override
104         protected Choreographer initialValue() {
105             Looper looper = Looper.myLooper();
106             if (looper == null) {
107                 throw new IllegalStateException("The current thread must have a looper!");
108             }
109             Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
110             if (looper == Looper.getMainLooper()) {
111                 mMainInstance = choreographer;
112             }
113             return choreographer;
114         }
115     };
116 
117     private static volatile Choreographer mMainInstance;
118 
119     // Thread local storage for the SF choreographer.
120     private static final ThreadLocal<Choreographer> sSfThreadInstance =
121             new ThreadLocal<Choreographer>() {
122                 @Override
123                 protected Choreographer initialValue() {
124                     Looper looper = Looper.myLooper();
125                     if (looper == null) {
126                         throw new IllegalStateException("The current thread must have a looper!");
127                     }
128                     return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
129                 }
130             };
131 
132     // Enable/disable vsync for animations and drawing.
133     private static final boolean USE_VSYNC = SystemProperties.getBoolean(
134             "debug.choreographer.vsync", true);
135 
136     // Enable/disable using the frame time instead of returning now.
137     private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
138             "debug.choreographer.frametime", true);
139 
140     // Set a limit to warn about skipped frames.
141     // Skipped frames imply jank.
142     private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
143             "debug.choreographer.skipwarning", 30);
144 
145     private static final int MSG_DO_FRAME = 0;
146     private static final int MSG_DO_SCHEDULE_VSYNC = 1;
147     private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
148 
149     // All frame callbacks posted by applications have this token.
150     private static final Object FRAME_CALLBACK_TOKEN = new Object() {
151         public String toString() { return "FRAME_CALLBACK_TOKEN"; }
152     };
153 
154     private final Object mLock = new Object();
155 
156     private final Looper mLooper;
157     private final FrameHandler mHandler;
158 
159     // The display event receiver can only be accessed by the looper thread to which
160     // it is attached.  We take care to ensure that we post message to the looper
161     // if appropriate when interacting with the display event receiver.
162     private final FrameDisplayEventReceiver mDisplayEventReceiver;
163 
164     private CallbackRecord mCallbackPool;
165 
166     private final CallbackQueue[] mCallbackQueues;
167 
168     private boolean mFrameScheduled;
169     private boolean mCallbacksRunning;
170     private long mLastFrameTimeNanos;
171     private long mFrameIntervalNanos;
172     private boolean mDebugPrintNextFrameTimeDelta;
173     private int mFPSDivisor = 1;
174 
175     /**
176      * Contains information about the current frame for jank-tracking,
177      * mainly timings of key events along with a bit of metadata about
178      * view tree state
179      *
180      * TODO: Is there a better home for this? Currently Choreographer
181      * is the only one with CALLBACK_ANIMATION start time, hence why this
182      * resides here.
183      *
184      * @hide
185      */
186     FrameInfo mFrameInfo = new FrameInfo();
187 
188     /**
189      * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
190      * @hide
191      */
192     private static final String[] CALLBACK_TRACE_TITLES = {
193             "input", "animation", "traversal", "commit"
194     };
195 
196     /**
197      * Callback type: Input callback.  Runs first.
198      * @hide
199      */
200     public static final int CALLBACK_INPUT = 0;
201 
202     /**
203      * Callback type: Animation callback.  Runs before traversals.
204      * @hide
205      */
206     @TestApi
207     public static final int CALLBACK_ANIMATION = 1;
208 
209     /**
210      * Callback type: Traversal callback.  Handles layout and draw.  Runs
211      * after all other asynchronous messages have been handled.
212      * @hide
213      */
214     public static final int CALLBACK_TRAVERSAL = 2;
215 
216     /**
217      * Callback type: Commit callback.  Handles post-draw operations for the frame.
218      * Runs after traversal completes.  The {@link #getFrameTime() frame time} reported
219      * during this callback may be updated to reflect delays that occurred while
220      * traversals were in progress in case heavy layout operations caused some frames
221      * to be skipped.  The frame time reported during this callback provides a better
222      * estimate of the start time of the frame in which animations (and other updates
223      * to the view hierarchy state) actually took effect.
224      * @hide
225      */
226     public static final int CALLBACK_COMMIT = 3;
227 
228     private static final int CALLBACK_LAST = CALLBACK_COMMIT;
229 
Choreographer(Looper looper, int vsyncSource)230     private Choreographer(Looper looper, int vsyncSource) {
231         mLooper = looper;
232         mHandler = new FrameHandler(looper);
233         mDisplayEventReceiver = USE_VSYNC
234                 ? new FrameDisplayEventReceiver(looper, vsyncSource)
235                 : null;
236         mLastFrameTimeNanos = Long.MIN_VALUE;
237 
238         mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
239 
240         mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
241         for (int i = 0; i <= CALLBACK_LAST; i++) {
242             mCallbackQueues[i] = new CallbackQueue();
243         }
244         // b/68769804: For low FPS experiments.
245         setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
246     }
247 
getRefreshRate()248     private static float getRefreshRate() {
249         DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
250                 Display.DEFAULT_DISPLAY);
251         return di.getMode().getRefreshRate();
252     }
253 
254     /**
255      * Gets the choreographer for the calling thread.  Must be called from
256      * a thread that already has a {@link android.os.Looper} associated with it.
257      *
258      * @return The choreographer for this thread.
259      * @throws IllegalStateException if the thread does not have a looper.
260      */
getInstance()261     public static Choreographer getInstance() {
262         return sThreadInstance.get();
263     }
264 
265     /**
266      * @hide
267      */
getSfInstance()268     public static Choreographer getSfInstance() {
269         return sSfThreadInstance.get();
270     }
271 
272     /**
273      * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
274      * @hide
275      */
getMainThreadInstance()276     public static Choreographer getMainThreadInstance() {
277         return mMainInstance;
278     }
279 
280     /** Destroys the calling thread's choreographer
281      * @hide
282      */
releaseInstance()283     public static void releaseInstance() {
284         Choreographer old = sThreadInstance.get();
285         sThreadInstance.remove();
286         old.dispose();
287     }
288 
dispose()289     private void dispose() {
290         mDisplayEventReceiver.dispose();
291     }
292 
293     /**
294      * The amount of time, in milliseconds, between each frame of the animation.
295      * <p>
296      * This is a requested time that the animation will attempt to honor, but the actual delay
297      * between frames may be different, depending on system load and capabilities. This is a static
298      * function because the same delay will be applied to all animations, since they are all
299      * run off of a single timing loop.
300      * </p><p>
301      * The frame delay may be ignored when the animation system uses an external timing
302      * source, such as the display refresh rate (vsync), to govern animations.
303      * </p>
304      *
305      * @return the requested time between frames, in milliseconds
306      * @hide
307      */
308     @TestApi
getFrameDelay()309     public static long getFrameDelay() {
310         return sFrameDelay;
311     }
312 
313     /**
314      * The amount of time, in milliseconds, between each frame of the animation.
315      * <p>
316      * This is a requested time that the animation will attempt to honor, but the actual delay
317      * between frames may be different, depending on system load and capabilities. This is a static
318      * function because the same delay will be applied to all animations, since they are all
319      * run off of a single timing loop.
320      * </p><p>
321      * The frame delay may be ignored when the animation system uses an external timing
322      * source, such as the display refresh rate (vsync), to govern animations.
323      * </p>
324      *
325      * @param frameDelay the requested time between frames, in milliseconds
326      * @hide
327      */
328     @TestApi
setFrameDelay(long frameDelay)329     public static void setFrameDelay(long frameDelay) {
330         sFrameDelay = frameDelay;
331     }
332 
333     /**
334      * Subtracts typical frame delay time from a delay interval in milliseconds.
335      * <p>
336      * This method can be used to compensate for animation delay times that have baked
337      * in assumptions about the frame delay.  For example, it's quite common for code to
338      * assume a 60Hz frame time and bake in a 16ms delay.  When we call
339      * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
340      * posting the animation callback but let the animation timer take care of the remaining
341      * frame delay time.
342      * </p><p>
343      * This method is somewhat conservative about how much of the frame delay it
344      * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
345      * default is 10ms even though many parts of the system assume 16ms.  Consequently,
346      * we might still wait 6ms before posting an animation callback that we want to run
347      * on the next frame, but this is much better than waiting a whole 16ms and likely
348      * missing the deadline.
349      * </p>
350      *
351      * @param delayMillis The original delay time including an assumed frame delay.
352      * @return The adjusted delay time with the assumed frame delay subtracted out.
353      * @hide
354      */
subtractFrameDelay(long delayMillis)355     public static long subtractFrameDelay(long delayMillis) {
356         final long frameDelay = sFrameDelay;
357         return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
358     }
359 
360     /**
361      * @return The refresh rate as the nanoseconds between frames
362      * @hide
363      */
getFrameIntervalNanos()364     public long getFrameIntervalNanos() {
365         return mFrameIntervalNanos;
366     }
367 
dump(String prefix, PrintWriter writer)368     void dump(String prefix, PrintWriter writer) {
369         String innerPrefix = prefix + "  ";
370         writer.print(prefix); writer.println("Choreographer:");
371         writer.print(innerPrefix); writer.print("mFrameScheduled=");
372                 writer.println(mFrameScheduled);
373         writer.print(innerPrefix); writer.print("mLastFrameTime=");
374                 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
375     }
376 
377     /**
378      * Posts a callback to run on the next frame.
379      * <p>
380      * The callback runs once then is automatically removed.
381      * </p>
382      *
383      * @param callbackType The callback type.
384      * @param action The callback action to run during the next frame.
385      * @param token The callback token, or null if none.
386      *
387      * @see #removeCallbacks
388      * @hide
389      */
390     @TestApi
postCallback(int callbackType, Runnable action, Object token)391     public void postCallback(int callbackType, Runnable action, Object token) {
392         postCallbackDelayed(callbackType, action, token, 0);
393     }
394 
395     /**
396      * Posts a callback to run on the next frame after the specified delay.
397      * <p>
398      * The callback runs once then is automatically removed.
399      * </p>
400      *
401      * @param callbackType The callback type.
402      * @param action The callback action to run during the next frame after the specified delay.
403      * @param token The callback token, or null if none.
404      * @param delayMillis The delay time in milliseconds.
405      *
406      * @see #removeCallback
407      * @hide
408      */
409     @TestApi
postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis)410     public void postCallbackDelayed(int callbackType,
411             Runnable action, Object token, long delayMillis) {
412         if (action == null) {
413             throw new IllegalArgumentException("action must not be null");
414         }
415         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
416             throw new IllegalArgumentException("callbackType is invalid");
417         }
418 
419         postCallbackDelayedInternal(callbackType, action, token, delayMillis);
420     }
421 
postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis)422     private void postCallbackDelayedInternal(int callbackType,
423             Object action, Object token, long delayMillis) {
424         if (DEBUG_FRAMES) {
425             Log.d(TAG, "PostCallback: type=" + callbackType
426                     + ", action=" + action + ", token=" + token
427                     + ", delayMillis=" + delayMillis);
428         }
429 
430         synchronized (mLock) {
431             final long now = SystemClock.uptimeMillis();
432             final long dueTime = now + delayMillis;
433             mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
434 
435             if (dueTime <= now) {
436                 scheduleFrameLocked(now);
437             } else {
438                 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
439                 msg.arg1 = callbackType;
440                 msg.setAsynchronous(true);
441                 mHandler.sendMessageAtTime(msg, dueTime);
442             }
443         }
444     }
445 
446     /**
447      * Removes callbacks that have the specified action and token.
448      *
449      * @param callbackType The callback type.
450      * @param action The action property of the callbacks to remove, or null to remove
451      * callbacks with any action.
452      * @param token The token property of the callbacks to remove, or null to remove
453      * callbacks with any token.
454      *
455      * @see #postCallback
456      * @see #postCallbackDelayed
457      * @hide
458      */
459     @TestApi
removeCallbacks(int callbackType, Runnable action, Object token)460     public void removeCallbacks(int callbackType, Runnable action, Object token) {
461         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
462             throw new IllegalArgumentException("callbackType is invalid");
463         }
464 
465         removeCallbacksInternal(callbackType, action, token);
466     }
467 
removeCallbacksInternal(int callbackType, Object action, Object token)468     private void removeCallbacksInternal(int callbackType, Object action, Object token) {
469         if (DEBUG_FRAMES) {
470             Log.d(TAG, "RemoveCallbacks: type=" + callbackType
471                     + ", action=" + action + ", token=" + token);
472         }
473 
474         synchronized (mLock) {
475             mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
476             if (action != null && token == null) {
477                 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
478             }
479         }
480     }
481 
482     /**
483      * Posts a frame callback to run on the next frame.
484      * <p>
485      * The callback runs once then is automatically removed.
486      * </p>
487      *
488      * @param callback The frame callback to run during the next frame.
489      *
490      * @see #postFrameCallbackDelayed
491      * @see #removeFrameCallback
492      */
postFrameCallback(FrameCallback callback)493     public void postFrameCallback(FrameCallback callback) {
494         postFrameCallbackDelayed(callback, 0);
495     }
496 
497     /**
498      * Posts a frame callback to run on the next frame after the specified delay.
499      * <p>
500      * The callback runs once then is automatically removed.
501      * </p>
502      *
503      * @param callback The frame callback to run during the next frame.
504      * @param delayMillis The delay time in milliseconds.
505      *
506      * @see #postFrameCallback
507      * @see #removeFrameCallback
508      */
postFrameCallbackDelayed(FrameCallback callback, long delayMillis)509     public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
510         if (callback == null) {
511             throw new IllegalArgumentException("callback must not be null");
512         }
513 
514         postCallbackDelayedInternal(CALLBACK_ANIMATION,
515                 callback, FRAME_CALLBACK_TOKEN, delayMillis);
516     }
517 
518     /**
519      * Removes a previously posted frame callback.
520      *
521      * @param callback The frame callback to remove.
522      *
523      * @see #postFrameCallback
524      * @see #postFrameCallbackDelayed
525      */
removeFrameCallback(FrameCallback callback)526     public void removeFrameCallback(FrameCallback callback) {
527         if (callback == null) {
528             throw new IllegalArgumentException("callback must not be null");
529         }
530 
531         removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
532     }
533 
534     /**
535      * Gets the time when the current frame started.
536      * <p>
537      * This method provides the time in milliseconds when the frame started being rendered.
538      * The frame time provides a stable time base for synchronizing animations
539      * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
540      * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
541      * time helps to reduce inter-frame jitter because the frame time is fixed at the time
542      * the frame was scheduled to start, regardless of when the animations or drawing
543      * callback actually runs.  All callbacks that run as part of rendering a frame will
544      * observe the same frame time so using the frame time also helps to synchronize effects
545      * that are performed by different callbacks.
546      * </p><p>
547      * Please note that the framework already takes care to process animations and
548      * drawing using the frame time as a stable time base.  Most applications should
549      * not need to use the frame time information directly.
550      * </p><p>
551      * This method should only be called from within a callback.
552      * </p>
553      *
554      * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
555      *
556      * @throws IllegalStateException if no frame is in progress.
557      * @hide
558      */
getFrameTime()559     public long getFrameTime() {
560         return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
561     }
562 
563     /**
564      * Same as {@link #getFrameTime()} but with nanosecond precision.
565      *
566      * @return The frame start time, in the {@link System#nanoTime()} time base.
567      *
568      * @throws IllegalStateException if no frame is in progress.
569      * @hide
570      */
getFrameTimeNanos()571     public long getFrameTimeNanos() {
572         synchronized (mLock) {
573             if (!mCallbacksRunning) {
574                 throw new IllegalStateException("This method must only be called as "
575                         + "part of a callback while a frame is in progress.");
576             }
577             return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
578         }
579     }
580 
581     /**
582      * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
583      * whether callbacks are currently running.
584      * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
585      * @hide
586      */
getLastFrameTimeNanos()587     public long getLastFrameTimeNanos() {
588         synchronized (mLock) {
589             return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
590         }
591     }
592 
scheduleFrameLocked(long now)593     private void scheduleFrameLocked(long now) {
594         if (!mFrameScheduled) {
595             mFrameScheduled = true;
596             if (USE_VSYNC) {
597                 if (DEBUG_FRAMES) {
598                     Log.d(TAG, "Scheduling next frame on vsync.");
599                 }
600 
601                 // If running on the Looper thread, then schedule the vsync immediately,
602                 // otherwise post a message to schedule the vsync from the UI thread
603                 // as soon as possible.
604                 if (isRunningOnLooperThreadLocked()) {
605                     scheduleVsyncLocked();
606                 } else {
607                     Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
608                     msg.setAsynchronous(true);
609                     mHandler.sendMessageAtFrontOfQueue(msg);
610                 }
611             } else {
612                 final long nextFrameTime = Math.max(
613                         mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
614                 if (DEBUG_FRAMES) {
615                     Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
616                 }
617                 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
618                 msg.setAsynchronous(true);
619                 mHandler.sendMessageAtTime(msg, nextFrameTime);
620             }
621         }
622     }
623 
setFPSDivisor(int divisor)624     void setFPSDivisor(int divisor) {
625         if (divisor <= 0) divisor = 1;
626         mFPSDivisor = divisor;
627         ThreadedRenderer.setFPSDivisor(divisor);
628     }
629 
doFrame(long frameTimeNanos, int frame)630     void doFrame(long frameTimeNanos, int frame) {
631         final long startNanos;
632         synchronized (mLock) {
633             if (!mFrameScheduled) {
634                 return; // no work to do
635             }
636 
637             if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
638                 mDebugPrintNextFrameTimeDelta = false;
639                 Log.d(TAG, "Frame time delta: "
640                         + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
641             }
642 
643             long intendedFrameTimeNanos = frameTimeNanos;
644             startNanos = System.nanoTime();
645             final long jitterNanos = startNanos - frameTimeNanos;
646             if (jitterNanos >= mFrameIntervalNanos) {
647                 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
648                 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
649                     Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
650                             + "The application may be doing too much work on its main thread.");
651                 }
652                 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
653                 if (DEBUG_JANK) {
654                     Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
655                             + "which is more than the frame interval of "
656                             + (mFrameIntervalNanos * 0.000001f) + " ms!  "
657                             + "Skipping " + skippedFrames + " frames and setting frame "
658                             + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
659                 }
660                 frameTimeNanos = startNanos - lastFrameOffset;
661             }
662 
663             if (frameTimeNanos < mLastFrameTimeNanos) {
664                 if (DEBUG_JANK) {
665                     Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
666                             + "previously skipped frame.  Waiting for next vsync.");
667                 }
668                 scheduleVsyncLocked();
669                 return;
670             }
671 
672             if (mFPSDivisor > 1) {
673                 long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
674                 if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
675                     scheduleVsyncLocked();
676                     return;
677                 }
678             }
679 
680             mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
681             mFrameScheduled = false;
682             mLastFrameTimeNanos = frameTimeNanos;
683         }
684 
685         try {
686             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
687             AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
688 
689             mFrameInfo.markInputHandlingStart();
690             doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
691 
692             mFrameInfo.markAnimationsStart();
693             doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
694 
695             mFrameInfo.markPerformTraversalsStart();
696             doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
697 
698             doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
699         } finally {
700             AnimationUtils.unlockAnimationClock();
701             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
702         }
703 
704         if (DEBUG_FRAMES) {
705             final long endNanos = System.nanoTime();
706             Log.d(TAG, "Frame " + frame + ": Finished, took "
707                     + (endNanos - startNanos) * 0.000001f + " ms, latency "
708                     + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
709         }
710     }
711 
doCallbacks(int callbackType, long frameTimeNanos)712     void doCallbacks(int callbackType, long frameTimeNanos) {
713         CallbackRecord callbacks;
714         synchronized (mLock) {
715             // We use "now" to determine when callbacks become due because it's possible
716             // for earlier processing phases in a frame to post callbacks that should run
717             // in a following phase, such as an input event that causes an animation to start.
718             final long now = System.nanoTime();
719             callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
720                     now / TimeUtils.NANOS_PER_MS);
721             if (callbacks == null) {
722                 return;
723             }
724             mCallbacksRunning = true;
725 
726             // Update the frame time if necessary when committing the frame.
727             // We only update the frame time if we are more than 2 frames late reaching
728             // the commit phase.  This ensures that the frame time which is observed by the
729             // callbacks will always increase from one frame to the next and never repeat.
730             // We never want the next frame's starting frame time to end up being less than
731             // or equal to the previous frame's commit frame time.  Keep in mind that the
732             // next frame has most likely already been scheduled by now so we play it
733             // safe by ensuring the commit time is always at least one frame behind.
734             if (callbackType == Choreographer.CALLBACK_COMMIT) {
735                 final long jitterNanos = now - frameTimeNanos;
736                 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
737                 if (jitterNanos >= 2 * mFrameIntervalNanos) {
738                     final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
739                             + mFrameIntervalNanos;
740                     if (DEBUG_JANK) {
741                         Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
742                                 + " ms which is more than twice the frame interval of "
743                                 + (mFrameIntervalNanos * 0.000001f) + " ms!  "
744                                 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
745                                 + " ms in the past.");
746                         mDebugPrintNextFrameTimeDelta = true;
747                     }
748                     frameTimeNanos = now - lastFrameOffset;
749                     mLastFrameTimeNanos = frameTimeNanos;
750                 }
751             }
752         }
753         try {
754             Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
755             for (CallbackRecord c = callbacks; c != null; c = c.next) {
756                 if (DEBUG_FRAMES) {
757                     Log.d(TAG, "RunCallback: type=" + callbackType
758                             + ", action=" + c.action + ", token=" + c.token
759                             + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
760                 }
761                 c.run(frameTimeNanos);
762             }
763         } finally {
764             synchronized (mLock) {
765                 mCallbacksRunning = false;
766                 do {
767                     final CallbackRecord next = callbacks.next;
768                     recycleCallbackLocked(callbacks);
769                     callbacks = next;
770                 } while (callbacks != null);
771             }
772             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
773         }
774     }
775 
doScheduleVsync()776     void doScheduleVsync() {
777         synchronized (mLock) {
778             if (mFrameScheduled) {
779                 scheduleVsyncLocked();
780             }
781         }
782     }
783 
doScheduleCallback(int callbackType)784     void doScheduleCallback(int callbackType) {
785         synchronized (mLock) {
786             if (!mFrameScheduled) {
787                 final long now = SystemClock.uptimeMillis();
788                 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
789                     scheduleFrameLocked(now);
790                 }
791             }
792         }
793     }
794 
scheduleVsyncLocked()795     private void scheduleVsyncLocked() {
796         mDisplayEventReceiver.scheduleVsync();
797     }
798 
isRunningOnLooperThreadLocked()799     private boolean isRunningOnLooperThreadLocked() {
800         return Looper.myLooper() == mLooper;
801     }
802 
obtainCallbackLocked(long dueTime, Object action, Object token)803     private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
804         CallbackRecord callback = mCallbackPool;
805         if (callback == null) {
806             callback = new CallbackRecord();
807         } else {
808             mCallbackPool = callback.next;
809             callback.next = null;
810         }
811         callback.dueTime = dueTime;
812         callback.action = action;
813         callback.token = token;
814         return callback;
815     }
816 
recycleCallbackLocked(CallbackRecord callback)817     private void recycleCallbackLocked(CallbackRecord callback) {
818         callback.action = null;
819         callback.token = null;
820         callback.next = mCallbackPool;
821         mCallbackPool = callback;
822     }
823 
824     /**
825      * Implement this interface to receive a callback when a new display frame is
826      * being rendered.  The callback is invoked on the {@link Looper} thread to
827      * which the {@link Choreographer} is attached.
828      */
829     public interface FrameCallback {
830         /**
831          * Called when a new display frame is being rendered.
832          * <p>
833          * This method provides the time in nanoseconds when the frame started being rendered.
834          * The frame time provides a stable time base for synchronizing animations
835          * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
836          * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
837          * time helps to reduce inter-frame jitter because the frame time is fixed at the time
838          * the frame was scheduled to start, regardless of when the animations or drawing
839          * callback actually runs.  All callbacks that run as part of rendering a frame will
840          * observe the same frame time so using the frame time also helps to synchronize effects
841          * that are performed by different callbacks.
842          * </p><p>
843          * Please note that the framework already takes care to process animations and
844          * drawing using the frame time as a stable time base.  Most applications should
845          * not need to use the frame time information directly.
846          * </p>
847          *
848          * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
849          * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
850          * to convert it to the {@link SystemClock#uptimeMillis()} time base.
851          */
doFrame(long frameTimeNanos)852         public void doFrame(long frameTimeNanos);
853     }
854 
855     private final class FrameHandler extends Handler {
FrameHandler(Looper looper)856         public FrameHandler(Looper looper) {
857             super(looper);
858         }
859 
860         @Override
handleMessage(Message msg)861         public void handleMessage(Message msg) {
862             switch (msg.what) {
863                 case MSG_DO_FRAME:
864                     doFrame(System.nanoTime(), 0);
865                     break;
866                 case MSG_DO_SCHEDULE_VSYNC:
867                     doScheduleVsync();
868                     break;
869                 case MSG_DO_SCHEDULE_CALLBACK:
870                     doScheduleCallback(msg.arg1);
871                     break;
872             }
873         }
874     }
875 
876     private final class FrameDisplayEventReceiver extends DisplayEventReceiver
877             implements Runnable {
878         private boolean mHavePendingVsync;
879         private long mTimestampNanos;
880         private int mFrame;
881 
FrameDisplayEventReceiver(Looper looper, int vsyncSource)882         public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
883             super(looper, vsyncSource);
884         }
885 
886         @Override
onVsync(long timestampNanos, int builtInDisplayId, int frame)887         public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
888             // Ignore vsync from secondary display.
889             // This can be problematic because the call to scheduleVsync() is a one-shot.
890             // We need to ensure that we will still receive the vsync from the primary
891             // display which is the one we really care about.  Ideally we should schedule
892             // vsync for a particular display.
893             // At this time Surface Flinger won't send us vsyncs for secondary displays
894             // but that could change in the future so let's log a message to help us remember
895             // that we need to fix this.
896             if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
897                 Log.d(TAG, "Received vsync from secondary display, but we don't support "
898                         + "this case yet.  Choreographer needs a way to explicitly request "
899                         + "vsync for a specific display to ensure it doesn't lose track "
900                         + "of its scheduled vsync.");
901                 scheduleVsync();
902                 return;
903             }
904 
905             // Post the vsync event to the Handler.
906             // The idea is to prevent incoming vsync events from completely starving
907             // the message queue.  If there are no messages in the queue with timestamps
908             // earlier than the frame time, then the vsync event will be processed immediately.
909             // Otherwise, messages that predate the vsync event will be handled first.
910             long now = System.nanoTime();
911             if (timestampNanos > now) {
912                 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
913                         + " ms in the future!  Check that graphics HAL is generating vsync "
914                         + "timestamps using the correct timebase.");
915                 timestampNanos = now;
916             }
917 
918             if (mHavePendingVsync) {
919                 Log.w(TAG, "Already have a pending vsync event.  There should only be "
920                         + "one at a time.");
921             } else {
922                 mHavePendingVsync = true;
923             }
924 
925             mTimestampNanos = timestampNanos;
926             mFrame = frame;
927             Message msg = Message.obtain(mHandler, this);
928             msg.setAsynchronous(true);
929             mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
930         }
931 
932         @Override
run()933         public void run() {
934             mHavePendingVsync = false;
935             doFrame(mTimestampNanos, mFrame);
936         }
937     }
938 
939     private static final class CallbackRecord {
940         public CallbackRecord next;
941         public long dueTime;
942         public Object action; // Runnable or FrameCallback
943         public Object token;
944 
run(long frameTimeNanos)945         public void run(long frameTimeNanos) {
946             if (token == FRAME_CALLBACK_TOKEN) {
947                 ((FrameCallback)action).doFrame(frameTimeNanos);
948             } else {
949                 ((Runnable)action).run();
950             }
951         }
952     }
953 
954     private final class CallbackQueue {
955         private CallbackRecord mHead;
956 
hasDueCallbacksLocked(long now)957         public boolean hasDueCallbacksLocked(long now) {
958             return mHead != null && mHead.dueTime <= now;
959         }
960 
extractDueCallbacksLocked(long now)961         public CallbackRecord extractDueCallbacksLocked(long now) {
962             CallbackRecord callbacks = mHead;
963             if (callbacks == null || callbacks.dueTime > now) {
964                 return null;
965             }
966 
967             CallbackRecord last = callbacks;
968             CallbackRecord next = last.next;
969             while (next != null) {
970                 if (next.dueTime > now) {
971                     last.next = null;
972                     break;
973                 }
974                 last = next;
975                 next = next.next;
976             }
977             mHead = next;
978             return callbacks;
979         }
980 
addCallbackLocked(long dueTime, Object action, Object token)981         public void addCallbackLocked(long dueTime, Object action, Object token) {
982             CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
983             CallbackRecord entry = mHead;
984             if (entry == null) {
985                 mHead = callback;
986                 return;
987             }
988             if (dueTime < entry.dueTime) {
989                 callback.next = entry;
990                 mHead = callback;
991                 return;
992             }
993             while (entry.next != null) {
994                 if (dueTime < entry.next.dueTime) {
995                     callback.next = entry.next;
996                     break;
997                 }
998                 entry = entry.next;
999             }
1000             entry.next = callback;
1001         }
1002 
removeCallbacksLocked(Object action, Object token)1003         public void removeCallbacksLocked(Object action, Object token) {
1004             CallbackRecord predecessor = null;
1005             for (CallbackRecord callback = mHead; callback != null;) {
1006                 final CallbackRecord next = callback.next;
1007                 if ((action == null || callback.action == action)
1008                         && (token == null || callback.token == token)) {
1009                     if (predecessor != null) {
1010                         predecessor.next = next;
1011                     } else {
1012                         mHead = next;
1013                     }
1014                     recycleCallbackLocked(callback);
1015                 } else {
1016                     predecessor = callback;
1017                 }
1018                 callback = next;
1019             }
1020         }
1021     }
1022 }
1023