blob: f8cfd0da49522cd960ba64bbc00b3f1e659eb7e6 [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 Jaggib29e3182018-04-30 18:51:56 +0200109 Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
110 if (looper == Looper.getMainLooper()) {
111 mMainInstance = choreographer;
112 }
113 return choreographer;
Jeff Brown96e942d2011-11-30 19:55:01 -0800114 }
115 };
116
Jorim Jaggib29e3182018-04-30 18:51:56 +0200117 private static volatile Choreographer mMainInstance;
118
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700119 // Thread local storage for the SF choreographer.
120 private static final ThreadLocal<Choreographer> sSfThreadInstance =
121 new ThreadLocal<Choreographer>() {
122 @Override
123 protected Choreographer initialValue() {
124 Looper looper = Looper.myLooper();
125 if (looper == null) {
126 throw new IllegalStateException("The current thread must have a looper!");
127 }
128 return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
129 }
130 };
131
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700132 // Enable/disable vsync for animations and drawing.
Jeff Brown96e942d2011-11-30 19:55:01 -0800133 private static final boolean USE_VSYNC = SystemProperties.getBoolean(
134 "debug.choreographer.vsync", true);
135
Jeff Brown20c4f872012-04-26 17:38:21 -0700136 // Enable/disable using the frame time instead of returning now.
137 private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
138 "debug.choreographer.frametime", true);
139
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700140 // Set a limit to warn about skipped frames.
141 // Skipped frames imply jank.
142 private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
143 "debug.choreographer.skipwarning", 30);
144
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700145 private static final int MSG_DO_FRAME = 0;
146 private static final int MSG_DO_SCHEDULE_VSYNC = 1;
147 private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
Jeff Brown96e942d2011-11-30 19:55:01 -0800148
Jeff Browncae80492012-05-21 16:33:39 -0700149 // All frame callbacks posted by applications have this token.
150 private static final Object FRAME_CALLBACK_TOKEN = new Object() {
151 public String toString() { return "FRAME_CALLBACK_TOKEN"; }
152 };
153
Jeff Brown87d0b032012-02-03 11:01:21 -0800154 private final Object mLock = new Object();
155
Jeff Brown96e942d2011-11-30 19:55:01 -0800156 private final Looper mLooper;
Jeff Brown96858852012-02-14 13:45:06 -0800157 private final FrameHandler mHandler;
Jeff Browncae80492012-05-21 16:33:39 -0700158
159 // The display event receiver can only be accessed by the looper thread to which
160 // it is attached. We take care to ensure that we post message to the looper
161 // if appropriate when interacting with the display event receiver.
Jeff Brown1654d0b2012-02-15 15:40:52 -0800162 private final FrameDisplayEventReceiver mDisplayEventReceiver;
Jeff Brown96858852012-02-14 13:45:06 -0800163
Jeff Browncae80492012-05-21 16:33:39 -0700164 private CallbackRecord mCallbackPool;
Jeff Brown96e942d2011-11-30 19:55:01 -0800165
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700166 private final CallbackQueue[] mCallbackQueues;
Jeff Brown96858852012-02-14 13:45:06 -0800167
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700168 private boolean mFrameScheduled;
Jeff Brown20c4f872012-04-26 17:38:21 -0700169 private boolean mCallbacksRunning;
170 private long mLastFrameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700171 private long mFrameIntervalNanos;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700172 private boolean mDebugPrintNextFrameTimeDelta;
John Reck9f516442017-09-25 10:27:21 -0700173 private int mFPSDivisor = 1;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700174
175 /**
John Reckba6adf62015-02-19 14:36:50 -0800176 * Contains information about the current frame for jank-tracking,
177 * mainly timings of key events along with a bit of metadata about
178 * view tree state
179 *
180 * TODO: Is there a better home for this? Currently Choreographer
181 * is the only one with CALLBACK_ANIMATION start time, hence why this
182 * resides here.
183 *
184 * @hide
185 */
186 FrameInfo mFrameInfo = new FrameInfo();
187
188 /**
Chris Craike22c59b2015-05-21 18:33:37 -0700189 * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
190 * @hide
191 */
192 private static final String[] CALLBACK_TRACE_TITLES = {
193 "input", "animation", "traversal", "commit"
194 };
195
196 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700197 * Callback type: Input callback. Runs first.
Jeff Browncae80492012-05-21 16:33:39 -0700198 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700199 */
200 public static final int CALLBACK_INPUT = 0;
201
202 /**
203 * Callback type: Animation callback. Runs before traversals.
Jeff Browncae80492012-05-21 16:33:39 -0700204 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700205 */
Doris Liu197a6742017-08-16 17:12:42 -0700206 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700207 public static final int CALLBACK_ANIMATION = 1;
208
209 /**
Jeff Brownc42b28d2015-04-06 19:49:02 -0700210 * Callback type: Traversal callback. Handles layout and draw. Runs
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700211 * after all other asynchronous messages have been handled.
Jeff Browncae80492012-05-21 16:33:39 -0700212 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700213 */
214 public static final int CALLBACK_TRAVERSAL = 2;
215
Jeff Brownc42b28d2015-04-06 19:49:02 -0700216 /**
217 * Callback type: Commit callback. Handles post-draw operations for the frame.
218 * Runs after traversal completes. The {@link #getFrameTime() frame time} reported
219 * during this callback may be updated to reflect delays that occurred while
220 * traversals were in progress in case heavy layout operations caused some frames
221 * to be skipped. The frame time reported during this callback provides a better
222 * estimate of the start time of the frame in which animations (and other updates
223 * to the view hierarchy state) actually took effect.
224 * @hide
225 */
226 public static final int CALLBACK_COMMIT = 3;
227
228 private static final int CALLBACK_LAST = CALLBACK_COMMIT;
Jeff Brown96e942d2011-11-30 19:55:01 -0800229
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700230 private Choreographer(Looper looper, int vsyncSource) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800231 mLooper = looper;
Jeff Brown96858852012-02-14 13:45:06 -0800232 mHandler = new FrameHandler(looper);
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700233 mDisplayEventReceiver = USE_VSYNC
234 ? new FrameDisplayEventReceiver(looper, vsyncSource)
235 : null;
Jeff Brown20c4f872012-04-26 17:38:21 -0700236 mLastFrameTimeNanos = Long.MIN_VALUE;
Jeff Brownd32460c2012-07-20 16:15:36 -0700237
Jeff Brownbd6e1502012-08-28 03:27:37 -0700238 mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700239
240 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
241 for (int i = 0; i <= CALLBACK_LAST; i++) {
242 mCallbackQueues[i] = new CallbackQueue();
243 }
Makoto Onukib708cbe2018-01-09 12:35:06 -0800244 // b/68769804: For low FPS experiments.
245 setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
Jeff Brown96e942d2011-11-30 19:55:01 -0800246 }
247
Jeff Brownbd6e1502012-08-28 03:27:37 -0700248 private static float getRefreshRate() {
249 DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
250 Display.DEFAULT_DISPLAY);
P.Y. Laligandb3b9eb32015-05-11 15:02:07 -0700251 return di.getMode().getRefreshRate();
Jeff Brownbd6e1502012-08-28 03:27:37 -0700252 }
253
Jeff Brown96e942d2011-11-30 19:55:01 -0800254 /**
Dianne Hackborn8bcd54b2012-01-31 19:04:53 -0800255 * Gets the choreographer for the calling thread. Must be called from
256 * a thread that already has a {@link android.os.Looper} associated with it.
Jeff Brown96e942d2011-11-30 19:55:01 -0800257 *
258 * @return The choreographer for this thread.
259 * @throws IllegalStateException if the thread does not have a looper.
260 */
261 public static Choreographer getInstance() {
262 return sThreadInstance.get();
263 }
264
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700265 /**
266 * @hide
267 */
268 public static Choreographer getSfInstance() {
269 return sSfThreadInstance.get();
270 }
271
Jorim Jaggib29e3182018-04-30 18:51:56 +0200272 /**
273 * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
274 * @hide
275 */
276 public static Choreographer getMainThreadInstance() {
277 return mMainInstance;
278 }
279
John Reckac04f4e2016-06-23 10:21:45 -0700280 /** Destroys the calling thread's choreographer
281 * @hide
282 */
283 public static void releaseInstance() {
284 Choreographer old = sThreadInstance.get();
285 sThreadInstance.remove();
286 old.dispose();
287 }
288
289 private void dispose() {
290 mDisplayEventReceiver.dispose();
291 }
292
Jeff Brown96e942d2011-11-30 19:55:01 -0800293 /**
Jeff Browncae80492012-05-21 16:33:39 -0700294 * The amount of time, in milliseconds, between each frame of the animation.
295 * <p>
296 * This is a requested time that the animation will attempt to honor, but the actual delay
297 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800298 * function because the same delay will be applied to all animations, since they are all
299 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700300 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800301 * The frame delay may be ignored when the animation system uses an external timing
302 * source, such as the display refresh rate (vsync), to govern animations.
Jeff Browncae80492012-05-21 16:33:39 -0700303 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800304 *
305 * @return the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700306 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800307 */
Doris Liu197a6742017-08-16 17:12:42 -0700308 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800309 public static long getFrameDelay() {
310 return sFrameDelay;
311 }
312
313 /**
Jeff Browncae80492012-05-21 16:33:39 -0700314 * The amount of time, in milliseconds, between each frame of the animation.
315 * <p>
316 * This is a requested time that the animation will attempt to honor, but the actual delay
317 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800318 * function because the same delay will be applied to all animations, since they are all
319 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700320 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800321 * The frame delay may be ignored when the animation system uses an external timing
322 * source, such as the display refresh rate (vsync), to govern animations.
Jeff Browncae80492012-05-21 16:33:39 -0700323 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800324 *
325 * @param frameDelay the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700326 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800327 */
Doris Liu197a6742017-08-16 17:12:42 -0700328 @TestApi
Jeff Brown96e942d2011-11-30 19:55:01 -0800329 public static void setFrameDelay(long frameDelay) {
330 sFrameDelay = frameDelay;
331 }
332
333 /**
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800334 * Subtracts typical frame delay time from a delay interval in milliseconds.
Jeff Browncae80492012-05-21 16:33:39 -0700335 * <p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800336 * This method can be used to compensate for animation delay times that have baked
337 * in assumptions about the frame delay. For example, it's quite common for code to
338 * assume a 60Hz frame time and bake in a 16ms delay. When we call
339 * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
340 * posting the animation callback but let the animation timer take care of the remaining
341 * frame delay time.
Jeff Browncae80492012-05-21 16:33:39 -0700342 * </p><p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800343 * This method is somewhat conservative about how much of the frame delay it
344 * subtracts. It uses the same value returned by {@link #getFrameDelay} which by
345 * default is 10ms even though many parts of the system assume 16ms. Consequently,
346 * we might still wait 6ms before posting an animation callback that we want to run
347 * on the next frame, but this is much better than waiting a whole 16ms and likely
348 * missing the deadline.
Jeff Browncae80492012-05-21 16:33:39 -0700349 * </p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800350 *
351 * @param delayMillis The original delay time including an assumed frame delay.
352 * @return The adjusted delay time with the assumed frame delay subtracted out.
Jeff Browncae80492012-05-21 16:33:39 -0700353 * @hide
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800354 */
355 public static long subtractFrameDelay(long delayMillis) {
356 final long frameDelay = sFrameDelay;
357 return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
358 }
359
John Reck18f16e62014-05-02 16:46:41 -0700360 /**
361 * @return The refresh rate as the nanoseconds between frames
362 * @hide
363 */
John Reck315c3292014-05-09 19:21:04 -0700364 public long getFrameIntervalNanos() {
John Reck18f16e62014-05-02 16:46:41 -0700365 return mFrameIntervalNanos;
366 }
367
Jeff Brown5182c782013-10-15 20:31:52 -0700368 void dump(String prefix, PrintWriter writer) {
369 String innerPrefix = prefix + " ";
370 writer.print(prefix); writer.println("Choreographer:");
371 writer.print(innerPrefix); writer.print("mFrameScheduled=");
372 writer.println(mFrameScheduled);
373 writer.print(innerPrefix); writer.print("mLastFrameTime=");
374 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
375 }
376
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800377 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700378 * Posts a callback to run on the next frame.
Jeff Browncae80492012-05-21 16:33:39 -0700379 * <p>
380 * The callback runs once then is automatically removed.
381 * </p>
Jeff Brown4a06c802012-02-15 15:06: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.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800385 * @param token The callback token, or null if none.
Jeff Brown4a06c802012-02-15 15:06:01 -0800386 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700387 * @see #removeCallbacks
Jeff Browncae80492012-05-21 16:33:39 -0700388 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800389 */
Doris Liu4f8a98c2018-01-16 18:13:57 -0800390 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700391 public void postCallback(int callbackType, Runnable action, Object token) {
392 postCallbackDelayed(callbackType, action, token, 0);
Jeff Brown87d0b032012-02-03 11:01:21 -0800393 }
394
Jeff Brown4a06c802012-02-15 15:06:01 -0800395 /**
Jeff Browncae80492012-05-21 16:33:39 -0700396 * Posts a callback to run on the next frame after the specified delay.
397 * <p>
398 * The callback runs once then is automatically removed.
399 * </p>
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800400 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700401 * @param callbackType The callback type.
402 * @param action The callback action to run during the next frame after the specified delay.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800403 * @param token The callback token, or null if none.
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800404 * @param delayMillis The delay time in milliseconds.
405 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700406 * @see #removeCallback
Jeff Browncae80492012-05-21 16:33:39 -0700407 * @hide
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800408 */
Doris Liu4f8a98c2018-01-16 18:13:57 -0800409 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700410 public void postCallbackDelayed(int callbackType,
411 Runnable action, Object token, long delayMillis) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800412 if (action == null) {
413 throw new IllegalArgumentException("action must not be null");
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800414 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700415 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
416 throw new IllegalArgumentException("callbackType is invalid");
417 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800418
Jeff Browncae80492012-05-21 16:33:39 -0700419 postCallbackDelayedInternal(callbackType, action, token, delayMillis);
420 }
421
422 private void postCallbackDelayedInternal(int callbackType,
423 Object action, Object token, long delayMillis) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700424 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700425 Log.d(TAG, "PostCallback: type=" + callbackType
426 + ", action=" + action + ", token=" + token
Jeff Brown43ea54b2012-03-09 14:37:48 -0800427 + ", delayMillis=" + delayMillis);
428 }
429
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800430 synchronized (mLock) {
431 final long now = SystemClock.uptimeMillis();
432 final long dueTime = now + delayMillis;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700433 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800434
435 if (dueTime <= now) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700436 scheduleFrameLocked(now);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800437 } else {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700438 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
439 msg.arg1 = callbackType;
440 msg.setAsynchronous(true);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800441 mHandler.sendMessageAtTime(msg, dueTime);
442 }
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800443 }
444 }
445
446 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700447 * Removes callbacks that have the specified action and token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800448 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700449 * @param callbackType The callback type.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800450 * @param action The action property of the callbacks to remove, or null to remove
451 * callbacks with any action.
452 * @param token The token property of the callbacks to remove, or null to remove
453 * callbacks with any token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800454 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700455 * @see #postCallback
456 * @see #postCallbackDelayed
Jeff Browncae80492012-05-21 16:33:39 -0700457 * @hide
Jeff Brown4a06c802012-02-15 15:06:01 -0800458 */
Doris Liu4f8a98c2018-01-16 18:13:57 -0800459 @TestApi
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700460 public void removeCallbacks(int callbackType, Runnable action, Object token) {
461 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
462 throw new IllegalArgumentException("callbackType is invalid");
463 }
464
Jeff Browncae80492012-05-21 16:33:39 -0700465 removeCallbacksInternal(callbackType, action, token);
466 }
467
468 private void removeCallbacksInternal(int callbackType, Object action, Object token) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700469 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700470 Log.d(TAG, "RemoveCallbacks: type=" + callbackType
471 + ", action=" + action + ", token=" + token);
Jeff Brown43ea54b2012-03-09 14:37:48 -0800472 }
473
Jeff Brown4a06c802012-02-15 15:06:01 -0800474 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700475 mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800476 if (action != null && token == null) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700477 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800478 }
Jeff Brown4a06c802012-02-15 15:06:01 -0800479 }
480 }
481
Jeff Brown20c4f872012-04-26 17:38:21 -0700482 /**
Jeff Browncae80492012-05-21 16:33:39 -0700483 * Posts a frame callback to run on the next frame.
484 * <p>
485 * The callback runs once then is automatically removed.
486 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700487 *
Jeff Browncae80492012-05-21 16:33:39 -0700488 * @param callback The frame callback to run during the next frame.
489 *
490 * @see #postFrameCallbackDelayed
491 * @see #removeFrameCallback
492 */
493 public void postFrameCallback(FrameCallback callback) {
494 postFrameCallbackDelayed(callback, 0);
495 }
496
497 /**
498 * Posts a frame callback to run on the next frame after the specified delay.
499 * <p>
500 * The callback runs once then is automatically removed.
501 * </p>
502 *
503 * @param callback The frame callback to run during the next frame.
504 * @param delayMillis The delay time in milliseconds.
505 *
506 * @see #postFrameCallback
507 * @see #removeFrameCallback
508 */
509 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
510 if (callback == null) {
511 throw new IllegalArgumentException("callback must not be null");
512 }
513
514 postCallbackDelayedInternal(CALLBACK_ANIMATION,
515 callback, FRAME_CALLBACK_TOKEN, delayMillis);
516 }
517
518 /**
519 * Removes a previously posted frame callback.
520 *
521 * @param callback The frame callback to remove.
522 *
523 * @see #postFrameCallback
524 * @see #postFrameCallbackDelayed
525 */
526 public void removeFrameCallback(FrameCallback callback) {
527 if (callback == null) {
528 throw new IllegalArgumentException("callback must not be null");
529 }
530
531 removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
532 }
533
534 /**
535 * Gets the time when the current frame started.
536 * <p>
John Reck8d8af3c2014-07-01 15:23:45 -0700537 * This method provides the time in milliseconds when the frame started being rendered.
Jeff Browncae80492012-05-21 16:33:39 -0700538 * The frame time provides a stable time base for synchronizing animations
539 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
540 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
541 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
542 * the frame was scheduled to start, regardless of when the animations or drawing
543 * callback actually runs. All callbacks that run as part of rendering a frame will
544 * observe the same frame time so using the frame time also helps to synchronize effects
545 * that are performed by different callbacks.
546 * </p><p>
547 * Please note that the framework already takes care to process animations and
548 * drawing using the frame time as a stable time base. Most applications should
549 * not need to use the frame time information directly.
550 * </p><p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700551 * This method should only be called from within a callback.
Jeff Browncae80492012-05-21 16:33:39 -0700552 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700553 *
554 * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
555 *
556 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700557 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700558 */
559 public long getFrameTime() {
John Reck315c3292014-05-09 19:21:04 -0700560 return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
Jeff Brown20c4f872012-04-26 17:38:21 -0700561 }
562
563 /**
564 * Same as {@link #getFrameTime()} but with nanosecond precision.
565 *
566 * @return The frame start time, in the {@link System#nanoTime()} time base.
567 *
568 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700569 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700570 */
571 public long getFrameTimeNanos() {
572 synchronized (mLock) {
573 if (!mCallbacksRunning) {
574 throw new IllegalStateException("This method must only be called as "
575 + "part of a callback while a frame is in progress.");
576 }
577 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
578 }
579 }
580
Jorim Jaggid6d6de62017-03-31 15:05:13 +0200581 /**
582 * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
583 * whether callbacks are currently running.
584 * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
585 * @hide
586 */
587 public long getLastFrameTimeNanos() {
588 synchronized (mLock) {
589 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
590 }
591 }
592
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700593 private void scheduleFrameLocked(long now) {
594 if (!mFrameScheduled) {
595 mFrameScheduled = true;
Jeff Brown96e942d2011-11-30 19:55:01 -0800596 if (USE_VSYNC) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700597 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700598 Log.d(TAG, "Scheduling next frame on vsync.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800599 }
Jeff Brown58aedbc2012-02-13 20:15:01 -0800600
601 // If running on the Looper thread, then schedule the vsync immediately,
602 // otherwise post a message to schedule the vsync from the UI thread
603 // as soon as possible.
Jeff Brown58aedbc2012-02-13 20:15:01 -0800604 if (isRunningOnLooperThreadLocked()) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800605 scheduleVsyncLocked();
Jeff Brown58aedbc2012-02-13 20:15:01 -0800606 } else {
Jeff Browne0dbd002012-02-15 19:34:58 -0800607 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
608 msg.setAsynchronous(true);
609 mHandler.sendMessageAtFrontOfQueue(msg);
Jeff Brown58aedbc2012-02-13 20:15:01 -0800610 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800611 } else {
Jeff Brown20c4f872012-04-26 17:38:21 -0700612 final long nextFrameTime = Math.max(
John Reck315c3292014-05-09 19:21:04 -0700613 mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700614 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700615 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800616 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700617 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
Jeff Browne0dbd002012-02-15 19:34:58 -0800618 msg.setAsynchronous(true);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700619 mHandler.sendMessageAtTime(msg, nextFrameTime);
Jeff Brown96e942d2011-11-30 19:55:01 -0800620 }
621 }
622 }
623
John Reck9f516442017-09-25 10:27:21 -0700624 void setFPSDivisor(int divisor) {
625 if (divisor <= 0) divisor = 1;
626 mFPSDivisor = divisor;
Makoto Onukib708cbe2018-01-09 12:35:06 -0800627 ThreadedRenderer.setFPSDivisor(divisor);
John Reck9f516442017-09-25 10:27:21 -0700628 }
629
Jeff Browncae80492012-05-21 16:33:39 -0700630 void doFrame(long frameTimeNanos, int frame) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700631 final long startNanos;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700632 synchronized (mLock) {
633 if (!mFrameScheduled) {
634 return; // no work to do
Jeff Brown96e942d2011-11-30 19:55:01 -0800635 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700636
Jeff Brownc42b28d2015-04-06 19:49:02 -0700637 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
638 mDebugPrintNextFrameTimeDelta = false;
639 Log.d(TAG, "Frame time delta: "
640 + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
641 }
642
John Reckba6adf62015-02-19 14:36:50 -0800643 long intendedFrameTimeNanos = frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700644 startNanos = System.nanoTime();
Jeff Browncae80492012-05-21 16:33:39 -0700645 final long jitterNanos = startNanos - frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700646 if (jitterNanos >= mFrameIntervalNanos) {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700647 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
648 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Jeff Brown265f1cc2012-06-11 18:01:06 -0700649 Log.i(TAG, "Skipped " + skippedFrames + " frames! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700650 + "The application may be doing too much work on its main thread.");
651 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700652 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700653 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700654 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
655 + "which is more than the frame interval of "
656 + (mFrameIntervalNanos * 0.000001f) + " ms! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700657 + "Skipping " + skippedFrames + " frames and setting frame "
658 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700659 }
Jeff Browncae80492012-05-21 16:33:39 -0700660 frameTimeNanos = startNanos - lastFrameOffset;
Jeff Brown59bbef02012-05-07 16:43:25 -0700661 }
662
Jeff Browncae80492012-05-21 16:33:39 -0700663 if (frameTimeNanos < mLastFrameTimeNanos) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700664 if (DEBUG_JANK) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700665 Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700666 + "previously skipped frame. Waiting for next vsync.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700667 }
668 scheduleVsyncLocked();
669 return;
670 }
671
John Reck9f516442017-09-25 10:27:21 -0700672 if (mFPSDivisor > 1) {
673 long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
674 if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
675 scheduleVsyncLocked();
676 return;
677 }
678 }
679
John Reckba6adf62015-02-19 14:36:50 -0800680 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700681 mFrameScheduled = false;
Jeff Browncae80492012-05-21 16:33:39 -0700682 mLastFrameTimeNanos = frameTimeNanos;
Jeff Brown20c4f872012-04-26 17:38:21 -0700683 }
684
Chris Craike22c59b2015-05-21 18:33:37 -0700685 try {
686 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
John Recka2acb4f2016-08-05 07:58:37 -0700687 AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
John Reckba6adf62015-02-19 14:36:50 -0800688
Chris Craike22c59b2015-05-21 18:33:37 -0700689 mFrameInfo.markInputHandlingStart();
690 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
John Reckba6adf62015-02-19 14:36:50 -0800691
Chris Craike22c59b2015-05-21 18:33:37 -0700692 mFrameInfo.markAnimationsStart();
693 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700694
Chris Craike22c59b2015-05-21 18:33:37 -0700695 mFrameInfo.markPerformTraversalsStart();
696 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
697
698 doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
699 } finally {
John Recka2acb4f2016-08-05 07:58:37 -0700700 AnimationUtils.unlockAnimationClock();
Chris Craike22c59b2015-05-21 18:33:37 -0700701 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
702 }
Jeff Brownc42b28d2015-04-06 19:49:02 -0700703
704 if (DEBUG_FRAMES) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700705 final long endNanos = System.nanoTime();
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700706 Log.d(TAG, "Frame " + frame + ": Finished, took "
Jeff Brown20c4f872012-04-26 17:38:21 -0700707 + (endNanos - startNanos) * 0.000001f + " ms, latency "
Jeff Browncae80492012-05-21 16:33:39 -0700708 + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800709 }
710 }
711
Jeff Browncae80492012-05-21 16:33:39 -0700712 void doCallbacks(int callbackType, long frameTimeNanos) {
713 CallbackRecord callbacks;
Jeff Brown96858852012-02-14 13:45:06 -0800714 synchronized (mLock) {
Jeff Browncae80492012-05-21 16:33:39 -0700715 // We use "now" to determine when callbacks become due because it's possible
716 // for earlier processing phases in a frame to post callbacks that should run
717 // in a following phase, such as an input event that causes an animation to start.
Jeff Brownc42b28d2015-04-06 19:49:02 -0700718 final long now = System.nanoTime();
719 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
720 now / TimeUtils.NANOS_PER_MS);
Jeff Brown20c4f872012-04-26 17:38:21 -0700721 if (callbacks == null) {
722 return;
723 }
724 mCallbacksRunning = true;
Jeff Brownc42b28d2015-04-06 19:49:02 -0700725
726 // Update the frame time if necessary when committing the frame.
727 // We only update the frame time if we are more than 2 frames late reaching
728 // the commit phase. This ensures that the frame time which is observed by the
729 // callbacks will always increase from one frame to the next and never repeat.
730 // We never want the next frame's starting frame time to end up being less than
731 // or equal to the previous frame's commit frame time. Keep in mind that the
732 // next frame has most likely already been scheduled by now so we play it
733 // safe by ensuring the commit time is always at least one frame behind.
734 if (callbackType == Choreographer.CALLBACK_COMMIT) {
735 final long jitterNanos = now - frameTimeNanos;
Chris Craike22c59b2015-05-21 18:33:37 -0700736 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
Jeff Brownc42b28d2015-04-06 19:49:02 -0700737 if (jitterNanos >= 2 * mFrameIntervalNanos) {
738 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
739 + mFrameIntervalNanos;
740 if (DEBUG_JANK) {
741 Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
742 + " ms which is more than twice the frame interval of "
743 + (mFrameIntervalNanos * 0.000001f) + " ms! "
744 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
745 + " ms in the past.");
746 mDebugPrintNextFrameTimeDelta = true;
747 }
748 frameTimeNanos = now - lastFrameOffset;
749 mLastFrameTimeNanos = frameTimeNanos;
750 }
751 }
Jeff Brown96858852012-02-14 13:45:06 -0800752 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700753 try {
Chris Craike22c59b2015-05-21 18:33:37 -0700754 Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
Jeff Browncae80492012-05-21 16:33:39 -0700755 for (CallbackRecord c = callbacks; c != null; c = c.next) {
Jeff Brownc42b28d2015-04-06 19:49:02 -0700756 if (DEBUG_FRAMES) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700757 Log.d(TAG, "RunCallback: type=" + callbackType
758 + ", action=" + c.action + ", token=" + c.token
759 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
760 }
Jeff Browncae80492012-05-21 16:33:39 -0700761 c.run(frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700762 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700763 } finally {
Jeff Brown96858852012-02-14 13:45:06 -0800764 synchronized (mLock) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700765 mCallbacksRunning = false;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700766 do {
Jeff Browncae80492012-05-21 16:33:39 -0700767 final CallbackRecord next = callbacks.next;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700768 recycleCallbackLocked(callbacks);
769 callbacks = next;
770 } while (callbacks != null);
Jeff Brown96858852012-02-14 13:45:06 -0800771 }
Chris Craike22c59b2015-05-21 18:33:37 -0700772 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Jeff Brown96858852012-02-14 13:45:06 -0800773 }
Jeff Brown96858852012-02-14 13:45:06 -0800774 }
775
776 void doScheduleVsync() {
777 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700778 if (mFrameScheduled) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800779 scheduleVsyncLocked();
780 }
Jeff Brown96858852012-02-14 13:45:06 -0800781 }
782 }
783
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700784 void doScheduleCallback(int callbackType) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800785 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700786 if (!mFrameScheduled) {
787 final long now = SystemClock.uptimeMillis();
788 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
789 scheduleFrameLocked(now);
790 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800791 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800792 }
793 }
794
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800795 private void scheduleVsyncLocked() {
796 mDisplayEventReceiver.scheduleVsync();
797 }
798
Jeff Brown58aedbc2012-02-13 20:15:01 -0800799 private boolean isRunningOnLooperThreadLocked() {
800 return Looper.myLooper() == mLooper;
801 }
802
Jeff Browncae80492012-05-21 16:33:39 -0700803 private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
804 CallbackRecord callback = mCallbackPool;
Jeff Brown96858852012-02-14 13:45:06 -0800805 if (callback == null) {
Jeff Browncae80492012-05-21 16:33:39 -0700806 callback = new CallbackRecord();
Jeff Brown96858852012-02-14 13:45:06 -0800807 } else {
808 mCallbackPool = callback.next;
809 callback.next = null;
810 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800811 callback.dueTime = dueTime;
812 callback.action = action;
813 callback.token = token;
Jeff Brown96858852012-02-14 13:45:06 -0800814 return callback;
815 }
816
Jeff Browncae80492012-05-21 16:33:39 -0700817 private void recycleCallbackLocked(CallbackRecord callback) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800818 callback.action = null;
819 callback.token = null;
Jeff Brown96858852012-02-14 13:45:06 -0800820 callback.next = mCallbackPool;
821 mCallbackPool = callback;
822 }
823
Jeff Browncae80492012-05-21 16:33:39 -0700824 /**
825 * Implement this interface to receive a callback when a new display frame is
826 * being rendered. The callback is invoked on the {@link Looper} thread to
827 * which the {@link Choreographer} is attached.
828 */
829 public interface FrameCallback {
830 /**
831 * Called when a new display frame is being rendered.
832 * <p>
833 * This method provides the time in nanoseconds when the frame started being rendered.
834 * The frame time provides a stable time base for synchronizing animations
835 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
836 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
837 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
838 * the frame was scheduled to start, regardless of when the animations or drawing
839 * callback actually runs. All callbacks that run as part of rendering a frame will
840 * observe the same frame time so using the frame time also helps to synchronize effects
841 * that are performed by different callbacks.
842 * </p><p>
843 * Please note that the framework already takes care to process animations and
844 * drawing using the frame time as a stable time base. Most applications should
845 * not need to use the frame time information directly.
846 * </p>
847 *
848 * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
849 * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000}
850 * to convert it to the {@link SystemClock#uptimeMillis()} time base.
851 */
852 public void doFrame(long frameTimeNanos);
853 }
854
Jeff Brown96858852012-02-14 13:45:06 -0800855 private final class FrameHandler extends Handler {
856 public FrameHandler(Looper looper) {
857 super(looper);
858 }
859
860 @Override
861 public void handleMessage(Message msg) {
862 switch (msg.what) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700863 case MSG_DO_FRAME:
Jeff Brown20c4f872012-04-26 17:38:21 -0700864 doFrame(System.nanoTime(), 0);
Jeff Brown96858852012-02-14 13:45:06 -0800865 break;
866 case MSG_DO_SCHEDULE_VSYNC:
867 doScheduleVsync();
868 break;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700869 case MSG_DO_SCHEDULE_CALLBACK:
870 doScheduleCallback(msg.arg1);
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800871 break;
Jeff Brown96858852012-02-14 13:45:06 -0800872 }
873 }
874 }
875
Jeff Brownb0806602012-05-16 12:50:41 -0700876 private final class FrameDisplayEventReceiver extends DisplayEventReceiver
877 implements Runnable {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700878 private boolean mHavePendingVsync;
Jeff Brownb0806602012-05-16 12:50:41 -0700879 private long mTimestampNanos;
880 private int mFrame;
881
Jorim Jaggi34a0cdb2017-06-08 15:40:38 -0700882 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
883 super(looper, vsyncSource);
Jeff Brown96e942d2011-11-30 19:55:01 -0800884 }
885
886 @Override
Jeff Browne87bf032012-09-20 18:30:13 -0700887 public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
888 // Ignore vsync from secondary display.
889 // This can be problematic because the call to scheduleVsync() is a one-shot.
890 // We need to ensure that we will still receive the vsync from the primary
891 // display which is the one we really care about. Ideally we should schedule
892 // vsync for a particular display.
893 // At this time Surface Flinger won't send us vsyncs for secondary displays
894 // but that could change in the future so let's log a message to help us remember
895 // that we need to fix this.
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800896 if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
Jeff Browne87bf032012-09-20 18:30:13 -0700897 Log.d(TAG, "Received vsync from secondary display, but we don't support "
898 + "this case yet. Choreographer needs a way to explicitly request "
899 + "vsync for a specific display to ensure it doesn't lose track "
900 + "of its scheduled vsync.");
901 scheduleVsync();
902 return;
903 }
904
Jeff Brownb0806602012-05-16 12:50:41 -0700905 // Post the vsync event to the Handler.
906 // The idea is to prevent incoming vsync events from completely starving
907 // the message queue. If there are no messages in the queue with timestamps
908 // earlier than the frame time, then the vsync event will be processed immediately.
909 // Otherwise, messages that predate the vsync event will be handled first.
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700910 long now = System.nanoTime();
911 if (timestampNanos > now) {
912 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
913 + " ms in the future! Check that graphics HAL is generating vsync "
914 + "timestamps using the correct timebase.");
915 timestampNanos = now;
916 }
917
Jeff Brownba7261132012-06-14 23:48:40 -0700918 if (mHavePendingVsync) {
919 Log.w(TAG, "Already have a pending vsync event. There should only be "
920 + "one at a time.");
921 } else {
922 mHavePendingVsync = true;
923 }
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700924
Jeff Brownb0806602012-05-16 12:50:41 -0700925 mTimestampNanos = timestampNanos;
926 mFrame = frame;
927 Message msg = Message.obtain(mHandler, this);
928 msg.setAsynchronous(true);
John Reck315c3292014-05-09 19:21:04 -0700929 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
Jeff Brownb0806602012-05-16 12:50:41 -0700930 }
931
932 @Override
933 public void run() {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700934 mHavePendingVsync = false;
Jeff Brownb0806602012-05-16 12:50:41 -0700935 doFrame(mTimestampNanos, mFrame);
Jeff Brown96e942d2011-11-30 19:55:01 -0800936 }
937 }
Jeff Brown96858852012-02-14 13:45:06 -0800938
Jeff Browncae80492012-05-21 16:33:39 -0700939 private static final class CallbackRecord {
940 public CallbackRecord next;
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800941 public long dueTime;
Jeff Browncae80492012-05-21 16:33:39 -0700942 public Object action; // Runnable or FrameCallback
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800943 public Object token;
Jeff Browncae80492012-05-21 16:33:39 -0700944
945 public void run(long frameTimeNanos) {
946 if (token == FRAME_CALLBACK_TOKEN) {
947 ((FrameCallback)action).doFrame(frameTimeNanos);
948 } else {
949 ((Runnable)action).run();
950 }
951 }
Jeff Brown96858852012-02-14 13:45:06 -0800952 }
Jeff Brown43ea54b2012-03-09 14:37:48 -0800953
954 private final class CallbackQueue {
Jeff Browncae80492012-05-21 16:33:39 -0700955 private CallbackRecord mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800956
957 public boolean hasDueCallbacksLocked(long now) {
958 return mHead != null && mHead.dueTime <= now;
959 }
960
Jeff Browncae80492012-05-21 16:33:39 -0700961 public CallbackRecord extractDueCallbacksLocked(long now) {
962 CallbackRecord callbacks = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800963 if (callbacks == null || callbacks.dueTime > now) {
964 return null;
965 }
966
Jeff Browncae80492012-05-21 16:33:39 -0700967 CallbackRecord last = callbacks;
968 CallbackRecord next = last.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800969 while (next != null) {
970 if (next.dueTime > now) {
971 last.next = null;
972 break;
973 }
974 last = next;
975 next = next.next;
976 }
977 mHead = next;
978 return callbacks;
979 }
980
Jeff Browncae80492012-05-21 16:33:39 -0700981 public void addCallbackLocked(long dueTime, Object action, Object token) {
982 CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
983 CallbackRecord entry = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800984 if (entry == null) {
985 mHead = callback;
986 return;
987 }
988 if (dueTime < entry.dueTime) {
989 callback.next = entry;
990 mHead = callback;
991 return;
992 }
993 while (entry.next != null) {
994 if (dueTime < entry.next.dueTime) {
995 callback.next = entry.next;
996 break;
997 }
998 entry = entry.next;
999 }
1000 entry.next = callback;
1001 }
1002
Jeff Browncae80492012-05-21 16:33:39 -07001003 public void removeCallbacksLocked(Object action, Object token) {
1004 CallbackRecord predecessor = null;
1005 for (CallbackRecord callback = mHead; callback != null;) {
1006 final CallbackRecord next = callback.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -08001007 if ((action == null || callback.action == action)
1008 && (token == null || callback.token == token)) {
1009 if (predecessor != null) {
1010 predecessor.next = next;
1011 } else {
1012 mHead = next;
1013 }
1014 recycleCallbackLocked(callback);
1015 } else {
1016 predecessor = callback;
1017 }
1018 callback = next;
1019 }
1020 }
1021 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001022}