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