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