blob: 28eb79ae1f2acbe60b5440cd9245da685c475ad5 [file] [log] [blame]
Jeff Brown96e942d2011-11-30 19:55:01 -08001/*
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
17package android.view;
18
Ady Abraham9c501aa2019-06-04 16:07:44 -070019import static android.view.DisplayEventReceiver.CONFIG_CHANGED_EVENT_SUPPRESS;
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -070020import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
21import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
22
Doris Liu197a6742017-08-16 17:12:42 -070023import android.annotation.TestApi;
Mathew Inwooda570dee2018-08-17 14:56:00 +010024import android.annotation.UnsupportedAppUsage;
John Reck8785ceb2018-10-29 16:45:58 -070025import android.graphics.FrameInfo;
Jeff Brownbd6e1502012-08-28 03:27:37 -070026import android.hardware.display.DisplayManagerGlobal;
Mathew Inwood8c854f82018-09-14 12:35:36 +010027import android.os.Build;
Jeff Brown96e942d2011-11-30 19:55:01 -080028import android.os.Handler;
29import android.os.Looper;
30import android.os.Message;
31import android.os.SystemClock;
32import android.os.SystemProperties;
Chris Craike22c59b2015-05-21 18:33:37 -070033import android.os.Trace;
Jeff Brown96e942d2011-11-30 19:55:01 -080034import android.util.Log;
Jeff Brown5182c782013-10-15 20:31:52 -070035import android.util.TimeUtils;
John Recka2acb4f2016-08-05 07:58:37 -070036import android.view.animation.AnimationUtils;
Jeff Brown5182c782013-10-15 20:31:52 -070037
38import java.io.PrintWriter;
Jeff Brown96e942d2011-11-30 19:55:01 -080039
40/**
Jeff Browncae80492012-05-21 16:33:39 -070041 * Coordinates the timing of animations, input and drawing.
42 * <p>
43 * The choreographer receives timing pulses (such as vertical synchronization)
44 * from the display subsystem then schedules work to occur as part of rendering
45 * the next display frame.
46 * </p><p>
47 * Applications typically interact with the choreographer indirectly using
48 * higher level abstractions in the animation framework or the view hierarchy.
49 * Here are some examples of things you can do using the higher-level APIs.
50 * </p>
51 * <ul>
52 * <li>To post an animation to be processed on a regular time basis synchronized with
53 * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
54 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
55 * frame, use {@link View#postOnAnimation}.</li>
56 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
57 * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
58 * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
59 * next display frame, use {@link View#postInvalidateOnAnimation()} or
60 * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
61 * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
62 * sync with display frame rendering, do nothing. This already happens automatically.
63 * {@link View#onDraw} will be called at the appropriate time.</li>
64 * </ul>
65 * <p>
66 * However, there are a few cases where you might want to use the functions of the
67 * choreographer directly in your application. Here are some examples.
68 * </p>
69 * <ul>
70 * <li>If your application does its rendering in a different thread, possibly using GL,
71 * or does not use the animation framework or view hierarchy at all
72 * and you want to ensure that it is appropriately synchronized with the display, then use
73 * {@link Choreographer#postFrameCallback}.</li>
74 * <li>... and that's about it.</li>
75 * </ul>
76 * <p>
77 * Each {@link Looper} thread has its own choreographer. Other threads can
78 * post callbacks to run on the choreographer but they will run on the {@link Looper}
79 * to which the choreographer belongs.
80 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -080081 */
Jeff Brown96858852012-02-14 13:45:06 -080082public final class Choreographer {
Jeff Brown96e942d2011-11-30 19:55:01 -080083 private static final String TAG = "Choreographer";
Jeff Brownc42b28d2015-04-06 19:49:02 -070084
85 // Prints debug messages about jank which was detected (low volume).
86 private static final boolean DEBUG_JANK = false;
87
88 // Prints debug messages about every frame and callback registered (high volume).
89 private static final boolean DEBUG_FRAMES = false;
Jeff Brown96e942d2011-11-30 19:55:01 -080090
91 // The default amount of time in ms between animation frames.
92 // When vsync is not enabled, we want to have some idea of how long we should
93 // wait before posting the next animation message. It is important that the
94 // default value be less than the true inter-frame delay on all devices to avoid
95 // situations where we might skip frames by waiting too long (we must compensate
96 // for jitter and hardware variations). Regardless of this value, the animation
97 // and display loop is ultimately rate-limited by how fast new graphics buffers can
98 // be dequeued.
99 private static final long DEFAULT_FRAME_DELAY = 10;
100
101 // The number of milliseconds between animation frames.
Jeff Brown87d0b032012-02-03 11:01:21 -0800102 private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
Jeff Brown96e942d2011-11-30 19:55:01 -0800103
104 // Thread local storage for the choreographer.
105 private static final ThreadLocal<Choreographer> sThreadInstance =
106 new ThreadLocal<Choreographer>() {
107 @Override
108 protected Choreographer initialValue() {
109 Looper looper = Looper.myLooper();
110 if (looper == null) {
111 throw new IllegalStateException("The current thread must have a looper!");
112 }
Jorim Jaggib29e3182018-04-30 18:51:56 +0200113 Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
114 if (looper == Looper.getMainLooper()) {
115 mMainInstance = choreographer;
116 }
117 return choreographer;
Jeff Brown96e942d2011-11-30 19:55:01 -0800118 }
119 };
120
Jorim Jaggib29e3182018-04-30 18:51:56 +0200121 private static volatile Choreographer mMainInstance;
122
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700123 // Thread local storage for the SF choreographer.
124 private static final ThreadLocal<Choreographer> sSfThreadInstance =
125 new ThreadLocal<Choreographer>() {
126 @Override
127 protected Choreographer initialValue() {
128 Looper looper = Looper.myLooper();
129 if (looper == null) {
130 throw new IllegalStateException("The current thread must have a looper!");
131 }
132 return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
133 }
134 };
135
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700136 // Enable/disable vsync for animations and drawing.
Nader Jawad21a4f7c2019-02-06 14:10:06 -0800137 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497)
Jeff Brown96e942d2011-11-30 19:55:01 -0800138 private static final boolean USE_VSYNC = SystemProperties.getBoolean(
139 "debug.choreographer.vsync", true);
140
Jeff Brown20c4f872012-04-26 17:38:21 -0700141 // Enable/disable using the frame time instead of returning now.
142 private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
143 "debug.choreographer.frametime", true);
144
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700145 // Set a limit to warn about skipped frames.
146 // Skipped frames imply jank.
147 private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
148 "debug.choreographer.skipwarning", 30);
149
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700150 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;
Jeff Brown96e942d2011-11-30 19:55:01 -0800153
Jeff Browncae80492012-05-21 16:33:39 -0700154 // All frame callbacks posted by applications have this token.
155 private static final Object FRAME_CALLBACK_TOKEN = new Object() {
156 public String toString() { return "FRAME_CALLBACK_TOKEN"; }
157 };
158
Mathew Inwood8c854f82018-09-14 12:35:36 +0100159 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Brown87d0b032012-02-03 11:01:21 -0800160 private final Object mLock = new Object();
161
Jeff Brown96e942d2011-11-30 19:55:01 -0800162 private final Looper mLooper;
Jeff Brown96858852012-02-14 13:45:06 -0800163 private final FrameHandler mHandler;
Jeff Browncae80492012-05-21 16:33:39 -0700164
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.
Mathew Inwooda570dee2018-08-17 14:56:00 +0100168 @UnsupportedAppUsage
Jeff Brown1654d0b2012-02-15 15:40:52 -0800169 private final FrameDisplayEventReceiver mDisplayEventReceiver;
Jeff Brown96858852012-02-14 13:45:06 -0800170
Jeff Browncae80492012-05-21 16:33:39 -0700171 private CallbackRecord mCallbackPool;
Jeff Brown96e942d2011-11-30 19:55:01 -0800172
Mathew Inwooda570dee2018-08-17 14:56:00 +0100173 @UnsupportedAppUsage
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700174 private final CallbackQueue[] mCallbackQueues;
Jeff Brown96858852012-02-14 13:45:06 -0800175
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700176 private boolean mFrameScheduled;
Jeff Brown20c4f872012-04-26 17:38:21 -0700177 private boolean mCallbacksRunning;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100178 @UnsupportedAppUsage
Jeff Brown20c4f872012-04-26 17:38:21 -0700179 private long mLastFrameTimeNanos;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100180 @UnsupportedAppUsage
Jeff Brown59bbef02012-05-07 16:43:25 -0700181 private long mFrameIntervalNanos;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700182 private boolean mDebugPrintNextFrameTimeDelta;
John Reck9f516442017-09-25 10:27:21 -0700183 private int mFPSDivisor = 1;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700184
185 /**
John Reckba6adf62015-02-19 14:36:50 -0800186 * Contains information about the current frame for jank-tracking,
187 * mainly timings of key events along with a bit of metadata about
188 * view tree state
189 *
190 * TODO: Is there a better home for this? Currently Choreographer
191 * is the only one with CALLBACK_ANIMATION start time, hence why this
192 * resides here.
193 *
194 * @hide
195 */
196 FrameInfo mFrameInfo = new FrameInfo();
197
198 /**
Chris Craike22c59b2015-05-21 18:33:37 -0700199 * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
200 * @hide
201 */
202 private static final String[] CALLBACK_TRACE_TITLES = {
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800203 "input", "animation", "insets_animation", "traversal", "commit"
Chris Craike22c59b2015-05-21 18:33:37 -0700204 };
205
206 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700207 * Callback type: Input callback. Runs first.
Jeff Browncae80492012-05-21 16:33:39 -0700208 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700209 */
210 public static final int CALLBACK_INPUT = 0;
211
212 /**
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800213 * Callback type: Animation callback. Runs before {@link #CALLBACK_INSETS_ANIMATION}.
Jeff Browncae80492012-05-21 16:33:39 -0700214 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700215 */
Doris Liu197a6742017-08-16 17:12:42 -0700216 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700217 public static final int CALLBACK_ANIMATION = 1;
218
219 /**
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800220 * 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.
225 * <p>
226 * Both input and animation may change insets, so we need to run this after these callbacks, but
227 * before traversals.
228 * <p>
229 * Runs before traversals.
230 * @hide
231 */
232 public static final int CALLBACK_INSETS_ANIMATION = 2;
233
234 /**
Jeff Brownc42b28d2015-04-06 19:49:02 -0700235 * Callback type: Traversal callback. Handles layout and draw. Runs
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700236 * after all other asynchronous messages have been handled.
Jeff Browncae80492012-05-21 16:33:39 -0700237 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700238 */
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800239 public static final int CALLBACK_TRAVERSAL = 3;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700240
Jeff Brownc42b28d2015-04-06 19:49:02 -0700241 /**
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.
249 * @hide
250 */
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800251 public static final int CALLBACK_COMMIT = 4;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700252
253 private static final int CALLBACK_LAST = CALLBACK_COMMIT;
Jeff Brown96e942d2011-11-30 19:55:01 -0800254
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700255 private Choreographer(Looper looper, int vsyncSource) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800256 mLooper = looper;
Jeff Brown96858852012-02-14 13:45:06 -0800257 mHandler = new FrameHandler(looper);
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700258 mDisplayEventReceiver = USE_VSYNC
259 ? new FrameDisplayEventReceiver(looper, vsyncSource)
260 : null;
Jeff Brown20c4f872012-04-26 17:38:21 -0700261 mLastFrameTimeNanos = Long.MIN_VALUE;
Jeff Brownd32460c2012-07-20 16:15:36 -0700262
Jeff Brownbd6e1502012-08-28 03:27:37 -0700263 mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700264
265 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
266 for (int i = 0; i <= CALLBACK_LAST; i++) {
267 mCallbackQueues[i] = new CallbackQueue();
268 }
Makoto Onukib708cbe2018-01-09 12:35:06 -0800269 // b/68769804: For low FPS experiments.
270 setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
Jeff Brown96e942d2011-11-30 19:55:01 -0800271 }
272
Jeff Brownbd6e1502012-08-28 03:27:37 -0700273 private static float getRefreshRate() {
274 DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
275 Display.DEFAULT_DISPLAY);
P.Y. Laligandb3b9eb32015-05-11 15:02:07 -0700276 return di.getMode().getRefreshRate();
Jeff Brownbd6e1502012-08-28 03:27:37 -0700277 }
278
Jeff Brown96e942d2011-11-30 19:55:01 -0800279 /**
Dianne Hackborn8bcd54b2012-01-31 19:04:53 -0800280 * 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.
Jeff Brown96e942d2011-11-30 19:55:01 -0800282 *
283 * @return The choreographer for this thread.
284 * @throws IllegalStateException if the thread does not have a looper.
285 */
286 public static Choreographer getInstance() {
287 return sThreadInstance.get();
288 }
289
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700290 /**
291 * @hide
292 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100293 @UnsupportedAppUsage
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700294 public static Choreographer getSfInstance() {
295 return sSfThreadInstance.get();
296 }
297
Jorim Jaggib29e3182018-04-30 18:51:56 +0200298 /**
299 * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
300 * @hide
301 */
302 public static Choreographer getMainThreadInstance() {
303 return mMainInstance;
304 }
305
John Reckac04f4e2016-06-23 10:21:45 -0700306 /** Destroys the calling thread's choreographer
307 * @hide
308 */
309 public static void releaseInstance() {
310 Choreographer old = sThreadInstance.get();
311 sThreadInstance.remove();
312 old.dispose();
313 }
314
315 private void dispose() {
316 mDisplayEventReceiver.dispose();
317 }
318
Jeff Brown96e942d2011-11-30 19:55:01 -0800319 /**
Jeff Browncae80492012-05-21 16:33:39 -0700320 * The amount of time, in milliseconds, between each frame of the animation.
321 * <p>
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
Jeff Brown96e942d2011-11-30 19:55:01 -0800324 * function because the same delay will be applied to all animations, since they are all
325 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700326 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800327 * 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.
Jeff Browncae80492012-05-21 16:33:39 -0700329 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800330 *
331 * @return the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700332 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800333 */
Artur Satayev5a525852019-10-31 15:15:50 +0000334 @UnsupportedAppUsage
Doris Liu197a6742017-08-16 17:12:42 -0700335 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800336 public static long getFrameDelay() {
337 return sFrameDelay;
338 }
339
340 /**
Jeff Browncae80492012-05-21 16:33:39 -0700341 * The amount of time, in milliseconds, between each frame of the animation.
342 * <p>
343 * This is a requested time that the animation will attempt to honor, but the actual delay
344 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800345 * function because the same delay will be applied to all animations, since they are all
346 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700347 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800348 * The frame delay may be ignored when the animation system uses an external timing
349 * source, such as the display refresh rate (vsync), to govern animations.
Jeff Browncae80492012-05-21 16:33:39 -0700350 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800351 *
352 * @param frameDelay the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700353 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800354 */
Doris Liu197a6742017-08-16 17:12:42 -0700355 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800356 public static void setFrameDelay(long frameDelay) {
357 sFrameDelay = frameDelay;
358 }
359
360 /**
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800361 * Subtracts typical frame delay time from a delay interval in milliseconds.
Jeff Browncae80492012-05-21 16:33:39 -0700362 * <p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800363 * This method can be used to compensate for animation delay times that have baked
364 * in assumptions about the frame delay. For example, it's quite common for code to
365 * assume a 60Hz frame time and bake in a 16ms delay. When we call
366 * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
367 * posting the animation callback but let the animation timer take care of the remaining
368 * frame delay time.
Jeff Browncae80492012-05-21 16:33:39 -0700369 * </p><p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800370 * This method is somewhat conservative about how much of the frame delay it
371 * subtracts. It uses the same value returned by {@link #getFrameDelay} which by
372 * default is 10ms even though many parts of the system assume 16ms. Consequently,
373 * we might still wait 6ms before posting an animation callback that we want to run
374 * on the next frame, but this is much better than waiting a whole 16ms and likely
375 * missing the deadline.
Jeff Browncae80492012-05-21 16:33:39 -0700376 * </p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800377 *
378 * @param delayMillis The original delay time including an assumed frame delay.
379 * @return The adjusted delay time with the assumed frame delay subtracted out.
Jeff Browncae80492012-05-21 16:33:39 -0700380 * @hide
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800381 */
382 public static long subtractFrameDelay(long delayMillis) {
383 final long frameDelay = sFrameDelay;
384 return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
385 }
386
John Reck18f16e62014-05-02 16:46:41 -0700387 /**
388 * @return The refresh rate as the nanoseconds between frames
389 * @hide
390 */
John Reck315c3292014-05-09 19:21:04 -0700391 public long getFrameIntervalNanos() {
John Reck18f16e62014-05-02 16:46:41 -0700392 return mFrameIntervalNanos;
393 }
394
Jeff Brown5182c782013-10-15 20:31:52 -0700395 void dump(String prefix, PrintWriter writer) {
396 String innerPrefix = prefix + " ";
397 writer.print(prefix); writer.println("Choreographer:");
398 writer.print(innerPrefix); writer.print("mFrameScheduled=");
399 writer.println(mFrameScheduled);
400 writer.print(innerPrefix); writer.print("mLastFrameTime=");
401 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
402 }
403
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800404 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700405 * Posts a callback to run on the next frame.
Jeff Browncae80492012-05-21 16:33:39 -0700406 * <p>
407 * The callback runs once then is automatically removed.
408 * </p>
Jeff Brown4a06c802012-02-15 15:06:01 -0800409 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700410 * @param callbackType The callback type.
411 * @param action The callback action to run during the next frame.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800412 * @param token The callback token, or null if none.
Jeff Brown4a06c802012-02-15 15:06:01 -0800413 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700414 * @see #removeCallbacks
Jeff Browncae80492012-05-21 16:33:39 -0700415 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800416 */
Artur Satayev5a525852019-10-31 15:15:50 +0000417 @UnsupportedAppUsage
Doris Liu4f8a98c2018-01-16 18:13:57 -0800418 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700419 public void postCallback(int callbackType, Runnable action, Object token) {
420 postCallbackDelayed(callbackType, action, token, 0);
Jeff Brown87d0b032012-02-03 11:01:21 -0800421 }
422
Jeff Brown4a06c802012-02-15 15:06:01 -0800423 /**
Jeff Browncae80492012-05-21 16:33:39 -0700424 * Posts a callback to run on the next frame after the specified delay.
425 * <p>
426 * The callback runs once then is automatically removed.
427 * </p>
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800428 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700429 * @param callbackType The callback type.
430 * @param action The callback action to run during the next frame after the specified delay.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800431 * @param token The callback token, or null if none.
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800432 * @param delayMillis The delay time in milliseconds.
433 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700434 * @see #removeCallback
Jeff Browncae80492012-05-21 16:33:39 -0700435 * @hide
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800436 */
Artur Satayev5a525852019-10-31 15:15:50 +0000437 @UnsupportedAppUsage
Doris Liu4f8a98c2018-01-16 18:13:57 -0800438 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700439 public void postCallbackDelayed(int callbackType,
440 Runnable action, Object token, long delayMillis) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800441 if (action == null) {
442 throw new IllegalArgumentException("action must not be null");
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800443 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700444 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
445 throw new IllegalArgumentException("callbackType is invalid");
446 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800447
Jeff Browncae80492012-05-21 16:33:39 -0700448 postCallbackDelayedInternal(callbackType, action, token, delayMillis);
449 }
450
451 private void postCallbackDelayedInternal(int callbackType,
452 Object action, Object token, long delayMillis) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700453 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700454 Log.d(TAG, "PostCallback: type=" + callbackType
455 + ", action=" + action + ", token=" + token
Jeff Brown43ea54b2012-03-09 14:37:48 -0800456 + ", delayMillis=" + delayMillis);
457 }
458
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800459 synchronized (mLock) {
460 final long now = SystemClock.uptimeMillis();
461 final long dueTime = now + delayMillis;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700462 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800463
464 if (dueTime <= now) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700465 scheduleFrameLocked(now);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800466 } else {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700467 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
468 msg.arg1 = callbackType;
469 msg.setAsynchronous(true);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800470 mHandler.sendMessageAtTime(msg, dueTime);
471 }
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800472 }
473 }
474
475 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700476 * Removes callbacks that have the specified action and token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800477 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700478 * @param callbackType The callback type.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800479 * @param action The action property of the callbacks to remove, or null to remove
480 * callbacks with any action.
481 * @param token The token property of the callbacks to remove, or null to remove
482 * callbacks with any token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800483 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700484 * @see #postCallback
485 * @see #postCallbackDelayed
Jeff Browncae80492012-05-21 16:33:39 -0700486 * @hide
Jeff Brown4a06c802012-02-15 15:06:01 -0800487 */
Artur Satayev5a525852019-10-31 15:15:50 +0000488 @UnsupportedAppUsage
Doris Liu4f8a98c2018-01-16 18:13:57 -0800489 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700490 public void removeCallbacks(int callbackType, Runnable action, Object token) {
491 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
492 throw new IllegalArgumentException("callbackType is invalid");
493 }
494
Jeff Browncae80492012-05-21 16:33:39 -0700495 removeCallbacksInternal(callbackType, action, token);
496 }
497
498 private void removeCallbacksInternal(int callbackType, Object action, Object token) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700499 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700500 Log.d(TAG, "RemoveCallbacks: type=" + callbackType
501 + ", action=" + action + ", token=" + token);
Jeff Brown43ea54b2012-03-09 14:37:48 -0800502 }
503
Jeff Brown4a06c802012-02-15 15:06:01 -0800504 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700505 mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800506 if (action != null && token == null) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700507 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800508 }
Jeff Brown4a06c802012-02-15 15:06:01 -0800509 }
510 }
511
Jeff Brown20c4f872012-04-26 17:38:21 -0700512 /**
Jeff Browncae80492012-05-21 16:33:39 -0700513 * Posts a frame callback to run on the next frame.
514 * <p>
515 * The callback runs once then is automatically removed.
516 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700517 *
Jeff Browncae80492012-05-21 16:33:39 -0700518 * @param callback The frame callback to run during the next frame.
519 *
520 * @see #postFrameCallbackDelayed
521 * @see #removeFrameCallback
522 */
523 public void postFrameCallback(FrameCallback callback) {
524 postFrameCallbackDelayed(callback, 0);
525 }
526
527 /**
528 * Posts a frame callback to run on the next frame after the specified delay.
529 * <p>
530 * The callback runs once then is automatically removed.
531 * </p>
532 *
533 * @param callback The frame callback to run during the next frame.
534 * @param delayMillis The delay time in milliseconds.
535 *
536 * @see #postFrameCallback
537 * @see #removeFrameCallback
538 */
539 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
540 if (callback == null) {
541 throw new IllegalArgumentException("callback must not be null");
542 }
543
544 postCallbackDelayedInternal(CALLBACK_ANIMATION,
545 callback, FRAME_CALLBACK_TOKEN, delayMillis);
546 }
547
548 /**
549 * Removes a previously posted frame callback.
550 *
551 * @param callback The frame callback to remove.
552 *
553 * @see #postFrameCallback
554 * @see #postFrameCallbackDelayed
555 */
556 public void removeFrameCallback(FrameCallback callback) {
557 if (callback == null) {
558 throw new IllegalArgumentException("callback must not be null");
559 }
560
561 removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
562 }
563
564 /**
565 * Gets the time when the current frame started.
566 * <p>
John Reck8d8af3c2014-07-01 15:23:45 -0700567 * This method provides the time in milliseconds when the frame started being rendered.
Jeff Browncae80492012-05-21 16:33:39 -0700568 * The frame time provides a stable time base for synchronizing animations
569 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
570 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
571 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
572 * the frame was scheduled to start, regardless of when the animations or drawing
573 * callback actually runs. All callbacks that run as part of rendering a frame will
574 * observe the same frame time so using the frame time also helps to synchronize effects
575 * that are performed by different callbacks.
576 * </p><p>
577 * Please note that the framework already takes care to process animations and
578 * drawing using the frame time as a stable time base. Most applications should
579 * not need to use the frame time information directly.
580 * </p><p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700581 * This method should only be called from within a callback.
Jeff Browncae80492012-05-21 16:33:39 -0700582 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700583 *
584 * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
585 *
586 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700587 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700588 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100589 @UnsupportedAppUsage
Jeff Brown20c4f872012-04-26 17:38:21 -0700590 public long getFrameTime() {
John Reck315c3292014-05-09 19:21:04 -0700591 return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
Jeff Brown20c4f872012-04-26 17:38:21 -0700592 }
593
594 /**
595 * Same as {@link #getFrameTime()} but with nanosecond precision.
596 *
597 * @return The frame start time, in the {@link System#nanoTime()} time base.
598 *
599 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700600 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700601 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100602 @UnsupportedAppUsage
Jeff Brown20c4f872012-04-26 17:38:21 -0700603 public long getFrameTimeNanos() {
604 synchronized (mLock) {
605 if (!mCallbacksRunning) {
606 throw new IllegalStateException("This method must only be called as "
607 + "part of a callback while a frame is in progress.");
608 }
609 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
610 }
611 }
612
Jorim Jaggid6d6de62017-03-31 15:05:13 +0200613 /**
614 * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
615 * whether callbacks are currently running.
616 * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
617 * @hide
618 */
619 public long getLastFrameTimeNanos() {
620 synchronized (mLock) {
621 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
622 }
623 }
624
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700625 private void scheduleFrameLocked(long now) {
626 if (!mFrameScheduled) {
627 mFrameScheduled = true;
Jeff Brown96e942d2011-11-30 19:55:01 -0800628 if (USE_VSYNC) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700629 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700630 Log.d(TAG, "Scheduling next frame on vsync.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800631 }
Jeff Brown58aedbc2012-02-13 20:15:01 -0800632
633 // If running on the Looper thread, then schedule the vsync immediately,
634 // otherwise post a message to schedule the vsync from the UI thread
635 // as soon as possible.
Jeff Brown58aedbc2012-02-13 20:15:01 -0800636 if (isRunningOnLooperThreadLocked()) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800637 scheduleVsyncLocked();
Jeff Brown58aedbc2012-02-13 20:15:01 -0800638 } else {
Jeff Browne0dbd002012-02-15 19:34:58 -0800639 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
640 msg.setAsynchronous(true);
641 mHandler.sendMessageAtFrontOfQueue(msg);
Jeff Brown58aedbc2012-02-13 20:15:01 -0800642 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800643 } else {
Jeff Brown20c4f872012-04-26 17:38:21 -0700644 final long nextFrameTime = Math.max(
John Reck315c3292014-05-09 19:21:04 -0700645 mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700646 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700647 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800648 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700649 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
Jeff Browne0dbd002012-02-15 19:34:58 -0800650 msg.setAsynchronous(true);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700651 mHandler.sendMessageAtTime(msg, nextFrameTime);
Jeff Brown96e942d2011-11-30 19:55:01 -0800652 }
653 }
654 }
655
John Reck9f516442017-09-25 10:27:21 -0700656 void setFPSDivisor(int divisor) {
657 if (divisor <= 0) divisor = 1;
658 mFPSDivisor = divisor;
Makoto Onukib708cbe2018-01-09 12:35:06 -0800659 ThreadedRenderer.setFPSDivisor(divisor);
John Reck9f516442017-09-25 10:27:21 -0700660 }
661
Mathew Inwooda570dee2018-08-17 14:56:00 +0100662 @UnsupportedAppUsage
Jeff Browncae80492012-05-21 16:33:39 -0700663 void doFrame(long frameTimeNanos, int frame) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700664 final long startNanos;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700665 synchronized (mLock) {
666 if (!mFrameScheduled) {
667 return; // no work to do
Jeff Brown96e942d2011-11-30 19:55:01 -0800668 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700669
Jeff Brownc42b28d2015-04-06 19:49:02 -0700670 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
671 mDebugPrintNextFrameTimeDelta = false;
672 Log.d(TAG, "Frame time delta: "
673 + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
674 }
675
John Reckba6adf62015-02-19 14:36:50 -0800676 long intendedFrameTimeNanos = frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700677 startNanos = System.nanoTime();
Jeff Browncae80492012-05-21 16:33:39 -0700678 final long jitterNanos = startNanos - frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700679 if (jitterNanos >= mFrameIntervalNanos) {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700680 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
681 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Jeff Brown265f1cc2012-06-11 18:01:06 -0700682 Log.i(TAG, "Skipped " + skippedFrames + " frames! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700683 + "The application may be doing too much work on its main thread.");
684 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700685 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700686 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700687 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
688 + "which is more than the frame interval of "
689 + (mFrameIntervalNanos * 0.000001f) + " ms! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700690 + "Skipping " + skippedFrames + " frames and setting frame "
691 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700692 }
Jeff Browncae80492012-05-21 16:33:39 -0700693 frameTimeNanos = startNanos - lastFrameOffset;
Jeff Brown59bbef02012-05-07 16:43:25 -0700694 }
695
Jeff Browncae80492012-05-21 16:33:39 -0700696 if (frameTimeNanos < mLastFrameTimeNanos) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700697 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700698 Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700699 + "previously skipped frame. Waiting for next vsync.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700700 }
701 scheduleVsyncLocked();
702 return;
703 }
704
John Reck9f516442017-09-25 10:27:21 -0700705 if (mFPSDivisor > 1) {
706 long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
707 if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
708 scheduleVsyncLocked();
709 return;
710 }
711 }
712
John Reckba6adf62015-02-19 14:36:50 -0800713 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700714 mFrameScheduled = false;
Jeff Browncae80492012-05-21 16:33:39 -0700715 mLastFrameTimeNanos = frameTimeNanos;
Jeff Brown20c4f872012-04-26 17:38:21 -0700716 }
717
Chris Craike22c59b2015-05-21 18:33:37 -0700718 try {
719 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
John Recka2acb4f2016-08-05 07:58:37 -0700720 AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
John Reckba6adf62015-02-19 14:36:50 -0800721
Chris Craike22c59b2015-05-21 18:33:37 -0700722 mFrameInfo.markInputHandlingStart();
723 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
John Reckba6adf62015-02-19 14:36:50 -0800724
Chris Craike22c59b2015-05-21 18:33:37 -0700725 mFrameInfo.markAnimationsStart();
726 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800727 doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700728
Chris Craike22c59b2015-05-21 18:33:37 -0700729 mFrameInfo.markPerformTraversalsStart();
730 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
731
732 doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
733 } finally {
John Recka2acb4f2016-08-05 07:58:37 -0700734 AnimationUtils.unlockAnimationClock();
Chris Craike22c59b2015-05-21 18:33:37 -0700735 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
736 }
Jeff Brownc42b28d2015-04-06 19:49:02 -0700737
738 if (DEBUG_FRAMES) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700739 final long endNanos = System.nanoTime();
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700740 Log.d(TAG, "Frame " + frame + ": Finished, took "
Jeff Brown20c4f872012-04-26 17:38:21 -0700741 + (endNanos - startNanos) * 0.000001f + " ms, latency "
Jeff Browncae80492012-05-21 16:33:39 -0700742 + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800743 }
744 }
745
Jeff Browncae80492012-05-21 16:33:39 -0700746 void doCallbacks(int callbackType, long frameTimeNanos) {
747 CallbackRecord callbacks;
Jeff Brown96858852012-02-14 13:45:06 -0800748 synchronized (mLock) {
Jeff Browncae80492012-05-21 16:33:39 -0700749 // We use "now" to determine when callbacks become due because it's possible
750 // for earlier processing phases in a frame to post callbacks that should run
751 // in a following phase, such as an input event that causes an animation to start.
Jeff Brownc42b28d2015-04-06 19:49:02 -0700752 final long now = System.nanoTime();
753 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
754 now / TimeUtils.NANOS_PER_MS);
Jeff Brown20c4f872012-04-26 17:38:21 -0700755 if (callbacks == null) {
756 return;
757 }
758 mCallbacksRunning = true;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700759
760 // Update the frame time if necessary when committing the frame.
761 // We only update the frame time if we are more than 2 frames late reaching
762 // the commit phase. This ensures that the frame time which is observed by the
763 // callbacks will always increase from one frame to the next and never repeat.
764 // We never want the next frame's starting frame time to end up being less than
765 // or equal to the previous frame's commit frame time. Keep in mind that the
766 // next frame has most likely already been scheduled by now so we play it
767 // safe by ensuring the commit time is always at least one frame behind.
768 if (callbackType == Choreographer.CALLBACK_COMMIT) {
769 final long jitterNanos = now - frameTimeNanos;
Chris Craike22c59b2015-05-21 18:33:37 -0700770 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700771 if (jitterNanos >= 2 * mFrameIntervalNanos) {
772 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
773 + mFrameIntervalNanos;
774 if (DEBUG_JANK) {
775 Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
776 + " ms which is more than twice the frame interval of "
777 + (mFrameIntervalNanos * 0.000001f) + " ms! "
778 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
779 + " ms in the past.");
780 mDebugPrintNextFrameTimeDelta = true;
781 }
782 frameTimeNanos = now - lastFrameOffset;
783 mLastFrameTimeNanos = frameTimeNanos;
784 }
785 }
Jeff Brown96858852012-02-14 13:45:06 -0800786 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700787 try {
Chris Craike22c59b2015-05-21 18:33:37 -0700788 Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
Jeff Browncae80492012-05-21 16:33:39 -0700789 for (CallbackRecord c = callbacks; c != null; c = c.next) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700790 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700791 Log.d(TAG, "RunCallback: type=" + callbackType
792 + ", action=" + c.action + ", token=" + c.token
793 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
794 }
Jeff Browncae80492012-05-21 16:33:39 -0700795 c.run(frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700796 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700797 } finally {
Jeff Brown96858852012-02-14 13:45:06 -0800798 synchronized (mLock) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700799 mCallbacksRunning = false;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700800 do {
Jeff Browncae80492012-05-21 16:33:39 -0700801 final CallbackRecord next = callbacks.next;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700802 recycleCallbackLocked(callbacks);
803 callbacks = next;
804 } while (callbacks != null);
Jeff Brown96858852012-02-14 13:45:06 -0800805 }
Chris Craike22c59b2015-05-21 18:33:37 -0700806 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Jeff Brown96858852012-02-14 13:45:06 -0800807 }
Jeff Brown96858852012-02-14 13:45:06 -0800808 }
809
810 void doScheduleVsync() {
811 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700812 if (mFrameScheduled) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800813 scheduleVsyncLocked();
814 }
Jeff Brown96858852012-02-14 13:45:06 -0800815 }
816 }
817
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700818 void doScheduleCallback(int callbackType) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800819 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700820 if (!mFrameScheduled) {
821 final long now = SystemClock.uptimeMillis();
822 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
823 scheduleFrameLocked(now);
824 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800825 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800826 }
827 }
828
Mathew Inwooda570dee2018-08-17 14:56:00 +0100829 @UnsupportedAppUsage
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800830 private void scheduleVsyncLocked() {
831 mDisplayEventReceiver.scheduleVsync();
832 }
833
Jeff Brown58aedbc2012-02-13 20:15:01 -0800834 private boolean isRunningOnLooperThreadLocked() {
835 return Looper.myLooper() == mLooper;
836 }
837
Jeff Browncae80492012-05-21 16:33:39 -0700838 private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
839 CallbackRecord callback = mCallbackPool;
Jeff Brown96858852012-02-14 13:45:06 -0800840 if (callback == null) {
Jeff Browncae80492012-05-21 16:33:39 -0700841 callback = new CallbackRecord();
Jeff Brown96858852012-02-14 13:45:06 -0800842 } else {
843 mCallbackPool = callback.next;
844 callback.next = null;
845 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800846 callback.dueTime = dueTime;
847 callback.action = action;
848 callback.token = token;
Jeff Brown96858852012-02-14 13:45:06 -0800849 return callback;
850 }
851
Jeff Browncae80492012-05-21 16:33:39 -0700852 private void recycleCallbackLocked(CallbackRecord callback) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800853 callback.action = null;
854 callback.token = null;
Jeff Brown96858852012-02-14 13:45:06 -0800855 callback.next = mCallbackPool;
856 mCallbackPool = callback;
857 }
858
Jeff Browncae80492012-05-21 16:33:39 -0700859 /**
860 * Implement this interface to receive a callback when a new display frame is
861 * being rendered. The callback is invoked on the {@link Looper} thread to
862 * which the {@link Choreographer} is attached.
863 */
864 public interface FrameCallback {
865 /**
866 * Called when a new display frame is being rendered.
867 * <p>
868 * This method provides the time in nanoseconds when the frame started being rendered.
869 * The frame time provides a stable time base for synchronizing animations
870 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
871 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
872 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
873 * the frame was scheduled to start, regardless of when the animations or drawing
874 * callback actually runs. All callbacks that run as part of rendering a frame will
875 * observe the same frame time so using the frame time also helps to synchronize effects
876 * that are performed by different callbacks.
877 * </p><p>
878 * Please note that the framework already takes care to process animations and
879 * drawing using the frame time as a stable time base. Most applications should
880 * not need to use the frame time information directly.
881 * </p>
882 *
883 * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
884 * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000}
885 * to convert it to the {@link SystemClock#uptimeMillis()} time base.
886 */
887 public void doFrame(long frameTimeNanos);
888 }
889
Jeff Brown96858852012-02-14 13:45:06 -0800890 private final class FrameHandler extends Handler {
891 public FrameHandler(Looper looper) {
892 super(looper);
893 }
894
895 @Override
896 public void handleMessage(Message msg) {
897 switch (msg.what) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700898 case MSG_DO_FRAME:
Jeff Brown20c4f872012-04-26 17:38:21 -0700899 doFrame(System.nanoTime(), 0);
Jeff Brown96858852012-02-14 13:45:06 -0800900 break;
901 case MSG_DO_SCHEDULE_VSYNC:
902 doScheduleVsync();
903 break;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700904 case MSG_DO_SCHEDULE_CALLBACK:
905 doScheduleCallback(msg.arg1);
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800906 break;
Jeff Brown96858852012-02-14 13:45:06 -0800907 }
908 }
909 }
910
Jeff Brownb0806602012-05-16 12:50:41 -0700911 private final class FrameDisplayEventReceiver extends DisplayEventReceiver
912 implements Runnable {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700913 private boolean mHavePendingVsync;
Jeff Brownb0806602012-05-16 12:50:41 -0700914 private long mTimestampNanos;
915 private int mFrame;
916
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700917 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
Ady Abraham9c501aa2019-06-04 16:07:44 -0700918 super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
Jeff Brown96e942d2011-11-30 19:55:01 -0800919 }
920
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800921 // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
922 // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
923 // for the internal display implicitly.
Jeff Brown96e942d2011-11-30 19:55:01 -0800924 @Override
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800925 public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
Jeff Brownb0806602012-05-16 12:50:41 -0700926 // Post the vsync event to the Handler.
927 // The idea is to prevent incoming vsync events from completely starving
928 // the message queue. If there are no messages in the queue with timestamps
929 // earlier than the frame time, then the vsync event will be processed immediately.
930 // Otherwise, messages that predate the vsync event will be handled first.
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700931 long now = System.nanoTime();
932 if (timestampNanos > now) {
933 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
934 + " ms in the future! Check that graphics HAL is generating vsync "
935 + "timestamps using the correct timebase.");
936 timestampNanos = now;
937 }
938
Jeff Brownba7261132012-06-14 23:48:40 -0700939 if (mHavePendingVsync) {
940 Log.w(TAG, "Already have a pending vsync event. There should only be "
941 + "one at a time.");
942 } else {
943 mHavePendingVsync = true;
944 }
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700945
Jeff Brownb0806602012-05-16 12:50:41 -0700946 mTimestampNanos = timestampNanos;
947 mFrame = frame;
948 Message msg = Message.obtain(mHandler, this);
949 msg.setAsynchronous(true);
John Reck315c3292014-05-09 19:21:04 -0700950 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
Jeff Brownb0806602012-05-16 12:50:41 -0700951 }
952
953 @Override
954 public void run() {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700955 mHavePendingVsync = false;
Jeff Brownb0806602012-05-16 12:50:41 -0700956 doFrame(mTimestampNanos, mFrame);
Jeff Brown96e942d2011-11-30 19:55:01 -0800957 }
958 }
Jeff Brown96858852012-02-14 13:45:06 -0800959
Jeff Browncae80492012-05-21 16:33:39 -0700960 private static final class CallbackRecord {
961 public CallbackRecord next;
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800962 public long dueTime;
Jeff Browncae80492012-05-21 16:33:39 -0700963 public Object action; // Runnable or FrameCallback
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800964 public Object token;
Jeff Browncae80492012-05-21 16:33:39 -0700965
Mathew Inwooda570dee2018-08-17 14:56:00 +0100966 @UnsupportedAppUsage
Jeff Browncae80492012-05-21 16:33:39 -0700967 public void run(long frameTimeNanos) {
968 if (token == FRAME_CALLBACK_TOKEN) {
969 ((FrameCallback)action).doFrame(frameTimeNanos);
970 } else {
971 ((Runnable)action).run();
972 }
973 }
Jeff Brown96858852012-02-14 13:45:06 -0800974 }
Jeff Brown43ea54b2012-03-09 14:37:48 -0800975
976 private final class CallbackQueue {
Jeff Browncae80492012-05-21 16:33:39 -0700977 private CallbackRecord mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800978
979 public boolean hasDueCallbacksLocked(long now) {
980 return mHead != null && mHead.dueTime <= now;
981 }
982
Jeff Browncae80492012-05-21 16:33:39 -0700983 public CallbackRecord extractDueCallbacksLocked(long now) {
984 CallbackRecord callbacks = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800985 if (callbacks == null || callbacks.dueTime > now) {
986 return null;
987 }
988
Jeff Browncae80492012-05-21 16:33:39 -0700989 CallbackRecord last = callbacks;
990 CallbackRecord next = last.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800991 while (next != null) {
992 if (next.dueTime > now) {
993 last.next = null;
994 break;
995 }
996 last = next;
997 next = next.next;
998 }
999 mHead = next;
1000 return callbacks;
1001 }
1002
Mathew Inwooda570dee2018-08-17 14:56:00 +01001003 @UnsupportedAppUsage
Jeff Browncae80492012-05-21 16:33:39 -07001004 public void addCallbackLocked(long dueTime, Object action, Object token) {
1005 CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
1006 CallbackRecord entry = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -08001007 if (entry == null) {
1008 mHead = callback;
1009 return;
1010 }
1011 if (dueTime < entry.dueTime) {
1012 callback.next = entry;
1013 mHead = callback;
1014 return;
1015 }
1016 while (entry.next != null) {
1017 if (dueTime < entry.next.dueTime) {
1018 callback.next = entry.next;
1019 break;
1020 }
1021 entry = entry.next;
1022 }
1023 entry.next = callback;
1024 }
1025
Jeff Browncae80492012-05-21 16:33:39 -07001026 public void removeCallbacksLocked(Object action, Object token) {
1027 CallbackRecord predecessor = null;
1028 for (CallbackRecord callback = mHead; callback != null;) {
1029 final CallbackRecord next = callback.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -08001030 if ((action == null || callback.action == action)
1031 && (token == null || callback.token == token)) {
1032 if (predecessor != null) {
1033 predecessor.next = next;
1034 } else {
1035 mHead = next;
1036 }
1037 recycleCallbackLocked(callback);
1038 } else {
1039 predecessor = callback;
1040 }
1041 callback = next;
1042 }
1043 }
1044 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001045}