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.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SuppressLint;
25 import android.annotation.TestApi;
26 import android.compat.annotation.UnsupportedAppUsage;
27 import android.graphics.FrameInfo;
28 import android.graphics.Insets;
29 import android.hardware.display.DisplayManagerGlobal;
30 import android.os.Build;
31 import android.os.Handler;
32 import android.os.Looper;
33 import android.os.Message;
34 import android.os.SystemClock;
35 import android.os.SystemProperties;
36 import android.os.Trace;
37 import android.util.Log;
38 import android.util.TimeUtils;
39 import android.view.animation.AnimationUtils;
40 
41 import java.io.PrintWriter;
42 
43 /**
44  * Coordinates the timing of animations, input and drawing.
45  * <p>
46  * The choreographer receives timing pulses (such as vertical synchronization)
47  * from the display subsystem then schedules work to occur as part of rendering
48  * the next display frame.
49  * </p><p>
50  * Applications typically interact with the choreographer indirectly using
51  * higher level abstractions in the animation framework or the view hierarchy.
52  * Here are some examples of things you can do using the higher-level APIs.
53  * </p>
54  * <ul>
55  * <li>To post an animation to be processed on a regular time basis synchronized with
56  * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
57  * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
58  * frame, use {@link View#postOnAnimation}.</li>
59  * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
60  * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
61  * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
62  * next display frame, use {@link View#postInvalidateOnAnimation()} or
63  * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
64  * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
65  * sync with display frame rendering, do nothing.  This already happens automatically.
66  * {@link View#onDraw} will be called at the appropriate time.</li>
67  * </ul>
68  * <p>
69  * However, there are a few cases where you might want to use the functions of the
70  * choreographer directly in your application.  Here are some examples.
71  * </p>
72  * <ul>
73  * <li>If your application does its rendering in a different thread, possibly using GL,
74  * or does not use the animation framework or view hierarchy at all
75  * and you want to ensure that it is appropriately synchronized with the display, then use
76  * {@link Choreographer#postFrameCallback}.</li>
77  * <li>... and that's about it.</li>
78  * </ul>
79  * <p>
80  * Each {@link Looper} thread has its own choreographer.  Other threads can
81  * post callbacks to run on the choreographer but they will run on the {@link Looper}
82  * to which the choreographer belongs.
83  * </p>
84  */
85 public final class Choreographer {
86     private static final String TAG = "Choreographer";
87 
88     // Prints debug messages about jank which was detected (low volume).
89     private static final boolean DEBUG_JANK = false;
90 
91     // Prints debug messages about every frame and callback registered (high volume).
92     private static final boolean DEBUG_FRAMES = false;
93 
94     // The default amount of time in ms between animation frames.
95     // When vsync is not enabled, we want to have some idea of how long we should
96     // wait before posting the next animation message.  It is important that the
97     // default value be less than the true inter-frame delay on all devices to avoid
98     // situations where we might skip frames by waiting too long (we must compensate
99     // for jitter and hardware variations).  Regardless of this value, the animation
100     // and display loop is ultimately rate-limited by how fast new graphics buffers can
101     // be dequeued.
102     private static final long DEFAULT_FRAME_DELAY = 10;
103 
104     // The number of milliseconds between animation frames.
105     private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
106 
107     // Thread local storage for the choreographer.
108     private static final ThreadLocal<Choreographer> sThreadInstance =
109             new ThreadLocal<Choreographer>() {
110         @Override
111         protected Choreographer initialValue() {
112             Looper looper = Looper.myLooper();
113             if (looper == null) {
114                 throw new IllegalStateException("The current thread must have a looper!");
115             }
116             Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
117             if (looper == Looper.getMainLooper()) {
118                 mMainInstance = choreographer;
119             }
120             return choreographer;
121         }
122     };
123 
124     private static volatile Choreographer mMainInstance;
125 
126     // Thread local storage for the SF choreographer.
127     private static final ThreadLocal<Choreographer> sSfThreadInstance =
128             new ThreadLocal<Choreographer>() {
129                 @Override
130                 protected Choreographer initialValue() {
131                     Looper looper = Looper.myLooper();
132                     if (looper == null) {
133                         throw new IllegalStateException("The current thread must have a looper!");
134                     }
135                     return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
136                 }
137             };
138 
139     // Enable/disable vsync for animations and drawing.
140     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497)
141     private static final boolean USE_VSYNC = SystemProperties.getBoolean(
142             "debug.choreographer.vsync", true);
143 
144     // Enable/disable using the frame time instead of returning now.
145     private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
146             "debug.choreographer.frametime", true);
147 
148     // Set a limit to warn about skipped frames.
149     // Skipped frames imply jank.
150     private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
151             "debug.choreographer.skipwarning", 30);
152 
153     private static final int MSG_DO_FRAME = 0;
154     private static final int MSG_DO_SCHEDULE_VSYNC = 1;
155     private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
156 
157     // All frame callbacks posted by applications have this token or VSYNC_CALLBACK_TOKEN.
158     private static final Object FRAME_CALLBACK_TOKEN = new Object() {
159         public String toString() { return "FRAME_CALLBACK_TOKEN"; }
160     };
161     private static final Object VSYNC_CALLBACK_TOKEN = new Object() {
162         public String toString() {
163             return "VSYNC_CALLBACK_TOKEN";
164         }
165     };
166 
167     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
168     private final Object mLock = new Object();
169 
170     private final Looper mLooper;
171     private final FrameHandler mHandler;
172 
173     // The display event receiver can only be accessed by the looper thread to which
174     // it is attached.  We take care to ensure that we post message to the looper
175     // if appropriate when interacting with the display event receiver.
176     @UnsupportedAppUsage
177     private final FrameDisplayEventReceiver mDisplayEventReceiver;
178 
179     private CallbackRecord mCallbackPool;
180 
181     @UnsupportedAppUsage
182     private final CallbackQueue[] mCallbackQueues;
183 
184     private boolean mFrameScheduled;
185     private boolean mCallbacksRunning;
186     @UnsupportedAppUsage
187     private long mLastFrameTimeNanos;
188 
189     /** DO NOT USE since this will not updated when screen refresh changes. */
190     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
191             publicAlternatives = "Use {@link android.view.Display#getRefreshRate} instead")
192     @Deprecated
193     private long mFrameIntervalNanos;
194     private long mLastFrameIntervalNanos;
195 
196     private boolean mDebugPrintNextFrameTimeDelta;
197     private int mFPSDivisor = 1;
198     private final DisplayEventReceiver.VsyncEventData mLastVsyncEventData =
199             new DisplayEventReceiver.VsyncEventData();
200     private final FrameData mFrameData = new FrameData();
201 
202     /**
203      * Contains information about the current frame for jank-tracking,
204      * mainly timings of key events along with a bit of metadata about
205      * view tree state
206      *
207      * TODO: Is there a better home for this? Currently Choreographer
208      * is the only one with CALLBACK_ANIMATION start time, hence why this
209      * resides here.
210      *
211      * @hide
212      */
213     FrameInfo mFrameInfo = new FrameInfo();
214 
215     /**
216      * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
217      * @hide
218      */
219     private static final String[] CALLBACK_TRACE_TITLES = {
220             "input", "animation", "insets_animation", "traversal", "commit"
221     };
222 
223     /**
224      * Callback type: Input callback.  Runs first.
225      * @hide
226      */
227     public static final int CALLBACK_INPUT = 0;
228 
229     /**
230      * Callback type: Animation callback.  Runs before {@link #CALLBACK_INSETS_ANIMATION}.
231      * @hide
232      */
233     @TestApi
234     public static final int CALLBACK_ANIMATION = 1;
235 
236     /**
237      * Callback type: Animation callback to handle inset updates. This is separate from
238      * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via
239      * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} for multiple
240      * ongoing animations but then update the whole view system with a single callback to
241      * {@link View#dispatchWindowInsetsAnimationProgress} that contains all the combined updated
242      * insets.
243      * <p>
244      * Both input and animation may change insets, so we need to run this after these callbacks, but
245      * before traversals.
246      * <p>
247      * Runs before traversals.
248      * @hide
249      */
250     public static final int CALLBACK_INSETS_ANIMATION = 2;
251 
252     /**
253      * Callback type: Traversal callback.  Handles layout and draw.  Runs
254      * after all other asynchronous messages have been handled.
255      * @hide
256      */
257     public static final int CALLBACK_TRAVERSAL = 3;
258 
259     /**
260      * Callback type: Commit callback.  Handles post-draw operations for the frame.
261      * Runs after traversal completes.  The {@link #getFrameTime() frame time} reported
262      * during this callback may be updated to reflect delays that occurred while
263      * traversals were in progress in case heavy layout operations caused some frames
264      * to be skipped.  The frame time reported during this callback provides a better
265      * estimate of the start time of the frame in which animations (and other updates
266      * to the view hierarchy state) actually took effect.
267      * @hide
268      */
269     public static final int CALLBACK_COMMIT = 4;
270 
271     private static final int CALLBACK_LAST = CALLBACK_COMMIT;
272 
Choreographer(Looper looper, int vsyncSource)273     private Choreographer(Looper looper, int vsyncSource) {
274         this(looper, vsyncSource, /* layerHandle */ 0L);
275     }
276 
Choreographer(Looper looper, int vsyncSource, long layerHandle)277     private Choreographer(Looper looper, int vsyncSource, long layerHandle) {
278         mLooper = looper;
279         mHandler = new FrameHandler(looper);
280         mDisplayEventReceiver = USE_VSYNC
281                 ? new FrameDisplayEventReceiver(looper, vsyncSource, layerHandle)
282                 : null;
283         mLastFrameTimeNanos = Long.MIN_VALUE;
284 
285         mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
286 
287         mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
288         for (int i = 0; i <= CALLBACK_LAST; i++) {
289             mCallbackQueues[i] = new CallbackQueue();
290         }
291         // b/68769804: For low FPS experiments.
292         setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
293     }
294 
getRefreshRate()295     private static float getRefreshRate() {
296         DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
297                 Display.DEFAULT_DISPLAY);
298         return di.getRefreshRate();
299     }
300 
301     /**
302      * Gets the choreographer for the calling thread.  Must be called from
303      * a thread that already has a {@link android.os.Looper} associated with it.
304      *
305      * @return The choreographer for this thread.
306      * @throws IllegalStateException if the thread does not have a looper.
307      */
getInstance()308     public static Choreographer getInstance() {
309         return sThreadInstance.get();
310     }
311 
312     /**
313      * @hide
314      */
315     @UnsupportedAppUsage
getSfInstance()316     public static Choreographer getSfInstance() {
317         return sSfThreadInstance.get();
318     }
319 
320     /**
321      * Gets the choreographer associated with the SurfaceControl.
322      *
323      * @param layerHandle to which the choreographer will be attached.
324      * @param looper      the choreographer is attached on this looper.
325      *
326      * @return The choreographer for the looper which is attached
327      * to the sourced SurfaceControl::mNativeHandle.
328      * @throws IllegalStateException if the looper sourced is null.
329      * @hide
330      */
331     @NonNull
getInstanceForSurfaceControl(long layerHandle, @NonNull Looper looper)332     static Choreographer getInstanceForSurfaceControl(long layerHandle,
333             @NonNull Looper looper) {
334         if (looper == null) {
335             throw new IllegalStateException("The current thread must have a looper!");
336         }
337         return new Choreographer(looper, VSYNC_SOURCE_APP, layerHandle);
338     }
339 
340     /**
341      * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
342      * @hide
343      */
getMainThreadInstance()344     public static Choreographer getMainThreadInstance() {
345         return mMainInstance;
346     }
347 
348     /** Destroys the calling thread's choreographer
349      * @hide
350      */
releaseInstance()351     public static void releaseInstance() {
352         Choreographer old = sThreadInstance.get();
353         sThreadInstance.remove();
354         old.dispose();
355     }
356 
dispose()357     private void dispose() {
358         mDisplayEventReceiver.dispose();
359     }
360 
361     /**
362      * Dispose the DisplayEventReceiver on the Choreographer.
363      * @hide
364      */
365     @UnsupportedAppUsage
invalidate()366     void invalidate() {
367         dispose();
368     }
369 
370     /**
371      * Check if the sourced looper and the current looper are same.
372      * @hide
373      */
isTheLooperSame(Looper looper)374     boolean isTheLooperSame(Looper looper) {
375         return mLooper == looper;
376     }
377 
378     /**
379      * The amount of time, in milliseconds, between each frame of the animation.
380      * <p>
381      * This is a requested time that the animation will attempt to honor, but the actual delay
382      * between frames may be different, depending on system load and capabilities. This is a static
383      * function because the same delay will be applied to all animations, since they are all
384      * run off of a single timing loop.
385      * </p><p>
386      * The frame delay may be ignored when the animation system uses an external timing
387      * source, such as the display refresh rate (vsync), to govern animations.
388      * </p>
389      *
390      * @return the requested time between frames, in milliseconds
391      * @hide
392      */
393     @UnsupportedAppUsage
394     @TestApi
getFrameDelay()395     public static long getFrameDelay() {
396         return sFrameDelay;
397     }
398 
399     /**
400      * The amount of time, in milliseconds, between each frame of the animation.
401      * <p>
402      * This is a requested time that the animation will attempt to honor, but the actual delay
403      * between frames may be different, depending on system load and capabilities. This is a static
404      * function because the same delay will be applied to all animations, since they are all
405      * run off of a single timing loop.
406      * </p><p>
407      * The frame delay may be ignored when the animation system uses an external timing
408      * source, such as the display refresh rate (vsync), to govern animations.
409      * </p>
410      *
411      * @param frameDelay the requested time between frames, in milliseconds
412      * @hide
413      */
414     @TestApi
setFrameDelay(long frameDelay)415     public static void setFrameDelay(long frameDelay) {
416         sFrameDelay = frameDelay;
417     }
418 
419     /**
420      * Subtracts typical frame delay time from a delay interval in milliseconds.
421      * <p>
422      * This method can be used to compensate for animation delay times that have baked
423      * in assumptions about the frame delay.  For example, it's quite common for code to
424      * assume a 60Hz frame time and bake in a 16ms delay.  When we call
425      * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
426      * posting the animation callback but let the animation timer take care of the remaining
427      * frame delay time.
428      * </p><p>
429      * This method is somewhat conservative about how much of the frame delay it
430      * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
431      * default is 10ms even though many parts of the system assume 16ms.  Consequently,
432      * we might still wait 6ms before posting an animation callback that we want to run
433      * on the next frame, but this is much better than waiting a whole 16ms and likely
434      * missing the deadline.
435      * </p>
436      *
437      * @param delayMillis The original delay time including an assumed frame delay.
438      * @return The adjusted delay time with the assumed frame delay subtracted out.
439      * @hide
440      */
subtractFrameDelay(long delayMillis)441     public static long subtractFrameDelay(long delayMillis) {
442         final long frameDelay = sFrameDelay;
443         return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
444     }
445 
446     /**
447      * @return The refresh rate as the nanoseconds between frames
448      * @hide
449      */
getFrameIntervalNanos()450     public long getFrameIntervalNanos() {
451         synchronized (mLock) {
452             return mLastFrameIntervalNanos;
453         }
454     }
455 
dump(String prefix, PrintWriter writer)456     void dump(String prefix, PrintWriter writer) {
457         String innerPrefix = prefix + "  ";
458         writer.print(prefix); writer.println("Choreographer:");
459         writer.print(innerPrefix); writer.print("mFrameScheduled=");
460                 writer.println(mFrameScheduled);
461         writer.print(innerPrefix); writer.print("mLastFrameTime=");
462                 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
463     }
464 
465     /**
466      * Posts a callback to run on the next frame.
467      * <p>
468      * The callback runs once then is automatically removed.
469      * </p>
470      *
471      * @param callbackType The callback type.
472      * @param action The callback action to run during the next frame.
473      * @param token The callback token, or null if none.
474      *
475      * @see #removeCallbacks
476      * @hide
477      */
478     @UnsupportedAppUsage
479     @TestApi
postCallback(int callbackType, Runnable action, Object token)480     public void postCallback(int callbackType, Runnable action, Object token) {
481         postCallbackDelayed(callbackType, action, token, 0);
482     }
483 
484     /**
485      * Posts a callback to run on the next frame after the specified delay.
486      * <p>
487      * The callback runs once then is automatically removed.
488      * </p>
489      *
490      * @param callbackType The callback type.
491      * @param action The callback action to run during the next frame after the specified delay.
492      * @param token The callback token, or null if none.
493      * @param delayMillis The delay time in milliseconds.
494      *
495      * @see #removeCallback
496      * @hide
497      */
498     @UnsupportedAppUsage
499     @TestApi
postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis)500     public void postCallbackDelayed(int callbackType,
501             Runnable action, Object token, long delayMillis) {
502         if (action == null) {
503             throw new IllegalArgumentException("action must not be null");
504         }
505         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
506             throw new IllegalArgumentException("callbackType is invalid");
507         }
508 
509         postCallbackDelayedInternal(callbackType, action, token, delayMillis);
510     }
511 
postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis)512     private void postCallbackDelayedInternal(int callbackType,
513             Object action, Object token, long delayMillis) {
514         if (DEBUG_FRAMES) {
515             Log.d(TAG, "PostCallback: type=" + callbackType
516                     + ", action=" + action + ", token=" + token
517                     + ", delayMillis=" + delayMillis);
518         }
519 
520         synchronized (mLock) {
521             final long now = SystemClock.uptimeMillis();
522             final long dueTime = now + delayMillis;
523             mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
524 
525             if (dueTime <= now) {
526                 scheduleFrameLocked(now);
527             } else {
528                 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
529                 msg.arg1 = callbackType;
530                 msg.setAsynchronous(true);
531                 mHandler.sendMessageAtTime(msg, dueTime);
532             }
533         }
534     }
535 
536     /**
537      * Posts a vsync callback to run on the next frame.
538      * <p>
539      * The callback runs once then is automatically removed.
540      * </p>
541      *
542      * @param callback The vsync callback to run during the next frame.
543      *
544      * @see #removeVsyncCallback
545      */
postVsyncCallback(@onNull VsyncCallback callback)546     public void postVsyncCallback(@NonNull VsyncCallback callback) {
547         if (callback == null) {
548             throw new IllegalArgumentException("callback must not be null");
549         }
550 
551         postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, VSYNC_CALLBACK_TOKEN, 0);
552     }
553 
554     /**
555      * Removes callbacks that have the specified action and token.
556      *
557      * @param callbackType The callback type.
558      * @param action The action property of the callbacks to remove, or null to remove
559      * callbacks with any action.
560      * @param token The token property of the callbacks to remove, or null to remove
561      * callbacks with any token.
562      *
563      * @see #postCallback
564      * @see #postCallbackDelayed
565      * @hide
566      */
567     @UnsupportedAppUsage
568     @TestApi
removeCallbacks(int callbackType, Runnable action, Object token)569     public void removeCallbacks(int callbackType, Runnable action, Object token) {
570         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
571             throw new IllegalArgumentException("callbackType is invalid");
572         }
573 
574         removeCallbacksInternal(callbackType, action, token);
575     }
576 
removeCallbacksInternal(int callbackType, Object action, Object token)577     private void removeCallbacksInternal(int callbackType, Object action, Object token) {
578         if (DEBUG_FRAMES) {
579             Log.d(TAG, "RemoveCallbacks: type=" + callbackType
580                     + ", action=" + action + ", token=" + token);
581         }
582 
583         synchronized (mLock) {
584             mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
585             if (action != null && token == null) {
586                 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
587             }
588         }
589     }
590 
591     /**
592      * Posts a frame callback to run on the next frame.
593      * <p>
594      * The callback runs once then is automatically removed.
595      * </p>
596      *
597      * @param callback The frame callback to run during the next frame.
598      *
599      * @see #postFrameCallbackDelayed
600      * @see #removeFrameCallback
601      */
postFrameCallback(FrameCallback callback)602     public void postFrameCallback(FrameCallback callback) {
603         postFrameCallbackDelayed(callback, 0);
604     }
605 
606     /**
607      * Posts a frame callback to run on the next frame after the specified delay.
608      * <p>
609      * The callback runs once then is automatically removed.
610      * </p>
611      *
612      * @param callback The frame callback to run during the next frame.
613      * @param delayMillis The delay time in milliseconds.
614      *
615      * @see #postFrameCallback
616      * @see #removeFrameCallback
617      */
postFrameCallbackDelayed(FrameCallback callback, long delayMillis)618     public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
619         if (callback == null) {
620             throw new IllegalArgumentException("callback must not be null");
621         }
622 
623         postCallbackDelayedInternal(CALLBACK_ANIMATION,
624                 callback, FRAME_CALLBACK_TOKEN, delayMillis);
625     }
626 
627     /**
628      * Removes a previously posted frame callback.
629      *
630      * @param callback The frame callback to remove.
631      *
632      * @see #postFrameCallback
633      * @see #postFrameCallbackDelayed
634      */
removeFrameCallback(FrameCallback callback)635     public void removeFrameCallback(FrameCallback callback) {
636         if (callback == null) {
637             throw new IllegalArgumentException("callback must not be null");
638         }
639 
640         removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
641     }
642 
643     /**
644      * Removes a previously posted vsync callback.
645      *
646      * @param callback The vsync callback to remove.
647      *
648      * @see #postVsyncCallback
649      */
removeVsyncCallback(@ullable VsyncCallback callback)650     public void removeVsyncCallback(@Nullable VsyncCallback callback) {
651         if (callback == null) {
652             throw new IllegalArgumentException("callback must not be null");
653         }
654 
655         removeCallbacksInternal(CALLBACK_ANIMATION, callback, VSYNC_CALLBACK_TOKEN);
656     }
657 
658     /**
659      * Gets the time when the current frame started.
660      * <p>
661      * This method provides the time in milliseconds when the frame started being rendered.
662      * The frame time provides a stable time base for synchronizing animations
663      * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
664      * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
665      * time helps to reduce inter-frame jitter because the frame time is fixed at the time
666      * the frame was scheduled to start, regardless of when the animations or drawing
667      * callback actually runs.  All callbacks that run as part of rendering a frame will
668      * observe the same frame time so using the frame time also helps to synchronize effects
669      * that are performed by different callbacks.
670      * </p><p>
671      * Please note that the framework already takes care to process animations and
672      * drawing using the frame time as a stable time base.  Most applications should
673      * not need to use the frame time information directly.
674      * </p><p>
675      * This method should only be called from within a callback.
676      * </p>
677      *
678      * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
679      *
680      * @throws IllegalStateException if no frame is in progress.
681      * @hide
682      */
683     @UnsupportedAppUsage
getFrameTime()684     public long getFrameTime() {
685         return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
686     }
687 
688     /**
689      * Same as {@link #getFrameTime()} but with nanosecond precision.
690      *
691      * @return The frame start time, in the {@link System#nanoTime()} time base.
692      *
693      * @throws IllegalStateException if no frame is in progress.
694      * @hide
695      */
696     @UnsupportedAppUsage
getFrameTimeNanos()697     public long getFrameTimeNanos() {
698         synchronized (mLock) {
699             if (!mCallbacksRunning) {
700                 throw new IllegalStateException("This method must only be called as "
701                         + "part of a callback while a frame is in progress.");
702             }
703             return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
704         }
705     }
706 
707     /**
708      * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
709      * whether callbacks are currently running.
710      * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
711      * @hide
712      */
getLastFrameTimeNanos()713     public long getLastFrameTimeNanos() {
714         synchronized (mLock) {
715             return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
716         }
717     }
718 
scheduleFrameLocked(long now)719     private void scheduleFrameLocked(long now) {
720         if (!mFrameScheduled) {
721             mFrameScheduled = true;
722             if (USE_VSYNC) {
723                 if (DEBUG_FRAMES) {
724                     Log.d(TAG, "Scheduling next frame on vsync.");
725                 }
726 
727                 // If running on the Looper thread, then schedule the vsync immediately,
728                 // otherwise post a message to schedule the vsync from the UI thread
729                 // as soon as possible.
730                 if (isRunningOnLooperThreadLocked()) {
731                     scheduleVsyncLocked();
732                 } else {
733                     Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
734                     msg.setAsynchronous(true);
735                     mHandler.sendMessageAtFrontOfQueue(msg);
736                 }
737             } else {
738                 final long nextFrameTime = Math.max(
739                         mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
740                 if (DEBUG_FRAMES) {
741                     Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
742                 }
743                 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
744                 msg.setAsynchronous(true);
745                 mHandler.sendMessageAtTime(msg, nextFrameTime);
746             }
747         }
748     }
749 
750     /**
751      * Returns the vsync id of the last frame callback. Client are expected to call
752      * this function from their frame callback function to get the vsyncId and pass
753      * it together with a buffer or transaction to the Surface Composer. Calling
754      * this function from anywhere else will return an undefined value.
755      *
756      * @hide
757      */
getVsyncId()758     public long getVsyncId() {
759         return mLastVsyncEventData.preferredFrameTimeline().vsyncId;
760     }
761 
762     /**
763      * Returns the frame deadline in {@link System#nanoTime()} timebase that it is allotted for the
764      * frame to be completed. Client are expected to call this function from their frame callback
765      * function. Calling this function from anywhere else will return an undefined value.
766      *
767      * @hide
768      */
getFrameDeadline()769     public long getFrameDeadline() {
770         return mLastVsyncEventData.preferredFrameTimeline().deadline;
771     }
772 
setFPSDivisor(int divisor)773     void setFPSDivisor(int divisor) {
774         if (divisor <= 0) divisor = 1;
775         mFPSDivisor = divisor;
776         ThreadedRenderer.setFPSDivisor(divisor);
777     }
778 
traceMessage(String msg)779     private void traceMessage(String msg) {
780         Trace.traceBegin(Trace.TRACE_TAG_VIEW, msg);
781         Trace.traceEnd(Trace.TRACE_TAG_VIEW);
782     }
783 
doFrame(long frameTimeNanos, int frame, DisplayEventReceiver.VsyncEventData vsyncEventData)784     void doFrame(long frameTimeNanos, int frame,
785             DisplayEventReceiver.VsyncEventData vsyncEventData) {
786         final long startNanos;
787         final long frameIntervalNanos = vsyncEventData.frameInterval;
788         boolean resynced = false;
789         try {
790             FrameTimeline timeline = mFrameData.update(frameTimeNanos, vsyncEventData);
791             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
792                 Trace.traceBegin(
793                         Trace.TRACE_TAG_VIEW, "Choreographer#doFrame " + timeline.mVsyncId);
794             }
795             synchronized (mLock) {
796                 if (!mFrameScheduled) {
797                     traceMessage("Frame not scheduled");
798                     return; // no work to do
799                 }
800 
801                 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
802                     mDebugPrintNextFrameTimeDelta = false;
803                     Log.d(TAG, "Frame time delta: "
804                             + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
805                 }
806 
807                 long intendedFrameTimeNanos = frameTimeNanos;
808                 startNanos = System.nanoTime();
809                 final long jitterNanos = startNanos - frameTimeNanos;
810                 if (jitterNanos >= frameIntervalNanos) {
811                     frameTimeNanos = startNanos;
812                     if (frameIntervalNanos == 0) {
813                         Log.i(TAG, "Vsync data empty due to timeout");
814                     } else {
815                         long lastFrameOffset = jitterNanos % frameIntervalNanos;
816                         frameTimeNanos = frameTimeNanos - lastFrameOffset;
817                         final long skippedFrames = jitterNanos / frameIntervalNanos;
818                         if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
819                             Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
820                                     + "The application may be doing too much work on its main "
821                                     + "thread.");
822                         }
823                         if (DEBUG_JANK) {
824                             Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
825                                     + "which is more than the frame interval of "
826                                     + (frameIntervalNanos * 0.000001f) + " ms!  "
827                                     + "Skipping " + skippedFrames + " frames and setting frame "
828                                     + "time to " + (lastFrameOffset * 0.000001f)
829                                     + " ms in the past.");
830                         }
831                     }
832                     timeline = mFrameData.update(
833                             frameTimeNanos, mDisplayEventReceiver, jitterNanos);
834                     resynced = true;
835                 }
836 
837                 if (frameTimeNanos < mLastFrameTimeNanos) {
838                     if (DEBUG_JANK) {
839                         Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
840                                 + "previously skipped frame.  Waiting for next vsync.");
841                     }
842                     traceMessage("Frame time goes backward");
843                     scheduleVsyncLocked();
844                     return;
845                 }
846 
847                 if (mFPSDivisor > 1) {
848                     long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
849                     if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
850                         traceMessage("Frame skipped due to FPSDivisor");
851                         scheduleVsyncLocked();
852                         return;
853                     }
854                 }
855 
856                 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos,
857                         vsyncEventData.preferredFrameTimeline().vsyncId,
858                         vsyncEventData.preferredFrameTimeline().deadline, startNanos,
859                         vsyncEventData.frameInterval);
860                 mFrameScheduled = false;
861                 mLastFrameTimeNanos = frameTimeNanos;
862                 mLastFrameIntervalNanos = frameIntervalNanos;
863                 mLastVsyncEventData.copyFrom(vsyncEventData);
864             }
865 
866             if (resynced && Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
867                 String message = String.format("Choreographer#doFrame - resynced to %d in %.1fms",
868                         timeline.mVsyncId, (timeline.mDeadlineNanos - startNanos) * 0.000001f);
869                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, message);
870             }
871 
872             AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
873 
874             mFrameInfo.markInputHandlingStart();
875             doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos);
876 
877             mFrameInfo.markAnimationsStart();
878             doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos);
879             doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos);
880 
881             mFrameInfo.markPerformTraversalsStart();
882             doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos);
883 
884             doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos);
885         } finally {
886             AnimationUtils.unlockAnimationClock();
887             if (resynced) {
888                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
889             }
890             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
891         }
892 
893         if (DEBUG_FRAMES) {
894             final long endNanos = System.nanoTime();
895             Log.d(TAG, "Frame " + frame + ": Finished, took "
896                     + (endNanos - startNanos) * 0.000001f + " ms, latency "
897                     + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
898         }
899     }
900 
doCallbacks(int callbackType, long frameIntervalNanos)901     void doCallbacks(int callbackType, long frameIntervalNanos) {
902         CallbackRecord callbacks;
903         long frameTimeNanos = mFrameData.mFrameTimeNanos;
904         synchronized (mLock) {
905             // We use "now" to determine when callbacks become due because it's possible
906             // for earlier processing phases in a frame to post callbacks that should run
907             // in a following phase, such as an input event that causes an animation to start.
908             final long now = System.nanoTime();
909             callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
910                     now / TimeUtils.NANOS_PER_MS);
911             if (callbacks == null) {
912                 return;
913             }
914             mCallbacksRunning = true;
915 
916             // Update the frame time if necessary when committing the frame.
917             // We only update the frame time if we are more than 2 frames late reaching
918             // the commit phase.  This ensures that the frame time which is observed by the
919             // callbacks will always increase from one frame to the next and never repeat.
920             // We never want the next frame's starting frame time to end up being less than
921             // or equal to the previous frame's commit frame time.  Keep in mind that the
922             // next frame has most likely already been scheduled by now so we play it
923             // safe by ensuring the commit time is always at least one frame behind.
924             if (callbackType == Choreographer.CALLBACK_COMMIT) {
925                 final long jitterNanos = now - frameTimeNanos;
926                 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
927                 if (jitterNanos >= 2 * frameIntervalNanos) {
928                     final long lastFrameOffset = jitterNanos % frameIntervalNanos
929                             + frameIntervalNanos;
930                     if (DEBUG_JANK) {
931                         Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
932                                 + " ms which is more than twice the frame interval of "
933                                 + (frameIntervalNanos * 0.000001f) + " ms!  "
934                                 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
935                                 + " ms in the past.");
936                         mDebugPrintNextFrameTimeDelta = true;
937                     }
938                     frameTimeNanos = now - lastFrameOffset;
939                     mLastFrameTimeNanos = frameTimeNanos;
940                     mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos);
941                 }
942             }
943         }
944         try {
945             Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
946             for (CallbackRecord c = callbacks; c != null; c = c.next) {
947                 if (DEBUG_FRAMES) {
948                     Log.d(TAG, "RunCallback: type=" + callbackType
949                             + ", action=" + c.action + ", token=" + c.token
950                             + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
951                 }
952                 c.run(mFrameData);
953             }
954         } finally {
955             synchronized (mLock) {
956                 mCallbacksRunning = false;
957                 do {
958                     final CallbackRecord next = callbacks.next;
959                     recycleCallbackLocked(callbacks);
960                     callbacks = next;
961                 } while (callbacks != null);
962             }
963             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
964         }
965     }
966 
doScheduleVsync()967     void doScheduleVsync() {
968         synchronized (mLock) {
969             if (mFrameScheduled) {
970                 scheduleVsyncLocked();
971             }
972         }
973     }
974 
doScheduleCallback(int callbackType)975     void doScheduleCallback(int callbackType) {
976         synchronized (mLock) {
977             if (!mFrameScheduled) {
978                 final long now = SystemClock.uptimeMillis();
979                 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
980                     scheduleFrameLocked(now);
981                 }
982             }
983         }
984     }
985 
986     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
scheduleVsyncLocked()987     private void scheduleVsyncLocked() {
988         try {
989             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
990             mDisplayEventReceiver.scheduleVsync();
991         } finally {
992             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
993         }
994     }
995 
isRunningOnLooperThreadLocked()996     private boolean isRunningOnLooperThreadLocked() {
997         return Looper.myLooper() == mLooper;
998     }
999 
obtainCallbackLocked(long dueTime, Object action, Object token)1000     private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
1001         CallbackRecord callback = mCallbackPool;
1002         if (callback == null) {
1003             callback = new CallbackRecord();
1004         } else {
1005             mCallbackPool = callback.next;
1006             callback.next = null;
1007         }
1008         callback.dueTime = dueTime;
1009         callback.action = action;
1010         callback.token = token;
1011         return callback;
1012     }
1013 
recycleCallbackLocked(CallbackRecord callback)1014     private void recycleCallbackLocked(CallbackRecord callback) {
1015         callback.action = null;
1016         callback.token = null;
1017         callback.next = mCallbackPool;
1018         mCallbackPool = callback;
1019     }
1020 
1021     /**
1022      * Implement this interface to receive a callback when a new display frame is
1023      * being rendered.  The callback is invoked on the {@link Looper} thread to
1024      * which the {@link Choreographer} is attached.
1025      */
1026     public interface FrameCallback {
1027         /**
1028          * Called when a new display frame is being rendered.
1029          * <p>
1030          * This method provides the time in nanoseconds when the frame started being rendered.
1031          * The frame time provides a stable time base for synchronizing animations
1032          * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
1033          * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
1034          * time helps to reduce inter-frame jitter because the frame time is fixed at the time
1035          * the frame was scheduled to start, regardless of when the animations or drawing
1036          * callback actually runs.  All callbacks that run as part of rendering a frame will
1037          * observe the same frame time so using the frame time also helps to synchronize effects
1038          * that are performed by different callbacks.
1039          * </p><p>
1040          * Please note that the framework already takes care to process animations and
1041          * drawing using the frame time as a stable time base.  Most applications should
1042          * not need to use the frame time information directly.
1043          * </p>
1044          *
1045          * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
1046          * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
1047          * to convert it to the {@link SystemClock#uptimeMillis()} time base.
1048          */
doFrame(long frameTimeNanos)1049         public void doFrame(long frameTimeNanos);
1050     }
1051 
1052     /** Holds data that describes one possible VSync frame event to render at. */
1053     public static class FrameTimeline {
1054         private long mVsyncId = FrameInfo.INVALID_VSYNC_ID;
1055         private long mExpectedPresentationTimeNanos = -1;
1056         private long mDeadlineNanos = -1;
1057         private boolean mInCallback = false;
1058 
FrameTimeline()1059         FrameTimeline() {
1060             // Intentionally empty; defined so that it is not API/public by default.
1061         }
1062 
setInCallback(boolean inCallback)1063         void setInCallback(boolean inCallback) {
1064             mInCallback = inCallback;
1065         }
1066 
checkInCallback()1067         private void checkInCallback() {
1068             if (!mInCallback) {
1069                 throw new IllegalStateException(
1070                         "FrameTimeline is not valid outside of the vsync callback");
1071             }
1072         }
1073 
update(long vsyncId, long expectedPresentationTimeNanos, long deadlineNanos)1074         void update(long vsyncId, long expectedPresentationTimeNanos, long deadlineNanos) {
1075             mVsyncId = vsyncId;
1076             mExpectedPresentationTimeNanos = expectedPresentationTimeNanos;
1077             mDeadlineNanos = deadlineNanos;
1078         }
1079 
1080         /**
1081          * The id that corresponds to this frame timeline, used to correlate a frame
1082          * produced by HWUI with the timeline data stored in Surface Flinger.
1083          */
getVsyncId()1084         public long getVsyncId() {
1085             checkInCallback();
1086             return mVsyncId;
1087         }
1088 
1089         /**
1090          * The time in {@link System#nanoTime()} timebase which this frame is expected to be
1091          * presented.
1092          */
getExpectedPresentationTimeNanos()1093         public long getExpectedPresentationTimeNanos() {
1094             checkInCallback();
1095             return mExpectedPresentationTimeNanos;
1096         }
1097 
1098         /**
1099          * The time in  {@link System#nanoTime()} timebase which this frame needs to be ready by.
1100          */
getDeadlineNanos()1101         public long getDeadlineNanos() {
1102             checkInCallback();
1103             return mDeadlineNanos;
1104         }
1105     }
1106 
1107     /**
1108      * The payload for {@link VsyncCallback} which includes frame information such as when
1109      * the frame started being rendered, and multiple possible frame timelines and their
1110      * information including deadline and expected present time.
1111      */
1112     public static class FrameData {
1113         private long mFrameTimeNanos;
1114         private FrameTimeline[] mFrameTimelines;
1115         private int mPreferredFrameTimelineIndex;
1116         private boolean mInCallback = false;
1117 
FrameData()1118         FrameData() {
1119             allocateFrameTimelines(DisplayEventReceiver.VsyncEventData.FRAME_TIMELINES_CAPACITY);
1120         }
1121 
1122         /** The time in nanoseconds when the frame started being rendered. */
getFrameTimeNanos()1123         public long getFrameTimeNanos() {
1124             checkInCallback();
1125             return mFrameTimeNanos;
1126         }
1127 
1128         /** The possible frame timelines, sorted chronologically. */
1129         @NonNull
1130         @SuppressLint("ArrayReturn") // For API consistency and speed.
getFrameTimelines()1131         public FrameTimeline[] getFrameTimelines() {
1132             checkInCallback();
1133             return mFrameTimelines;
1134         }
1135 
1136         /** The platform-preferred frame timeline. */
1137         @NonNull
getPreferredFrameTimeline()1138         public FrameTimeline getPreferredFrameTimeline() {
1139             checkInCallback();
1140             return mFrameTimelines[mPreferredFrameTimelineIndex];
1141         }
1142 
setInCallback(boolean inCallback)1143         void setInCallback(boolean inCallback) {
1144             mInCallback = inCallback;
1145             for (int i = 0; i < mFrameTimelines.length; i++) {
1146                 mFrameTimelines[i].setInCallback(inCallback);
1147             }
1148         }
1149 
checkInCallback()1150         private void checkInCallback() {
1151             if (!mInCallback) {
1152                 throw new IllegalStateException(
1153                         "FrameData is not valid outside of the vsync callback");
1154             }
1155         }
1156 
allocateFrameTimelines(int length)1157         private void allocateFrameTimelines(int length) {
1158             // Maintain one default frame timeline for API (such as getFrameTimelines and
1159             // getPreferredFrameTimeline) consistency. It should have default data when accessed.
1160             length = Math.max(1, length);
1161 
1162             if (mFrameTimelines == null || mFrameTimelines.length != length) {
1163                 mFrameTimelines = new FrameTimeline[length];
1164                 for (int i = 0; i < mFrameTimelines.length; i++) {
1165                     mFrameTimelines[i] = new FrameTimeline();
1166                 }
1167             }
1168         }
1169 
1170         /**
1171          * Update the frame data with a {@code DisplayEventReceiver.VsyncEventData} received from
1172          * native.
1173          */
update( long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData)1174         FrameTimeline update(
1175                 long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
1176             allocateFrameTimelines(vsyncEventData.frameTimelinesLength);
1177             mFrameTimeNanos = frameTimeNanos;
1178             mPreferredFrameTimelineIndex = vsyncEventData.preferredFrameTimelineIndex;
1179             for (int i = 0; i < mFrameTimelines.length; i++) {
1180                 DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
1181                         vsyncEventData.frameTimelines[i];
1182                 mFrameTimelines[i].update(frameTimeline.vsyncId,
1183                         frameTimeline.expectedPresentationTime, frameTimeline.deadline);
1184             }
1185             return mFrameTimelines[mPreferredFrameTimelineIndex];
1186         }
1187 
1188         /**
1189          * Update the frame data when the frame is late.
1190          *
1191          * @param jitterNanos currentTime - frameTime
1192          */
update( long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos)1193         FrameTimeline update(
1194                 long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos) {
1195             int newPreferredIndex = 0;
1196             final long minimumDeadline =
1197                     mFrameTimelines[mPreferredFrameTimelineIndex].mDeadlineNanos + jitterNanos;
1198             // Look for a non-past deadline timestamp in the existing frame data. Otherwise, binder
1199             // query for new frame data. Note that binder is relatively slow, O(ms), so it is
1200             // only called when the existing frame data does not hold a valid frame.
1201             while (newPreferredIndex < mFrameTimelines.length - 1
1202                     && mFrameTimelines[newPreferredIndex].mDeadlineNanos < minimumDeadline) {
1203                 newPreferredIndex++;
1204             }
1205 
1206             long newPreferredDeadline = mFrameTimelines[newPreferredIndex].mDeadlineNanos;
1207             if (newPreferredDeadline < minimumDeadline) {
1208                 DisplayEventReceiver.VsyncEventData latestVsyncEventData =
1209                         displayEventReceiver.getLatestVsyncEventData();
1210                 if (latestVsyncEventData == null) {
1211                     Log.w(TAG, "Could not get latest VsyncEventData. Did SurfaceFlinger crash?");
1212                 } else {
1213                     update(frameTimeNanos, latestVsyncEventData);
1214                 }
1215             } else {
1216                 update(frameTimeNanos, newPreferredIndex);
1217             }
1218             return mFrameTimelines[mPreferredFrameTimelineIndex];
1219         }
1220 
update(long frameTimeNanos, int newPreferredFrameTimelineIndex)1221         void update(long frameTimeNanos, int newPreferredFrameTimelineIndex) {
1222             mFrameTimeNanos = frameTimeNanos;
1223             mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex;
1224         }
1225     }
1226 
1227     /**
1228      * Implement this interface to receive a callback to start the next frame. The callback is
1229      * invoked on the {@link Looper} thread to which the {@link Choreographer} is attached. The
1230      * callback payload contains information about multiple possible frames, allowing choice of
1231      * the appropriate frame based on latency requirements.
1232      *
1233      * @see FrameCallback
1234      */
1235     public interface VsyncCallback {
1236         /**
1237          * Called when a new display frame is being rendered.
1238          *
1239          * @param data The payload which includes frame information. Divide nanosecond values by
1240          *             {@code 1000000} to convert it to the {@link SystemClock#uptimeMillis()}
1241          *             time base. {@code data} is not valid outside of {@code onVsync} and should
1242          *             not be accessed outside the callback.
1243          * @see FrameCallback#doFrame
1244          **/
onVsync(@onNull FrameData data)1245         void onVsync(@NonNull FrameData data);
1246     }
1247 
1248     private final class FrameHandler extends Handler {
FrameHandler(Looper looper)1249         public FrameHandler(Looper looper) {
1250             super(looper);
1251         }
1252 
1253         @Override
handleMessage(Message msg)1254         public void handleMessage(Message msg) {
1255             switch (msg.what) {
1256                 case MSG_DO_FRAME:
1257                     doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData());
1258                     break;
1259                 case MSG_DO_SCHEDULE_VSYNC:
1260                     doScheduleVsync();
1261                     break;
1262                 case MSG_DO_SCHEDULE_CALLBACK:
1263                     doScheduleCallback(msg.arg1);
1264                     break;
1265             }
1266         }
1267     }
1268 
1269     private final class FrameDisplayEventReceiver extends DisplayEventReceiver
1270             implements Runnable {
1271         private boolean mHavePendingVsync;
1272         private long mTimestampNanos;
1273         private int mFrame;
1274         private final VsyncEventData mLastVsyncEventData = new VsyncEventData();
1275 
FrameDisplayEventReceiver(Looper looper, int vsyncSource, long layerHandle)1276         FrameDisplayEventReceiver(Looper looper, int vsyncSource, long layerHandle) {
1277             super(looper, vsyncSource, /* eventRegistration */ 0, layerHandle);
1278         }
1279 
1280         // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
1281         // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
1282         // for the internal display implicitly.
1283         @Override
onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData)1284         public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
1285                 VsyncEventData vsyncEventData) {
1286             try {
1287                 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1288                     Trace.traceBegin(Trace.TRACE_TAG_VIEW,
1289                             "Choreographer#onVsync "
1290                                     + vsyncEventData.preferredFrameTimeline().vsyncId);
1291                 }
1292                 // Post the vsync event to the Handler.
1293                 // The idea is to prevent incoming vsync events from completely starving
1294                 // the message queue.  If there are no messages in the queue with timestamps
1295                 // earlier than the frame time, then the vsync event will be processed immediately.
1296                 // Otherwise, messages that predate the vsync event will be handled first.
1297                 long now = System.nanoTime();
1298                 if (timestampNanos > now) {
1299                     Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
1300                             + " ms in the future!  Check that graphics HAL is generating vsync "
1301                             + "timestamps using the correct timebase.");
1302                     timestampNanos = now;
1303                 }
1304 
1305                 if (mHavePendingVsync) {
1306                     Log.w(TAG, "Already have a pending vsync event.  There should only be "
1307                             + "one at a time.");
1308                 } else {
1309                     mHavePendingVsync = true;
1310                 }
1311 
1312                 mTimestampNanos = timestampNanos;
1313                 mFrame = frame;
1314                 mLastVsyncEventData.copyFrom(vsyncEventData);
1315                 Message msg = Message.obtain(mHandler, this);
1316                 msg.setAsynchronous(true);
1317                 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
1318             } finally {
1319                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1320             }
1321         }
1322 
1323         @Override
run()1324         public void run() {
1325             mHavePendingVsync = false;
1326             doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
1327         }
1328     }
1329 
1330     private static final class CallbackRecord {
1331         public CallbackRecord next;
1332         public long dueTime;
1333         /** Runnable or FrameCallback or VsyncCallback object. */
1334         public Object action;
1335         /** Denotes the action type. */
1336         public Object token;
1337 
1338         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
run(long frameTimeNanos)1339         public void run(long frameTimeNanos) {
1340             if (token == FRAME_CALLBACK_TOKEN) {
1341                 ((FrameCallback)action).doFrame(frameTimeNanos);
1342             } else {
1343                 ((Runnable)action).run();
1344             }
1345         }
1346 
run(FrameData frameData)1347         void run(FrameData frameData) {
1348             frameData.setInCallback(true);
1349             if (token == VSYNC_CALLBACK_TOKEN) {
1350                 ((VsyncCallback) action).onVsync(frameData);
1351             } else {
1352                 run(frameData.getFrameTimeNanos());
1353             }
1354             frameData.setInCallback(false);
1355         }
1356     }
1357 
1358     private final class CallbackQueue {
1359         private CallbackRecord mHead;
1360 
hasDueCallbacksLocked(long now)1361         public boolean hasDueCallbacksLocked(long now) {
1362             return mHead != null && mHead.dueTime <= now;
1363         }
1364 
extractDueCallbacksLocked(long now)1365         public CallbackRecord extractDueCallbacksLocked(long now) {
1366             CallbackRecord callbacks = mHead;
1367             if (callbacks == null || callbacks.dueTime > now) {
1368                 return null;
1369             }
1370 
1371             CallbackRecord last = callbacks;
1372             CallbackRecord next = last.next;
1373             while (next != null) {
1374                 if (next.dueTime > now) {
1375                     last.next = null;
1376                     break;
1377                 }
1378                 last = next;
1379                 next = next.next;
1380             }
1381             mHead = next;
1382             return callbacks;
1383         }
1384 
1385         @UnsupportedAppUsage
addCallbackLocked(long dueTime, Object action, Object token)1386         public void addCallbackLocked(long dueTime, Object action, Object token) {
1387             CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
1388             CallbackRecord entry = mHead;
1389             if (entry == null) {
1390                 mHead = callback;
1391                 return;
1392             }
1393             if (dueTime < entry.dueTime) {
1394                 callback.next = entry;
1395                 mHead = callback;
1396                 return;
1397             }
1398             while (entry.next != null) {
1399                 if (dueTime < entry.next.dueTime) {
1400                     callback.next = entry.next;
1401                     break;
1402                 }
1403                 entry = entry.next;
1404             }
1405             entry.next = callback;
1406         }
1407 
removeCallbacksLocked(Object action, Object token)1408         public void removeCallbacksLocked(Object action, Object token) {
1409             CallbackRecord predecessor = null;
1410             for (CallbackRecord callback = mHead; callback != null;) {
1411                 final CallbackRecord next = callback.next;
1412                 if ((action == null || callback.action == action)
1413                         && (token == null || callback.token == token)) {
1414                     if (predecessor != null) {
1415                         predecessor.next = next;
1416                     } else {
1417                         mHead = next;
1418                     }
1419                     recycleCallbackLocked(callback);
1420                 } else {
1421                     predecessor = callback;
1422                 }
1423                 callback = next;
1424             }
1425         }
1426     }
1427 }
1428