1 /* 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 17 package android.view; 18 19 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP; 20 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER; 21 22 import android.hardware.display.DisplayManagerGlobal; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.os.Message; 26 import android.os.SystemClock; 27 import android.os.SystemProperties; 28 import android.os.Trace; 29 import android.util.Log; 30 import android.util.TimeUtils; 31 import android.view.animation.AnimationUtils; 32 33 import java.io.PrintWriter; 34 35 /** 36 * Coordinates the timing of animations, input and drawing. 37 * <p> 38 * The choreographer receives timing pulses (such as vertical synchronization) 39 * from the display subsystem then schedules work to occur as part of rendering 40 * the next display frame. 41 * </p><p> 42 * Applications typically interact with the choreographer indirectly using 43 * higher level abstractions in the animation framework or the view hierarchy. 44 * Here are some examples of things you can do using the higher-level APIs. 45 * </p> 46 * <ul> 47 * <li>To post an animation to be processed on a regular time basis synchronized with 48 * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li> 49 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display 50 * frame, use {@link View#postOnAnimation}.</li> 51 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display 52 * frame after a delay, use {@link View#postOnAnimationDelayed}.</li> 53 * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the 54 * next display frame, use {@link View#postInvalidateOnAnimation()} or 55 * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li> 56 * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in 57 * sync with display frame rendering, do nothing. This already happens automatically. 58 * {@link View#onDraw} will be called at the appropriate time.</li> 59 * </ul> 60 * <p> 61 * However, there are a few cases where you might want to use the functions of the 62 * choreographer directly in your application. Here are some examples. 63 * </p> 64 * <ul> 65 * <li>If your application does its rendering in a different thread, possibly using GL, 66 * or does not use the animation framework or view hierarchy at all 67 * and you want to ensure that it is appropriately synchronized with the display, then use 68 * {@link Choreographer#postFrameCallback}.</li> 69 * <li>... and that's about it.</li> 70 * </ul> 71 * <p> 72 * Each {@link Looper} thread has its own choreographer. Other threads can 73 * post callbacks to run on the choreographer but they will run on the {@link Looper} 74 * to which the choreographer belongs. 75 * </p> 76 */ 77 public final class Choreographer { 78 private static final String TAG = "Choreographer"; 79 80 // Prints debug messages about jank which was detected (low volume). 81 private static final boolean DEBUG_JANK = false; 82 83 // Prints debug messages about every frame and callback registered (high volume). 84 private static final boolean DEBUG_FRAMES = false; 85 86 // The default amount of time in ms between animation frames. 87 // When vsync is not enabled, we want to have some idea of how long we should 88 // wait before posting the next animation message. It is important that the 89 // default value be less than the true inter-frame delay on all devices to avoid 90 // situations where we might skip frames by waiting too long (we must compensate 91 // for jitter and hardware variations). Regardless of this value, the animation 92 // and display loop is ultimately rate-limited by how fast new graphics buffers can 93 // be dequeued. 94 private static final long DEFAULT_FRAME_DELAY = 10; 95 96 // The number of milliseconds between animation frames. 97 private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY; 98 99 // Thread local storage for the choreographer. 100 private static final ThreadLocal<Choreographer> sThreadInstance = 101 new ThreadLocal<Choreographer>() { 102 @Override 103 protected Choreographer initialValue() { 104 Looper looper = Looper.myLooper(); 105 if (looper == null) { 106 throw new IllegalStateException("The current thread must have a looper!"); 107 } 108 return new Choreographer(looper, VSYNC_SOURCE_APP); 109 } 110 }; 111 112 // Thread local storage for the SF choreographer. 113 private static final ThreadLocal<Choreographer> sSfThreadInstance = 114 new ThreadLocal<Choreographer>() { 115 @Override 116 protected Choreographer initialValue() { 117 Looper looper = Looper.myLooper(); 118 if (looper == null) { 119 throw new IllegalStateException("The current thread must have a looper!"); 120 } 121 return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER); 122 } 123 }; 124 125 // Enable/disable vsync for animations and drawing. 126 private static final boolean USE_VSYNC = SystemProperties.getBoolean( 127 "debug.choreographer.vsync", true); 128 129 // Enable/disable using the frame time instead of returning now. 130 private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean( 131 "debug.choreographer.frametime", true); 132 133 // Set a limit to warn about skipped frames. 134 // Skipped frames imply jank. 135 private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt( 136 "debug.choreographer.skipwarning", 30); 137 138 private static final int MSG_DO_FRAME = 0; 139 private static final int MSG_DO_SCHEDULE_VSYNC = 1; 140 private static final int MSG_DO_SCHEDULE_CALLBACK = 2; 141 142 // All frame callbacks posted by applications have this token. 143 private static final Object FRAME_CALLBACK_TOKEN = new Object() { 144 public String toString() { return "FRAME_CALLBACK_TOKEN"; } 145 }; 146 147 private final Object mLock = new Object(); 148 149 private final Looper mLooper; 150 private final FrameHandler mHandler; 151 152 // The display event receiver can only be accessed by the looper thread to which 153 // it is attached. We take care to ensure that we post message to the looper 154 // if appropriate when interacting with the display event receiver. 155 private final FrameDisplayEventReceiver mDisplayEventReceiver; 156 157 private CallbackRecord mCallbackPool; 158 159 private final CallbackQueue[] mCallbackQueues; 160 161 private boolean mFrameScheduled; 162 private boolean mCallbacksRunning; 163 private long mLastFrameTimeNanos; 164 private long mFrameIntervalNanos; 165 private boolean mDebugPrintNextFrameTimeDelta; 166 167 /** 168 * Contains information about the current frame for jank-tracking, 169 * mainly timings of key events along with a bit of metadata about 170 * view tree state 171 * 172 * TODO: Is there a better home for this? Currently Choreographer 173 * is the only one with CALLBACK_ANIMATION start time, hence why this 174 * resides here. 175 * 176 * @hide 177 */ 178 FrameInfo mFrameInfo = new FrameInfo(); 179 180 /** 181 * Must be kept in sync with CALLBACK_* ints below, used to index into this array. 182 * @hide 183 */ 184 private static final String[] CALLBACK_TRACE_TITLES = { 185 "input", "animation", "traversal", "commit" 186 }; 187 188 /** 189 * Callback type: Input callback. Runs first. 190 * @hide 191 */ 192 public static final int CALLBACK_INPUT = 0; 193 194 /** 195 * Callback type: Animation callback. Runs before traversals. 196 * @hide 197 */ 198 public static final int CALLBACK_ANIMATION = 1; 199 200 /** 201 * Callback type: Traversal callback. Handles layout and draw. Runs 202 * after all other asynchronous messages have been handled. 203 * @hide 204 */ 205 public static final int CALLBACK_TRAVERSAL = 2; 206 207 /** 208 * Callback type: Commit callback. Handles post-draw operations for the frame. 209 * Runs after traversal completes. The {@link #getFrameTime() frame time} reported 210 * during this callback may be updated to reflect delays that occurred while 211 * traversals were in progress in case heavy layout operations caused some frames 212 * to be skipped. The frame time reported during this callback provides a better 213 * estimate of the start time of the frame in which animations (and other updates 214 * to the view hierarchy state) actually took effect. 215 * @hide 216 */ 217 public static final int CALLBACK_COMMIT = 3; 218 219 private static final int CALLBACK_LAST = CALLBACK_COMMIT; 220 Choreographer(Looper looper, int vsyncSource)221 private Choreographer(Looper looper, int vsyncSource) { 222 mLooper = looper; 223 mHandler = new FrameHandler(looper); 224 mDisplayEventReceiver = USE_VSYNC 225 ? new FrameDisplayEventReceiver(looper, vsyncSource) 226 : null; 227 mLastFrameTimeNanos = Long.MIN_VALUE; 228 229 mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); 230 231 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; 232 for (int i = 0; i <= CALLBACK_LAST; i++) { 233 mCallbackQueues[i] = new CallbackQueue(); 234 } 235 } 236 getRefreshRate()237 private static float getRefreshRate() { 238 DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo( 239 Display.DEFAULT_DISPLAY); 240 return di.getMode().getRefreshRate(); 241 } 242 243 /** 244 * Gets the choreographer for the calling thread. Must be called from 245 * a thread that already has a {@link android.os.Looper} associated with it. 246 * 247 * @return The choreographer for this thread. 248 * @throws IllegalStateException if the thread does not have a looper. 249 */ getInstance()250 public static Choreographer getInstance() { 251 return sThreadInstance.get(); 252 } 253 254 /** 255 * @hide 256 */ getSfInstance()257 public static Choreographer getSfInstance() { 258 return sSfThreadInstance.get(); 259 } 260 261 /** Destroys the calling thread's choreographer 262 * @hide 263 */ releaseInstance()264 public static void releaseInstance() { 265 Choreographer old = sThreadInstance.get(); 266 sThreadInstance.remove(); 267 old.dispose(); 268 } 269 dispose()270 private void dispose() { 271 mDisplayEventReceiver.dispose(); 272 } 273 274 /** 275 * The amount of time, in milliseconds, between each frame of the animation. 276 * <p> 277 * This is a requested time that the animation will attempt to honor, but the actual delay 278 * between frames may be different, depending on system load and capabilities. This is a static 279 * function because the same delay will be applied to all animations, since they are all 280 * run off of a single timing loop. 281 * </p><p> 282 * The frame delay may be ignored when the animation system uses an external timing 283 * source, such as the display refresh rate (vsync), to govern animations. 284 * </p> 285 * 286 * @return the requested time between frames, in milliseconds 287 * @hide 288 */ getFrameDelay()289 public static long getFrameDelay() { 290 return sFrameDelay; 291 } 292 293 /** 294 * 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 298 * function because the same delay will be applied to all animations, since they are all 299 * run off of a single timing loop. 300 * </p><p> 301 * 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. 303 * </p> 304 * 305 * @param frameDelay the requested time between frames, in milliseconds 306 * @hide 307 */ setFrameDelay(long frameDelay)308 public static void setFrameDelay(long frameDelay) { 309 sFrameDelay = frameDelay; 310 } 311 312 /** 313 * Subtracts typical frame delay time from a delay interval in milliseconds. 314 * <p> 315 * This method can be used to compensate for animation delay times that have baked 316 * in assumptions about the frame delay. For example, it's quite common for code to 317 * assume a 60Hz frame time and bake in a 16ms delay. When we call 318 * {@link #postAnimationCallbackDelayed} we want to know how long to wait before 319 * posting the animation callback but let the animation timer take care of the remaining 320 * frame delay time. 321 * </p><p> 322 * This method is somewhat conservative about how much of the frame delay it 323 * subtracts. It uses the same value returned by {@link #getFrameDelay} which by 324 * default is 10ms even though many parts of the system assume 16ms. Consequently, 325 * we might still wait 6ms before posting an animation callback that we want to run 326 * on the next frame, but this is much better than waiting a whole 16ms and likely 327 * missing the deadline. 328 * </p> 329 * 330 * @param delayMillis The original delay time including an assumed frame delay. 331 * @return The adjusted delay time with the assumed frame delay subtracted out. 332 * @hide 333 */ subtractFrameDelay(long delayMillis)334 public static long subtractFrameDelay(long delayMillis) { 335 final long frameDelay = sFrameDelay; 336 return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay; 337 } 338 339 /** 340 * @return The refresh rate as the nanoseconds between frames 341 * @hide 342 */ getFrameIntervalNanos()343 public long getFrameIntervalNanos() { 344 return mFrameIntervalNanos; 345 } 346 dump(String prefix, PrintWriter writer)347 void dump(String prefix, PrintWriter writer) { 348 String innerPrefix = prefix + " "; 349 writer.print(prefix); writer.println("Choreographer:"); 350 writer.print(innerPrefix); writer.print("mFrameScheduled="); 351 writer.println(mFrameScheduled); 352 writer.print(innerPrefix); writer.print("mLastFrameTime="); 353 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000)); 354 } 355 356 /** 357 * Posts a callback to run on the next frame. 358 * <p> 359 * The callback runs once then is automatically removed. 360 * </p> 361 * 362 * @param callbackType The callback type. 363 * @param action The callback action to run during the next frame. 364 * @param token The callback token, or null if none. 365 * 366 * @see #removeCallbacks 367 * @hide 368 */ postCallback(int callbackType, Runnable action, Object token)369 public void postCallback(int callbackType, Runnable action, Object token) { 370 postCallbackDelayed(callbackType, action, token, 0); 371 } 372 373 /** 374 * Posts a callback to run on the next frame after the specified delay. 375 * <p> 376 * The callback runs once then is automatically removed. 377 * </p> 378 * 379 * @param callbackType The callback type. 380 * @param action The callback action to run during the next frame after the specified delay. 381 * @param token The callback token, or null if none. 382 * @param delayMillis The delay time in milliseconds. 383 * 384 * @see #removeCallback 385 * @hide 386 */ postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis)387 public void postCallbackDelayed(int callbackType, 388 Runnable action, Object token, long delayMillis) { 389 if (action == null) { 390 throw new IllegalArgumentException("action must not be null"); 391 } 392 if (callbackType < 0 || callbackType > CALLBACK_LAST) { 393 throw new IllegalArgumentException("callbackType is invalid"); 394 } 395 396 postCallbackDelayedInternal(callbackType, action, token, delayMillis); 397 } 398 postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis)399 private void postCallbackDelayedInternal(int callbackType, 400 Object action, Object token, long delayMillis) { 401 if (DEBUG_FRAMES) { 402 Log.d(TAG, "PostCallback: type=" + callbackType 403 + ", action=" + action + ", token=" + token 404 + ", delayMillis=" + delayMillis); 405 } 406 407 synchronized (mLock) { 408 final long now = SystemClock.uptimeMillis(); 409 final long dueTime = now + delayMillis; 410 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); 411 412 if (dueTime <= now) { 413 scheduleFrameLocked(now); 414 } else { 415 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); 416 msg.arg1 = callbackType; 417 msg.setAsynchronous(true); 418 mHandler.sendMessageAtTime(msg, dueTime); 419 } 420 } 421 } 422 423 /** 424 * Removes callbacks that have the specified action and token. 425 * 426 * @param callbackType The callback type. 427 * @param action The action property of the callbacks to remove, or null to remove 428 * callbacks with any action. 429 * @param token The token property of the callbacks to remove, or null to remove 430 * callbacks with any token. 431 * 432 * @see #postCallback 433 * @see #postCallbackDelayed 434 * @hide 435 */ removeCallbacks(int callbackType, Runnable action, Object token)436 public void removeCallbacks(int callbackType, Runnable action, Object token) { 437 if (callbackType < 0 || callbackType > CALLBACK_LAST) { 438 throw new IllegalArgumentException("callbackType is invalid"); 439 } 440 441 removeCallbacksInternal(callbackType, action, token); 442 } 443 removeCallbacksInternal(int callbackType, Object action, Object token)444 private void removeCallbacksInternal(int callbackType, Object action, Object token) { 445 if (DEBUG_FRAMES) { 446 Log.d(TAG, "RemoveCallbacks: type=" + callbackType 447 + ", action=" + action + ", token=" + token); 448 } 449 450 synchronized (mLock) { 451 mCallbackQueues[callbackType].removeCallbacksLocked(action, token); 452 if (action != null && token == null) { 453 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action); 454 } 455 } 456 } 457 458 /** 459 * Posts a frame callback to run on the next frame. 460 * <p> 461 * The callback runs once then is automatically removed. 462 * </p> 463 * 464 * @param callback The frame callback to run during the next frame. 465 * 466 * @see #postFrameCallbackDelayed 467 * @see #removeFrameCallback 468 */ postFrameCallback(FrameCallback callback)469 public void postFrameCallback(FrameCallback callback) { 470 postFrameCallbackDelayed(callback, 0); 471 } 472 473 /** 474 * Posts a frame callback to run on the next frame after the specified delay. 475 * <p> 476 * The callback runs once then is automatically removed. 477 * </p> 478 * 479 * @param callback The frame callback to run during the next frame. 480 * @param delayMillis The delay time in milliseconds. 481 * 482 * @see #postFrameCallback 483 * @see #removeFrameCallback 484 */ postFrameCallbackDelayed(FrameCallback callback, long delayMillis)485 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) { 486 if (callback == null) { 487 throw new IllegalArgumentException("callback must not be null"); 488 } 489 490 postCallbackDelayedInternal(CALLBACK_ANIMATION, 491 callback, FRAME_CALLBACK_TOKEN, delayMillis); 492 } 493 494 /** 495 * Removes a previously posted frame callback. 496 * 497 * @param callback The frame callback to remove. 498 * 499 * @see #postFrameCallback 500 * @see #postFrameCallbackDelayed 501 */ removeFrameCallback(FrameCallback callback)502 public void removeFrameCallback(FrameCallback callback) { 503 if (callback == null) { 504 throw new IllegalArgumentException("callback must not be null"); 505 } 506 507 removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN); 508 } 509 510 /** 511 * Gets the time when the current frame started. 512 * <p> 513 * This method provides the time in milliseconds when the frame started being rendered. 514 * The frame time provides a stable time base for synchronizing animations 515 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()} 516 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame 517 * time helps to reduce inter-frame jitter because the frame time is fixed at the time 518 * the frame was scheduled to start, regardless of when the animations or drawing 519 * callback actually runs. All callbacks that run as part of rendering a frame will 520 * observe the same frame time so using the frame time also helps to synchronize effects 521 * that are performed by different callbacks. 522 * </p><p> 523 * Please note that the framework already takes care to process animations and 524 * drawing using the frame time as a stable time base. Most applications should 525 * not need to use the frame time information directly. 526 * </p><p> 527 * This method should only be called from within a callback. 528 * </p> 529 * 530 * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base. 531 * 532 * @throws IllegalStateException if no frame is in progress. 533 * @hide 534 */ getFrameTime()535 public long getFrameTime() { 536 return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS; 537 } 538 539 /** 540 * Same as {@link #getFrameTime()} but with nanosecond precision. 541 * 542 * @return The frame start time, in the {@link System#nanoTime()} time base. 543 * 544 * @throws IllegalStateException if no frame is in progress. 545 * @hide 546 */ getFrameTimeNanos()547 public long getFrameTimeNanos() { 548 synchronized (mLock) { 549 if (!mCallbacksRunning) { 550 throw new IllegalStateException("This method must only be called as " 551 + "part of a callback while a frame is in progress."); 552 } 553 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime(); 554 } 555 } 556 557 /** 558 * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter 559 * whether callbacks are currently running. 560 * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base. 561 * @hide 562 */ getLastFrameTimeNanos()563 public long getLastFrameTimeNanos() { 564 synchronized (mLock) { 565 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime(); 566 } 567 } 568 scheduleFrameLocked(long now)569 private void scheduleFrameLocked(long now) { 570 if (!mFrameScheduled) { 571 mFrameScheduled = true; 572 if (USE_VSYNC) { 573 if (DEBUG_FRAMES) { 574 Log.d(TAG, "Scheduling next frame on vsync."); 575 } 576 577 // If running on the Looper thread, then schedule the vsync immediately, 578 // otherwise post a message to schedule the vsync from the UI thread 579 // as soon as possible. 580 if (isRunningOnLooperThreadLocked()) { 581 scheduleVsyncLocked(); 582 } else { 583 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); 584 msg.setAsynchronous(true); 585 mHandler.sendMessageAtFrontOfQueue(msg); 586 } 587 } else { 588 final long nextFrameTime = Math.max( 589 mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now); 590 if (DEBUG_FRAMES) { 591 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms."); 592 } 593 Message msg = mHandler.obtainMessage(MSG_DO_FRAME); 594 msg.setAsynchronous(true); 595 mHandler.sendMessageAtTime(msg, nextFrameTime); 596 } 597 } 598 } 599 doFrame(long frameTimeNanos, int frame)600 void doFrame(long frameTimeNanos, int frame) { 601 final long startNanos; 602 synchronized (mLock) { 603 if (!mFrameScheduled) { 604 return; // no work to do 605 } 606 607 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) { 608 mDebugPrintNextFrameTimeDelta = false; 609 Log.d(TAG, "Frame time delta: " 610 + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms"); 611 } 612 613 long intendedFrameTimeNanos = frameTimeNanos; 614 startNanos = System.nanoTime(); 615 final long jitterNanos = startNanos - frameTimeNanos; 616 if (jitterNanos >= mFrameIntervalNanos) { 617 final long skippedFrames = jitterNanos / mFrameIntervalNanos; 618 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { 619 Log.i(TAG, "Skipped " + skippedFrames + " frames! " 620 + "The application may be doing too much work on its main thread."); 621 } 622 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos; 623 if (DEBUG_JANK) { 624 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " 625 + "which is more than the frame interval of " 626 + (mFrameIntervalNanos * 0.000001f) + " ms! " 627 + "Skipping " + skippedFrames + " frames and setting frame " 628 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past."); 629 } 630 frameTimeNanos = startNanos - lastFrameOffset; 631 } 632 633 if (frameTimeNanos < mLastFrameTimeNanos) { 634 if (DEBUG_JANK) { 635 Log.d(TAG, "Frame time appears to be going backwards. May be due to a " 636 + "previously skipped frame. Waiting for next vsync."); 637 } 638 scheduleVsyncLocked(); 639 return; 640 } 641 642 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos); 643 mFrameScheduled = false; 644 mLastFrameTimeNanos = frameTimeNanos; 645 } 646 647 try { 648 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame"); 649 AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); 650 651 mFrameInfo.markInputHandlingStart(); 652 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); 653 654 mFrameInfo.markAnimationsStart(); 655 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); 656 657 mFrameInfo.markPerformTraversalsStart(); 658 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); 659 660 doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); 661 } finally { 662 AnimationUtils.unlockAnimationClock(); 663 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 664 } 665 666 if (DEBUG_FRAMES) { 667 final long endNanos = System.nanoTime(); 668 Log.d(TAG, "Frame " + frame + ": Finished, took " 669 + (endNanos - startNanos) * 0.000001f + " ms, latency " 670 + (startNanos - frameTimeNanos) * 0.000001f + " ms."); 671 } 672 } 673 doCallbacks(int callbackType, long frameTimeNanos)674 void doCallbacks(int callbackType, long frameTimeNanos) { 675 CallbackRecord callbacks; 676 synchronized (mLock) { 677 // We use "now" to determine when callbacks become due because it's possible 678 // for earlier processing phases in a frame to post callbacks that should run 679 // in a following phase, such as an input event that causes an animation to start. 680 final long now = System.nanoTime(); 681 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked( 682 now / TimeUtils.NANOS_PER_MS); 683 if (callbacks == null) { 684 return; 685 } 686 mCallbacksRunning = true; 687 688 // Update the frame time if necessary when committing the frame. 689 // We only update the frame time if we are more than 2 frames late reaching 690 // the commit phase. This ensures that the frame time which is observed by the 691 // callbacks will always increase from one frame to the next and never repeat. 692 // We never want the next frame's starting frame time to end up being less than 693 // or equal to the previous frame's commit frame time. Keep in mind that the 694 // next frame has most likely already been scheduled by now so we play it 695 // safe by ensuring the commit time is always at least one frame behind. 696 if (callbackType == Choreographer.CALLBACK_COMMIT) { 697 final long jitterNanos = now - frameTimeNanos; 698 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos); 699 if (jitterNanos >= 2 * mFrameIntervalNanos) { 700 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos 701 + mFrameIntervalNanos; 702 if (DEBUG_JANK) { 703 Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f) 704 + " ms which is more than twice the frame interval of " 705 + (mFrameIntervalNanos * 0.000001f) + " ms! " 706 + "Setting frame time to " + (lastFrameOffset * 0.000001f) 707 + " ms in the past."); 708 mDebugPrintNextFrameTimeDelta = true; 709 } 710 frameTimeNanos = now - lastFrameOffset; 711 mLastFrameTimeNanos = frameTimeNanos; 712 } 713 } 714 } 715 try { 716 Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]); 717 for (CallbackRecord c = callbacks; c != null; c = c.next) { 718 if (DEBUG_FRAMES) { 719 Log.d(TAG, "RunCallback: type=" + callbackType 720 + ", action=" + c.action + ", token=" + c.token 721 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime)); 722 } 723 c.run(frameTimeNanos); 724 } 725 } finally { 726 synchronized (mLock) { 727 mCallbacksRunning = false; 728 do { 729 final CallbackRecord next = callbacks.next; 730 recycleCallbackLocked(callbacks); 731 callbacks = next; 732 } while (callbacks != null); 733 } 734 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 735 } 736 } 737 doScheduleVsync()738 void doScheduleVsync() { 739 synchronized (mLock) { 740 if (mFrameScheduled) { 741 scheduleVsyncLocked(); 742 } 743 } 744 } 745 doScheduleCallback(int callbackType)746 void doScheduleCallback(int callbackType) { 747 synchronized (mLock) { 748 if (!mFrameScheduled) { 749 final long now = SystemClock.uptimeMillis(); 750 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) { 751 scheduleFrameLocked(now); 752 } 753 } 754 } 755 } 756 scheduleVsyncLocked()757 private void scheduleVsyncLocked() { 758 mDisplayEventReceiver.scheduleVsync(); 759 } 760 isRunningOnLooperThreadLocked()761 private boolean isRunningOnLooperThreadLocked() { 762 return Looper.myLooper() == mLooper; 763 } 764 obtainCallbackLocked(long dueTime, Object action, Object token)765 private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) { 766 CallbackRecord callback = mCallbackPool; 767 if (callback == null) { 768 callback = new CallbackRecord(); 769 } else { 770 mCallbackPool = callback.next; 771 callback.next = null; 772 } 773 callback.dueTime = dueTime; 774 callback.action = action; 775 callback.token = token; 776 return callback; 777 } 778 recycleCallbackLocked(CallbackRecord callback)779 private void recycleCallbackLocked(CallbackRecord callback) { 780 callback.action = null; 781 callback.token = null; 782 callback.next = mCallbackPool; 783 mCallbackPool = callback; 784 } 785 786 /** 787 * Implement this interface to receive a callback when a new display frame is 788 * being rendered. The callback is invoked on the {@link Looper} thread to 789 * which the {@link Choreographer} is attached. 790 */ 791 public interface FrameCallback { 792 /** 793 * Called when a new display frame is being rendered. 794 * <p> 795 * This method provides the time in nanoseconds when the frame started being rendered. 796 * The frame time provides a stable time base for synchronizing animations 797 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()} 798 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame 799 * time helps to reduce inter-frame jitter because the frame time is fixed at the time 800 * the frame was scheduled to start, regardless of when the animations or drawing 801 * callback actually runs. All callbacks that run as part of rendering a frame will 802 * observe the same frame time so using the frame time also helps to synchronize effects 803 * that are performed by different callbacks. 804 * </p><p> 805 * Please note that the framework already takes care to process animations and 806 * drawing using the frame time as a stable time base. Most applications should 807 * not need to use the frame time information directly. 808 * </p> 809 * 810 * @param frameTimeNanos The time in nanoseconds when the frame started being rendered, 811 * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000} 812 * to convert it to the {@link SystemClock#uptimeMillis()} time base. 813 */ doFrame(long frameTimeNanos)814 public void doFrame(long frameTimeNanos); 815 } 816 817 private final class FrameHandler extends Handler { FrameHandler(Looper looper)818 public FrameHandler(Looper looper) { 819 super(looper); 820 } 821 822 @Override handleMessage(Message msg)823 public void handleMessage(Message msg) { 824 switch (msg.what) { 825 case MSG_DO_FRAME: 826 doFrame(System.nanoTime(), 0); 827 break; 828 case MSG_DO_SCHEDULE_VSYNC: 829 doScheduleVsync(); 830 break; 831 case MSG_DO_SCHEDULE_CALLBACK: 832 doScheduleCallback(msg.arg1); 833 break; 834 } 835 } 836 } 837 838 private final class FrameDisplayEventReceiver extends DisplayEventReceiver 839 implements Runnable { 840 private boolean mHavePendingVsync; 841 private long mTimestampNanos; 842 private int mFrame; 843 FrameDisplayEventReceiver(Looper looper, int vsyncSource)844 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) { 845 super(looper, vsyncSource); 846 } 847 848 @Override onVsync(long timestampNanos, int builtInDisplayId, int frame)849 public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { 850 // Ignore vsync from secondary display. 851 // This can be problematic because the call to scheduleVsync() is a one-shot. 852 // We need to ensure that we will still receive the vsync from the primary 853 // display which is the one we really care about. Ideally we should schedule 854 // vsync for a particular display. 855 // At this time Surface Flinger won't send us vsyncs for secondary displays 856 // but that could change in the future so let's log a message to help us remember 857 // that we need to fix this. 858 if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { 859 Log.d(TAG, "Received vsync from secondary display, but we don't support " 860 + "this case yet. Choreographer needs a way to explicitly request " 861 + "vsync for a specific display to ensure it doesn't lose track " 862 + "of its scheduled vsync."); 863 scheduleVsync(); 864 return; 865 } 866 867 // Post the vsync event to the Handler. 868 // The idea is to prevent incoming vsync events from completely starving 869 // the message queue. If there are no messages in the queue with timestamps 870 // earlier than the frame time, then the vsync event will be processed immediately. 871 // Otherwise, messages that predate the vsync event will be handled first. 872 long now = System.nanoTime(); 873 if (timestampNanos > now) { 874 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f) 875 + " ms in the future! Check that graphics HAL is generating vsync " 876 + "timestamps using the correct timebase."); 877 timestampNanos = now; 878 } 879 880 if (mHavePendingVsync) { 881 Log.w(TAG, "Already have a pending vsync event. There should only be " 882 + "one at a time."); 883 } else { 884 mHavePendingVsync = true; 885 } 886 887 mTimestampNanos = timestampNanos; 888 mFrame = frame; 889 Message msg = Message.obtain(mHandler, this); 890 msg.setAsynchronous(true); 891 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); 892 } 893 894 @Override run()895 public void run() { 896 mHavePendingVsync = false; 897 doFrame(mTimestampNanos, mFrame); 898 } 899 } 900 901 private static final class CallbackRecord { 902 public CallbackRecord next; 903 public long dueTime; 904 public Object action; // Runnable or FrameCallback 905 public Object token; 906 run(long frameTimeNanos)907 public void run(long frameTimeNanos) { 908 if (token == FRAME_CALLBACK_TOKEN) { 909 ((FrameCallback)action).doFrame(frameTimeNanos); 910 } else { 911 ((Runnable)action).run(); 912 } 913 } 914 } 915 916 private final class CallbackQueue { 917 private CallbackRecord mHead; 918 hasDueCallbacksLocked(long now)919 public boolean hasDueCallbacksLocked(long now) { 920 return mHead != null && mHead.dueTime <= now; 921 } 922 extractDueCallbacksLocked(long now)923 public CallbackRecord extractDueCallbacksLocked(long now) { 924 CallbackRecord callbacks = mHead; 925 if (callbacks == null || callbacks.dueTime > now) { 926 return null; 927 } 928 929 CallbackRecord last = callbacks; 930 CallbackRecord next = last.next; 931 while (next != null) { 932 if (next.dueTime > now) { 933 last.next = null; 934 break; 935 } 936 last = next; 937 next = next.next; 938 } 939 mHead = next; 940 return callbacks; 941 } 942 addCallbackLocked(long dueTime, Object action, Object token)943 public void addCallbackLocked(long dueTime, Object action, Object token) { 944 CallbackRecord callback = obtainCallbackLocked(dueTime, action, token); 945 CallbackRecord entry = mHead; 946 if (entry == null) { 947 mHead = callback; 948 return; 949 } 950 if (dueTime < entry.dueTime) { 951 callback.next = entry; 952 mHead = callback; 953 return; 954 } 955 while (entry.next != null) { 956 if (dueTime < entry.next.dueTime) { 957 callback.next = entry.next; 958 break; 959 } 960 entry = entry.next; 961 } 962 entry.next = callback; 963 } 964 removeCallbacksLocked(Object action, Object token)965 public void removeCallbacksLocked(Object action, Object token) { 966 CallbackRecord predecessor = null; 967 for (CallbackRecord callback = mHead; callback != null;) { 968 final CallbackRecord next = callback.next; 969 if ((action == null || callback.action == action) 970 && (token == null || callback.token == token)) { 971 if (predecessor != null) { 972 predecessor.next = next; 973 } else { 974 mHead = next; 975 } 976 recycleCallbackLocked(callback); 977 } else { 978 predecessor = callback; 979 } 980 callback = next; 981 } 982 } 983 } 984 } 985