blob: 2ffa1c5eb4c0548b6bf381fa595cd7b4e0aa3699 [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;
Jeff Brownbd6e1502012-08-28 03:27:37 -070023import android.hardware.display.DisplayManagerGlobal;
Jeff Brown96e942d2011-11-30 19:55:01 -080024import android.os.Handler;
25import android.os.Looper;
26import android.os.Message;
27import android.os.SystemClock;
28import android.os.SystemProperties;
Chris Craike22c59b2015-05-21 18:33:37 -070029import android.os.Trace;
Jeff Brown96e942d2011-11-30 19:55:01 -080030import android.util.Log;
Jeff Brown5182c782013-10-15 20:31:52 -070031import android.util.TimeUtils;
John Recka2acb4f2016-08-05 07:58:37 -070032import android.view.animation.AnimationUtils;
Jeff Brown5182c782013-10-15 20:31:52 -070033
34import java.io.PrintWriter;
Jeff Brown96e942d2011-11-30 19:55:01 -080035
36/**
Jeff Browncae80492012-05-21 16:33:39 -070037 * Coordinates the timing of animations, input and drawing.
38 * <p>
39 * The choreographer receives timing pulses (such as vertical synchronization)
40 * from the display subsystem then schedules work to occur as part of rendering
41 * the next display frame.
42 * </p><p>
43 * Applications typically interact with the choreographer indirectly using
44 * higher level abstractions in the animation framework or the view hierarchy.
45 * Here are some examples of things you can do using the higher-level APIs.
46 * </p>
47 * <ul>
48 * <li>To post an animation to be processed on a regular time basis synchronized with
49 * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
50 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
51 * frame, use {@link View#postOnAnimation}.</li>
52 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
53 * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
54 * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
55 * next display frame, use {@link View#postInvalidateOnAnimation()} or
56 * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
57 * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
58 * sync with display frame rendering, do nothing. This already happens automatically.
59 * {@link View#onDraw} will be called at the appropriate time.</li>
60 * </ul>
61 * <p>
62 * However, there are a few cases where you might want to use the functions of the
63 * choreographer directly in your application. Here are some examples.
64 * </p>
65 * <ul>
66 * <li>If your application does its rendering in a different thread, possibly using GL,
67 * or does not use the animation framework or view hierarchy at all
68 * and you want to ensure that it is appropriately synchronized with the display, then use
69 * {@link Choreographer#postFrameCallback}.</li>
70 * <li>... and that's about it.</li>
71 * </ul>
72 * <p>
73 * Each {@link Looper} thread has its own choreographer. Other threads can
74 * post callbacks to run on the choreographer but they will run on the {@link Looper}
75 * to which the choreographer belongs.
76 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -080077 */
Jeff Brown96858852012-02-14 13:45:06 -080078public final class Choreographer {
Jeff Brown96e942d2011-11-30 19:55:01 -080079 private static final String TAG = "Choreographer";
Jeff Brownc42b28d2015-04-06 19:49:02 -070080
81 // Prints debug messages about jank which was detected (low volume).
82 private static final boolean DEBUG_JANK = false;
83
84 // Prints debug messages about every frame and callback registered (high volume).
85 private static final boolean DEBUG_FRAMES = false;
Jeff Brown96e942d2011-11-30 19:55:01 -080086
87 // The default amount of time in ms between animation frames.
88 // When vsync is not enabled, we want to have some idea of how long we should
89 // wait before posting the next animation message. It is important that the
90 // default value be less than the true inter-frame delay on all devices to avoid
91 // situations where we might skip frames by waiting too long (we must compensate
92 // for jitter and hardware variations). Regardless of this value, the animation
93 // and display loop is ultimately rate-limited by how fast new graphics buffers can
94 // be dequeued.
95 private static final long DEFAULT_FRAME_DELAY = 10;
96
97 // The number of milliseconds between animation frames.
Jeff Brown87d0b032012-02-03 11:01:21 -080098 private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
Jeff Brown96e942d2011-11-30 19:55:01 -080099
100 // Thread local storage for the choreographer.
101 private static final ThreadLocal<Choreographer> sThreadInstance =
102 new ThreadLocal<Choreographer>() {
103 @Override
104 protected Choreographer initialValue() {
105 Looper looper = Looper.myLooper();
106 if (looper == null) {
107 throw new IllegalStateException("The current thread must have a looper!");
108 }
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700109 return new Choreographer(looper, VSYNC_SOURCE_APP);
Jeff Brown96e942d2011-11-30 19:55:01 -0800110 }
111 };
112
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700113 // Thread local storage for the SF choreographer.
114 private static final ThreadLocal<Choreographer> sSfThreadInstance =
115 new ThreadLocal<Choreographer>() {
116 @Override
117 protected Choreographer initialValue() {
118 Looper looper = Looper.myLooper();
119 if (looper == null) {
120 throw new IllegalStateException("The current thread must have a looper!");
121 }
122 return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
123 }
124 };
125
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700126 // Enable/disable vsync for animations and drawing.
Jeff Brown96e942d2011-11-30 19:55:01 -0800127 private static final boolean USE_VSYNC = SystemProperties.getBoolean(
128 "debug.choreographer.vsync", true);
129
Jeff Brown20c4f872012-04-26 17:38:21 -0700130 // Enable/disable using the frame time instead of returning now.
131 private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
132 "debug.choreographer.frametime", true);
133
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700134 // Set a limit to warn about skipped frames.
135 // Skipped frames imply jank.
136 private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
137 "debug.choreographer.skipwarning", 30);
138
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700139 private static final int MSG_DO_FRAME = 0;
140 private static final int MSG_DO_SCHEDULE_VSYNC = 1;
141 private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
Jeff Brown96e942d2011-11-30 19:55:01 -0800142
Jeff Browncae80492012-05-21 16:33:39 -0700143 // All frame callbacks posted by applications have this token.
144 private static final Object FRAME_CALLBACK_TOKEN = new Object() {
145 public String toString() { return "FRAME_CALLBACK_TOKEN"; }
146 };
147
Jeff Brown87d0b032012-02-03 11:01:21 -0800148 private final Object mLock = new Object();
149
Jeff Brown96e942d2011-11-30 19:55:01 -0800150 private final Looper mLooper;
Jeff Brown96858852012-02-14 13:45:06 -0800151 private final FrameHandler mHandler;
Jeff Browncae80492012-05-21 16:33:39 -0700152
153 // The display event receiver can only be accessed by the looper thread to which
154 // it is attached. We take care to ensure that we post message to the looper
155 // if appropriate when interacting with the display event receiver.
Jeff Brown1654d0b2012-02-15 15:40:52 -0800156 private final FrameDisplayEventReceiver mDisplayEventReceiver;
Jeff Brown96858852012-02-14 13:45:06 -0800157
Jeff Browncae80492012-05-21 16:33:39 -0700158 private CallbackRecord mCallbackPool;
Jeff Brown96e942d2011-11-30 19:55:01 -0800159
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700160 private final CallbackQueue[] mCallbackQueues;
Jeff Brown96858852012-02-14 13:45:06 -0800161
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700162 private boolean mFrameScheduled;
Jeff Brown20c4f872012-04-26 17:38:21 -0700163 private boolean mCallbacksRunning;
164 private long mLastFrameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700165 private long mFrameIntervalNanos;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700166 private boolean mDebugPrintNextFrameTimeDelta;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700167
168 /**
John Reckba6adf62015-02-19 14:36:50 -0800169 * Contains information about the current frame for jank-tracking,
170 * mainly timings of key events along with a bit of metadata about
171 * view tree state
172 *
173 * TODO: Is there a better home for this? Currently Choreographer
174 * is the only one with CALLBACK_ANIMATION start time, hence why this
175 * resides here.
176 *
177 * @hide
178 */
179 FrameInfo mFrameInfo = new FrameInfo();
180
181 /**
Chris Craike22c59b2015-05-21 18:33:37 -0700182 * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
183 * @hide
184 */
185 private static final String[] CALLBACK_TRACE_TITLES = {
186 "input", "animation", "traversal", "commit"
187 };
188
189 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700190 * Callback type: Input callback. Runs first.
Jeff Browncae80492012-05-21 16:33:39 -0700191 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700192 */
193 public static final int CALLBACK_INPUT = 0;
194
195 /**
196 * Callback type: Animation callback. Runs before traversals.
Jeff Browncae80492012-05-21 16:33:39 -0700197 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700198 */
Doris Liu197a6742017-08-16 17:12:42 -0700199 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700200 public static final int CALLBACK_ANIMATION = 1;
201
202 /**
Jeff Brownc42b28d2015-04-06 19:49:02 -0700203 * Callback type: Traversal callback. Handles layout and draw. Runs
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700204 * after all other asynchronous messages have been handled.
Jeff Browncae80492012-05-21 16:33:39 -0700205 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700206 */
207 public static final int CALLBACK_TRAVERSAL = 2;
208
Jeff Brownc42b28d2015-04-06 19:49:02 -0700209 /**
210 * Callback type: Commit callback. Handles post-draw operations for the frame.
211 * Runs after traversal completes. The {@link #getFrameTime() frame time} reported
212 * during this callback may be updated to reflect delays that occurred while
213 * traversals were in progress in case heavy layout operations caused some frames
214 * to be skipped. The frame time reported during this callback provides a better
215 * estimate of the start time of the frame in which animations (and other updates
216 * to the view hierarchy state) actually took effect.
217 * @hide
218 */
219 public static final int CALLBACK_COMMIT = 3;
220
221 private static final int CALLBACK_LAST = CALLBACK_COMMIT;
Jeff Brown96e942d2011-11-30 19:55:01 -0800222
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700223 private Choreographer(Looper looper, int vsyncSource) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800224 mLooper = looper;
Jeff Brown96858852012-02-14 13:45:06 -0800225 mHandler = new FrameHandler(looper);
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700226 mDisplayEventReceiver = USE_VSYNC
227 ? new FrameDisplayEventReceiver(looper, vsyncSource)
228 : null;
Jeff Brown20c4f872012-04-26 17:38:21 -0700229 mLastFrameTimeNanos = Long.MIN_VALUE;
Jeff Brownd32460c2012-07-20 16:15:36 -0700230
Jeff Brownbd6e1502012-08-28 03:27:37 -0700231 mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700232
233 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
234 for (int i = 0; i <= CALLBACK_LAST; i++) {
235 mCallbackQueues[i] = new CallbackQueue();
236 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800237 }
238
Jeff Brownbd6e1502012-08-28 03:27:37 -0700239 private static float getRefreshRate() {
240 DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
241 Display.DEFAULT_DISPLAY);
P.Y. Laligandb3b9eb32015-05-11 15:02:07 -0700242 return di.getMode().getRefreshRate();
Jeff Brownbd6e1502012-08-28 03:27:37 -0700243 }
244
Jeff Brown96e942d2011-11-30 19:55:01 -0800245 /**
Dianne Hackborn8bcd54b2012-01-31 19:04:53 -0800246 * Gets the choreographer for the calling thread. Must be called from
247 * a thread that already has a {@link android.os.Looper} associated with it.
Jeff Brown96e942d2011-11-30 19:55:01 -0800248 *
249 * @return The choreographer for this thread.
250 * @throws IllegalStateException if the thread does not have a looper.
251 */
252 public static Choreographer getInstance() {
253 return sThreadInstance.get();
254 }
255
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700256 /**
257 * @hide
258 */
259 public static Choreographer getSfInstance() {
260 return sSfThreadInstance.get();
261 }
262
John Reckac04f4e2016-06-23 10:21:45 -0700263 /** Destroys the calling thread's choreographer
264 * @hide
265 */
266 public static void releaseInstance() {
267 Choreographer old = sThreadInstance.get();
268 sThreadInstance.remove();
269 old.dispose();
270 }
271
272 private void dispose() {
273 mDisplayEventReceiver.dispose();
274 }
275
Jeff Brown96e942d2011-11-30 19:55:01 -0800276 /**
Jeff Browncae80492012-05-21 16:33:39 -0700277 * The amount of time, in milliseconds, between each frame of the animation.
278 * <p>
279 * This is a requested time that the animation will attempt to honor, but the actual delay
280 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800281 * function because the same delay will be applied to all animations, since they are all
282 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700283 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800284 * The frame delay may be ignored when the animation system uses an external timing
285 * source, such as the display refresh rate (vsync), to govern animations.
Jeff Browncae80492012-05-21 16:33:39 -0700286 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800287 *
288 * @return the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700289 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800290 */
Doris Liu197a6742017-08-16 17:12:42 -0700291 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800292 public static long getFrameDelay() {
293 return sFrameDelay;
294 }
295
296 /**
Jeff Browncae80492012-05-21 16:33:39 -0700297 * The amount of time, in milliseconds, between each frame of the animation.
298 * <p>
299 * This is a requested time that the animation will attempt to honor, but the actual delay
300 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800301 * function because the same delay will be applied to all animations, since they are all
302 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700303 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800304 * The frame delay may be ignored when the animation system uses an external timing
305 * source, such as the display refresh rate (vsync), to govern animations.
Jeff Browncae80492012-05-21 16:33:39 -0700306 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800307 *
308 * @param frameDelay the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700309 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800310 */
Doris Liu197a6742017-08-16 17:12:42 -0700311 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800312 public static void setFrameDelay(long frameDelay) {
313 sFrameDelay = frameDelay;
314 }
315
316 /**
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800317 * Subtracts typical frame delay time from a delay interval in milliseconds.
Jeff Browncae80492012-05-21 16:33:39 -0700318 * <p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800319 * This method can be used to compensate for animation delay times that have baked
320 * in assumptions about the frame delay. For example, it's quite common for code to
321 * assume a 60Hz frame time and bake in a 16ms delay. When we call
322 * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
323 * posting the animation callback but let the animation timer take care of the remaining
324 * frame delay time.
Jeff Browncae80492012-05-21 16:33:39 -0700325 * </p><p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800326 * This method is somewhat conservative about how much of the frame delay it
327 * subtracts. It uses the same value returned by {@link #getFrameDelay} which by
328 * default is 10ms even though many parts of the system assume 16ms. Consequently,
329 * we might still wait 6ms before posting an animation callback that we want to run
330 * on the next frame, but this is much better than waiting a whole 16ms and likely
331 * missing the deadline.
Jeff Browncae80492012-05-21 16:33:39 -0700332 * </p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800333 *
334 * @param delayMillis The original delay time including an assumed frame delay.
335 * @return The adjusted delay time with the assumed frame delay subtracted out.
Jeff Browncae80492012-05-21 16:33:39 -0700336 * @hide
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800337 */
338 public static long subtractFrameDelay(long delayMillis) {
339 final long frameDelay = sFrameDelay;
340 return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
341 }
342
John Reck18f16e62014-05-02 16:46:41 -0700343 /**
344 * @return The refresh rate as the nanoseconds between frames
345 * @hide
346 */
John Reck315c3292014-05-09 19:21:04 -0700347 public long getFrameIntervalNanos() {
John Reck18f16e62014-05-02 16:46:41 -0700348 return mFrameIntervalNanos;
349 }
350
Jeff Brown5182c782013-10-15 20:31:52 -0700351 void dump(String prefix, PrintWriter writer) {
352 String innerPrefix = prefix + " ";
353 writer.print(prefix); writer.println("Choreographer:");
354 writer.print(innerPrefix); writer.print("mFrameScheduled=");
355 writer.println(mFrameScheduled);
356 writer.print(innerPrefix); writer.print("mLastFrameTime=");
357 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
358 }
359
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800360 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700361 * Posts a callback to run on the next frame.
Jeff Browncae80492012-05-21 16:33:39 -0700362 * <p>
363 * The callback runs once then is automatically removed.
364 * </p>
Jeff Brown4a06c802012-02-15 15:06:01 -0800365 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700366 * @param callbackType The callback type.
367 * @param action The callback action to run during the next frame.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800368 * @param token The callback token, or null if none.
Jeff Brown4a06c802012-02-15 15:06:01 -0800369 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700370 * @see #removeCallbacks
Jeff Browncae80492012-05-21 16:33:39 -0700371 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800372 */
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700373 public void postCallback(int callbackType, Runnable action, Object token) {
374 postCallbackDelayed(callbackType, action, token, 0);
Jeff Brown87d0b032012-02-03 11:01:21 -0800375 }
376
Jeff Brown4a06c802012-02-15 15:06:01 -0800377 /**
Jeff Browncae80492012-05-21 16:33:39 -0700378 * Posts a callback to run on the next frame after the specified delay.
379 * <p>
380 * The callback runs once then is automatically removed.
381 * </p>
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800382 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700383 * @param callbackType The callback type.
384 * @param action The callback action to run during the next frame after the specified delay.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800385 * @param token The callback token, or null if none.
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800386 * @param delayMillis The delay time in milliseconds.
387 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700388 * @see #removeCallback
Jeff Browncae80492012-05-21 16:33:39 -0700389 * @hide
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800390 */
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700391 public void postCallbackDelayed(int callbackType,
392 Runnable action, Object token, long delayMillis) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800393 if (action == null) {
394 throw new IllegalArgumentException("action must not be null");
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800395 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700396 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
397 throw new IllegalArgumentException("callbackType is invalid");
398 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800399
Jeff Browncae80492012-05-21 16:33:39 -0700400 postCallbackDelayedInternal(callbackType, action, token, delayMillis);
401 }
402
403 private void postCallbackDelayedInternal(int callbackType,
404 Object action, Object token, long delayMillis) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700405 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700406 Log.d(TAG, "PostCallback: type=" + callbackType
407 + ", action=" + action + ", token=" + token
Jeff Brown43ea54b2012-03-09 14:37:48 -0800408 + ", delayMillis=" + delayMillis);
409 }
410
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800411 synchronized (mLock) {
412 final long now = SystemClock.uptimeMillis();
413 final long dueTime = now + delayMillis;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700414 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800415
416 if (dueTime <= now) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700417 scheduleFrameLocked(now);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800418 } else {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700419 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
420 msg.arg1 = callbackType;
421 msg.setAsynchronous(true);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800422 mHandler.sendMessageAtTime(msg, dueTime);
423 }
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800424 }
425 }
426
427 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700428 * Removes callbacks that have the specified action and token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800429 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700430 * @param callbackType The callback type.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800431 * @param action The action property of the callbacks to remove, or null to remove
432 * callbacks with any action.
433 * @param token The token property of the callbacks to remove, or null to remove
434 * callbacks with any token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800435 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700436 * @see #postCallback
437 * @see #postCallbackDelayed
Jeff Browncae80492012-05-21 16:33:39 -0700438 * @hide
Jeff Brown4a06c802012-02-15 15:06:01 -0800439 */
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700440 public void removeCallbacks(int callbackType, Runnable action, Object token) {
441 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
442 throw new IllegalArgumentException("callbackType is invalid");
443 }
444
Jeff Browncae80492012-05-21 16:33:39 -0700445 removeCallbacksInternal(callbackType, action, token);
446 }
447
448 private void removeCallbacksInternal(int callbackType, Object action, Object token) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700449 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700450 Log.d(TAG, "RemoveCallbacks: type=" + callbackType
451 + ", action=" + action + ", token=" + token);
Jeff Brown43ea54b2012-03-09 14:37:48 -0800452 }
453
Jeff Brown4a06c802012-02-15 15:06:01 -0800454 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700455 mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800456 if (action != null && token == null) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700457 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800458 }
Jeff Brown4a06c802012-02-15 15:06:01 -0800459 }
460 }
461
Jeff Brown20c4f872012-04-26 17:38:21 -0700462 /**
Jeff Browncae80492012-05-21 16:33:39 -0700463 * Posts a frame callback to run on the next frame.
464 * <p>
465 * The callback runs once then is automatically removed.
466 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700467 *
Jeff Browncae80492012-05-21 16:33:39 -0700468 * @param callback The frame callback to run during the next frame.
469 *
470 * @see #postFrameCallbackDelayed
471 * @see #removeFrameCallback
472 */
473 public void postFrameCallback(FrameCallback callback) {
474 postFrameCallbackDelayed(callback, 0);
475 }
476
477 /**
478 * Posts a frame callback to run on the next frame after the specified delay.
479 * <p>
480 * The callback runs once then is automatically removed.
481 * </p>
482 *
483 * @param callback The frame callback to run during the next frame.
484 * @param delayMillis The delay time in milliseconds.
485 *
486 * @see #postFrameCallback
487 * @see #removeFrameCallback
488 */
489 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
490 if (callback == null) {
491 throw new IllegalArgumentException("callback must not be null");
492 }
493
494 postCallbackDelayedInternal(CALLBACK_ANIMATION,
495 callback, FRAME_CALLBACK_TOKEN, delayMillis);
496 }
497
498 /**
499 * Removes a previously posted frame callback.
500 *
501 * @param callback The frame callback to remove.
502 *
503 * @see #postFrameCallback
504 * @see #postFrameCallbackDelayed
505 */
506 public void removeFrameCallback(FrameCallback callback) {
507 if (callback == null) {
508 throw new IllegalArgumentException("callback must not be null");
509 }
510
511 removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
512 }
513
514 /**
515 * Gets the time when the current frame started.
516 * <p>
John Reck8d8af3c2014-07-01 15:23:45 -0700517 * This method provides the time in milliseconds when the frame started being rendered.
Jeff Browncae80492012-05-21 16:33:39 -0700518 * The frame time provides a stable time base for synchronizing animations
519 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
520 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
521 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
522 * the frame was scheduled to start, regardless of when the animations or drawing
523 * callback actually runs. All callbacks that run as part of rendering a frame will
524 * observe the same frame time so using the frame time also helps to synchronize effects
525 * that are performed by different callbacks.
526 * </p><p>
527 * Please note that the framework already takes care to process animations and
528 * drawing using the frame time as a stable time base. Most applications should
529 * not need to use the frame time information directly.
530 * </p><p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700531 * This method should only be called from within a callback.
Jeff Browncae80492012-05-21 16:33:39 -0700532 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700533 *
534 * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
535 *
536 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700537 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700538 */
539 public long getFrameTime() {
John Reck315c3292014-05-09 19:21:04 -0700540 return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
Jeff Brown20c4f872012-04-26 17:38:21 -0700541 }
542
543 /**
544 * Same as {@link #getFrameTime()} but with nanosecond precision.
545 *
546 * @return The frame start time, in the {@link System#nanoTime()} time base.
547 *
548 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700549 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700550 */
551 public long getFrameTimeNanos() {
552 synchronized (mLock) {
553 if (!mCallbacksRunning) {
554 throw new IllegalStateException("This method must only be called as "
555 + "part of a callback while a frame is in progress.");
556 }
557 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
558 }
559 }
560
Jorim Jaggid6d6de62017-03-31 15:05:13 +0200561 /**
562 * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
563 * whether callbacks are currently running.
564 * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
565 * @hide
566 */
567 public long getLastFrameTimeNanos() {
568 synchronized (mLock) {
569 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
570 }
571 }
572
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700573 private void scheduleFrameLocked(long now) {
574 if (!mFrameScheduled) {
575 mFrameScheduled = true;
Jeff Brown96e942d2011-11-30 19:55:01 -0800576 if (USE_VSYNC) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700577 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700578 Log.d(TAG, "Scheduling next frame on vsync.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800579 }
Jeff Brown58aedbc2012-02-13 20:15:01 -0800580
581 // If running on the Looper thread, then schedule the vsync immediately,
582 // otherwise post a message to schedule the vsync from the UI thread
583 // as soon as possible.
Jeff Brown58aedbc2012-02-13 20:15:01 -0800584 if (isRunningOnLooperThreadLocked()) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800585 scheduleVsyncLocked();
Jeff Brown58aedbc2012-02-13 20:15:01 -0800586 } else {
Jeff Browne0dbd002012-02-15 19:34:58 -0800587 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
588 msg.setAsynchronous(true);
589 mHandler.sendMessageAtFrontOfQueue(msg);
Jeff Brown58aedbc2012-02-13 20:15:01 -0800590 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800591 } else {
Jeff Brown20c4f872012-04-26 17:38:21 -0700592 final long nextFrameTime = Math.max(
John Reck315c3292014-05-09 19:21:04 -0700593 mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700594 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700595 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800596 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700597 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
Jeff Browne0dbd002012-02-15 19:34:58 -0800598 msg.setAsynchronous(true);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700599 mHandler.sendMessageAtTime(msg, nextFrameTime);
Jeff Brown96e942d2011-11-30 19:55:01 -0800600 }
601 }
602 }
603
Jeff Browncae80492012-05-21 16:33:39 -0700604 void doFrame(long frameTimeNanos, int frame) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700605 final long startNanos;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700606 synchronized (mLock) {
607 if (!mFrameScheduled) {
608 return; // no work to do
Jeff Brown96e942d2011-11-30 19:55:01 -0800609 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700610
Jeff Brownc42b28d2015-04-06 19:49:02 -0700611 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
612 mDebugPrintNextFrameTimeDelta = false;
613 Log.d(TAG, "Frame time delta: "
614 + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
615 }
616
John Reckba6adf62015-02-19 14:36:50 -0800617 long intendedFrameTimeNanos = frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700618 startNanos = System.nanoTime();
Jeff Browncae80492012-05-21 16:33:39 -0700619 final long jitterNanos = startNanos - frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700620 if (jitterNanos >= mFrameIntervalNanos) {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700621 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
622 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Jeff Brown265f1cc2012-06-11 18:01:06 -0700623 Log.i(TAG, "Skipped " + skippedFrames + " frames! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700624 + "The application may be doing too much work on its main thread.");
625 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700626 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700627 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700628 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
629 + "which is more than the frame interval of "
630 + (mFrameIntervalNanos * 0.000001f) + " ms! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700631 + "Skipping " + skippedFrames + " frames and setting frame "
632 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700633 }
Jeff Browncae80492012-05-21 16:33:39 -0700634 frameTimeNanos = startNanos - lastFrameOffset;
Jeff Brown59bbef02012-05-07 16:43:25 -0700635 }
636
Jeff Browncae80492012-05-21 16:33:39 -0700637 if (frameTimeNanos < mLastFrameTimeNanos) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700638 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700639 Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700640 + "previously skipped frame. Waiting for next vsync.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700641 }
642 scheduleVsyncLocked();
643 return;
644 }
645
John Reckba6adf62015-02-19 14:36:50 -0800646 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700647 mFrameScheduled = false;
Jeff Browncae80492012-05-21 16:33:39 -0700648 mLastFrameTimeNanos = frameTimeNanos;
Jeff Brown20c4f872012-04-26 17:38:21 -0700649 }
650
Chris Craike22c59b2015-05-21 18:33:37 -0700651 try {
652 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
John Recka2acb4f2016-08-05 07:58:37 -0700653 AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
John Reckba6adf62015-02-19 14:36:50 -0800654
Chris Craike22c59b2015-05-21 18:33:37 -0700655 mFrameInfo.markInputHandlingStart();
656 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
John Reckba6adf62015-02-19 14:36:50 -0800657
Chris Craike22c59b2015-05-21 18:33:37 -0700658 mFrameInfo.markAnimationsStart();
659 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700660
Chris Craike22c59b2015-05-21 18:33:37 -0700661 mFrameInfo.markPerformTraversalsStart();
662 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
663
664 doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
665 } finally {
John Recka2acb4f2016-08-05 07:58:37 -0700666 AnimationUtils.unlockAnimationClock();
Chris Craike22c59b2015-05-21 18:33:37 -0700667 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
668 }
Jeff Brownc42b28d2015-04-06 19:49:02 -0700669
670 if (DEBUG_FRAMES) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700671 final long endNanos = System.nanoTime();
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700672 Log.d(TAG, "Frame " + frame + ": Finished, took "
Jeff Brown20c4f872012-04-26 17:38:21 -0700673 + (endNanos - startNanos) * 0.000001f + " ms, latency "
Jeff Browncae80492012-05-21 16:33:39 -0700674 + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800675 }
676 }
677
Jeff Browncae80492012-05-21 16:33:39 -0700678 void doCallbacks(int callbackType, long frameTimeNanos) {
679 CallbackRecord callbacks;
Jeff Brown96858852012-02-14 13:45:06 -0800680 synchronized (mLock) {
Jeff Browncae80492012-05-21 16:33:39 -0700681 // We use "now" to determine when callbacks become due because it's possible
682 // for earlier processing phases in a frame to post callbacks that should run
683 // in a following phase, such as an input event that causes an animation to start.
Jeff Brownc42b28d2015-04-06 19:49:02 -0700684 final long now = System.nanoTime();
685 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
686 now / TimeUtils.NANOS_PER_MS);
Jeff Brown20c4f872012-04-26 17:38:21 -0700687 if (callbacks == null) {
688 return;
689 }
690 mCallbacksRunning = true;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700691
692 // Update the frame time if necessary when committing the frame.
693 // We only update the frame time if we are more than 2 frames late reaching
694 // the commit phase. This ensures that the frame time which is observed by the
695 // callbacks will always increase from one frame to the next and never repeat.
696 // We never want the next frame's starting frame time to end up being less than
697 // or equal to the previous frame's commit frame time. Keep in mind that the
698 // next frame has most likely already been scheduled by now so we play it
699 // safe by ensuring the commit time is always at least one frame behind.
700 if (callbackType == Choreographer.CALLBACK_COMMIT) {
701 final long jitterNanos = now - frameTimeNanos;
Chris Craike22c59b2015-05-21 18:33:37 -0700702 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700703 if (jitterNanos >= 2 * mFrameIntervalNanos) {
704 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
705 + mFrameIntervalNanos;
706 if (DEBUG_JANK) {
707 Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
708 + " ms which is more than twice the frame interval of "
709 + (mFrameIntervalNanos * 0.000001f) + " ms! "
710 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
711 + " ms in the past.");
712 mDebugPrintNextFrameTimeDelta = true;
713 }
714 frameTimeNanos = now - lastFrameOffset;
715 mLastFrameTimeNanos = frameTimeNanos;
716 }
717 }
Jeff Brown96858852012-02-14 13:45:06 -0800718 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700719 try {
Chris Craike22c59b2015-05-21 18:33:37 -0700720 Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
Jeff Browncae80492012-05-21 16:33:39 -0700721 for (CallbackRecord c = callbacks; c != null; c = c.next) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700722 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700723 Log.d(TAG, "RunCallback: type=" + callbackType
724 + ", action=" + c.action + ", token=" + c.token
725 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
726 }
Jeff Browncae80492012-05-21 16:33:39 -0700727 c.run(frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700728 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700729 } finally {
Jeff Brown96858852012-02-14 13:45:06 -0800730 synchronized (mLock) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700731 mCallbacksRunning = false;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700732 do {
Jeff Browncae80492012-05-21 16:33:39 -0700733 final CallbackRecord next = callbacks.next;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700734 recycleCallbackLocked(callbacks);
735 callbacks = next;
736 } while (callbacks != null);
Jeff Brown96858852012-02-14 13:45:06 -0800737 }
Chris Craike22c59b2015-05-21 18:33:37 -0700738 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Jeff Brown96858852012-02-14 13:45:06 -0800739 }
Jeff Brown96858852012-02-14 13:45:06 -0800740 }
741
742 void doScheduleVsync() {
743 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700744 if (mFrameScheduled) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800745 scheduleVsyncLocked();
746 }
Jeff Brown96858852012-02-14 13:45:06 -0800747 }
748 }
749
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700750 void doScheduleCallback(int callbackType) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800751 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700752 if (!mFrameScheduled) {
753 final long now = SystemClock.uptimeMillis();
754 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
755 scheduleFrameLocked(now);
756 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800757 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800758 }
759 }
760
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800761 private void scheduleVsyncLocked() {
762 mDisplayEventReceiver.scheduleVsync();
763 }
764
Jeff Brown58aedbc2012-02-13 20:15:01 -0800765 private boolean isRunningOnLooperThreadLocked() {
766 return Looper.myLooper() == mLooper;
767 }
768
Jeff Browncae80492012-05-21 16:33:39 -0700769 private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
770 CallbackRecord callback = mCallbackPool;
Jeff Brown96858852012-02-14 13:45:06 -0800771 if (callback == null) {
Jeff Browncae80492012-05-21 16:33:39 -0700772 callback = new CallbackRecord();
Jeff Brown96858852012-02-14 13:45:06 -0800773 } else {
774 mCallbackPool = callback.next;
775 callback.next = null;
776 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800777 callback.dueTime = dueTime;
778 callback.action = action;
779 callback.token = token;
Jeff Brown96858852012-02-14 13:45:06 -0800780 return callback;
781 }
782
Jeff Browncae80492012-05-21 16:33:39 -0700783 private void recycleCallbackLocked(CallbackRecord callback) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800784 callback.action = null;
785 callback.token = null;
Jeff Brown96858852012-02-14 13:45:06 -0800786 callback.next = mCallbackPool;
787 mCallbackPool = callback;
788 }
789
Jeff Browncae80492012-05-21 16:33:39 -0700790 /**
791 * Implement this interface to receive a callback when a new display frame is
792 * being rendered. The callback is invoked on the {@link Looper} thread to
793 * which the {@link Choreographer} is attached.
794 */
795 public interface FrameCallback {
796 /**
797 * Called when a new display frame is being rendered.
798 * <p>
799 * This method provides the time in nanoseconds when the frame started being rendered.
800 * The frame time provides a stable time base for synchronizing animations
801 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
802 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
803 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
804 * the frame was scheduled to start, regardless of when the animations or drawing
805 * callback actually runs. All callbacks that run as part of rendering a frame will
806 * observe the same frame time so using the frame time also helps to synchronize effects
807 * that are performed by different callbacks.
808 * </p><p>
809 * Please note that the framework already takes care to process animations and
810 * drawing using the frame time as a stable time base. Most applications should
811 * not need to use the frame time information directly.
812 * </p>
813 *
814 * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
815 * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000}
816 * to convert it to the {@link SystemClock#uptimeMillis()} time base.
817 */
818 public void doFrame(long frameTimeNanos);
819 }
820
Jeff Brown96858852012-02-14 13:45:06 -0800821 private final class FrameHandler extends Handler {
822 public FrameHandler(Looper looper) {
823 super(looper);
824 }
825
826 @Override
827 public void handleMessage(Message msg) {
828 switch (msg.what) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700829 case MSG_DO_FRAME:
Jeff Brown20c4f872012-04-26 17:38:21 -0700830 doFrame(System.nanoTime(), 0);
Jeff Brown96858852012-02-14 13:45:06 -0800831 break;
832 case MSG_DO_SCHEDULE_VSYNC:
833 doScheduleVsync();
834 break;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700835 case MSG_DO_SCHEDULE_CALLBACK:
836 doScheduleCallback(msg.arg1);
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800837 break;
Jeff Brown96858852012-02-14 13:45:06 -0800838 }
839 }
840 }
841
Jeff Brownb0806602012-05-16 12:50:41 -0700842 private final class FrameDisplayEventReceiver extends DisplayEventReceiver
843 implements Runnable {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700844 private boolean mHavePendingVsync;
Jeff Brownb0806602012-05-16 12:50:41 -0700845 private long mTimestampNanos;
846 private int mFrame;
847
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700848 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
849 super(looper, vsyncSource);
Jeff Brown96e942d2011-11-30 19:55:01 -0800850 }
851
852 @Override
Jeff Browne87bf032012-09-20 18:30:13 -0700853 public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
854 // Ignore vsync from secondary display.
855 // This can be problematic because the call to scheduleVsync() is a one-shot.
856 // We need to ensure that we will still receive the vsync from the primary
857 // display which is the one we really care about. Ideally we should schedule
858 // vsync for a particular display.
859 // At this time Surface Flinger won't send us vsyncs for secondary displays
860 // but that could change in the future so let's log a message to help us remember
861 // that we need to fix this.
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800862 if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
Jeff Browne87bf032012-09-20 18:30:13 -0700863 Log.d(TAG, "Received vsync from secondary display, but we don't support "
864 + "this case yet. Choreographer needs a way to explicitly request "
865 + "vsync for a specific display to ensure it doesn't lose track "
866 + "of its scheduled vsync.");
867 scheduleVsync();
868 return;
869 }
870
Jeff Brownb0806602012-05-16 12:50:41 -0700871 // Post the vsync event to the Handler.
872 // The idea is to prevent incoming vsync events from completely starving
873 // the message queue. If there are no messages in the queue with timestamps
874 // earlier than the frame time, then the vsync event will be processed immediately.
875 // Otherwise, messages that predate the vsync event will be handled first.
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700876 long now = System.nanoTime();
877 if (timestampNanos > now) {
878 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
879 + " ms in the future! Check that graphics HAL is generating vsync "
880 + "timestamps using the correct timebase.");
881 timestampNanos = now;
882 }
883
Jeff Brownba7261132012-06-14 23:48:40 -0700884 if (mHavePendingVsync) {
885 Log.w(TAG, "Already have a pending vsync event. There should only be "
886 + "one at a time.");
887 } else {
888 mHavePendingVsync = true;
889 }
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700890
Jeff Brownb0806602012-05-16 12:50:41 -0700891 mTimestampNanos = timestampNanos;
892 mFrame = frame;
893 Message msg = Message.obtain(mHandler, this);
894 msg.setAsynchronous(true);
John Reck315c3292014-05-09 19:21:04 -0700895 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
Jeff Brownb0806602012-05-16 12:50:41 -0700896 }
897
898 @Override
899 public void run() {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700900 mHavePendingVsync = false;
Jeff Brownb0806602012-05-16 12:50:41 -0700901 doFrame(mTimestampNanos, mFrame);
Jeff Brown96e942d2011-11-30 19:55:01 -0800902 }
903 }
Jeff Brown96858852012-02-14 13:45:06 -0800904
Jeff Browncae80492012-05-21 16:33:39 -0700905 private static final class CallbackRecord {
906 public CallbackRecord next;
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800907 public long dueTime;
Jeff Browncae80492012-05-21 16:33:39 -0700908 public Object action; // Runnable or FrameCallback
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800909 public Object token;
Jeff Browncae80492012-05-21 16:33:39 -0700910
911 public void run(long frameTimeNanos) {
912 if (token == FRAME_CALLBACK_TOKEN) {
913 ((FrameCallback)action).doFrame(frameTimeNanos);
914 } else {
915 ((Runnable)action).run();
916 }
917 }
Jeff Brown96858852012-02-14 13:45:06 -0800918 }
Jeff Brown43ea54b2012-03-09 14:37:48 -0800919
920 private final class CallbackQueue {
Jeff Browncae80492012-05-21 16:33:39 -0700921 private CallbackRecord mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800922
923 public boolean hasDueCallbacksLocked(long now) {
924 return mHead != null && mHead.dueTime <= now;
925 }
926
Jeff Browncae80492012-05-21 16:33:39 -0700927 public CallbackRecord extractDueCallbacksLocked(long now) {
928 CallbackRecord callbacks = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800929 if (callbacks == null || callbacks.dueTime > now) {
930 return null;
931 }
932
Jeff Browncae80492012-05-21 16:33:39 -0700933 CallbackRecord last = callbacks;
934 CallbackRecord next = last.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800935 while (next != null) {
936 if (next.dueTime > now) {
937 last.next = null;
938 break;
939 }
940 last = next;
941 next = next.next;
942 }
943 mHead = next;
944 return callbacks;
945 }
946
Jeff Browncae80492012-05-21 16:33:39 -0700947 public void addCallbackLocked(long dueTime, Object action, Object token) {
948 CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
949 CallbackRecord entry = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800950 if (entry == null) {
951 mHead = callback;
952 return;
953 }
954 if (dueTime < entry.dueTime) {
955 callback.next = entry;
956 mHead = callback;
957 return;
958 }
959 while (entry.next != null) {
960 if (dueTime < entry.next.dueTime) {
961 callback.next = entry.next;
962 break;
963 }
964 entry = entry.next;
965 }
966 entry.next = callback;
967 }
968
Jeff Browncae80492012-05-21 16:33:39 -0700969 public void removeCallbacksLocked(Object action, Object token) {
970 CallbackRecord predecessor = null;
971 for (CallbackRecord callback = mHead; callback != null;) {
972 final CallbackRecord next = callback.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800973 if ((action == null || callback.action == action)
974 && (token == null || callback.token == token)) {
975 if (predecessor != null) {
976 predecessor.next = next;
977 } else {
978 mHead = next;
979 }
980 recycleCallbackLocked(callback);
981 } else {
982 predecessor = callback;
983 }
984 callback = next;
985 }
986 }
987 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800988}