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