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