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