PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

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

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