blob: e95b5caa4fa085e24d460184f2472ca79487eac1 [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 */
Doris Liu197a6742017-08-16 17:12:42 -0700334 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800335 public static long getFrameDelay() {
336 return sFrameDelay;
337 }
338
339 /**
Jeff Browncae80492012-05-21 16:33:39 -0700340 * The amount of time, in milliseconds, between each frame of the animation.
341 * <p>
342 * This is a requested time that the animation will attempt to honor, but the actual delay
343 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800344 * function because the same delay will be applied to all animations, since they are all
345 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700346 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800347 * 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.
Jeff Browncae80492012-05-21 16:33:39 -0700349 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800350 *
351 * @param frameDelay the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700352 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800353 */
Doris Liu197a6742017-08-16 17:12:42 -0700354 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800355 public static void setFrameDelay(long frameDelay) {
356 sFrameDelay = frameDelay;
357 }
358
359 /**
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800360 * Subtracts typical frame delay time from a delay interval in milliseconds.
Jeff Browncae80492012-05-21 16:33:39 -0700361 * <p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800362 * This method can be used to compensate for animation delay times that have baked
363 * in assumptions about the frame delay. For example, it's quite common for code to
364 * assume a 60Hz frame time and bake in a 16ms delay. When we call
365 * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
366 * posting the animation callback but let the animation timer take care of the remaining
367 * frame delay time.
Jeff Browncae80492012-05-21 16:33:39 -0700368 * </p><p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800369 * 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.
Jeff Browncae80492012-05-21 16:33:39 -0700375 * </p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800376 *
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.
Jeff Browncae80492012-05-21 16:33:39 -0700379 * @hide
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800380 */
381 public static long subtractFrameDelay(long delayMillis) {
382 final long frameDelay = sFrameDelay;
383 return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
384 }
385
John Reck18f16e62014-05-02 16:46:41 -0700386 /**
387 * @return The refresh rate as the nanoseconds between frames
388 * @hide
389 */
John Reck315c3292014-05-09 19:21:04 -0700390 public long getFrameIntervalNanos() {
John Reck18f16e62014-05-02 16:46:41 -0700391 return mFrameIntervalNanos;
392 }
393
Jeff Brown5182c782013-10-15 20:31:52 -0700394 void dump(String prefix, PrintWriter writer) {
395 String innerPrefix = prefix + " ";
396 writer.print(prefix); writer.println("Choreographer:");
397 writer.print(innerPrefix); writer.print("mFrameScheduled=");
398 writer.println(mFrameScheduled);
399 writer.print(innerPrefix); writer.print("mLastFrameTime=");
400 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
401 }
402
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800403 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700404 * Posts a callback to run on the next frame.
Jeff Browncae80492012-05-21 16:33:39 -0700405 * <p>
406 * The callback runs once then is automatically removed.
407 * </p>
Jeff Brown4a06c802012-02-15 15:06:01 -0800408 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700409 * @param callbackType The callback type.
410 * @param action The callback action to run during the next frame.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800411 * @param token The callback token, or null if none.
Jeff Brown4a06c802012-02-15 15:06:01 -0800412 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700413 * @see #removeCallbacks
Jeff Browncae80492012-05-21 16:33:39 -0700414 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800415 */
Doris Liu4f8a98c2018-01-16 18:13:57 -0800416 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700417 public void postCallback(int callbackType, Runnable action, Object token) {
418 postCallbackDelayed(callbackType, action, token, 0);
Jeff Brown87d0b032012-02-03 11:01:21 -0800419 }
420
Jeff Brown4a06c802012-02-15 15:06:01 -0800421 /**
Jeff Browncae80492012-05-21 16:33:39 -0700422 * Posts a callback to run on the next frame after the specified delay.
423 * <p>
424 * The callback runs once then is automatically removed.
425 * </p>
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800426 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700427 * @param callbackType The callback type.
428 * @param action The callback action to run during the next frame after the specified delay.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800429 * @param token The callback token, or null if none.
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800430 * @param delayMillis The delay time in milliseconds.
431 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700432 * @see #removeCallback
Jeff Browncae80492012-05-21 16:33:39 -0700433 * @hide
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800434 */
Doris Liu4f8a98c2018-01-16 18:13:57 -0800435 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700436 public void postCallbackDelayed(int callbackType,
437 Runnable action, Object token, long delayMillis) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800438 if (action == null) {
439 throw new IllegalArgumentException("action must not be null");
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800440 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700441 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
442 throw new IllegalArgumentException("callbackType is invalid");
443 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800444
Jeff Browncae80492012-05-21 16:33:39 -0700445 postCallbackDelayedInternal(callbackType, action, token, delayMillis);
446 }
447
448 private void postCallbackDelayedInternal(int callbackType,
449 Object action, Object token, long delayMillis) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700450 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700451 Log.d(TAG, "PostCallback: type=" + callbackType
452 + ", action=" + action + ", token=" + token
Jeff Brown43ea54b2012-03-09 14:37:48 -0800453 + ", delayMillis=" + delayMillis);
454 }
455
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800456 synchronized (mLock) {
457 final long now = SystemClock.uptimeMillis();
458 final long dueTime = now + delayMillis;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700459 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800460
461 if (dueTime <= now) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700462 scheduleFrameLocked(now);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800463 } else {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700464 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
465 msg.arg1 = callbackType;
466 msg.setAsynchronous(true);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800467 mHandler.sendMessageAtTime(msg, dueTime);
468 }
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800469 }
470 }
471
472 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700473 * Removes callbacks that have the specified action and token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800474 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700475 * @param callbackType The callback type.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800476 * @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.
Jeff Brown4a06c802012-02-15 15:06:01 -0800480 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700481 * @see #postCallback
482 * @see #postCallbackDelayed
Jeff Browncae80492012-05-21 16:33:39 -0700483 * @hide
Jeff Brown4a06c802012-02-15 15:06:01 -0800484 */
Doris Liu4f8a98c2018-01-16 18:13:57 -0800485 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700486 public void removeCallbacks(int callbackType, Runnable action, Object token) {
487 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
488 throw new IllegalArgumentException("callbackType is invalid");
489 }
490
Jeff Browncae80492012-05-21 16:33:39 -0700491 removeCallbacksInternal(callbackType, action, token);
492 }
493
494 private void removeCallbacksInternal(int callbackType, Object action, Object token) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700495 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700496 Log.d(TAG, "RemoveCallbacks: type=" + callbackType
497 + ", action=" + action + ", token=" + token);
Jeff Brown43ea54b2012-03-09 14:37:48 -0800498 }
499
Jeff Brown4a06c802012-02-15 15:06:01 -0800500 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700501 mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800502 if (action != null && token == null) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700503 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800504 }
Jeff Brown4a06c802012-02-15 15:06:01 -0800505 }
506 }
507
Jeff Brown20c4f872012-04-26 17:38:21 -0700508 /**
Jeff Browncae80492012-05-21 16:33:39 -0700509 * Posts a frame callback to run on the next frame.
510 * <p>
511 * The callback runs once then is automatically removed.
512 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700513 *
Jeff Browncae80492012-05-21 16:33:39 -0700514 * @param callback The frame callback to run during the next frame.
515 *
516 * @see #postFrameCallbackDelayed
517 * @see #removeFrameCallback
518 */
519 public void postFrameCallback(FrameCallback callback) {
520 postFrameCallbackDelayed(callback, 0);
521 }
522
523 /**
524 * Posts a frame callback to run on the next frame after the specified delay.
525 * <p>
526 * The callback runs once then is automatically removed.
527 * </p>
528 *
529 * @param callback The frame callback to run during the next frame.
530 * @param delayMillis The delay time in milliseconds.
531 *
532 * @see #postFrameCallback
533 * @see #removeFrameCallback
534 */
535 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
536 if (callback == null) {
537 throw new IllegalArgumentException("callback must not be null");
538 }
539
540 postCallbackDelayedInternal(CALLBACK_ANIMATION,
541 callback, FRAME_CALLBACK_TOKEN, delayMillis);
542 }
543
544 /**
545 * Removes a previously posted frame callback.
546 *
547 * @param callback The frame callback to remove.
548 *
549 * @see #postFrameCallback
550 * @see #postFrameCallbackDelayed
551 */
552 public void removeFrameCallback(FrameCallback callback) {
553 if (callback == null) {
554 throw new IllegalArgumentException("callback must not be null");
555 }
556
557 removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
558 }
559
560 /**
561 * Gets the time when the current frame started.
562 * <p>
John Reck8d8af3c2014-07-01 15:23:45 -0700563 * This method provides the time in milliseconds when the frame started being rendered.
Jeff Browncae80492012-05-21 16:33:39 -0700564 * 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.
572 * </p><p>
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.
576 * </p><p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700577 * This method should only be called from within a callback.
Jeff Browncae80492012-05-21 16:33:39 -0700578 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700579 *
580 * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
581 *
582 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700583 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700584 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100585 @UnsupportedAppUsage
Jeff Brown20c4f872012-04-26 17:38:21 -0700586 public long getFrameTime() {
John Reck315c3292014-05-09 19:21:04 -0700587 return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
Jeff Brown20c4f872012-04-26 17:38:21 -0700588 }
589
590 /**
591 * Same as {@link #getFrameTime()} but with nanosecond precision.
592 *
593 * @return The frame start time, in the {@link System#nanoTime()} time base.
594 *
595 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700596 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700597 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100598 @UnsupportedAppUsage
Jeff Brown20c4f872012-04-26 17:38:21 -0700599 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.");
604 }
605 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
606 }
607 }
608
Jorim Jaggid6d6de62017-03-31 15:05:13 +0200609 /**
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.
613 * @hide
614 */
615 public long getLastFrameTimeNanos() {
616 synchronized (mLock) {
617 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
618 }
619 }
620
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700621 private void scheduleFrameLocked(long now) {
622 if (!mFrameScheduled) {
623 mFrameScheduled = true;
Jeff Brown96e942d2011-11-30 19:55:01 -0800624 if (USE_VSYNC) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700625 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700626 Log.d(TAG, "Scheduling next frame on vsync.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800627 }
Jeff Brown58aedbc2012-02-13 20:15:01 -0800628
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.
Jeff Brown58aedbc2012-02-13 20:15:01 -0800632 if (isRunningOnLooperThreadLocked()) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800633 scheduleVsyncLocked();
Jeff Brown58aedbc2012-02-13 20:15:01 -0800634 } else {
Jeff Browne0dbd002012-02-15 19:34:58 -0800635 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
636 msg.setAsynchronous(true);
637 mHandler.sendMessageAtFrontOfQueue(msg);
Jeff Brown58aedbc2012-02-13 20:15:01 -0800638 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800639 } else {
Jeff Brown20c4f872012-04-26 17:38:21 -0700640 final long nextFrameTime = Math.max(
John Reck315c3292014-05-09 19:21:04 -0700641 mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700642 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700643 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800644 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700645 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
Jeff Browne0dbd002012-02-15 19:34:58 -0800646 msg.setAsynchronous(true);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700647 mHandler.sendMessageAtTime(msg, nextFrameTime);
Jeff Brown96e942d2011-11-30 19:55:01 -0800648 }
649 }
650 }
651
John Reck9f516442017-09-25 10:27:21 -0700652 void setFPSDivisor(int divisor) {
653 if (divisor <= 0) divisor = 1;
654 mFPSDivisor = divisor;
Makoto Onukib708cbe2018-01-09 12:35:06 -0800655 ThreadedRenderer.setFPSDivisor(divisor);
John Reck9f516442017-09-25 10:27:21 -0700656 }
657
Mathew Inwooda570dee2018-08-17 14:56:00 +0100658 @UnsupportedAppUsage
Jeff Browncae80492012-05-21 16:33:39 -0700659 void doFrame(long frameTimeNanos, int frame) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700660 final long startNanos;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700661 synchronized (mLock) {
662 if (!mFrameScheduled) {
663 return; // no work to do
Jeff Brown96e942d2011-11-30 19:55:01 -0800664 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700665
Jeff Brownc42b28d2015-04-06 19:49:02 -0700666 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
667 mDebugPrintNextFrameTimeDelta = false;
668 Log.d(TAG, "Frame time delta: "
669 + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
670 }
671
John Reckba6adf62015-02-19 14:36:50 -0800672 long intendedFrameTimeNanos = frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700673 startNanos = System.nanoTime();
Jeff Browncae80492012-05-21 16:33:39 -0700674 final long jitterNanos = startNanos - frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700675 if (jitterNanos >= mFrameIntervalNanos) {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700676 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
677 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Jeff Brown265f1cc2012-06-11 18:01:06 -0700678 Log.i(TAG, "Skipped " + skippedFrames + " frames! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700679 + "The application may be doing too much work on its main thread.");
680 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700681 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700682 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700683 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
684 + "which is more than the frame interval of "
685 + (mFrameIntervalNanos * 0.000001f) + " ms! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700686 + "Skipping " + skippedFrames + " frames and setting frame "
687 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700688 }
Jeff Browncae80492012-05-21 16:33:39 -0700689 frameTimeNanos = startNanos - lastFrameOffset;
Jeff Brown59bbef02012-05-07 16:43:25 -0700690 }
691
Jeff Browncae80492012-05-21 16:33:39 -0700692 if (frameTimeNanos < mLastFrameTimeNanos) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700693 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700694 Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700695 + "previously skipped frame. Waiting for next vsync.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700696 }
697 scheduleVsyncLocked();
698 return;
699 }
700
John Reck9f516442017-09-25 10:27:21 -0700701 if (mFPSDivisor > 1) {
702 long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
703 if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
704 scheduleVsyncLocked();
705 return;
706 }
707 }
708
John Reckba6adf62015-02-19 14:36:50 -0800709 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700710 mFrameScheduled = false;
Jeff Browncae80492012-05-21 16:33:39 -0700711 mLastFrameTimeNanos = frameTimeNanos;
Jeff Brown20c4f872012-04-26 17:38:21 -0700712 }
713
Chris Craike22c59b2015-05-21 18:33:37 -0700714 try {
715 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
John Recka2acb4f2016-08-05 07:58:37 -0700716 AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
John Reckba6adf62015-02-19 14:36:50 -0800717
Chris Craike22c59b2015-05-21 18:33:37 -0700718 mFrameInfo.markInputHandlingStart();
719 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
John Reckba6adf62015-02-19 14:36:50 -0800720
Chris Craike22c59b2015-05-21 18:33:37 -0700721 mFrameInfo.markAnimationsStart();
722 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800723 doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700724
Chris Craike22c59b2015-05-21 18:33:37 -0700725 mFrameInfo.markPerformTraversalsStart();
726 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
727
728 doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
729 } finally {
John Recka2acb4f2016-08-05 07:58:37 -0700730 AnimationUtils.unlockAnimationClock();
Chris Craike22c59b2015-05-21 18:33:37 -0700731 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
732 }
Jeff Brownc42b28d2015-04-06 19:49:02 -0700733
734 if (DEBUG_FRAMES) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700735 final long endNanos = System.nanoTime();
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700736 Log.d(TAG, "Frame " + frame + ": Finished, took "
Jeff Brown20c4f872012-04-26 17:38:21 -0700737 + (endNanos - startNanos) * 0.000001f + " ms, latency "
Jeff Browncae80492012-05-21 16:33:39 -0700738 + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800739 }
740 }
741
Jeff Browncae80492012-05-21 16:33:39 -0700742 void doCallbacks(int callbackType, long frameTimeNanos) {
743 CallbackRecord callbacks;
Jeff Brown96858852012-02-14 13:45:06 -0800744 synchronized (mLock) {
Jeff Browncae80492012-05-21 16:33:39 -0700745 // 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.
Jeff Brownc42b28d2015-04-06 19:49:02 -0700748 final long now = System.nanoTime();
749 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
750 now / TimeUtils.NANOS_PER_MS);
Jeff Brown20c4f872012-04-26 17:38:21 -0700751 if (callbacks == null) {
752 return;
753 }
754 mCallbacksRunning = true;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700755
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;
Chris Craike22c59b2015-05-21 18:33:37 -0700766 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700767 if (jitterNanos >= 2 * mFrameIntervalNanos) {
768 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
769 + mFrameIntervalNanos;
770 if (DEBUG_JANK) {
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;
777 }
778 frameTimeNanos = now - lastFrameOffset;
779 mLastFrameTimeNanos = frameTimeNanos;
780 }
781 }
Jeff Brown96858852012-02-14 13:45:06 -0800782 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700783 try {
Chris Craike22c59b2015-05-21 18:33:37 -0700784 Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
Jeff Browncae80492012-05-21 16:33:39 -0700785 for (CallbackRecord c = callbacks; c != null; c = c.next) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700786 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700787 Log.d(TAG, "RunCallback: type=" + callbackType
788 + ", action=" + c.action + ", token=" + c.token
789 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
790 }
Jeff Browncae80492012-05-21 16:33:39 -0700791 c.run(frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700792 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700793 } finally {
Jeff Brown96858852012-02-14 13:45:06 -0800794 synchronized (mLock) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700795 mCallbacksRunning = false;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700796 do {
Jeff Browncae80492012-05-21 16:33:39 -0700797 final CallbackRecord next = callbacks.next;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700798 recycleCallbackLocked(callbacks);
799 callbacks = next;
800 } while (callbacks != null);
Jeff Brown96858852012-02-14 13:45:06 -0800801 }
Chris Craike22c59b2015-05-21 18:33:37 -0700802 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Jeff Brown96858852012-02-14 13:45:06 -0800803 }
Jeff Brown96858852012-02-14 13:45:06 -0800804 }
805
806 void doScheduleVsync() {
807 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700808 if (mFrameScheduled) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800809 scheduleVsyncLocked();
810 }
Jeff Brown96858852012-02-14 13:45:06 -0800811 }
812 }
813
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700814 void doScheduleCallback(int callbackType) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800815 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700816 if (!mFrameScheduled) {
817 final long now = SystemClock.uptimeMillis();
818 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
819 scheduleFrameLocked(now);
820 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800821 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800822 }
823 }
824
Mathew Inwooda570dee2018-08-17 14:56:00 +0100825 @UnsupportedAppUsage
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800826 private void scheduleVsyncLocked() {
827 mDisplayEventReceiver.scheduleVsync();
828 }
829
Jeff Brown58aedbc2012-02-13 20:15:01 -0800830 private boolean isRunningOnLooperThreadLocked() {
831 return Looper.myLooper() == mLooper;
832 }
833
Jeff Browncae80492012-05-21 16:33:39 -0700834 private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
835 CallbackRecord callback = mCallbackPool;
Jeff Brown96858852012-02-14 13:45:06 -0800836 if (callback == null) {
Jeff Browncae80492012-05-21 16:33:39 -0700837 callback = new CallbackRecord();
Jeff Brown96858852012-02-14 13:45:06 -0800838 } else {
839 mCallbackPool = callback.next;
840 callback.next = null;
841 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800842 callback.dueTime = dueTime;
843 callback.action = action;
844 callback.token = token;
Jeff Brown96858852012-02-14 13:45:06 -0800845 return callback;
846 }
847
Jeff Browncae80492012-05-21 16:33:39 -0700848 private void recycleCallbackLocked(CallbackRecord callback) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800849 callback.action = null;
850 callback.token = null;
Jeff Brown96858852012-02-14 13:45:06 -0800851 callback.next = mCallbackPool;
852 mCallbackPool = callback;
853 }
854
Jeff Browncae80492012-05-21 16:33:39 -0700855 /**
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.
859 */
860 public interface FrameCallback {
861 /**
862 * Called when a new display frame is being rendered.
863 * <p>
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.
873 * </p><p>
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.
877 * </p>
878 *
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.
882 */
883 public void doFrame(long frameTimeNanos);
884 }
885
Jeff Brown96858852012-02-14 13:45:06 -0800886 private final class FrameHandler extends Handler {
887 public FrameHandler(Looper looper) {
888 super(looper);
889 }
890
891 @Override
892 public void handleMessage(Message msg) {
893 switch (msg.what) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700894 case MSG_DO_FRAME:
Jeff Brown20c4f872012-04-26 17:38:21 -0700895 doFrame(System.nanoTime(), 0);
Jeff Brown96858852012-02-14 13:45:06 -0800896 break;
897 case MSG_DO_SCHEDULE_VSYNC:
898 doScheduleVsync();
899 break;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700900 case MSG_DO_SCHEDULE_CALLBACK:
901 doScheduleCallback(msg.arg1);
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800902 break;
Jeff Brown96858852012-02-14 13:45:06 -0800903 }
904 }
905 }
906
Jeff Brownb0806602012-05-16 12:50:41 -0700907 private final class FrameDisplayEventReceiver extends DisplayEventReceiver
908 implements Runnable {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700909 private boolean mHavePendingVsync;
Jeff Brownb0806602012-05-16 12:50:41 -0700910 private long mTimestampNanos;
911 private int mFrame;
912
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700913 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
Ady Abraham9c501aa2019-06-04 16:07:44 -0700914 super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
Jeff Brown96e942d2011-11-30 19:55:01 -0800915 }
916
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800917 // 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.
Jeff Brown96e942d2011-11-30 19:55:01 -0800920 @Override
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800921 public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
Jeff Brownb0806602012-05-16 12:50:41 -0700922 // 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.
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700927 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;
933 }
934
Jeff Brownba7261132012-06-14 23:48:40 -0700935 if (mHavePendingVsync) {
936 Log.w(TAG, "Already have a pending vsync event. There should only be "
937 + "one at a time.");
938 } else {
939 mHavePendingVsync = true;
940 }
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700941
Jeff Brownb0806602012-05-16 12:50:41 -0700942 mTimestampNanos = timestampNanos;
943 mFrame = frame;
944 Message msg = Message.obtain(mHandler, this);
945 msg.setAsynchronous(true);
John Reck315c3292014-05-09 19:21:04 -0700946 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
Jeff Brownb0806602012-05-16 12:50:41 -0700947 }
948
949 @Override
950 public void run() {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700951 mHavePendingVsync = false;
Jeff Brownb0806602012-05-16 12:50:41 -0700952 doFrame(mTimestampNanos, mFrame);
Jeff Brown96e942d2011-11-30 19:55:01 -0800953 }
954 }
Jeff Brown96858852012-02-14 13:45:06 -0800955
Jeff Browncae80492012-05-21 16:33:39 -0700956 private static final class CallbackRecord {
957 public CallbackRecord next;
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800958 public long dueTime;
Jeff Browncae80492012-05-21 16:33:39 -0700959 public Object action; // Runnable or FrameCallback
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800960 public Object token;
Jeff Browncae80492012-05-21 16:33:39 -0700961
Mathew Inwooda570dee2018-08-17 14:56:00 +0100962 @UnsupportedAppUsage
Jeff Browncae80492012-05-21 16:33:39 -0700963 public void run(long frameTimeNanos) {
964 if (token == FRAME_CALLBACK_TOKEN) {
965 ((FrameCallback)action).doFrame(frameTimeNanos);
966 } else {
967 ((Runnable)action).run();
968 }
969 }
Jeff Brown96858852012-02-14 13:45:06 -0800970 }
Jeff Brown43ea54b2012-03-09 14:37:48 -0800971
972 private final class CallbackQueue {
Jeff Browncae80492012-05-21 16:33:39 -0700973 private CallbackRecord mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800974
975 public boolean hasDueCallbacksLocked(long now) {
976 return mHead != null && mHead.dueTime <= now;
977 }
978
Jeff Browncae80492012-05-21 16:33:39 -0700979 public CallbackRecord extractDueCallbacksLocked(long now) {
980 CallbackRecord callbacks = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800981 if (callbacks == null || callbacks.dueTime > now) {
982 return null;
983 }
984
Jeff Browncae80492012-05-21 16:33:39 -0700985 CallbackRecord last = callbacks;
986 CallbackRecord next = last.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800987 while (next != null) {
988 if (next.dueTime > now) {
989 last.next = null;
990 break;
991 }
992 last = next;
993 next = next.next;
994 }
995 mHead = next;
996 return callbacks;
997 }
998
Mathew Inwooda570dee2018-08-17 14:56:00 +0100999 @UnsupportedAppUsage
Jeff Browncae80492012-05-21 16:33:39 -07001000 public void addCallbackLocked(long dueTime, Object action, Object token) {
1001 CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
1002 CallbackRecord entry = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -08001003 if (entry == null) {
1004 mHead = callback;
1005 return;
1006 }
1007 if (dueTime < entry.dueTime) {
1008 callback.next = entry;
1009 mHead = callback;
1010 return;
1011 }
1012 while (entry.next != null) {
1013 if (dueTime < entry.next.dueTime) {
1014 callback.next = entry.next;
1015 break;
1016 }
1017 entry = entry.next;
1018 }
1019 entry.next = callback;
1020 }
1021
Jeff Browncae80492012-05-21 16:33:39 -07001022 public void removeCallbacksLocked(Object action, Object token) {
1023 CallbackRecord predecessor = null;
1024 for (CallbackRecord callback = mHead; callback != null;) {
1025 final CallbackRecord next = callback.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -08001026 if ((action == null || callback.action == action)
1027 && (token == null || callback.token == token)) {
1028 if (predecessor != null) {
1029 predecessor.next = next;
1030 } else {
1031 mHead = next;
1032 }
1033 recycleCallbackLocked(callback);
1034 } else {
1035 predecessor = callback;
1036 }
1037 callback = next;
1038 }
1039 }
1040 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001041}