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