blob: 987edf7761d2e74e4b0f029c9bd0a100f95bfc9b [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
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -070019import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
20import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
21
Doris Liu197a6742017-08-16 17:12:42 -070022import android.annotation.TestApi;
Artur Satayevad9254c2019-12-10 17:47:54 +000023import android.compat.annotation.UnsupportedAppUsage;
John Reck8785ceb2018-10-29 16:45:58 -070024import android.graphics.FrameInfo;
Tarandeep Singh54554e22019-11-01 14:43:05 -070025import android.graphics.Insets;
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
Tarandeep Singh54554e22019-11-01 14:43:05 -0700222 * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} for multiple
223 * ongoing animations but then update the whole view system with a single callback to
224 * {@link View#dispatchWindowInsetsAnimationProgress} that contains all the combined updated
225 * insets.
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800226 * <p>
227 * Both input and animation may change insets, so we need to run this after these callbacks, but
228 * before traversals.
229 * <p>
230 * Runs before traversals.
231 * @hide
232 */
233 public static final int CALLBACK_INSETS_ANIMATION = 2;
234
235 /**
Jeff Brownc42b28d2015-04-06 19:49:02 -0700236 * Callback type: Traversal callback. Handles layout and draw. Runs
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700237 * after all other asynchronous messages have been handled.
Jeff Browncae80492012-05-21 16:33:39 -0700238 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700239 */
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800240 public static final int CALLBACK_TRAVERSAL = 3;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700241
Jeff Brownc42b28d2015-04-06 19:49:02 -0700242 /**
243 * Callback type: Commit callback. Handles post-draw operations for the frame.
244 * Runs after traversal completes. The {@link #getFrameTime() frame time} reported
245 * during this callback may be updated to reflect delays that occurred while
246 * traversals were in progress in case heavy layout operations caused some frames
247 * to be skipped. The frame time reported during this callback provides a better
248 * estimate of the start time of the frame in which animations (and other updates
249 * to the view hierarchy state) actually took effect.
250 * @hide
251 */
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800252 public static final int CALLBACK_COMMIT = 4;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700253
254 private static final int CALLBACK_LAST = CALLBACK_COMMIT;
Jeff Brown96e942d2011-11-30 19:55:01 -0800255
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700256 private Choreographer(Looper looper, int vsyncSource) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800257 mLooper = looper;
Jeff Brown96858852012-02-14 13:45:06 -0800258 mHandler = new FrameHandler(looper);
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700259 mDisplayEventReceiver = USE_VSYNC
260 ? new FrameDisplayEventReceiver(looper, vsyncSource)
261 : null;
Jeff Brown20c4f872012-04-26 17:38:21 -0700262 mLastFrameTimeNanos = Long.MIN_VALUE;
Jeff Brownd32460c2012-07-20 16:15:36 -0700263
Jeff Brownbd6e1502012-08-28 03:27:37 -0700264 mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700265
266 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
267 for (int i = 0; i <= CALLBACK_LAST; i++) {
268 mCallbackQueues[i] = new CallbackQueue();
269 }
Makoto Onukib708cbe2018-01-09 12:35:06 -0800270 // b/68769804: For low FPS experiments.
271 setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
Jeff Brown96e942d2011-11-30 19:55:01 -0800272 }
273
Jeff Brownbd6e1502012-08-28 03:27:37 -0700274 private static float getRefreshRate() {
275 DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
276 Display.DEFAULT_DISPLAY);
P.Y. Laligandb3b9eb32015-05-11 15:02:07 -0700277 return di.getMode().getRefreshRate();
Jeff Brownbd6e1502012-08-28 03:27:37 -0700278 }
279
Jeff Brown96e942d2011-11-30 19:55:01 -0800280 /**
Dianne Hackborn8bcd54b2012-01-31 19:04:53 -0800281 * Gets the choreographer for the calling thread. Must be called from
282 * a thread that already has a {@link android.os.Looper} associated with it.
Jeff Brown96e942d2011-11-30 19:55:01 -0800283 *
284 * @return The choreographer for this thread.
285 * @throws IllegalStateException if the thread does not have a looper.
286 */
287 public static Choreographer getInstance() {
288 return sThreadInstance.get();
289 }
290
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700291 /**
292 * @hide
293 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100294 @UnsupportedAppUsage
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700295 public static Choreographer getSfInstance() {
296 return sSfThreadInstance.get();
297 }
298
Jorim Jaggib29e3182018-04-30 18:51:56 +0200299 /**
300 * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
301 * @hide
302 */
303 public static Choreographer getMainThreadInstance() {
304 return mMainInstance;
305 }
306
John Reckac04f4e2016-06-23 10:21:45 -0700307 /** Destroys the calling thread's choreographer
308 * @hide
309 */
310 public static void releaseInstance() {
311 Choreographer old = sThreadInstance.get();
312 sThreadInstance.remove();
313 old.dispose();
314 }
315
316 private void dispose() {
317 mDisplayEventReceiver.dispose();
318 }
319
Jeff Brown96e942d2011-11-30 19:55:01 -0800320 /**
Jeff Browncae80492012-05-21 16:33:39 -0700321 * The amount of time, in milliseconds, between each frame of the animation.
322 * <p>
323 * This is a requested time that the animation will attempt to honor, but the actual delay
324 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800325 * function because the same delay will be applied to all animations, since they are all
326 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700327 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800328 * The frame delay may be ignored when the animation system uses an external timing
329 * source, such as the display refresh rate (vsync), to govern animations.
Jeff Browncae80492012-05-21 16:33:39 -0700330 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800331 *
332 * @return the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700333 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800334 */
Artur Satayevf0b7d0b2019-11-04 11:16:45 +0000335 @UnsupportedAppUsage
Doris Liu197a6742017-08-16 17:12:42 -0700336 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800337 public static long getFrameDelay() {
338 return sFrameDelay;
339 }
340
341 /**
Jeff Browncae80492012-05-21 16:33:39 -0700342 * The amount of time, in milliseconds, between each frame of the animation.
343 * <p>
344 * This is a requested time that the animation will attempt to honor, but the actual delay
345 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800346 * function because the same delay will be applied to all animations, since they are all
347 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700348 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800349 * The frame delay may be ignored when the animation system uses an external timing
350 * source, such as the display refresh rate (vsync), to govern animations.
Jeff Browncae80492012-05-21 16:33:39 -0700351 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800352 *
353 * @param frameDelay the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700354 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800355 */
Doris Liu197a6742017-08-16 17:12:42 -0700356 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800357 public static void setFrameDelay(long frameDelay) {
358 sFrameDelay = frameDelay;
359 }
360
361 /**
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800362 * Subtracts typical frame delay time from a delay interval in milliseconds.
Jeff Browncae80492012-05-21 16:33:39 -0700363 * <p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800364 * This method can be used to compensate for animation delay times that have baked
365 * in assumptions about the frame delay. For example, it's quite common for code to
366 * assume a 60Hz frame time and bake in a 16ms delay. When we call
367 * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
368 * posting the animation callback but let the animation timer take care of the remaining
369 * frame delay time.
Jeff Browncae80492012-05-21 16:33:39 -0700370 * </p><p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800371 * This method is somewhat conservative about how much of the frame delay it
372 * subtracts. It uses the same value returned by {@link #getFrameDelay} which by
373 * default is 10ms even though many parts of the system assume 16ms. Consequently,
374 * we might still wait 6ms before posting an animation callback that we want to run
375 * on the next frame, but this is much better than waiting a whole 16ms and likely
376 * missing the deadline.
Jeff Browncae80492012-05-21 16:33:39 -0700377 * </p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800378 *
379 * @param delayMillis The original delay time including an assumed frame delay.
380 * @return The adjusted delay time with the assumed frame delay subtracted out.
Jeff Browncae80492012-05-21 16:33:39 -0700381 * @hide
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800382 */
383 public static long subtractFrameDelay(long delayMillis) {
384 final long frameDelay = sFrameDelay;
385 return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
386 }
387
John Reck18f16e62014-05-02 16:46:41 -0700388 /**
389 * @return The refresh rate as the nanoseconds between frames
390 * @hide
391 */
John Reck315c3292014-05-09 19:21:04 -0700392 public long getFrameIntervalNanos() {
John Reck18f16e62014-05-02 16:46:41 -0700393 return mFrameIntervalNanos;
394 }
395
Jeff Brown5182c782013-10-15 20:31:52 -0700396 void dump(String prefix, PrintWriter writer) {
397 String innerPrefix = prefix + " ";
398 writer.print(prefix); writer.println("Choreographer:");
399 writer.print(innerPrefix); writer.print("mFrameScheduled=");
400 writer.println(mFrameScheduled);
401 writer.print(innerPrefix); writer.print("mLastFrameTime=");
402 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
403 }
404
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800405 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700406 * Posts a callback to run on the next frame.
Jeff Browncae80492012-05-21 16:33:39 -0700407 * <p>
408 * The callback runs once then is automatically removed.
409 * </p>
Jeff Brown4a06c802012-02-15 15:06:01 -0800410 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700411 * @param callbackType The callback type.
412 * @param action The callback action to run during the next frame.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800413 * @param token The callback token, or null if none.
Jeff Brown4a06c802012-02-15 15:06:01 -0800414 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700415 * @see #removeCallbacks
Jeff Browncae80492012-05-21 16:33:39 -0700416 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800417 */
Artur Satayevf0b7d0b2019-11-04 11:16:45 +0000418 @UnsupportedAppUsage
Doris Liu4f8a98c2018-01-16 18:13:57 -0800419 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700420 public void postCallback(int callbackType, Runnable action, Object token) {
421 postCallbackDelayed(callbackType, action, token, 0);
Jeff Brown87d0b032012-02-03 11:01:21 -0800422 }
423
Jeff Brown4a06c802012-02-15 15:06:01 -0800424 /**
Jeff Browncae80492012-05-21 16:33:39 -0700425 * Posts a callback to run on the next frame after the specified delay.
426 * <p>
427 * The callback runs once then is automatically removed.
428 * </p>
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800429 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700430 * @param callbackType The callback type.
431 * @param action The callback action to run during the next frame after the specified delay.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800432 * @param token The callback token, or null if none.
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800433 * @param delayMillis The delay time in milliseconds.
434 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700435 * @see #removeCallback
Jeff Browncae80492012-05-21 16:33:39 -0700436 * @hide
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800437 */
Artur Satayevf0b7d0b2019-11-04 11:16:45 +0000438 @UnsupportedAppUsage
Doris Liu4f8a98c2018-01-16 18:13:57 -0800439 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700440 public void postCallbackDelayed(int callbackType,
441 Runnable action, Object token, long delayMillis) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800442 if (action == null) {
443 throw new IllegalArgumentException("action must not be null");
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800444 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700445 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
446 throw new IllegalArgumentException("callbackType is invalid");
447 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800448
Jeff Browncae80492012-05-21 16:33:39 -0700449 postCallbackDelayedInternal(callbackType, action, token, delayMillis);
450 }
451
452 private void postCallbackDelayedInternal(int callbackType,
453 Object action, Object token, long delayMillis) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700454 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700455 Log.d(TAG, "PostCallback: type=" + callbackType
456 + ", action=" + action + ", token=" + token
Jeff Brown43ea54b2012-03-09 14:37:48 -0800457 + ", delayMillis=" + delayMillis);
458 }
459
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800460 synchronized (mLock) {
461 final long now = SystemClock.uptimeMillis();
462 final long dueTime = now + delayMillis;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700463 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800464
465 if (dueTime <= now) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700466 scheduleFrameLocked(now);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800467 } else {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700468 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
469 msg.arg1 = callbackType;
470 msg.setAsynchronous(true);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800471 mHandler.sendMessageAtTime(msg, dueTime);
472 }
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800473 }
474 }
475
476 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700477 * Removes callbacks that have the specified action and token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800478 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700479 * @param callbackType The callback type.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800480 * @param action The action property of the callbacks to remove, or null to remove
481 * callbacks with any action.
482 * @param token The token property of the callbacks to remove, or null to remove
483 * callbacks with any token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800484 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700485 * @see #postCallback
486 * @see #postCallbackDelayed
Jeff Browncae80492012-05-21 16:33:39 -0700487 * @hide
Jeff Brown4a06c802012-02-15 15:06:01 -0800488 */
Artur Satayevf0b7d0b2019-11-04 11:16:45 +0000489 @UnsupportedAppUsage
Doris Liu4f8a98c2018-01-16 18:13:57 -0800490 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700491 public void removeCallbacks(int callbackType, Runnable action, Object token) {
492 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
493 throw new IllegalArgumentException("callbackType is invalid");
494 }
495
Jeff Browncae80492012-05-21 16:33:39 -0700496 removeCallbacksInternal(callbackType, action, token);
497 }
498
499 private void removeCallbacksInternal(int callbackType, Object action, Object token) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700500 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700501 Log.d(TAG, "RemoveCallbacks: type=" + callbackType
502 + ", action=" + action + ", token=" + token);
Jeff Brown43ea54b2012-03-09 14:37:48 -0800503 }
504
Jeff Brown4a06c802012-02-15 15:06:01 -0800505 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700506 mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800507 if (action != null && token == null) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700508 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800509 }
Jeff Brown4a06c802012-02-15 15:06:01 -0800510 }
511 }
512
Jeff Brown20c4f872012-04-26 17:38:21 -0700513 /**
Jeff Browncae80492012-05-21 16:33:39 -0700514 * Posts a frame callback to run on the next frame.
515 * <p>
516 * The callback runs once then is automatically removed.
517 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700518 *
Jeff Browncae80492012-05-21 16:33:39 -0700519 * @param callback The frame callback to run during the next frame.
520 *
521 * @see #postFrameCallbackDelayed
522 * @see #removeFrameCallback
523 */
524 public void postFrameCallback(FrameCallback callback) {
525 postFrameCallbackDelayed(callback, 0);
526 }
527
528 /**
529 * Posts a frame callback to run on the next frame after the specified delay.
530 * <p>
531 * The callback runs once then is automatically removed.
532 * </p>
533 *
534 * @param callback The frame callback to run during the next frame.
535 * @param delayMillis The delay time in milliseconds.
536 *
537 * @see #postFrameCallback
538 * @see #removeFrameCallback
539 */
540 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
541 if (callback == null) {
542 throw new IllegalArgumentException("callback must not be null");
543 }
544
545 postCallbackDelayedInternal(CALLBACK_ANIMATION,
546 callback, FRAME_CALLBACK_TOKEN, delayMillis);
547 }
548
549 /**
550 * Removes a previously posted frame callback.
551 *
552 * @param callback The frame callback to remove.
553 *
554 * @see #postFrameCallback
555 * @see #postFrameCallbackDelayed
556 */
557 public void removeFrameCallback(FrameCallback callback) {
558 if (callback == null) {
559 throw new IllegalArgumentException("callback must not be null");
560 }
561
562 removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
563 }
564
565 /**
566 * Gets the time when the current frame started.
567 * <p>
John Reck8d8af3c2014-07-01 15:23:45 -0700568 * This method provides the time in milliseconds when the frame started being rendered.
Jeff Browncae80492012-05-21 16:33:39 -0700569 * The frame time provides a stable time base for synchronizing animations
570 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
571 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
572 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
573 * the frame was scheduled to start, regardless of when the animations or drawing
574 * callback actually runs. All callbacks that run as part of rendering a frame will
575 * observe the same frame time so using the frame time also helps to synchronize effects
576 * that are performed by different callbacks.
577 * </p><p>
578 * Please note that the framework already takes care to process animations and
579 * drawing using the frame time as a stable time base. Most applications should
580 * not need to use the frame time information directly.
581 * </p><p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700582 * This method should only be called from within a callback.
Jeff Browncae80492012-05-21 16:33:39 -0700583 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700584 *
585 * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
586 *
587 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700588 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700589 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100590 @UnsupportedAppUsage
Jeff Brown20c4f872012-04-26 17:38:21 -0700591 public long getFrameTime() {
John Reck315c3292014-05-09 19:21:04 -0700592 return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
Jeff Brown20c4f872012-04-26 17:38:21 -0700593 }
594
595 /**
596 * Same as {@link #getFrameTime()} but with nanosecond precision.
597 *
598 * @return The frame start time, in the {@link System#nanoTime()} time base.
599 *
600 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700601 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700602 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100603 @UnsupportedAppUsage
Jeff Brown20c4f872012-04-26 17:38:21 -0700604 public long getFrameTimeNanos() {
605 synchronized (mLock) {
606 if (!mCallbacksRunning) {
607 throw new IllegalStateException("This method must only be called as "
608 + "part of a callback while a frame is in progress.");
609 }
610 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
611 }
612 }
613
Jorim Jaggid6d6de62017-03-31 15:05:13 +0200614 /**
615 * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
616 * whether callbacks are currently running.
617 * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
618 * @hide
619 */
620 public long getLastFrameTimeNanos() {
621 synchronized (mLock) {
622 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
623 }
624 }
625
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700626 private void scheduleFrameLocked(long now) {
627 if (!mFrameScheduled) {
628 mFrameScheduled = true;
Jeff Brown96e942d2011-11-30 19:55:01 -0800629 if (USE_VSYNC) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700630 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700631 Log.d(TAG, "Scheduling next frame on vsync.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800632 }
Jeff Brown58aedbc2012-02-13 20:15:01 -0800633
634 // If running on the Looper thread, then schedule the vsync immediately,
635 // otherwise post a message to schedule the vsync from the UI thread
636 // as soon as possible.
Jeff Brown58aedbc2012-02-13 20:15:01 -0800637 if (isRunningOnLooperThreadLocked()) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800638 scheduleVsyncLocked();
Jeff Brown58aedbc2012-02-13 20:15:01 -0800639 } else {
Jeff Browne0dbd002012-02-15 19:34:58 -0800640 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
641 msg.setAsynchronous(true);
642 mHandler.sendMessageAtFrontOfQueue(msg);
Jeff Brown58aedbc2012-02-13 20:15:01 -0800643 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800644 } else {
Jeff Brown20c4f872012-04-26 17:38:21 -0700645 final long nextFrameTime = Math.max(
John Reck315c3292014-05-09 19:21:04 -0700646 mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700647 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700648 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800649 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700650 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
Jeff Browne0dbd002012-02-15 19:34:58 -0800651 msg.setAsynchronous(true);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700652 mHandler.sendMessageAtTime(msg, nextFrameTime);
Jeff Brown96e942d2011-11-30 19:55:01 -0800653 }
654 }
655 }
656
John Reck9f516442017-09-25 10:27:21 -0700657 void setFPSDivisor(int divisor) {
658 if (divisor <= 0) divisor = 1;
659 mFPSDivisor = divisor;
Makoto Onukib708cbe2018-01-09 12:35:06 -0800660 ThreadedRenderer.setFPSDivisor(divisor);
John Reck9f516442017-09-25 10:27:21 -0700661 }
662
Mathew Inwooda570dee2018-08-17 14:56:00 +0100663 @UnsupportedAppUsage
Jeff Browncae80492012-05-21 16:33:39 -0700664 void doFrame(long frameTimeNanos, int frame) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700665 final long startNanos;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700666 synchronized (mLock) {
667 if (!mFrameScheduled) {
668 return; // no work to do
Jeff Brown96e942d2011-11-30 19:55:01 -0800669 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700670
Jeff Brownc42b28d2015-04-06 19:49:02 -0700671 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
672 mDebugPrintNextFrameTimeDelta = false;
673 Log.d(TAG, "Frame time delta: "
674 + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
675 }
676
John Reckba6adf62015-02-19 14:36:50 -0800677 long intendedFrameTimeNanos = frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700678 startNanos = System.nanoTime();
Jeff Browncae80492012-05-21 16:33:39 -0700679 final long jitterNanos = startNanos - frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700680 if (jitterNanos >= mFrameIntervalNanos) {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700681 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
682 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Jeff Brown265f1cc2012-06-11 18:01:06 -0700683 Log.i(TAG, "Skipped " + skippedFrames + " frames! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700684 + "The application may be doing too much work on its main thread.");
685 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700686 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700687 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700688 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
689 + "which is more than the frame interval of "
690 + (mFrameIntervalNanos * 0.000001f) + " ms! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700691 + "Skipping " + skippedFrames + " frames and setting frame "
692 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700693 }
Jeff Browncae80492012-05-21 16:33:39 -0700694 frameTimeNanos = startNanos - lastFrameOffset;
Jeff Brown59bbef02012-05-07 16:43:25 -0700695 }
696
Jeff Browncae80492012-05-21 16:33:39 -0700697 if (frameTimeNanos < mLastFrameTimeNanos) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700698 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700699 Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700700 + "previously skipped frame. Waiting for next vsync.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700701 }
702 scheduleVsyncLocked();
703 return;
704 }
705
John Reck9f516442017-09-25 10:27:21 -0700706 if (mFPSDivisor > 1) {
707 long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
708 if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
709 scheduleVsyncLocked();
710 return;
711 }
712 }
713
John Reckba6adf62015-02-19 14:36:50 -0800714 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700715 mFrameScheduled = false;
Jeff Browncae80492012-05-21 16:33:39 -0700716 mLastFrameTimeNanos = frameTimeNanos;
Jeff Brown20c4f872012-04-26 17:38:21 -0700717 }
718
Chris Craike22c59b2015-05-21 18:33:37 -0700719 try {
720 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
John Recka2acb4f2016-08-05 07:58:37 -0700721 AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
John Reckba6adf62015-02-19 14:36:50 -0800722
Chris Craike22c59b2015-05-21 18:33:37 -0700723 mFrameInfo.markInputHandlingStart();
724 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
John Reckba6adf62015-02-19 14:36:50 -0800725
Chris Craike22c59b2015-05-21 18:33:37 -0700726 mFrameInfo.markAnimationsStart();
727 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800728 doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700729
Chris Craike22c59b2015-05-21 18:33:37 -0700730 mFrameInfo.markPerformTraversalsStart();
731 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
732
733 doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
734 } finally {
John Recka2acb4f2016-08-05 07:58:37 -0700735 AnimationUtils.unlockAnimationClock();
Chris Craike22c59b2015-05-21 18:33:37 -0700736 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
737 }
Jeff Brownc42b28d2015-04-06 19:49:02 -0700738
739 if (DEBUG_FRAMES) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700740 final long endNanos = System.nanoTime();
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700741 Log.d(TAG, "Frame " + frame + ": Finished, took "
Jeff Brown20c4f872012-04-26 17:38:21 -0700742 + (endNanos - startNanos) * 0.000001f + " ms, latency "
Jeff Browncae80492012-05-21 16:33:39 -0700743 + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800744 }
745 }
746
Jeff Browncae80492012-05-21 16:33:39 -0700747 void doCallbacks(int callbackType, long frameTimeNanos) {
748 CallbackRecord callbacks;
Jeff Brown96858852012-02-14 13:45:06 -0800749 synchronized (mLock) {
Jeff Browncae80492012-05-21 16:33:39 -0700750 // We use "now" to determine when callbacks become due because it's possible
751 // for earlier processing phases in a frame to post callbacks that should run
752 // in a following phase, such as an input event that causes an animation to start.
Jeff Brownc42b28d2015-04-06 19:49:02 -0700753 final long now = System.nanoTime();
754 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
755 now / TimeUtils.NANOS_PER_MS);
Jeff Brown20c4f872012-04-26 17:38:21 -0700756 if (callbacks == null) {
757 return;
758 }
759 mCallbacksRunning = true;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700760
761 // Update the frame time if necessary when committing the frame.
762 // We only update the frame time if we are more than 2 frames late reaching
763 // the commit phase. This ensures that the frame time which is observed by the
764 // callbacks will always increase from one frame to the next and never repeat.
765 // We never want the next frame's starting frame time to end up being less than
766 // or equal to the previous frame's commit frame time. Keep in mind that the
767 // next frame has most likely already been scheduled by now so we play it
768 // safe by ensuring the commit time is always at least one frame behind.
769 if (callbackType == Choreographer.CALLBACK_COMMIT) {
770 final long jitterNanos = now - frameTimeNanos;
Chris Craike22c59b2015-05-21 18:33:37 -0700771 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700772 if (jitterNanos >= 2 * mFrameIntervalNanos) {
773 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
774 + mFrameIntervalNanos;
775 if (DEBUG_JANK) {
776 Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
777 + " ms which is more than twice the frame interval of "
778 + (mFrameIntervalNanos * 0.000001f) + " ms! "
779 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
780 + " ms in the past.");
781 mDebugPrintNextFrameTimeDelta = true;
782 }
783 frameTimeNanos = now - lastFrameOffset;
784 mLastFrameTimeNanos = frameTimeNanos;
785 }
786 }
Jeff Brown96858852012-02-14 13:45:06 -0800787 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700788 try {
Chris Craike22c59b2015-05-21 18:33:37 -0700789 Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
Jeff Browncae80492012-05-21 16:33:39 -0700790 for (CallbackRecord c = callbacks; c != null; c = c.next) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700791 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700792 Log.d(TAG, "RunCallback: type=" + callbackType
793 + ", action=" + c.action + ", token=" + c.token
794 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
795 }
Jeff Browncae80492012-05-21 16:33:39 -0700796 c.run(frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700797 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700798 } finally {
Jeff Brown96858852012-02-14 13:45:06 -0800799 synchronized (mLock) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700800 mCallbacksRunning = false;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700801 do {
Jeff Browncae80492012-05-21 16:33:39 -0700802 final CallbackRecord next = callbacks.next;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700803 recycleCallbackLocked(callbacks);
804 callbacks = next;
805 } while (callbacks != null);
Jeff Brown96858852012-02-14 13:45:06 -0800806 }
Chris Craike22c59b2015-05-21 18:33:37 -0700807 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Jeff Brown96858852012-02-14 13:45:06 -0800808 }
Jeff Brown96858852012-02-14 13:45:06 -0800809 }
810
811 void doScheduleVsync() {
812 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700813 if (mFrameScheduled) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800814 scheduleVsyncLocked();
815 }
Jeff Brown96858852012-02-14 13:45:06 -0800816 }
817 }
818
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700819 void doScheduleCallback(int callbackType) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800820 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700821 if (!mFrameScheduled) {
822 final long now = SystemClock.uptimeMillis();
823 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
824 scheduleFrameLocked(now);
825 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800826 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800827 }
828 }
829
Mathew Inwooda570dee2018-08-17 14:56:00 +0100830 @UnsupportedAppUsage
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800831 private void scheduleVsyncLocked() {
832 mDisplayEventReceiver.scheduleVsync();
833 }
834
Jeff Brown58aedbc2012-02-13 20:15:01 -0800835 private boolean isRunningOnLooperThreadLocked() {
836 return Looper.myLooper() == mLooper;
837 }
838
Jeff Browncae80492012-05-21 16:33:39 -0700839 private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
840 CallbackRecord callback = mCallbackPool;
Jeff Brown96858852012-02-14 13:45:06 -0800841 if (callback == null) {
Jeff Browncae80492012-05-21 16:33:39 -0700842 callback = new CallbackRecord();
Jeff Brown96858852012-02-14 13:45:06 -0800843 } else {
844 mCallbackPool = callback.next;
845 callback.next = null;
846 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800847 callback.dueTime = dueTime;
848 callback.action = action;
849 callback.token = token;
Jeff Brown96858852012-02-14 13:45:06 -0800850 return callback;
851 }
852
Jeff Browncae80492012-05-21 16:33:39 -0700853 private void recycleCallbackLocked(CallbackRecord callback) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800854 callback.action = null;
855 callback.token = null;
Jeff Brown96858852012-02-14 13:45:06 -0800856 callback.next = mCallbackPool;
857 mCallbackPool = callback;
858 }
859
Jeff Browncae80492012-05-21 16:33:39 -0700860 /**
861 * Implement this interface to receive a callback when a new display frame is
862 * being rendered. The callback is invoked on the {@link Looper} thread to
863 * which the {@link Choreographer} is attached.
864 */
865 public interface FrameCallback {
866 /**
867 * Called when a new display frame is being rendered.
868 * <p>
869 * This method provides the time in nanoseconds when the frame started being rendered.
870 * The frame time provides a stable time base for synchronizing animations
871 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
872 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
873 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
874 * the frame was scheduled to start, regardless of when the animations or drawing
875 * callback actually runs. All callbacks that run as part of rendering a frame will
876 * observe the same frame time so using the frame time also helps to synchronize effects
877 * that are performed by different callbacks.
878 * </p><p>
879 * Please note that the framework already takes care to process animations and
880 * drawing using the frame time as a stable time base. Most applications should
881 * not need to use the frame time information directly.
882 * </p>
883 *
884 * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
885 * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000}
886 * to convert it to the {@link SystemClock#uptimeMillis()} time base.
887 */
888 public void doFrame(long frameTimeNanos);
889 }
890
Jeff Brown96858852012-02-14 13:45:06 -0800891 private final class FrameHandler extends Handler {
892 public FrameHandler(Looper looper) {
893 super(looper);
894 }
895
896 @Override
897 public void handleMessage(Message msg) {
898 switch (msg.what) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700899 case MSG_DO_FRAME:
Jeff Brown20c4f872012-04-26 17:38:21 -0700900 doFrame(System.nanoTime(), 0);
Jeff Brown96858852012-02-14 13:45:06 -0800901 break;
902 case MSG_DO_SCHEDULE_VSYNC:
903 doScheduleVsync();
904 break;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700905 case MSG_DO_SCHEDULE_CALLBACK:
906 doScheduleCallback(msg.arg1);
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800907 break;
Jeff Brown96858852012-02-14 13:45:06 -0800908 }
909 }
910 }
911
Jeff Brownb0806602012-05-16 12:50:41 -0700912 private final class FrameDisplayEventReceiver extends DisplayEventReceiver
913 implements Runnable {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700914 private boolean mHavePendingVsync;
Jeff Brownb0806602012-05-16 12:50:41 -0700915 private long mTimestampNanos;
916 private int mFrame;
917
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700918 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
Ady Abraham9c501aa2019-06-04 16:07:44 -0700919 super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
Jeff Brown96e942d2011-11-30 19:55:01 -0800920 }
921
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800922 // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
923 // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
924 // for the internal display implicitly.
Jeff Brown96e942d2011-11-30 19:55:01 -0800925 @Override
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800926 public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
Jeff Brownb0806602012-05-16 12:50:41 -0700927 // Post the vsync event to the Handler.
928 // The idea is to prevent incoming vsync events from completely starving
929 // the message queue. If there are no messages in the queue with timestamps
930 // earlier than the frame time, then the vsync event will be processed immediately.
931 // Otherwise, messages that predate the vsync event will be handled first.
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700932 long now = System.nanoTime();
933 if (timestampNanos > now) {
934 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
935 + " ms in the future! Check that graphics HAL is generating vsync "
936 + "timestamps using the correct timebase.");
937 timestampNanos = now;
938 }
939
Jeff Brownba7261132012-06-14 23:48:40 -0700940 if (mHavePendingVsync) {
941 Log.w(TAG, "Already have a pending vsync event. There should only be "
942 + "one at a time.");
943 } else {
944 mHavePendingVsync = true;
945 }
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700946
Jeff Brownb0806602012-05-16 12:50:41 -0700947 mTimestampNanos = timestampNanos;
948 mFrame = frame;
949 Message msg = Message.obtain(mHandler, this);
950 msg.setAsynchronous(true);
John Reck315c3292014-05-09 19:21:04 -0700951 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
Jeff Brownb0806602012-05-16 12:50:41 -0700952 }
953
954 @Override
955 public void run() {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700956 mHavePendingVsync = false;
Jeff Brownb0806602012-05-16 12:50:41 -0700957 doFrame(mTimestampNanos, mFrame);
Jeff Brown96e942d2011-11-30 19:55:01 -0800958 }
959 }
Jeff Brown96858852012-02-14 13:45:06 -0800960
Jeff Browncae80492012-05-21 16:33:39 -0700961 private static final class CallbackRecord {
962 public CallbackRecord next;
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800963 public long dueTime;
Jeff Browncae80492012-05-21 16:33:39 -0700964 public Object action; // Runnable or FrameCallback
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800965 public Object token;
Jeff Browncae80492012-05-21 16:33:39 -0700966
Mathew Inwooda570dee2018-08-17 14:56:00 +0100967 @UnsupportedAppUsage
Jeff Browncae80492012-05-21 16:33:39 -0700968 public void run(long frameTimeNanos) {
969 if (token == FRAME_CALLBACK_TOKEN) {
970 ((FrameCallback)action).doFrame(frameTimeNanos);
971 } else {
972 ((Runnable)action).run();
973 }
974 }
Jeff Brown96858852012-02-14 13:45:06 -0800975 }
Jeff Brown43ea54b2012-03-09 14:37:48 -0800976
977 private final class CallbackQueue {
Jeff Browncae80492012-05-21 16:33:39 -0700978 private CallbackRecord mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800979
980 public boolean hasDueCallbacksLocked(long now) {
981 return mHead != null && mHead.dueTime <= now;
982 }
983
Jeff Browncae80492012-05-21 16:33:39 -0700984 public CallbackRecord extractDueCallbacksLocked(long now) {
985 CallbackRecord callbacks = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800986 if (callbacks == null || callbacks.dueTime > now) {
987 return null;
988 }
989
Jeff Browncae80492012-05-21 16:33:39 -0700990 CallbackRecord last = callbacks;
991 CallbackRecord next = last.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800992 while (next != null) {
993 if (next.dueTime > now) {
994 last.next = null;
995 break;
996 }
997 last = next;
998 next = next.next;
999 }
1000 mHead = next;
1001 return callbacks;
1002 }
1003
Mathew Inwooda570dee2018-08-17 14:56:00 +01001004 @UnsupportedAppUsage
Jeff Browncae80492012-05-21 16:33:39 -07001005 public void addCallbackLocked(long dueTime, Object action, Object token) {
1006 CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
1007 CallbackRecord entry = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -08001008 if (entry == null) {
1009 mHead = callback;
1010 return;
1011 }
1012 if (dueTime < entry.dueTime) {
1013 callback.next = entry;
1014 mHead = callback;
1015 return;
1016 }
1017 while (entry.next != null) {
1018 if (dueTime < entry.next.dueTime) {
1019 callback.next = entry.next;
1020 break;
1021 }
1022 entry = entry.next;
1023 }
1024 entry.next = callback;
1025 }
1026
Jeff Browncae80492012-05-21 16:33:39 -07001027 public void removeCallbacksLocked(Object action, Object token) {
1028 CallbackRecord predecessor = null;
1029 for (CallbackRecord callback = mHead; callback != null;) {
1030 final CallbackRecord next = callback.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -08001031 if ((action == null || callback.action == action)
1032 && (token == null || callback.token == token)) {
1033 if (predecessor != null) {
1034 predecessor.next = next;
1035 } else {
1036 mHead = next;
1037 }
1038 recycleCallbackLocked(callback);
1039 } else {
1040 predecessor = callback;
1041 }
1042 callback = next;
1043 }
1044 }
1045 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001046}