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