PageRenderTime 103ms CodeModel.GetById 21ms RepoModel.GetById 3ms app.codeStats 0ms

/core/java/android/view/Choreographer.java

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