PageRenderTime 37ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

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

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