PageRenderTime 56ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

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

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