blob: f28e4b58108f892a3e0315a43e9efb23eb83c9ae [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
Jeff Brownbd6e1502012-08-28 03:27:37 -070019import android.hardware.display.DisplayManagerGlobal;
Jeff Brown96e942d2011-11-30 19:55:01 -080020import android.os.Handler;
21import android.os.Looper;
22import android.os.Message;
23import android.os.SystemClock;
24import android.os.SystemProperties;
25import android.util.Log;
26
27/**
Jeff Browncae80492012-05-21 16:33:39 -070028 * Coordinates the timing of animations, input and drawing.
29 * <p>
30 * The choreographer receives timing pulses (such as vertical synchronization)
31 * from the display subsystem then schedules work to occur as part of rendering
32 * the next display frame.
33 * </p><p>
34 * Applications typically interact with the choreographer indirectly using
35 * higher level abstractions in the animation framework or the view hierarchy.
36 * Here are some examples of things you can do using the higher-level APIs.
37 * </p>
38 * <ul>
39 * <li>To post an animation to be processed on a regular time basis synchronized with
40 * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
41 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
42 * frame, use {@link View#postOnAnimation}.</li>
43 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
44 * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
45 * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
46 * next display frame, use {@link View#postInvalidateOnAnimation()} or
47 * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
48 * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
49 * sync with display frame rendering, do nothing. This already happens automatically.
50 * {@link View#onDraw} will be called at the appropriate time.</li>
51 * </ul>
52 * <p>
53 * However, there are a few cases where you might want to use the functions of the
54 * choreographer directly in your application. Here are some examples.
55 * </p>
56 * <ul>
57 * <li>If your application does its rendering in a different thread, possibly using GL,
58 * or does not use the animation framework or view hierarchy at all
59 * and you want to ensure that it is appropriately synchronized with the display, then use
60 * {@link Choreographer#postFrameCallback}.</li>
61 * <li>... and that's about it.</li>
62 * </ul>
63 * <p>
64 * Each {@link Looper} thread has its own choreographer. Other threads can
65 * post callbacks to run on the choreographer but they will run on the {@link Looper}
66 * to which the choreographer belongs.
67 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -080068 */
Jeff Brown96858852012-02-14 13:45:06 -080069public final class Choreographer {
Jeff Brown96e942d2011-11-30 19:55:01 -080070 private static final String TAG = "Choreographer";
71 private static final boolean DEBUG = false;
72
73 // The default amount of time in ms between animation frames.
74 // When vsync is not enabled, we want to have some idea of how long we should
75 // wait before posting the next animation message. It is important that the
76 // default value be less than the true inter-frame delay on all devices to avoid
77 // situations where we might skip frames by waiting too long (we must compensate
78 // for jitter and hardware variations). Regardless of this value, the animation
79 // and display loop is ultimately rate-limited by how fast new graphics buffers can
80 // be dequeued.
81 private static final long DEFAULT_FRAME_DELAY = 10;
82
83 // The number of milliseconds between animation frames.
Jeff Brown87d0b032012-02-03 11:01:21 -080084 private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
Jeff Brown96e942d2011-11-30 19:55:01 -080085
86 // Thread local storage for the choreographer.
87 private static final ThreadLocal<Choreographer> sThreadInstance =
88 new ThreadLocal<Choreographer>() {
89 @Override
90 protected Choreographer initialValue() {
91 Looper looper = Looper.myLooper();
92 if (looper == null) {
93 throw new IllegalStateException("The current thread must have a looper!");
94 }
95 return new Choreographer(looper);
96 }
97 };
98
Jeff Brownebb2d8d2012-03-23 17:14:34 -070099 // Enable/disable vsync for animations and drawing.
Jeff Brown96e942d2011-11-30 19:55:01 -0800100 private static final boolean USE_VSYNC = SystemProperties.getBoolean(
101 "debug.choreographer.vsync", true);
102
Jeff Brown20c4f872012-04-26 17:38:21 -0700103 // Enable/disable using the frame time instead of returning now.
104 private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
105 "debug.choreographer.frametime", true);
106
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700107 // Set a limit to warn about skipped frames.
108 // Skipped frames imply jank.
109 private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
110 "debug.choreographer.skipwarning", 30);
111
Jeff Brown20c4f872012-04-26 17:38:21 -0700112 private static final long NANOS_PER_MS = 1000000;
113
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700114 private static final int MSG_DO_FRAME = 0;
115 private static final int MSG_DO_SCHEDULE_VSYNC = 1;
116 private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
Jeff Brown96e942d2011-11-30 19:55:01 -0800117
Jeff Browncae80492012-05-21 16:33:39 -0700118 // All frame callbacks posted by applications have this token.
119 private static final Object FRAME_CALLBACK_TOKEN = new Object() {
120 public String toString() { return "FRAME_CALLBACK_TOKEN"; }
121 };
122
Jeff Brown87d0b032012-02-03 11:01:21 -0800123 private final Object mLock = new Object();
124
Jeff Brown96e942d2011-11-30 19:55:01 -0800125 private final Looper mLooper;
Jeff Brown96858852012-02-14 13:45:06 -0800126 private final FrameHandler mHandler;
Jeff Browncae80492012-05-21 16:33:39 -0700127
128 // The display event receiver can only be accessed by the looper thread to which
129 // it is attached. We take care to ensure that we post message to the looper
130 // if appropriate when interacting with the display event receiver.
Jeff Brown1654d0b2012-02-15 15:40:52 -0800131 private final FrameDisplayEventReceiver mDisplayEventReceiver;
Jeff Brown96858852012-02-14 13:45:06 -0800132
Jeff Browncae80492012-05-21 16:33:39 -0700133 private CallbackRecord mCallbackPool;
Jeff Brown96e942d2011-11-30 19:55:01 -0800134
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700135 private final CallbackQueue[] mCallbackQueues;
Jeff Brown96858852012-02-14 13:45:06 -0800136
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700137 private boolean mFrameScheduled;
Jeff Brown20c4f872012-04-26 17:38:21 -0700138 private boolean mCallbacksRunning;
139 private long mLastFrameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700140 private long mFrameIntervalNanos;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700141
142 /**
143 * Callback type: Input callback. Runs first.
Jeff Browncae80492012-05-21 16:33:39 -0700144 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700145 */
146 public static final int CALLBACK_INPUT = 0;
147
148 /**
149 * Callback type: Animation callback. Runs before traversals.
Jeff Browncae80492012-05-21 16:33:39 -0700150 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700151 */
152 public static final int CALLBACK_ANIMATION = 1;
153
154 /**
155 * Callback type: Traversal callback. Handles layout and draw. Runs last
156 * after all other asynchronous messages have been handled.
Jeff Browncae80492012-05-21 16:33:39 -0700157 * @hide
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700158 */
159 public static final int CALLBACK_TRAVERSAL = 2;
160
161 private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL;
Jeff Brown96e942d2011-11-30 19:55:01 -0800162
163 private Choreographer(Looper looper) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800164 mLooper = looper;
Jeff Brown96858852012-02-14 13:45:06 -0800165 mHandler = new FrameHandler(looper);
Jeff Brown1654d0b2012-02-15 15:40:52 -0800166 mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
Jeff Brown20c4f872012-04-26 17:38:21 -0700167 mLastFrameTimeNanos = Long.MIN_VALUE;
Jeff Brownd32460c2012-07-20 16:15:36 -0700168
Jeff Brownbd6e1502012-08-28 03:27:37 -0700169 mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700170
171 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
172 for (int i = 0; i <= CALLBACK_LAST; i++) {
173 mCallbackQueues[i] = new CallbackQueue();
174 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800175 }
176
Jeff Brownbd6e1502012-08-28 03:27:37 -0700177 private static float getRefreshRate() {
178 DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
179 Display.DEFAULT_DISPLAY);
180 return di.refreshRate;
181 }
182
Jeff Brown96e942d2011-11-30 19:55:01 -0800183 /**
Dianne Hackborn8bcd54b2012-01-31 19:04:53 -0800184 * Gets the choreographer for the calling thread. Must be called from
185 * a thread that already has a {@link android.os.Looper} associated with it.
Jeff Brown96e942d2011-11-30 19:55:01 -0800186 *
187 * @return The choreographer for this thread.
188 * @throws IllegalStateException if the thread does not have a looper.
189 */
190 public static Choreographer getInstance() {
191 return sThreadInstance.get();
192 }
193
194 /**
Jeff Browncae80492012-05-21 16:33:39 -0700195 * The amount of time, in milliseconds, between each frame of the animation.
196 * <p>
197 * This is a requested time that the animation will attempt to honor, but the actual delay
198 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800199 * function because the same delay will be applied to all animations, since they are all
200 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700201 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800202 * The frame delay may be ignored when the animation system uses an external timing
203 * source, such as the display refresh rate (vsync), to govern animations.
Jeff Browncae80492012-05-21 16:33:39 -0700204 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800205 *
206 * @return the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700207 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800208 */
209 public static long getFrameDelay() {
210 return sFrameDelay;
211 }
212
213 /**
Jeff Browncae80492012-05-21 16:33:39 -0700214 * The amount of time, in milliseconds, between each frame of the animation.
215 * <p>
216 * This is a requested time that the animation will attempt to honor, but the actual delay
217 * between frames may be different, depending on system load and capabilities. This is a static
Jeff Brown96e942d2011-11-30 19:55:01 -0800218 * function because the same delay will be applied to all animations, since they are all
219 * run off of a single timing loop.
Jeff Browncae80492012-05-21 16:33:39 -0700220 * </p><p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800221 * The frame delay may be ignored when the animation system uses an external timing
222 * source, such as the display refresh rate (vsync), to govern animations.
Jeff Browncae80492012-05-21 16:33:39 -0700223 * </p>
Jeff Brown96e942d2011-11-30 19:55:01 -0800224 *
225 * @param frameDelay the requested time between frames, in milliseconds
Jeff Browncae80492012-05-21 16:33:39 -0700226 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800227 */
228 public static void setFrameDelay(long frameDelay) {
229 sFrameDelay = frameDelay;
230 }
231
232 /**
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800233 * Subtracts typical frame delay time from a delay interval in milliseconds.
Jeff Browncae80492012-05-21 16:33:39 -0700234 * <p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800235 * This method can be used to compensate for animation delay times that have baked
236 * in assumptions about the frame delay. For example, it's quite common for code to
237 * assume a 60Hz frame time and bake in a 16ms delay. When we call
238 * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
239 * posting the animation callback but let the animation timer take care of the remaining
240 * frame delay time.
Jeff Browncae80492012-05-21 16:33:39 -0700241 * </p><p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800242 * This method is somewhat conservative about how much of the frame delay it
243 * subtracts. It uses the same value returned by {@link #getFrameDelay} which by
244 * default is 10ms even though many parts of the system assume 16ms. Consequently,
245 * we might still wait 6ms before posting an animation callback that we want to run
246 * on the next frame, but this is much better than waiting a whole 16ms and likely
247 * missing the deadline.
Jeff Browncae80492012-05-21 16:33:39 -0700248 * </p>
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800249 *
250 * @param delayMillis The original delay time including an assumed frame delay.
251 * @return The adjusted delay time with the assumed frame delay subtracted out.
Jeff Browncae80492012-05-21 16:33:39 -0700252 * @hide
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800253 */
254 public static long subtractFrameDelay(long delayMillis) {
255 final long frameDelay = sFrameDelay;
256 return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
257 }
258
259 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700260 * Posts a callback to run on the next frame.
Jeff Browncae80492012-05-21 16:33:39 -0700261 * <p>
262 * The callback runs once then is automatically removed.
263 * </p>
Jeff Brown4a06c802012-02-15 15:06:01 -0800264 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700265 * @param callbackType The callback type.
266 * @param action The callback action to run during the next frame.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800267 * @param token The callback token, or null if none.
Jeff Brown4a06c802012-02-15 15:06:01 -0800268 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700269 * @see #removeCallbacks
Jeff Browncae80492012-05-21 16:33:39 -0700270 * @hide
Jeff Brown96e942d2011-11-30 19:55:01 -0800271 */
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700272 public void postCallback(int callbackType, Runnable action, Object token) {
273 postCallbackDelayed(callbackType, action, token, 0);
Jeff Brown87d0b032012-02-03 11:01:21 -0800274 }
275
Jeff Brown4a06c802012-02-15 15:06:01 -0800276 /**
Jeff Browncae80492012-05-21 16:33:39 -0700277 * Posts a callback to run on the next frame after the specified delay.
278 * <p>
279 * The callback runs once then is automatically removed.
280 * </p>
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800281 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700282 * @param callbackType The callback type.
283 * @param action The callback action to run during the next frame after the specified delay.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800284 * @param token The callback token, or null if none.
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800285 * @param delayMillis The delay time in milliseconds.
286 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700287 * @see #removeCallback
Jeff Browncae80492012-05-21 16:33:39 -0700288 * @hide
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800289 */
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700290 public void postCallbackDelayed(int callbackType,
291 Runnable action, Object token, long delayMillis) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800292 if (action == null) {
293 throw new IllegalArgumentException("action must not be null");
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800294 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700295 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
296 throw new IllegalArgumentException("callbackType is invalid");
297 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800298
Jeff Browncae80492012-05-21 16:33:39 -0700299 postCallbackDelayedInternal(callbackType, action, token, delayMillis);
300 }
301
302 private void postCallbackDelayedInternal(int callbackType,
303 Object action, Object token, long delayMillis) {
Jeff Brown43ea54b2012-03-09 14:37:48 -0800304 if (DEBUG) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700305 Log.d(TAG, "PostCallback: type=" + callbackType
306 + ", action=" + action + ", token=" + token
Jeff Brown43ea54b2012-03-09 14:37:48 -0800307 + ", delayMillis=" + delayMillis);
308 }
309
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800310 synchronized (mLock) {
311 final long now = SystemClock.uptimeMillis();
312 final long dueTime = now + delayMillis;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700313 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800314
315 if (dueTime <= now) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700316 scheduleFrameLocked(now);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800317 } else {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700318 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
319 msg.arg1 = callbackType;
320 msg.setAsynchronous(true);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800321 mHandler.sendMessageAtTime(msg, dueTime);
322 }
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800323 }
324 }
325
326 /**
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700327 * Removes callbacks that have the specified action and token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800328 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700329 * @param callbackType The callback type.
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800330 * @param action The action property of the callbacks to remove, or null to remove
331 * callbacks with any action.
332 * @param token The token property of the callbacks to remove, or null to remove
333 * callbacks with any token.
Jeff Brown4a06c802012-02-15 15:06:01 -0800334 *
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700335 * @see #postCallback
336 * @see #postCallbackDelayed
Jeff Browncae80492012-05-21 16:33:39 -0700337 * @hide
Jeff Brown4a06c802012-02-15 15:06:01 -0800338 */
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700339 public void removeCallbacks(int callbackType, Runnable action, Object token) {
340 if (callbackType < 0 || callbackType > CALLBACK_LAST) {
341 throw new IllegalArgumentException("callbackType is invalid");
342 }
343
Jeff Browncae80492012-05-21 16:33:39 -0700344 removeCallbacksInternal(callbackType, action, token);
345 }
346
347 private void removeCallbacksInternal(int callbackType, Object action, Object token) {
Jeff Brown43ea54b2012-03-09 14:37:48 -0800348 if (DEBUG) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700349 Log.d(TAG, "RemoveCallbacks: type=" + callbackType
350 + ", action=" + action + ", token=" + token);
Jeff Brown43ea54b2012-03-09 14:37:48 -0800351 }
352
Jeff Brown4a06c802012-02-15 15:06:01 -0800353 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700354 mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800355 if (action != null && token == null) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700356 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800357 }
Jeff Brown4a06c802012-02-15 15:06:01 -0800358 }
359 }
360
Jeff Brown20c4f872012-04-26 17:38:21 -0700361 /**
Jeff Browncae80492012-05-21 16:33:39 -0700362 * Posts a frame callback to run on the next frame.
363 * <p>
364 * The callback runs once then is automatically removed.
365 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700366 *
Jeff Browncae80492012-05-21 16:33:39 -0700367 * @param callback The frame callback to run during the next frame.
368 *
369 * @see #postFrameCallbackDelayed
370 * @see #removeFrameCallback
371 */
372 public void postFrameCallback(FrameCallback callback) {
373 postFrameCallbackDelayed(callback, 0);
374 }
375
376 /**
377 * Posts a frame callback to run on the next frame after the specified delay.
378 * <p>
379 * The callback runs once then is automatically removed.
380 * </p>
381 *
382 * @param callback The frame callback to run during the next frame.
383 * @param delayMillis The delay time in milliseconds.
384 *
385 * @see #postFrameCallback
386 * @see #removeFrameCallback
387 */
388 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
389 if (callback == null) {
390 throw new IllegalArgumentException("callback must not be null");
391 }
392
393 postCallbackDelayedInternal(CALLBACK_ANIMATION,
394 callback, FRAME_CALLBACK_TOKEN, delayMillis);
395 }
396
397 /**
398 * Removes a previously posted frame callback.
399 *
400 * @param callback The frame callback to remove.
401 *
402 * @see #postFrameCallback
403 * @see #postFrameCallbackDelayed
404 */
405 public void removeFrameCallback(FrameCallback callback) {
406 if (callback == null) {
407 throw new IllegalArgumentException("callback must not be null");
408 }
409
410 removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
411 }
412
413 /**
414 * Gets the time when the current frame started.
415 * <p>
416 * This method provides the time in nanoseconds when the frame started being rendered.
417 * The frame time provides a stable time base for synchronizing animations
418 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
419 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
420 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
421 * the frame was scheduled to start, regardless of when the animations or drawing
422 * callback actually runs. All callbacks that run as part of rendering a frame will
423 * observe the same frame time so using the frame time also helps to synchronize effects
424 * that are performed by different callbacks.
425 * </p><p>
426 * Please note that the framework already takes care to process animations and
427 * drawing using the frame time as a stable time base. Most applications should
428 * not need to use the frame time information directly.
429 * </p><p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700430 * This method should only be called from within a callback.
Jeff Browncae80492012-05-21 16:33:39 -0700431 * </p>
Jeff Brown20c4f872012-04-26 17:38:21 -0700432 *
433 * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
434 *
435 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700436 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700437 */
438 public long getFrameTime() {
439 return getFrameTimeNanos() / NANOS_PER_MS;
440 }
441
442 /**
443 * Same as {@link #getFrameTime()} but with nanosecond precision.
444 *
445 * @return The frame start time, in the {@link System#nanoTime()} time base.
446 *
447 * @throws IllegalStateException if no frame is in progress.
Jeff Browncae80492012-05-21 16:33:39 -0700448 * @hide
Jeff Brown20c4f872012-04-26 17:38:21 -0700449 */
450 public long getFrameTimeNanos() {
451 synchronized (mLock) {
452 if (!mCallbacksRunning) {
453 throw new IllegalStateException("This method must only be called as "
454 + "part of a callback while a frame is in progress.");
455 }
456 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
457 }
458 }
459
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700460 private void scheduleFrameLocked(long now) {
461 if (!mFrameScheduled) {
462 mFrameScheduled = true;
Jeff Brown96e942d2011-11-30 19:55:01 -0800463 if (USE_VSYNC) {
464 if (DEBUG) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700465 Log.d(TAG, "Scheduling next frame on vsync.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800466 }
Jeff Brown58aedbc2012-02-13 20:15:01 -0800467
468 // If running on the Looper thread, then schedule the vsync immediately,
469 // otherwise post a message to schedule the vsync from the UI thread
470 // as soon as possible.
Jeff Brown58aedbc2012-02-13 20:15:01 -0800471 if (isRunningOnLooperThreadLocked()) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800472 scheduleVsyncLocked();
Jeff Brown58aedbc2012-02-13 20:15:01 -0800473 } else {
Jeff Browne0dbd002012-02-15 19:34:58 -0800474 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
475 msg.setAsynchronous(true);
476 mHandler.sendMessageAtFrontOfQueue(msg);
Jeff Brown58aedbc2012-02-13 20:15:01 -0800477 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800478 } else {
Jeff Brown20c4f872012-04-26 17:38:21 -0700479 final long nextFrameTime = Math.max(
480 mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
Jeff Brown96e942d2011-11-30 19:55:01 -0800481 if (DEBUG) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700482 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800483 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700484 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
Jeff Browne0dbd002012-02-15 19:34:58 -0800485 msg.setAsynchronous(true);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700486 mHandler.sendMessageAtTime(msg, nextFrameTime);
Jeff Brown96e942d2011-11-30 19:55:01 -0800487 }
488 }
489 }
490
Jeff Browncae80492012-05-21 16:33:39 -0700491 void doFrame(long frameTimeNanos, int frame) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700492 final long startNanos;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700493 synchronized (mLock) {
494 if (!mFrameScheduled) {
495 return; // no work to do
Jeff Brown96e942d2011-11-30 19:55:01 -0800496 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700497
498 startNanos = System.nanoTime();
Jeff Browncae80492012-05-21 16:33:39 -0700499 final long jitterNanos = startNanos - frameTimeNanos;
Jeff Brown59bbef02012-05-07 16:43:25 -0700500 if (jitterNanos >= mFrameIntervalNanos) {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700501 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
502 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Jeff Brown265f1cc2012-06-11 18:01:06 -0700503 Log.i(TAG, "Skipped " + skippedFrames + " frames! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700504 + "The application may be doing too much work on its main thread.");
505 }
Jeff Brown59bbef02012-05-07 16:43:25 -0700506 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
507 if (DEBUG) {
508 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
509 + "which is more than the frame interval of "
510 + (mFrameIntervalNanos * 0.000001f) + " ms! "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700511 + "Skipping " + skippedFrames + " frames and setting frame "
512 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700513 }
Jeff Browncae80492012-05-21 16:33:39 -0700514 frameTimeNanos = startNanos - lastFrameOffset;
Jeff Brown59bbef02012-05-07 16:43:25 -0700515 }
516
Jeff Browncae80492012-05-21 16:33:39 -0700517 if (frameTimeNanos < mLastFrameTimeNanos) {
Jeff Brown59bbef02012-05-07 16:43:25 -0700518 if (DEBUG) {
519 Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700520 + "previously skipped frame. Waiting for next vsync.");
Jeff Brown59bbef02012-05-07 16:43:25 -0700521 }
522 scheduleVsyncLocked();
523 return;
524 }
525
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700526 mFrameScheduled = false;
Jeff Browncae80492012-05-21 16:33:39 -0700527 mLastFrameTimeNanos = frameTimeNanos;
Jeff Brown20c4f872012-04-26 17:38:21 -0700528 }
529
Jeff Browncae80492012-05-21 16:33:39 -0700530 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
531 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
532 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700533
534 if (DEBUG) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700535 final long endNanos = System.nanoTime();
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700536 Log.d(TAG, "Frame " + frame + ": Finished, took "
Jeff Brown20c4f872012-04-26 17:38:21 -0700537 + (endNanos - startNanos) * 0.000001f + " ms, latency "
Jeff Browncae80492012-05-21 16:33:39 -0700538 + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
Jeff Brown96e942d2011-11-30 19:55:01 -0800539 }
540 }
541
Jeff Browncae80492012-05-21 16:33:39 -0700542 void doCallbacks(int callbackType, long frameTimeNanos) {
543 CallbackRecord callbacks;
Jeff Brown96858852012-02-14 13:45:06 -0800544 synchronized (mLock) {
Jeff Browncae80492012-05-21 16:33:39 -0700545 // We use "now" to determine when callbacks become due because it's possible
546 // for earlier processing phases in a frame to post callbacks that should run
547 // in a following phase, such as an input event that causes an animation to start.
Jeff Brown20c4f872012-04-26 17:38:21 -0700548 final long now = SystemClock.uptimeMillis();
549 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
550 if (callbacks == null) {
551 return;
552 }
553 mCallbacksRunning = true;
Jeff Brown96858852012-02-14 13:45:06 -0800554 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700555 try {
Jeff Browncae80492012-05-21 16:33:39 -0700556 for (CallbackRecord c = callbacks; c != null; c = c.next) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700557 if (DEBUG) {
558 Log.d(TAG, "RunCallback: type=" + callbackType
559 + ", action=" + c.action + ", token=" + c.token
560 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
561 }
Jeff Browncae80492012-05-21 16:33:39 -0700562 c.run(frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700563 }
Jeff Brown20c4f872012-04-26 17:38:21 -0700564 } finally {
Jeff Brown96858852012-02-14 13:45:06 -0800565 synchronized (mLock) {
Jeff Brown20c4f872012-04-26 17:38:21 -0700566 mCallbacksRunning = false;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700567 do {
Jeff Browncae80492012-05-21 16:33:39 -0700568 final CallbackRecord next = callbacks.next;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700569 recycleCallbackLocked(callbacks);
570 callbacks = next;
571 } while (callbacks != null);
Jeff Brown96858852012-02-14 13:45:06 -0800572 }
573 }
Jeff Brown96858852012-02-14 13:45:06 -0800574 }
575
576 void doScheduleVsync() {
577 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700578 if (mFrameScheduled) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800579 scheduleVsyncLocked();
580 }
Jeff Brown96858852012-02-14 13:45:06 -0800581 }
582 }
583
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700584 void doScheduleCallback(int callbackType) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800585 synchronized (mLock) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700586 if (!mFrameScheduled) {
587 final long now = SystemClock.uptimeMillis();
588 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
589 scheduleFrameLocked(now);
590 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800591 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800592 }
593 }
594
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800595 private void scheduleVsyncLocked() {
596 mDisplayEventReceiver.scheduleVsync();
597 }
598
Jeff Brown58aedbc2012-02-13 20:15:01 -0800599 private boolean isRunningOnLooperThreadLocked() {
600 return Looper.myLooper() == mLooper;
601 }
602
Jeff Browncae80492012-05-21 16:33:39 -0700603 private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
604 CallbackRecord callback = mCallbackPool;
Jeff Brown96858852012-02-14 13:45:06 -0800605 if (callback == null) {
Jeff Browncae80492012-05-21 16:33:39 -0700606 callback = new CallbackRecord();
Jeff Brown96858852012-02-14 13:45:06 -0800607 } else {
608 mCallbackPool = callback.next;
609 callback.next = null;
610 }
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800611 callback.dueTime = dueTime;
612 callback.action = action;
613 callback.token = token;
Jeff Brown96858852012-02-14 13:45:06 -0800614 return callback;
615 }
616
Jeff Browncae80492012-05-21 16:33:39 -0700617 private void recycleCallbackLocked(CallbackRecord callback) {
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800618 callback.action = null;
619 callback.token = null;
Jeff Brown96858852012-02-14 13:45:06 -0800620 callback.next = mCallbackPool;
621 mCallbackPool = callback;
622 }
623
Jeff Browncae80492012-05-21 16:33:39 -0700624 /**
625 * Implement this interface to receive a callback when a new display frame is
626 * being rendered. The callback is invoked on the {@link Looper} thread to
627 * which the {@link Choreographer} is attached.
628 */
629 public interface FrameCallback {
630 /**
631 * Called when a new display frame is being rendered.
632 * <p>
633 * This method provides the time in nanoseconds when the frame started being rendered.
634 * The frame time provides a stable time base for synchronizing animations
635 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
636 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
637 * time helps to reduce inter-frame jitter because the frame time is fixed at the time
638 * the frame was scheduled to start, regardless of when the animations or drawing
639 * callback actually runs. All callbacks that run as part of rendering a frame will
640 * observe the same frame time so using the frame time also helps to synchronize effects
641 * that are performed by different callbacks.
642 * </p><p>
643 * Please note that the framework already takes care to process animations and
644 * drawing using the frame time as a stable time base. Most applications should
645 * not need to use the frame time information directly.
646 * </p>
647 *
648 * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
649 * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000}
650 * to convert it to the {@link SystemClock#uptimeMillis()} time base.
651 */
652 public void doFrame(long frameTimeNanos);
653 }
654
Jeff Brown96858852012-02-14 13:45:06 -0800655 private final class FrameHandler extends Handler {
656 public FrameHandler(Looper looper) {
657 super(looper);
658 }
659
660 @Override
661 public void handleMessage(Message msg) {
662 switch (msg.what) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700663 case MSG_DO_FRAME:
Jeff Brown20c4f872012-04-26 17:38:21 -0700664 doFrame(System.nanoTime(), 0);
Jeff Brown96858852012-02-14 13:45:06 -0800665 break;
666 case MSG_DO_SCHEDULE_VSYNC:
667 doScheduleVsync();
668 break;
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700669 case MSG_DO_SCHEDULE_CALLBACK:
670 doScheduleCallback(msg.arg1);
Jeff Brown2b6cb9a2012-03-05 17:21:01 -0800671 break;
Jeff Brown96858852012-02-14 13:45:06 -0800672 }
673 }
674 }
675
Jeff Brownb0806602012-05-16 12:50:41 -0700676 private final class FrameDisplayEventReceiver extends DisplayEventReceiver
677 implements Runnable {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700678 private boolean mHavePendingVsync;
Jeff Brownb0806602012-05-16 12:50:41 -0700679 private long mTimestampNanos;
680 private int mFrame;
681
Jeff Brown96e942d2011-11-30 19:55:01 -0800682 public FrameDisplayEventReceiver(Looper looper) {
683 super(looper);
684 }
685
686 @Override
Jeff Browne87bf032012-09-20 18:30:13 -0700687 public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
688 // Ignore vsync from secondary display.
689 // This can be problematic because the call to scheduleVsync() is a one-shot.
690 // We need to ensure that we will still receive the vsync from the primary
691 // display which is the one we really care about. Ideally we should schedule
692 // vsync for a particular display.
693 // At this time Surface Flinger won't send us vsyncs for secondary displays
694 // but that could change in the future so let's log a message to help us remember
695 // that we need to fix this.
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800696 if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
Jeff Browne87bf032012-09-20 18:30:13 -0700697 Log.d(TAG, "Received vsync from secondary display, but we don't support "
698 + "this case yet. Choreographer needs a way to explicitly request "
699 + "vsync for a specific display to ensure it doesn't lose track "
700 + "of its scheduled vsync.");
701 scheduleVsync();
702 return;
703 }
704
Jeff Brownb0806602012-05-16 12:50:41 -0700705 // Post the vsync event to the Handler.
706 // The idea is to prevent incoming vsync events from completely starving
707 // the message queue. If there are no messages in the queue with timestamps
708 // earlier than the frame time, then the vsync event will be processed immediately.
709 // Otherwise, messages that predate the vsync event will be handled first.
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700710 long now = System.nanoTime();
711 if (timestampNanos > now) {
712 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
713 + " ms in the future! Check that graphics HAL is generating vsync "
714 + "timestamps using the correct timebase.");
715 timestampNanos = now;
716 }
717
Jeff Brownba7261132012-06-14 23:48:40 -0700718 if (mHavePendingVsync) {
719 Log.w(TAG, "Already have a pending vsync event. There should only be "
720 + "one at a time.");
721 } else {
722 mHavePendingVsync = true;
723 }
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700724
Jeff Brownb0806602012-05-16 12:50:41 -0700725 mTimestampNanos = timestampNanos;
726 mFrame = frame;
727 Message msg = Message.obtain(mHandler, this);
728 msg.setAsynchronous(true);
729 mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
730 }
731
732 @Override
733 public void run() {
Jeff Brown4fdf9c62012-06-11 15:25:48 -0700734 mHavePendingVsync = false;
Jeff Brownb0806602012-05-16 12:50:41 -0700735 doFrame(mTimestampNanos, mFrame);
Jeff Brown96e942d2011-11-30 19:55:01 -0800736 }
737 }
Jeff Brown96858852012-02-14 13:45:06 -0800738
Jeff Browncae80492012-05-21 16:33:39 -0700739 private static final class CallbackRecord {
740 public CallbackRecord next;
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800741 public long dueTime;
Jeff Browncae80492012-05-21 16:33:39 -0700742 public Object action; // Runnable or FrameCallback
Jeff Brown7ae9d5f2012-03-05 19:33:49 -0800743 public Object token;
Jeff Browncae80492012-05-21 16:33:39 -0700744
745 public void run(long frameTimeNanos) {
746 if (token == FRAME_CALLBACK_TOKEN) {
747 ((FrameCallback)action).doFrame(frameTimeNanos);
748 } else {
749 ((Runnable)action).run();
750 }
751 }
Jeff Brown96858852012-02-14 13:45:06 -0800752 }
Jeff Brown43ea54b2012-03-09 14:37:48 -0800753
754 private final class CallbackQueue {
Jeff Browncae80492012-05-21 16:33:39 -0700755 private CallbackRecord mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800756
757 public boolean hasDueCallbacksLocked(long now) {
758 return mHead != null && mHead.dueTime <= now;
759 }
760
Jeff Browncae80492012-05-21 16:33:39 -0700761 public CallbackRecord extractDueCallbacksLocked(long now) {
762 CallbackRecord callbacks = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800763 if (callbacks == null || callbacks.dueTime > now) {
764 return null;
765 }
766
Jeff Browncae80492012-05-21 16:33:39 -0700767 CallbackRecord last = callbacks;
768 CallbackRecord next = last.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800769 while (next != null) {
770 if (next.dueTime > now) {
771 last.next = null;
772 break;
773 }
774 last = next;
775 next = next.next;
776 }
777 mHead = next;
778 return callbacks;
779 }
780
Jeff Browncae80492012-05-21 16:33:39 -0700781 public void addCallbackLocked(long dueTime, Object action, Object token) {
782 CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
783 CallbackRecord entry = mHead;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800784 if (entry == null) {
785 mHead = callback;
786 return;
787 }
788 if (dueTime < entry.dueTime) {
789 callback.next = entry;
790 mHead = callback;
791 return;
792 }
793 while (entry.next != null) {
794 if (dueTime < entry.next.dueTime) {
795 callback.next = entry.next;
796 break;
797 }
798 entry = entry.next;
799 }
800 entry.next = callback;
801 }
802
Jeff Browncae80492012-05-21 16:33:39 -0700803 public void removeCallbacksLocked(Object action, Object token) {
804 CallbackRecord predecessor = null;
805 for (CallbackRecord callback = mHead; callback != null;) {
806 final CallbackRecord next = callback.next;
Jeff Brown43ea54b2012-03-09 14:37:48 -0800807 if ((action == null || callback.action == action)
808 && (token == null || callback.token == token)) {
809 if (predecessor != null) {
810 predecessor.next = next;
811 } else {
812 mHead = next;
813 }
814 recycleCallbackLocked(callback);
815 } else {
816 predecessor = callback;
817 }
818 callback = next;
819 }
820 }
821 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800822}