• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 DisplayEventReceiver.VsyncEventData mLastVsyncEventData =
199             new DisplayEventReceiver.VsyncEventData();
200 
201     /**
202      * Contains information about the current frame for jank-tracking,
203      * mainly timings of key events along with a bit of metadata about
204      * view tree state
205      *
206      * TODO: Is there a better home for this? Currently Choreographer
207      * is the only one with CALLBACK_ANIMATION start time, hence why this
208      * resides here.
209      *
210      * @hide
211      */
212     FrameInfo mFrameInfo = new FrameInfo();
213 
214     /**
215      * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
216      * @hide
217      */
218     private static final String[] CALLBACK_TRACE_TITLES = {
219             "input", "animation", "insets_animation", "traversal", "commit"
220     };
221 
222     /**
223      * Callback type: Input callback.  Runs first.
224      * @hide
225      */
226     public static final int CALLBACK_INPUT = 0;
227 
228     /**
229      * Callback type: Animation callback.  Runs before {@link #CALLBACK_INSETS_ANIMATION}.
230      * @hide
231      */
232     @TestApi
233     public static final int CALLBACK_ANIMATION = 1;
234 
235     /**
236      * Callback type: Animation callback to handle inset updates. This is separate from
237      * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via
238      * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} for multiple
239      * ongoing animations but then update the whole view system with a single callback to
240      * {@link View#dispatchWindowInsetsAnimationProgress} that contains all the combined updated
241      * insets.
242      * <p>
243      * Both input and animation may change insets, so we need to run this after these callbacks, but
244      * before traversals.
245      * <p>
246      * Runs before traversals.
247      * @hide
248      */
249     public static final int CALLBACK_INSETS_ANIMATION = 2;
250 
251     /**
252      * Callback type: Traversal callback.  Handles layout and draw.  Runs
253      * after all other asynchronous messages have been handled.
254      * @hide
255      */
256     public static final int CALLBACK_TRAVERSAL = 3;
257 
258     /**
259      * Callback type: Commit callback.  Handles post-draw operations for the frame.
260      * Runs after traversal completes.  The {@link #getFrameTime() frame time} reported
261      * during this callback may be updated to reflect delays that occurred while
262      * traversals were in progress in case heavy layout operations caused some frames
263      * to be skipped.  The frame time reported during this callback provides a better
264      * estimate of the start time of the frame in which animations (and other updates
265      * to the view hierarchy state) actually took effect.
266      * @hide
267      */
268     public static final int CALLBACK_COMMIT = 4;
269 
270     private static final int CALLBACK_LAST = CALLBACK_COMMIT;
271 
Choreographer(Looper looper, int vsyncSource)272     private Choreographer(Looper looper, int vsyncSource) {
273         mLooper = looper;
274         mHandler = new FrameHandler(looper);
275         mDisplayEventReceiver = USE_VSYNC
276                 ? new FrameDisplayEventReceiver(looper, vsyncSource)
277                 : null;
278         mLastFrameTimeNanos = Long.MIN_VALUE;
279 
280         mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
281 
282         mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
283         for (int i = 0; i <= CALLBACK_LAST; i++) {
284             mCallbackQueues[i] = new CallbackQueue();
285         }
286         // b/68769804: For low FPS experiments.
287         setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
288     }
289 
getRefreshRate()290     private static float getRefreshRate() {
291         DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
292                 Display.DEFAULT_DISPLAY);
293         return di.getRefreshRate();
294     }
295 
296     /**
297      * Gets the choreographer for the calling thread.  Must be called from
298      * a thread that already has a {@link android.os.Looper} associated with it.
299      *
300      * @return The choreographer for this thread.
301      * @throws IllegalStateException if the thread does not have a looper.
302      */
getInstance()303     public static Choreographer getInstance() {
304         return sThreadInstance.get();
305     }
306 
307     /**
308      * @hide
309      */
310     @UnsupportedAppUsage
getSfInstance()311     public static Choreographer getSfInstance() {
312         return sSfThreadInstance.get();
313     }
314 
315     /**
316      * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
317      * @hide
318      */
getMainThreadInstance()319     public static Choreographer getMainThreadInstance() {
320         return mMainInstance;
321     }
322 
323     /** Destroys the calling thread's choreographer
324      * @hide
325      */
releaseInstance()326     public static void releaseInstance() {
327         Choreographer old = sThreadInstance.get();
328         sThreadInstance.remove();
329         old.dispose();
330     }
331 
dispose()332     private void dispose() {
333         mDisplayEventReceiver.dispose();
334     }
335 
336     /**
337      * The amount of time, in milliseconds, between each frame of the animation.
338      * <p>
339      * This is a requested time that the animation will attempt to honor, but the actual delay
340      * between frames may be different, depending on system load and capabilities. This is a static
341      * function because the same delay will be applied to all animations, since they are all
342      * run off of a single timing loop.
343      * </p><p>
344      * The frame delay may be ignored when the animation system uses an external timing
345      * source, such as the display refresh rate (vsync), to govern animations.
346      * </p>
347      *
348      * @return the requested time between frames, in milliseconds
349      * @hide
350      */
351     @UnsupportedAppUsage
352     @TestApi
getFrameDelay()353     public static long getFrameDelay() {
354         return sFrameDelay;
355     }
356 
357     /**
358      * The amount of time, in milliseconds, between each frame of the animation.
359      * <p>
360      * This is a requested time that the animation will attempt to honor, but the actual delay
361      * between frames may be different, depending on system load and capabilities. This is a static
362      * function because the same delay will be applied to all animations, since they are all
363      * run off of a single timing loop.
364      * </p><p>
365      * The frame delay may be ignored when the animation system uses an external timing
366      * source, such as the display refresh rate (vsync), to govern animations.
367      * </p>
368      *
369      * @param frameDelay the requested time between frames, in milliseconds
370      * @hide
371      */
372     @TestApi
setFrameDelay(long frameDelay)373     public static void setFrameDelay(long frameDelay) {
374         sFrameDelay = frameDelay;
375     }
376 
377     /**
378      * Subtracts typical frame delay time from a delay interval in milliseconds.
379      * <p>
380      * This method can be used to compensate for animation delay times that have baked
381      * in assumptions about the frame delay.  For example, it's quite common for code to
382      * assume a 60Hz frame time and bake in a 16ms delay.  When we call
383      * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
384      * posting the animation callback but let the animation timer take care of the remaining
385      * frame delay time.
386      * </p><p>
387      * This method is somewhat conservative about how much of the frame delay it
388      * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
389      * default is 10ms even though many parts of the system assume 16ms.  Consequently,
390      * we might still wait 6ms before posting an animation callback that we want to run
391      * on the next frame, but this is much better than waiting a whole 16ms and likely
392      * missing the deadline.
393      * </p>
394      *
395      * @param delayMillis The original delay time including an assumed frame delay.
396      * @return The adjusted delay time with the assumed frame delay subtracted out.
397      * @hide
398      */
subtractFrameDelay(long delayMillis)399     public static long subtractFrameDelay(long delayMillis) {
400         final long frameDelay = sFrameDelay;
401         return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
402     }
403 
404     /**
405      * @return The refresh rate as the nanoseconds between frames
406      * @hide
407      */
getFrameIntervalNanos()408     public long getFrameIntervalNanos() {
409         synchronized (mLock) {
410             return mLastFrameIntervalNanos;
411         }
412     }
413 
dump(String prefix, PrintWriter writer)414     void dump(String prefix, PrintWriter writer) {
415         String innerPrefix = prefix + "  ";
416         writer.print(prefix); writer.println("Choreographer:");
417         writer.print(innerPrefix); writer.print("mFrameScheduled=");
418                 writer.println(mFrameScheduled);
419         writer.print(innerPrefix); writer.print("mLastFrameTime=");
420                 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
421     }
422 
423     /**
424      * Posts a callback to run on the next frame.
425      * <p>
426      * The callback runs once then is automatically removed.
427      * </p>
428      *
429      * @param callbackType The callback type.
430      * @param action The callback action to run during the next frame.
431      * @param token The callback token, or null if none.
432      *
433      * @see #removeCallbacks
434      * @hide
435      */
436     @UnsupportedAppUsage
437     @TestApi
postCallback(int callbackType, Runnable action, Object token)438     public void postCallback(int callbackType, Runnable action, Object token) {
439         postCallbackDelayed(callbackType, action, token, 0);
440     }
441 
442     /**
443      * Posts a callback to run on the next frame after the specified delay.
444      * <p>
445      * The callback runs once then is automatically removed.
446      * </p>
447      *
448      * @param callbackType The callback type.
449      * @param action The callback action to run during the next frame after the specified delay.
450      * @param token The callback token, or null if none.
451      * @param delayMillis The delay time in milliseconds.
452      *
453      * @see #removeCallback
454      * @hide
455      */
456     @UnsupportedAppUsage
457     @TestApi
postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis)458     public void postCallbackDelayed(int callbackType,
459             Runnable action, Object token, long delayMillis) {
460         if (action == null) {
461             throw new IllegalArgumentException("action must not be null");
462         }
463         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
464             throw new IllegalArgumentException("callbackType is invalid");
465         }
466 
467         postCallbackDelayedInternal(callbackType, action, token, delayMillis);
468     }
469 
postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis)470     private void postCallbackDelayedInternal(int callbackType,
471             Object action, Object token, long delayMillis) {
472         if (DEBUG_FRAMES) {
473             Log.d(TAG, "PostCallback: type=" + callbackType
474                     + ", action=" + action + ", token=" + token
475                     + ", delayMillis=" + delayMillis);
476         }
477 
478         synchronized (mLock) {
479             final long now = SystemClock.uptimeMillis();
480             final long dueTime = now + delayMillis;
481             mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
482 
483             if (dueTime <= now) {
484                 scheduleFrameLocked(now);
485             } else {
486                 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
487                 msg.arg1 = callbackType;
488                 msg.setAsynchronous(true);
489                 mHandler.sendMessageAtTime(msg, dueTime);
490             }
491         }
492     }
493 
494     /**
495      * Posts a vsync callback to run on the next frame.
496      * <p>
497      * The callback runs once then is automatically removed.
498      * </p>
499      *
500      * @param callback The vsync callback to run during the next frame.
501      *
502      * @see #removeVsyncCallback
503      */
postVsyncCallback(@onNull VsyncCallback callback)504     public void postVsyncCallback(@NonNull VsyncCallback callback) {
505         if (callback == null) {
506             throw new IllegalArgumentException("callback must not be null");
507         }
508 
509         postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, VSYNC_CALLBACK_TOKEN, 0);
510     }
511 
512     /**
513      * Removes callbacks that have the specified action and token.
514      *
515      * @param callbackType The callback type.
516      * @param action The action property of the callbacks to remove, or null to remove
517      * callbacks with any action.
518      * @param token The token property of the callbacks to remove, or null to remove
519      * callbacks with any token.
520      *
521      * @see #postCallback
522      * @see #postCallbackDelayed
523      * @hide
524      */
525     @UnsupportedAppUsage
526     @TestApi
removeCallbacks(int callbackType, Runnable action, Object token)527     public void removeCallbacks(int callbackType, Runnable action, Object token) {
528         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
529             throw new IllegalArgumentException("callbackType is invalid");
530         }
531 
532         removeCallbacksInternal(callbackType, action, token);
533     }
534 
removeCallbacksInternal(int callbackType, Object action, Object token)535     private void removeCallbacksInternal(int callbackType, Object action, Object token) {
536         if (DEBUG_FRAMES) {
537             Log.d(TAG, "RemoveCallbacks: type=" + callbackType
538                     + ", action=" + action + ", token=" + token);
539         }
540 
541         synchronized (mLock) {
542             mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
543             if (action != null && token == null) {
544                 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
545             }
546         }
547     }
548 
549     /**
550      * Posts a frame callback to run on the next frame.
551      * <p>
552      * The callback runs once then is automatically removed.
553      * </p>
554      *
555      * @param callback The frame callback to run during the next frame.
556      *
557      * @see #postFrameCallbackDelayed
558      * @see #removeFrameCallback
559      */
postFrameCallback(FrameCallback callback)560     public void postFrameCallback(FrameCallback callback) {
561         postFrameCallbackDelayed(callback, 0);
562     }
563 
564     /**
565      * Posts a frame callback to run on the next frame after the specified delay.
566      * <p>
567      * The callback runs once then is automatically removed.
568      * </p>
569      *
570      * @param callback The frame callback to run during the next frame.
571      * @param delayMillis The delay time in milliseconds.
572      *
573      * @see #postFrameCallback
574      * @see #removeFrameCallback
575      */
postFrameCallbackDelayed(FrameCallback callback, long delayMillis)576     public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
577         if (callback == null) {
578             throw new IllegalArgumentException("callback must not be null");
579         }
580 
581         postCallbackDelayedInternal(CALLBACK_ANIMATION,
582                 callback, FRAME_CALLBACK_TOKEN, delayMillis);
583     }
584 
585     /**
586      * Removes a previously posted frame callback.
587      *
588      * @param callback The frame callback to remove.
589      *
590      * @see #postFrameCallback
591      * @see #postFrameCallbackDelayed
592      */
removeFrameCallback(FrameCallback callback)593     public void removeFrameCallback(FrameCallback callback) {
594         if (callback == null) {
595             throw new IllegalArgumentException("callback must not be null");
596         }
597 
598         removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
599     }
600 
601     /**
602      * Removes a previously posted vsync callback.
603      *
604      * @param callback The vsync callback to remove.
605      *
606      * @see #postVsyncCallback
607      */
removeVsyncCallback(@ullable VsyncCallback callback)608     public void removeVsyncCallback(@Nullable VsyncCallback callback) {
609         if (callback == null) {
610             throw new IllegalArgumentException("callback must not be null");
611         }
612 
613         removeCallbacksInternal(CALLBACK_ANIMATION, callback, VSYNC_CALLBACK_TOKEN);
614     }
615 
616     /**
617      * Gets the time when the current frame started.
618      * <p>
619      * This method provides the time in milliseconds when the frame started being rendered.
620      * The frame time provides a stable time base for synchronizing animations
621      * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
622      * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
623      * time helps to reduce inter-frame jitter because the frame time is fixed at the time
624      * the frame was scheduled to start, regardless of when the animations or drawing
625      * callback actually runs.  All callbacks that run as part of rendering a frame will
626      * observe the same frame time so using the frame time also helps to synchronize effects
627      * that are performed by different callbacks.
628      * </p><p>
629      * Please note that the framework already takes care to process animations and
630      * drawing using the frame time as a stable time base.  Most applications should
631      * not need to use the frame time information directly.
632      * </p><p>
633      * This method should only be called from within a callback.
634      * </p>
635      *
636      * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
637      *
638      * @throws IllegalStateException if no frame is in progress.
639      * @hide
640      */
641     @UnsupportedAppUsage
getFrameTime()642     public long getFrameTime() {
643         return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
644     }
645 
646     /**
647      * Same as {@link #getFrameTime()} but with nanosecond precision.
648      *
649      * @return The frame start time, in the {@link System#nanoTime()} time base.
650      *
651      * @throws IllegalStateException if no frame is in progress.
652      * @hide
653      */
654     @UnsupportedAppUsage
getFrameTimeNanos()655     public long getFrameTimeNanos() {
656         synchronized (mLock) {
657             if (!mCallbacksRunning) {
658                 throw new IllegalStateException("This method must only be called as "
659                         + "part of a callback while a frame is in progress.");
660             }
661             return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
662         }
663     }
664 
665     /**
666      * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
667      * whether callbacks are currently running.
668      * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
669      * @hide
670      */
getLastFrameTimeNanos()671     public long getLastFrameTimeNanos() {
672         synchronized (mLock) {
673             return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
674         }
675     }
676 
scheduleFrameLocked(long now)677     private void scheduleFrameLocked(long now) {
678         if (!mFrameScheduled) {
679             mFrameScheduled = true;
680             if (USE_VSYNC) {
681                 if (DEBUG_FRAMES) {
682                     Log.d(TAG, "Scheduling next frame on vsync.");
683                 }
684 
685                 // If running on the Looper thread, then schedule the vsync immediately,
686                 // otherwise post a message to schedule the vsync from the UI thread
687                 // as soon as possible.
688                 if (isRunningOnLooperThreadLocked()) {
689                     scheduleVsyncLocked();
690                 } else {
691                     Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
692                     msg.setAsynchronous(true);
693                     mHandler.sendMessageAtFrontOfQueue(msg);
694                 }
695             } else {
696                 final long nextFrameTime = Math.max(
697                         mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
698                 if (DEBUG_FRAMES) {
699                     Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
700                 }
701                 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
702                 msg.setAsynchronous(true);
703                 mHandler.sendMessageAtTime(msg, nextFrameTime);
704             }
705         }
706     }
707 
708     /**
709      * Returns the vsync id of the last frame callback. Client are expected to call
710      * this function from their frame callback function to get the vsyncId and pass
711      * it together with a buffer or transaction to the Surface Composer. Calling
712      * this function from anywhere else will return an undefined value.
713      *
714      * @hide
715      */
getVsyncId()716     public long getVsyncId() {
717         return mLastVsyncEventData.preferredFrameTimeline().vsyncId;
718     }
719 
720     /**
721      * Returns the frame deadline in {@link System#nanoTime()} timebase that it is allotted for the
722      * frame to be completed. Client are expected to call this function from their frame callback
723      * function. Calling this function from anywhere else will return an undefined value.
724      *
725      * @hide
726      */
getFrameDeadline()727     public long getFrameDeadline() {
728         return mLastVsyncEventData.preferredFrameTimeline().deadline;
729     }
730 
setFPSDivisor(int divisor)731     void setFPSDivisor(int divisor) {
732         if (divisor <= 0) divisor = 1;
733         mFPSDivisor = divisor;
734         ThreadedRenderer.setFPSDivisor(divisor);
735     }
736 
traceMessage(String msg)737     private void traceMessage(String msg) {
738         Trace.traceBegin(Trace.TRACE_TAG_VIEW, msg);
739         Trace.traceEnd(Trace.TRACE_TAG_VIEW);
740     }
741 
doFrame(long frameTimeNanos, int frame, DisplayEventReceiver.VsyncEventData vsyncEventData)742     void doFrame(long frameTimeNanos, int frame,
743             DisplayEventReceiver.VsyncEventData vsyncEventData) {
744         final long startNanos;
745         final long frameIntervalNanos = vsyncEventData.frameInterval;
746         try {
747             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
748                 Trace.traceBegin(Trace.TRACE_TAG_VIEW,
749                         "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId);
750             }
751             FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData);
752             synchronized (mLock) {
753                 if (!mFrameScheduled) {
754                     traceMessage("Frame not scheduled");
755                     return; // no work to do
756                 }
757 
758                 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
759                     mDebugPrintNextFrameTimeDelta = false;
760                     Log.d(TAG, "Frame time delta: "
761                             + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
762                 }
763 
764                 long intendedFrameTimeNanos = frameTimeNanos;
765                 startNanos = System.nanoTime();
766                 final long jitterNanos = startNanos - frameTimeNanos;
767                 if (jitterNanos >= frameIntervalNanos) {
768                     long lastFrameOffset = 0;
769                     if (frameIntervalNanos == 0) {
770                         Log.i(TAG, "Vsync data empty due to timeout");
771                     } else {
772                         lastFrameOffset = jitterNanos % frameIntervalNanos;
773                         final long skippedFrames = jitterNanos / frameIntervalNanos;
774                         if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
775                             Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
776                                     + "The application may be doing too much work on its main "
777                                     + "thread.");
778                         }
779                         if (DEBUG_JANK) {
780                             Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
781                                     + "which is more than the frame interval of "
782                                     + (frameIntervalNanos * 0.000001f) + " ms!  "
783                                     + "Skipping " + skippedFrames + " frames and setting frame "
784                                     + "time to " + (lastFrameOffset * 0.000001f)
785                                     + " ms in the past.");
786                         }
787                     }
788                     frameTimeNanos = startNanos - lastFrameOffset;
789                     frameData.updateFrameData(frameTimeNanos);
790                 }
791 
792                 if (frameTimeNanos < mLastFrameTimeNanos) {
793                     if (DEBUG_JANK) {
794                         Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
795                                 + "previously skipped frame.  Waiting for next vsync.");
796                     }
797                     traceMessage("Frame time goes backward");
798                     scheduleVsyncLocked();
799                     return;
800                 }
801 
802                 if (mFPSDivisor > 1) {
803                     long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
804                     if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
805                         traceMessage("Frame skipped due to FPSDivisor");
806                         scheduleVsyncLocked();
807                         return;
808                     }
809                 }
810 
811                 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos,
812                         vsyncEventData.preferredFrameTimeline().vsyncId,
813                         vsyncEventData.preferredFrameTimeline().deadline, startNanos,
814                         vsyncEventData.frameInterval);
815                 mFrameScheduled = false;
816                 mLastFrameTimeNanos = frameTimeNanos;
817                 mLastFrameIntervalNanos = frameIntervalNanos;
818                 mLastVsyncEventData = vsyncEventData;
819             }
820 
821             AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
822 
823             mFrameInfo.markInputHandlingStart();
824             doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos);
825 
826             mFrameInfo.markAnimationsStart();
827             doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos);
828             doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData,
829                     frameIntervalNanos);
830 
831             mFrameInfo.markPerformTraversalsStart();
832             doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos);
833 
834             doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos);
835         } finally {
836             AnimationUtils.unlockAnimationClock();
837             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
838         }
839 
840         if (DEBUG_FRAMES) {
841             final long endNanos = System.nanoTime();
842             Log.d(TAG, "Frame " + frame + ": Finished, took "
843                     + (endNanos - startNanos) * 0.000001f + " ms, latency "
844                     + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
845         }
846     }
847 
doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos)848     void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) {
849         CallbackRecord callbacks;
850         long frameTimeNanos = frameData.mFrameTimeNanos;
851         synchronized (mLock) {
852             // We use "now" to determine when callbacks become due because it's possible
853             // for earlier processing phases in a frame to post callbacks that should run
854             // in a following phase, such as an input event that causes an animation to start.
855             final long now = System.nanoTime();
856             callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
857                     now / TimeUtils.NANOS_PER_MS);
858             if (callbacks == null) {
859                 return;
860             }
861             mCallbacksRunning = true;
862 
863             // Update the frame time if necessary when committing the frame.
864             // We only update the frame time if we are more than 2 frames late reaching
865             // the commit phase.  This ensures that the frame time which is observed by the
866             // callbacks will always increase from one frame to the next and never repeat.
867             // We never want the next frame's starting frame time to end up being less than
868             // or equal to the previous frame's commit frame time.  Keep in mind that the
869             // next frame has most likely already been scheduled by now so we play it
870             // safe by ensuring the commit time is always at least one frame behind.
871             if (callbackType == Choreographer.CALLBACK_COMMIT) {
872                 final long jitterNanos = now - frameTimeNanos;
873                 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
874                 if (jitterNanos >= 2 * frameIntervalNanos) {
875                     final long lastFrameOffset = jitterNanos % frameIntervalNanos
876                             + frameIntervalNanos;
877                     if (DEBUG_JANK) {
878                         Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
879                                 + " ms which is more than twice the frame interval of "
880                                 + (frameIntervalNanos * 0.000001f) + " ms!  "
881                                 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
882                                 + " ms in the past.");
883                         mDebugPrintNextFrameTimeDelta = true;
884                     }
885                     frameTimeNanos = now - lastFrameOffset;
886                     mLastFrameTimeNanos = frameTimeNanos;
887                     frameData.updateFrameData(frameTimeNanos);
888                 }
889             }
890         }
891         try {
892             Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
893             for (CallbackRecord c = callbacks; c != null; c = c.next) {
894                 if (DEBUG_FRAMES) {
895                     Log.d(TAG, "RunCallback: type=" + callbackType
896                             + ", action=" + c.action + ", token=" + c.token
897                             + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
898                 }
899                 c.run(frameData);
900             }
901         } finally {
902             synchronized (mLock) {
903                 mCallbacksRunning = false;
904                 do {
905                     final CallbackRecord next = callbacks.next;
906                     recycleCallbackLocked(callbacks);
907                     callbacks = next;
908                 } while (callbacks != null);
909             }
910             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
911         }
912     }
913 
doScheduleVsync()914     void doScheduleVsync() {
915         synchronized (mLock) {
916             if (mFrameScheduled) {
917                 scheduleVsyncLocked();
918             }
919         }
920     }
921 
doScheduleCallback(int callbackType)922     void doScheduleCallback(int callbackType) {
923         synchronized (mLock) {
924             if (!mFrameScheduled) {
925                 final long now = SystemClock.uptimeMillis();
926                 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
927                     scheduleFrameLocked(now);
928                 }
929             }
930         }
931     }
932 
933     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
scheduleVsyncLocked()934     private void scheduleVsyncLocked() {
935         try {
936             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
937             mDisplayEventReceiver.scheduleVsync();
938         } finally {
939             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
940         }
941     }
942 
isRunningOnLooperThreadLocked()943     private boolean isRunningOnLooperThreadLocked() {
944         return Looper.myLooper() == mLooper;
945     }
946 
obtainCallbackLocked(long dueTime, Object action, Object token)947     private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
948         CallbackRecord callback = mCallbackPool;
949         if (callback == null) {
950             callback = new CallbackRecord();
951         } else {
952             mCallbackPool = callback.next;
953             callback.next = null;
954         }
955         callback.dueTime = dueTime;
956         callback.action = action;
957         callback.token = token;
958         return callback;
959     }
960 
recycleCallbackLocked(CallbackRecord callback)961     private void recycleCallbackLocked(CallbackRecord callback) {
962         callback.action = null;
963         callback.token = null;
964         callback.next = mCallbackPool;
965         mCallbackPool = callback;
966     }
967 
968     /**
969      * Implement this interface to receive a callback when a new display frame is
970      * being rendered.  The callback is invoked on the {@link Looper} thread to
971      * which the {@link Choreographer} is attached.
972      */
973     public interface FrameCallback {
974         /**
975          * Called when a new display frame is being rendered.
976          * <p>
977          * This method provides the time in nanoseconds when the frame started being rendered.
978          * The frame time provides a stable time base for synchronizing animations
979          * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
980          * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
981          * time helps to reduce inter-frame jitter because the frame time is fixed at the time
982          * the frame was scheduled to start, regardless of when the animations or drawing
983          * callback actually runs.  All callbacks that run as part of rendering a frame will
984          * observe the same frame time so using the frame time also helps to synchronize effects
985          * that are performed by different callbacks.
986          * </p><p>
987          * Please note that the framework already takes care to process animations and
988          * drawing using the frame time as a stable time base.  Most applications should
989          * not need to use the frame time information directly.
990          * </p>
991          *
992          * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
993          * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
994          * to convert it to the {@link SystemClock#uptimeMillis()} time base.
995          */
doFrame(long frameTimeNanos)996         public void doFrame(long frameTimeNanos);
997     }
998 
999     /** Holds data that describes one possible VSync frame event to render at. */
1000     public static class FrameTimeline {
1001         static final FrameTimeline INVALID_FRAME_TIMELINE = new FrameTimeline(
1002                 FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE);
1003 
FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos)1004         FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) {
1005             this.mVsyncId = vsyncId;
1006             this.mExpectedPresentTimeNanos = expectedPresentTimeNanos;
1007             this.mDeadlineNanos = deadlineNanos;
1008         }
1009 
1010         private long mVsyncId;
1011         private long mExpectedPresentTimeNanos;
1012         private long mDeadlineNanos;
1013 
1014         /**
1015          * The id that corresponds to this frame timeline, used to correlate a frame
1016          * produced by HWUI with the timeline data stored in Surface Flinger.
1017          */
getVsyncId()1018         public long getVsyncId() {
1019             return mVsyncId;
1020         }
1021 
1022         /** Reset the vsync ID to invalid. */
resetVsyncId()1023         void resetVsyncId() {
1024             mVsyncId = FrameInfo.INVALID_VSYNC_ID;
1025         }
1026 
1027         /**
1028          * The time in {@link System#nanoTime()} timebase which this frame is expected to be
1029          * presented.
1030          */
getExpectedPresentationTimeNanos()1031         public long getExpectedPresentationTimeNanos() {
1032             return mExpectedPresentTimeNanos;
1033         }
1034 
1035         /**
1036          * The time in  {@link System#nanoTime()} timebase which this frame needs to be ready by.
1037          */
getDeadlineNanos()1038         public long getDeadlineNanos() {
1039             return mDeadlineNanos;
1040         }
1041     }
1042 
1043     /**
1044      * The payload for {@link VsyncCallback} which includes frame information such as when
1045      * the frame started being rendered, and multiple possible frame timelines and their
1046      * information including deadline and expected present time.
1047      */
1048     public static class FrameData {
1049         static final FrameTimeline[] INVALID_FRAME_TIMELINES = new FrameTimeline[0];
FrameData()1050         FrameData() {
1051             this.mFrameTimelines = INVALID_FRAME_TIMELINES;
1052             this.mPreferredFrameTimeline = FrameTimeline.INVALID_FRAME_TIMELINE;
1053         }
1054 
FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData)1055         FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
1056             FrameTimeline[] frameTimelines =
1057                     new FrameTimeline[vsyncEventData.frameTimelines.length];
1058             for (int i = 0; i <  vsyncEventData.frameTimelines.length; i++) {
1059                 DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
1060                         vsyncEventData.frameTimelines[i];
1061                 frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId,
1062                         frameTimeline.expectedPresentTime, frameTimeline.deadline);
1063             }
1064             this.mFrameTimeNanos = frameTimeNanos;
1065             this.mFrameTimelines = frameTimelines;
1066             this.mPreferredFrameTimeline =
1067                     frameTimelines[vsyncEventData.preferredFrameTimelineIndex];
1068         }
1069 
1070         private long mFrameTimeNanos;
1071         private FrameTimeline[] mFrameTimelines;
1072         private FrameTimeline mPreferredFrameTimeline;
1073 
updateFrameData(long frameTimeNanos)1074         void updateFrameData(long frameTimeNanos) {
1075             mFrameTimeNanos = frameTimeNanos;
1076             for (FrameTimeline ft : mFrameTimelines) {
1077                 // The ID is no longer valid because the frame time that was registered with the ID
1078                 // no longer matches.
1079                 // TODO(b/205721584): Ask SF for valid vsync information.
1080                 ft.resetVsyncId();
1081             }
1082         }
1083 
1084         /** The time in nanoseconds when the frame started being rendered. */
getFrameTimeNanos()1085         public long getFrameTimeNanos() {
1086             return mFrameTimeNanos;
1087         }
1088 
1089         /** The possible frame timelines, sorted chronologically. */
1090         @NonNull
1091         @SuppressLint("ArrayReturn") // For API consistency and speed.
getFrameTimelines()1092         public FrameTimeline[] getFrameTimelines() {
1093             return mFrameTimelines;
1094         }
1095 
1096         /** The platform-preferred frame timeline. */
1097         @NonNull
getPreferredFrameTimeline()1098         public FrameTimeline getPreferredFrameTimeline() {
1099             return mPreferredFrameTimeline;
1100         }
1101 
convertFrameTimelines( DisplayEventReceiver.VsyncEventData vsyncEventData)1102         private FrameTimeline[] convertFrameTimelines(
1103                 DisplayEventReceiver.VsyncEventData vsyncEventData) {
1104             FrameTimeline[] frameTimelines =
1105                     new FrameTimeline[vsyncEventData.frameTimelines.length];
1106             for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) {
1107                 DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
1108                         vsyncEventData.frameTimelines[i];
1109                 frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId,
1110                         frameTimeline.expectedPresentTime, frameTimeline.deadline);
1111             }
1112             return frameTimelines;
1113         }
1114     }
1115 
1116     /**
1117      * Implement this interface to receive a callback to start the next frame. The callback is
1118      * invoked on the {@link Looper} thread to which the {@link Choreographer} is attached. The
1119      * callback payload contains information about multiple possible frames, allowing choice of
1120      * the appropriate frame based on latency requirements.
1121      *
1122      * @see FrameCallback
1123      */
1124     public interface VsyncCallback {
1125         /**
1126          * Called when a new display frame is being rendered.
1127          *
1128          * @param data The payload which includes frame information. Divide nanosecond values by
1129          *             {@code 1000000} to convert it to the {@link SystemClock#uptimeMillis()}
1130          *             time base.
1131          * @see FrameCallback#doFrame
1132          **/
onVsync(@onNull FrameData data)1133         void onVsync(@NonNull FrameData data);
1134     }
1135 
1136     private final class FrameHandler extends Handler {
FrameHandler(Looper looper)1137         public FrameHandler(Looper looper) {
1138             super(looper);
1139         }
1140 
1141         @Override
handleMessage(Message msg)1142         public void handleMessage(Message msg) {
1143             switch (msg.what) {
1144                 case MSG_DO_FRAME:
1145                     doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData());
1146                     break;
1147                 case MSG_DO_SCHEDULE_VSYNC:
1148                     doScheduleVsync();
1149                     break;
1150                 case MSG_DO_SCHEDULE_CALLBACK:
1151                     doScheduleCallback(msg.arg1);
1152                     break;
1153             }
1154         }
1155     }
1156 
1157     private final class FrameDisplayEventReceiver extends DisplayEventReceiver
1158             implements Runnable {
1159         private boolean mHavePendingVsync;
1160         private long mTimestampNanos;
1161         private int mFrame;
1162         private VsyncEventData mLastVsyncEventData = new VsyncEventData();
1163 
FrameDisplayEventReceiver(Looper looper, int vsyncSource)1164         public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
1165             super(looper, vsyncSource, 0);
1166         }
1167 
1168         // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
1169         // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
1170         // for the internal display implicitly.
1171         @Override
onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData)1172         public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
1173                 VsyncEventData vsyncEventData) {
1174             try {
1175                 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
1176                     Trace.traceBegin(Trace.TRACE_TAG_VIEW,
1177                             "Choreographer#onVsync "
1178                                     + vsyncEventData.preferredFrameTimeline().vsyncId);
1179                 }
1180                 // Post the vsync event to the Handler.
1181                 // The idea is to prevent incoming vsync events from completely starving
1182                 // the message queue.  If there are no messages in the queue with timestamps
1183                 // earlier than the frame time, then the vsync event will be processed immediately.
1184                 // Otherwise, messages that predate the vsync event will be handled first.
1185                 long now = System.nanoTime();
1186                 if (timestampNanos > now) {
1187                     Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
1188                             + " ms in the future!  Check that graphics HAL is generating vsync "
1189                             + "timestamps using the correct timebase.");
1190                     timestampNanos = now;
1191                 }
1192 
1193                 if (mHavePendingVsync) {
1194                     Log.w(TAG, "Already have a pending vsync event.  There should only be "
1195                             + "one at a time.");
1196                 } else {
1197                     mHavePendingVsync = true;
1198                 }
1199 
1200                 mTimestampNanos = timestampNanos;
1201                 mFrame = frame;
1202                 mLastVsyncEventData = vsyncEventData;
1203                 Message msg = Message.obtain(mHandler, this);
1204                 msg.setAsynchronous(true);
1205                 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
1206             } finally {
1207                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1208             }
1209         }
1210 
1211         @Override
run()1212         public void run() {
1213             mHavePendingVsync = false;
1214             doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
1215         }
1216     }
1217 
1218     private static final class CallbackRecord {
1219         public CallbackRecord next;
1220         public long dueTime;
1221         /** Runnable or FrameCallback or VsyncCallback object. */
1222         public Object action;
1223         /** Denotes the action type. */
1224         public Object token;
1225 
1226         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
run(long frameTimeNanos)1227         public void run(long frameTimeNanos) {
1228             if (token == FRAME_CALLBACK_TOKEN) {
1229                 ((FrameCallback)action).doFrame(frameTimeNanos);
1230             } else {
1231                 ((Runnable)action).run();
1232             }
1233         }
1234 
run(FrameData frameData)1235         void run(FrameData frameData) {
1236             if (token == VSYNC_CALLBACK_TOKEN) {
1237                 ((VsyncCallback) action).onVsync(frameData);
1238             } else {
1239                 run(frameData.getFrameTimeNanos());
1240             }
1241         }
1242     }
1243 
1244     private final class CallbackQueue {
1245         private CallbackRecord mHead;
1246 
hasDueCallbacksLocked(long now)1247         public boolean hasDueCallbacksLocked(long now) {
1248             return mHead != null && mHead.dueTime <= now;
1249         }
1250 
extractDueCallbacksLocked(long now)1251         public CallbackRecord extractDueCallbacksLocked(long now) {
1252             CallbackRecord callbacks = mHead;
1253             if (callbacks == null || callbacks.dueTime > now) {
1254                 return null;
1255             }
1256 
1257             CallbackRecord last = callbacks;
1258             CallbackRecord next = last.next;
1259             while (next != null) {
1260                 if (next.dueTime > now) {
1261                     last.next = null;
1262                     break;
1263                 }
1264                 last = next;
1265                 next = next.next;
1266             }
1267             mHead = next;
1268             return callbacks;
1269         }
1270 
1271         @UnsupportedAppUsage
addCallbackLocked(long dueTime, Object action, Object token)1272         public void addCallbackLocked(long dueTime, Object action, Object token) {
1273             CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
1274             CallbackRecord entry = mHead;
1275             if (entry == null) {
1276                 mHead = callback;
1277                 return;
1278             }
1279             if (dueTime < entry.dueTime) {
1280                 callback.next = entry;
1281                 mHead = callback;
1282                 return;
1283             }
1284             while (entry.next != null) {
1285                 if (dueTime < entry.next.dueTime) {
1286                     callback.next = entry.next;
1287                     break;
1288                 }
1289                 entry = entry.next;
1290             }
1291             entry.next = callback;
1292         }
1293 
removeCallbacksLocked(Object action, Object token)1294         public void removeCallbacksLocked(Object action, Object token) {
1295             CallbackRecord predecessor = null;
1296             for (CallbackRecord callback = mHead; callback != null;) {
1297                 final CallbackRecord next = callback.next;
1298                 if ((action == null || callback.action == action)
1299                         && (token == null || callback.token == token)) {
1300                     if (predecessor != null) {
1301                         predecessor.next = next;
1302                     } else {
1303                         mHead = next;
1304                     }
1305                     recycleCallbackLocked(callback);
1306                 } else {
1307                     predecessor = callback;
1308                 }
1309                 callback = next;
1310             }
1311         }
1312     }
1313 }
1314