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