2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 import static android.view.DisplayEventReceiver.CONFIG_CHANGED_EVENT_SUPPRESS;
20 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
21 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
23 import android.annotation.TestApi;
24 import android.annotation.UnsupportedAppUsage;
25 import android.graphics.FrameInfo;
26 import android.hardware.display.DisplayManagerGlobal;
27 import android.os.Build;
28 import android.os.Handler;
29 import android.os.Looper;
30 import android.os.Message;
31 import android.os.SystemClock;
32 import android.os.SystemProperties;
33 import android.os.Trace;
34 import android.util.Log;
35 import android.util.TimeUtils;
36 import android.view.animation.AnimationUtils;
38 import java.io.PrintWriter;
41 * Coordinates the timing of animations, input and drawing.
43 * The choreographer receives timing pulses (such as vertical synchronization)
44 * from the display subsystem then schedules work to occur as part of rendering
45 * the next display frame.
47 * Applications typically interact with the choreographer indirectly using
48 * higher level abstractions in the animation framework or the view hierarchy.
49 * Here are some examples of things you can do using the higher-level APIs.
52 * <li>To post an animation to be processed on a regular time basis synchronized with
53 * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
54 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
55 * frame, use {@link View#postOnAnimation}.</li>
56 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
57 * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
58 * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
59 * next display frame, use {@link View#postInvalidateOnAnimation()} or
60 * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
61 * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
62 * sync with display frame rendering, do nothing. This already happens automatically.
63 * {@link View#onDraw} will be called at the appropriate time.</li>
66 * However, there are a few cases where you might want to use the functions of the
67 * choreographer directly in your application. Here are some examples.
70 * <li>If your application does its rendering in a different thread, possibly using GL,
71 * or does not use the animation framework or view hierarchy at all
72 * and you want to ensure that it is appropriately synchronized with the display, then use
73 * {@link Choreographer#postFrameCallback}.</li>
74 * <li>... and that's about it.</li>
77 * Each {@link Looper} thread has its own choreographer. Other threads can
78 * post callbacks to run on the choreographer but they will run on the {@link Looper}
79 * to which the choreographer belongs.
82 public final class Choreographer {
83 private static final String TAG = "Choreographer";
85 // Prints debug messages about jank which was detected (low volume).
86 private static final boolean DEBUG_JANK = false;
88 // Prints debug messages about every frame and callback registered (high volume).
89 private static final boolean DEBUG_FRAMES = false;
91 // The default amount of time in ms between animation frames.
92 // When vsync is not enabled, we want to have some idea of how long we should
93 // wait before posting the next animation message. It is important that the
94 // default value be less than the true inter-frame delay on all devices to avoid
95 // situations where we might skip frames by waiting too long (we must compensate
96 // for jitter and hardware variations). Regardless of this value, the animation
97 // and display loop is ultimately rate-limited by how fast new graphics buffers can
99 private static final long DEFAULT_FRAME_DELAY = 10;
101 // The number of milliseconds between animation frames.
102 private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
104 // Thread local storage for the choreographer.
105 private static final ThreadLocal<Choreographer> sThreadInstance =
106 new ThreadLocal<Choreographer>() {
108 protected Choreographer initialValue() {
109 Looper looper = Looper.myLooper();
110 if (looper == null) {
111 throw new IllegalStateException("The current thread must have a looper!");
113 Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
114 if (looper == Looper.getMainLooper()) {
115 mMainInstance = choreographer;
117 return choreographer;
121 private static volatile Choreographer mMainInstance;
123 // Thread local storage for the SF choreographer.
124 private static final ThreadLocal<Choreographer> sSfThreadInstance =
125 new ThreadLocal<Choreographer>() {
127 protected Choreographer initialValue() {
128 Looper looper = Looper.myLooper();
129 if (looper == null) {
130 throw new IllegalStateException("The current thread must have a looper!");
132 return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
136 // Enable/disable vsync for animations and drawing.
137 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497)
138 private static final boolean USE_VSYNC = SystemProperties.getBoolean(
139 "debug.choreographer.vsync", true);
141 // Enable/disable using the frame time instead of returning now.
142 private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
143 "debug.choreographer.frametime", true);
145 // Set a limit to warn about skipped frames.
146 // Skipped frames imply jank.
147 private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
148 "debug.choreographer.skipwarning", 30);
150 private static final int MSG_DO_FRAME = 0;
151 private static final int MSG_DO_SCHEDULE_VSYNC = 1;
152 private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
154 // All frame callbacks posted by applications have this token.
155 private static final Object FRAME_CALLBACK_TOKEN = new Object() {
156 public String toString() { return "FRAME_CALLBACK_TOKEN"; }
159 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
160 private final Object mLock = new Object();
162 private final Looper mLooper;
163 private final FrameHandler mHandler;
165 // The display event receiver can only be accessed by the looper thread to which
166 // it is attached. We take care to ensure that we post message to the looper
167 // if appropriate when interacting with the display event receiver.
169 private final FrameDisplayEventReceiver mDisplayEventReceiver;
171 private CallbackRecord mCallbackPool;
174 private final CallbackQueue[] mCallbackQueues;
176 private boolean mFrameScheduled;
177 private boolean mCallbacksRunning;
179 private long mLastFrameTimeNanos;
181 private long mFrameIntervalNanos;
182 private boolean mDebugPrintNextFrameTimeDelta;
183 private int mFPSDivisor = 1;
186 * Contains information about the current frame for jank-tracking,
187 * mainly timings of key events along with a bit of metadata about
190 * TODO: Is there a better home for this? Currently Choreographer
191 * is the only one with CALLBACK_ANIMATION start time, hence why this
196 FrameInfo mFrameInfo = new FrameInfo();
199 * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
202 private static final String[] CALLBACK_TRACE_TITLES = {
203 "input", "animation", "insets_animation", "traversal", "commit"
207 * Callback type: Input callback. Runs first.
210 public static final int CALLBACK_INPUT = 0;
213 * Callback type: Animation callback. Runs before {@link #CALLBACK_INSETS_ANIMATION}.
217 public static final int CALLBACK_ANIMATION = 1;
220 * Callback type: Animation callback to handle inset updates. This is separate from
221 * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via
222 * {@link WindowInsetsAnimationController#changeInsets} for multiple ongoing animations but then
223 * update the whole view system with a single callback to {@link View#dispatchWindowInsetsAnimationProgress}
224 * that contains all the combined updated insets.
226 * Both input and animation may change insets, so we need to run this after these callbacks, but
229 * Runs before traversals.
232 public static final int CALLBACK_INSETS_ANIMATION = 2;
235 * Callback type: Traversal callback. Handles layout and draw. Runs
236 * after all other asynchronous messages have been handled.
239 public static final int CALLBACK_TRAVERSAL = 3;
242 * Callback type: Commit callback. Handles post-draw operations for the frame.
243 * Runs after traversal completes. The {@link #getFrameTime() frame time} reported
244 * during this callback may be updated to reflect delays that occurred while
245 * traversals were in progress in case heavy layout operations caused some frames
246 * to be skipped. The frame time reported during this callback provides a better
247 * estimate of the start time of the frame in which animations (and other updates
248 * to the view hierarchy state) actually took effect.
251 public static final int CALLBACK_COMMIT = 4;
253 private static final int CALLBACK_LAST = CALLBACK_COMMIT;
255 private Choreographer(Looper looper, int vsyncSource) {
257 mHandler = new FrameHandler(looper);
258 mDisplayEventReceiver = USE_VSYNC
259 ? new FrameDisplayEventReceiver(looper, vsyncSource)
261 mLastFrameTimeNanos = Long.MIN_VALUE;
263 mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
265 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
266 for (int i = 0; i <= CALLBACK_LAST; i++) {
267 mCallbackQueues[i] = new CallbackQueue();
269 // b/68769804: For low FPS experiments.
270 setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
273 private static float getRefreshRate() {
274 DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
275 Display.DEFAULT_DISPLAY);
276 return di.getMode().getRefreshRate();
280 * Gets the choreographer for the calling thread. Must be called from
281 * a thread that already has a {@link android.os.Looper} associated with it.
283 * @return The choreographer for this thread.
284 * @throws IllegalStateException if the thread does not have a looper.
286 public static Choreographer getInstance() {
287 return sThreadInstance.get();
294 public static Choreographer getSfInstance() {
295 return sSfThreadInstance.get();
299 * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
302 public static Choreographer getMainThreadInstance() {
303 return mMainInstance;
306 /** Destroys the calling thread's choreographer
309 public static void releaseInstance() {
310 Choreographer old = sThreadInstance.get();
311 sThreadInstance.remove();
315 private void dispose() {
316 mDisplayEventReceiver.dispose();
320 * The amount of time, in milliseconds, between each frame of the animation.
322 * This is a requested time that the animation will attempt to honor, but the actual delay
323 * between frames may be different, depending on system load and capabilities. This is a static
324 * function because the same delay will be applied to all animations, since they are all
325 * run off of a single timing loop.
327 * The frame delay may be ignored when the animation system uses an external timing
328 * source, such as the display refresh rate (vsync), to govern animations.
331 * @return the requested time between frames, in milliseconds
335 public static long getFrameDelay() {
340 * The amount of time, in milliseconds, between each frame of the animation.
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.
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.
351 * @param frameDelay the requested time between frames, in milliseconds
355 public static void setFrameDelay(long frameDelay) {
356 sFrameDelay = frameDelay;
360 * Subtracts typical frame delay time from a delay interval in milliseconds.
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
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.
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.
381 public static long subtractFrameDelay(long delayMillis) {
382 final long frameDelay = sFrameDelay;
383 return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
387 * @return The refresh rate as the nanoseconds between frames
390 public long getFrameIntervalNanos() {
391 return mFrameIntervalNanos;
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));
404 * Posts a callback to run on the next frame.
406 * The callback runs once then is automatically removed.
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.
413 * @see #removeCallbacks
417 public void postCallback(int callbackType, Runnable action, Object token) {
418 postCallbackDelayed(callbackType, action, token, 0);
422 * Posts a callback to run on the next frame after the specified delay.
424 * The callback runs once then is automatically removed.
427 * @param callbackType The callback type.
428 * @param action The callback action to run during the next frame after the specified delay.
429 * @param token The callback token, or null if none.
430 * @param delayMillis The delay time in milliseconds.
432 * @see #removeCallback
436 public void postCallbackDelayed(int callbackType,
437 Runnable action, Object token, long delayMillis) {
438 if (action == null) {
439 throw new IllegalArgumentException("action must not be null");
441 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
442 throw new IllegalArgumentException("callbackType is invalid");
445 postCallbackDelayedInternal(callbackType, action, token, delayMillis);
448 private void postCallbackDelayedInternal(int callbackType,
449 Object action, Object token, long delayMillis) {
451 Log.d(TAG, "PostCallback: type=" + callbackType
452 + ", action=" + action + ", token=" + token
453 + ", delayMillis=" + delayMillis);
456 synchronized (mLock) {
457 final long now = SystemClock.uptimeMillis();
458 final long dueTime = now + delayMillis;
459 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
461 if (dueTime <= now) {
462 scheduleFrameLocked(now);
464 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
465 msg.arg1 = callbackType;
466 msg.setAsynchronous(true);
467 mHandler.sendMessageAtTime(msg, dueTime);
473 * Removes callbacks that have the specified action and token.
475 * @param callbackType The callback type.
476 * @param action The action property of the callbacks to remove, or null to remove
477 * callbacks with any action.
478 * @param token The token property of the callbacks to remove, or null to remove
479 * callbacks with any token.
482 * @see #postCallbackDelayed
486 public void removeCallbacks(int callbackType, Runnable action, Object token) {
487 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
488 throw new IllegalArgumentException("callbackType is invalid");
491 removeCallbacksInternal(callbackType, action, token);
494 private void removeCallbacksInternal(int callbackType, Object action, Object token) {
496 Log.d(TAG, "RemoveCallbacks: type=" + callbackType
497 + ", action=" + action + ", token=" + token);
500 synchronized (mLock) {
501 mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
502 if (action != null && token == null) {
503 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
509 * Posts a frame callback to run on the next frame.
511 * The callback runs once then is automatically removed.
514 * @param callback The frame callback to run during the next frame.
516 * @see #postFrameCallbackDelayed
517 * @see #removeFrameCallback
519 public void postFrameCallback(FrameCallback callback) {
520 postFrameCallbackDelayed(callback, 0);
524 * Posts a frame callback to run on the next frame after the specified delay.
526 * The callback runs once then is automatically removed.
529 * @param callback The frame callback to run during the next frame.
530 * @param delayMillis The delay time in milliseconds.
532 * @see #postFrameCallback
533 * @see #removeFrameCallback
535 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
536 if (callback == null) {
537 throw new IllegalArgumentException("callback must not be null");
540 postCallbackDelayedInternal(CALLBACK_ANIMATION,
541 callback, FRAME_CALLBACK_TOKEN, delayMillis);
545 * Removes a previously posted frame callback.
547 * @param callback The frame callback to remove.
549 * @see #postFrameCallback
550 * @see #postFrameCallbackDelayed
552 public void removeFrameCallback(FrameCallback callback) {
553 if (callback == null) {
554 throw new IllegalArgumentException("callback must not be null");
557 removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
561 * Gets the time when the current frame started.
563 * This method provides the time in milliseconds when the frame started being rendered.
564 * The frame time provides a stable time base for synchronizing animations
565 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
566 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
567 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
568 * the frame was scheduled to start, regardless of when the animations or drawing
569 * callback actually runs. All callbacks that run as part of rendering a frame will
570 * observe the same frame time so using the frame time also helps to synchronize effects
571 * that are performed by different callbacks.
573 * Please note that the framework already takes care to process animations and
574 * drawing using the frame time as a stable time base. Most applications should
575 * not need to use the frame time information directly.
577 * This method should only be called from within a callback.
580 * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
582 * @throws IllegalStateException if no frame is in progress.
586 public long getFrameTime() {
587 return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
591 * Same as {@link #getFrameTime()} but with nanosecond precision.
593 * @return The frame start time, in the {@link System#nanoTime()} time base.
595 * @throws IllegalStateException if no frame is in progress.
599 public long getFrameTimeNanos() {
600 synchronized (mLock) {
601 if (!mCallbacksRunning) {
602 throw new IllegalStateException("This method must only be called as "
603 + "part of a callback while a frame is in progress.");
605 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
610 * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
611 * whether callbacks are currently running.
612 * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
615 public long getLastFrameTimeNanos() {
616 synchronized (mLock) {
617 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
621 private void scheduleFrameLocked(long now) {
622 if (!mFrameScheduled) {
623 mFrameScheduled = true;
626 Log.d(TAG, "Scheduling next frame on vsync.");
629 // If running on the Looper thread, then schedule the vsync immediately,
630 // otherwise post a message to schedule the vsync from the UI thread
631 // as soon as possible.
632 if (isRunningOnLooperThreadLocked()) {
633 scheduleVsyncLocked();
635 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
636 msg.setAsynchronous(true);
637 mHandler.sendMessageAtFrontOfQueue(msg);
640 final long nextFrameTime = Math.max(
641 mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
643 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
645 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
646 msg.setAsynchronous(true);
647 mHandler.sendMessageAtTime(msg, nextFrameTime);
652 void setFPSDivisor(int divisor) {
653 if (divisor <= 0) divisor = 1;
654 mFPSDivisor = divisor;
655 ThreadedRenderer.setFPSDivisor(divisor);
659 void doFrame(long frameTimeNanos, int frame) {
660 final long startNanos;
661 synchronized (mLock) {
662 if (!mFrameScheduled) {
663 return; // no work to do
666 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
667 mDebugPrintNextFrameTimeDelta = false;
668 Log.d(TAG, "Frame time delta: "
669 + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
672 long intendedFrameTimeNanos = frameTimeNanos;
673 startNanos = System.nanoTime();
674 final long jitterNanos = startNanos - frameTimeNanos;
675 if (jitterNanos >= mFrameIntervalNanos) {
676 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
677 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
678 Log.i(TAG, "Skipped " + skippedFrames + " frames! "
679 + "The application may be doing too much work on its main thread.");
681 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
683 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
684 + "which is more than the frame interval of "
685 + (mFrameIntervalNanos * 0.000001f) + " ms! "
686 + "Skipping " + skippedFrames + " frames and setting frame "
687 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
689 frameTimeNanos = startNanos - lastFrameOffset;
692 if (frameTimeNanos < mLastFrameTimeNanos) {
694 Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
695 + "previously skipped frame. Waiting for next vsync.");
697 scheduleVsyncLocked();
701 if (mFPSDivisor > 1) {
702 long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
703 if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
704 scheduleVsyncLocked();
709 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
710 mFrameScheduled = false;
711 mLastFrameTimeNanos = frameTimeNanos;
715 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
716 AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
718 mFrameInfo.markInputHandlingStart();
719 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
721 mFrameInfo.markAnimationsStart();
722 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
723 doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
725 mFrameInfo.markPerformTraversalsStart();
726 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
728 doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
730 AnimationUtils.unlockAnimationClock();
731 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
735 final long endNanos = System.nanoTime();
736 Log.d(TAG, "Frame " + frame + ": Finished, took "
737 + (endNanos - startNanos) * 0.000001f + " ms, latency "
738 + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
742 void doCallbacks(int callbackType, long frameTimeNanos) {
743 CallbackRecord callbacks;
744 synchronized (mLock) {
745 // We use "now" to determine when callbacks become due because it's possible
746 // for earlier processing phases in a frame to post callbacks that should run
747 // in a following phase, such as an input event that causes an animation to start.
748 final long now = System.nanoTime();
749 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
750 now / TimeUtils.NANOS_PER_MS);
751 if (callbacks == null) {
754 mCallbacksRunning = true;
756 // Update the frame time if necessary when committing the frame.
757 // We only update the frame time if we are more than 2 frames late reaching
758 // the commit phase. This ensures that the frame time which is observed by the
759 // callbacks will always increase from one frame to the next and never repeat.
760 // We never want the next frame's starting frame time to end up being less than
761 // or equal to the previous frame's commit frame time. Keep in mind that the
762 // next frame has most likely already been scheduled by now so we play it
763 // safe by ensuring the commit time is always at least one frame behind.
764 if (callbackType == Choreographer.CALLBACK_COMMIT) {
765 final long jitterNanos = now - frameTimeNanos;
766 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
767 if (jitterNanos >= 2 * mFrameIntervalNanos) {
768 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
769 + mFrameIntervalNanos;
771 Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
772 + " ms which is more than twice the frame interval of "
773 + (mFrameIntervalNanos * 0.000001f) + " ms! "
774 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
775 + " ms in the past.");
776 mDebugPrintNextFrameTimeDelta = true;
778 frameTimeNanos = now - lastFrameOffset;
779 mLastFrameTimeNanos = frameTimeNanos;
784 Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
785 for (CallbackRecord c = callbacks; c != null; c = c.next) {
787 Log.d(TAG, "RunCallback: type=" + callbackType
788 + ", action=" + c.action + ", token=" + c.token
789 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
791 c.run(frameTimeNanos);
794 synchronized (mLock) {
795 mCallbacksRunning = false;
797 final CallbackRecord next = callbacks.next;
798 recycleCallbackLocked(callbacks);
800 } while (callbacks != null);
802 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
806 void doScheduleVsync() {
807 synchronized (mLock) {
808 if (mFrameScheduled) {
809 scheduleVsyncLocked();
814 void doScheduleCallback(int callbackType) {
815 synchronized (mLock) {
816 if (!mFrameScheduled) {
817 final long now = SystemClock.uptimeMillis();
818 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
819 scheduleFrameLocked(now);
826 private void scheduleVsyncLocked() {
827 mDisplayEventReceiver.scheduleVsync();
830 private boolean isRunningOnLooperThreadLocked() {
831 return Looper.myLooper() == mLooper;
834 private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
835 CallbackRecord callback = mCallbackPool;
836 if (callback == null) {
837 callback = new CallbackRecord();
839 mCallbackPool = callback.next;
840 callback.next = null;
842 callback.dueTime = dueTime;
843 callback.action = action;
844 callback.token = token;
848 private void recycleCallbackLocked(CallbackRecord callback) {
849 callback.action = null;
850 callback.token = null;
851 callback.next = mCallbackPool;
852 mCallbackPool = callback;
856 * Implement this interface to receive a callback when a new display frame is
857 * being rendered. The callback is invoked on the {@link Looper} thread to
858 * which the {@link Choreographer} is attached.
860 public interface FrameCallback {
862 * Called when a new display frame is being rendered.
864 * This method provides the time in nanoseconds when the frame started being rendered.
865 * The frame time provides a stable time base for synchronizing animations
866 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
867 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
868 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
869 * the frame was scheduled to start, regardless of when the animations or drawing
870 * callback actually runs. All callbacks that run as part of rendering a frame will
871 * observe the same frame time so using the frame time also helps to synchronize effects
872 * that are performed by different callbacks.
874 * Please note that the framework already takes care to process animations and
875 * drawing using the frame time as a stable time base. Most applications should
876 * not need to use the frame time information directly.
879 * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
880 * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000}
881 * to convert it to the {@link SystemClock#uptimeMillis()} time base.
883 public void doFrame(long frameTimeNanos);
886 private final class FrameHandler extends Handler {
887 public FrameHandler(Looper looper) {
892 public void handleMessage(Message msg) {
895 doFrame(System.nanoTime(), 0);
897 case MSG_DO_SCHEDULE_VSYNC:
900 case MSG_DO_SCHEDULE_CALLBACK:
901 doScheduleCallback(msg.arg1);
907 private final class FrameDisplayEventReceiver extends DisplayEventReceiver
908 implements Runnable {
909 private boolean mHavePendingVsync;
910 private long mTimestampNanos;
913 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
914 super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
917 // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
918 // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
919 // for the internal display implicitly.
921 public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
922 // Post the vsync event to the Handler.
923 // The idea is to prevent incoming vsync events from completely starving
924 // the message queue. If there are no messages in the queue with timestamps
925 // earlier than the frame time, then the vsync event will be processed immediately.
926 // Otherwise, messages that predate the vsync event will be handled first.
927 long now = System.nanoTime();
928 if (timestampNanos > now) {
929 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
930 + " ms in the future! Check that graphics HAL is generating vsync "
931 + "timestamps using the correct timebase.");
932 timestampNanos = now;
935 if (mHavePendingVsync) {
936 Log.w(TAG, "Already have a pending vsync event. There should only be "
939 mHavePendingVsync = true;
942 mTimestampNanos = timestampNanos;
944 Message msg = Message.obtain(mHandler, this);
945 msg.setAsynchronous(true);
946 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
951 mHavePendingVsync = false;
952 doFrame(mTimestampNanos, mFrame);
956 private static final class CallbackRecord {
957 public CallbackRecord next;
959 public Object action; // Runnable or FrameCallback
963 public void run(long frameTimeNanos) {
964 if (token == FRAME_CALLBACK_TOKEN) {
965 ((FrameCallback)action).doFrame(frameTimeNanos);
967 ((Runnable)action).run();
972 private final class CallbackQueue {
973 private CallbackRecord mHead;
975 public boolean hasDueCallbacksLocked(long now) {
976 return mHead != null && mHead.dueTime <= now;
979 public CallbackRecord extractDueCallbacksLocked(long now) {
980 CallbackRecord callbacks = mHead;
981 if (callbacks == null || callbacks.dueTime > now) {
985 CallbackRecord last = callbacks;
986 CallbackRecord next = last.next;
987 while (next != null) {
988 if (next.dueTime > now) {
1000 public void addCallbackLocked(long dueTime, Object action, Object token) {
1001 CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
1002 CallbackRecord entry = mHead;
1003 if (entry == null) {
1007 if (dueTime < entry.dueTime) {
1008 callback.next = entry;
1012 while (entry.next != null) {
1013 if (dueTime < entry.next.dueTime) {
1014 callback.next = entry.next;
1019 entry.next = callback;
1022 public void removeCallbacksLocked(Object action, Object token) {
1023 CallbackRecord predecessor = null;
1024 for (CallbackRecord callback = mHead; callback != null;) {
1025 final CallbackRecord next = callback.next;
1026 if ((action == null || callback.action == action)
1027 && (token == null || callback.token == token)) {
1028 if (predecessor != null) {
1029 predecessor.next = next;
1033 recycleCallbackLocked(callback);
1035 predecessor = callback;