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