Loading core/java/android/view/Choreographer.java +74 −66 Original line number Diff line number Diff line Loading @@ -197,6 +197,7 @@ public final class Choreographer { private int mFPSDivisor = 1; private DisplayEventReceiver.VsyncEventData mLastVsyncEventData = new DisplayEventReceiver.VsyncEventData(); private final FrameData mFrameData = new FrameData(); /** * Contains information about the current frame for jank-tracking, Loading Loading @@ -789,7 +790,7 @@ public final class Choreographer { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId); } FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData); mFrameData.update(frameTimeNanos, vsyncEventData); synchronized (mLock) { if (!mFrameScheduled) { traceMessage("Frame not scheduled"); Loading Loading @@ -827,7 +828,7 @@ public final class Choreographer { + " ms in the past."); } } frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos); mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos); } if (frameTimeNanos < mLastFrameTimeNanos) { Loading Loading @@ -862,17 +863,16 @@ public final class Choreographer { AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); mFrameInfo.markInputHandlingStart(); doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos); mFrameInfo.markAnimationsStart(); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos); mFrameInfo.markPerformTraversalsStart(); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos); } finally { AnimationUtils.unlockAnimationClock(); Trace.traceEnd(Trace.TRACE_TAG_VIEW); Loading @@ -886,9 +886,9 @@ public final class Choreographer { } } void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) { void doCallbacks(int callbackType, long frameIntervalNanos) { CallbackRecord callbacks; long frameTimeNanos = frameData.mFrameTimeNanos; long frameTimeNanos = mFrameData.getFrameTimeNanos(); synchronized (mLock) { // We use "now" to determine when callbacks become due because it's possible // for earlier processing phases in a frame to post callbacks that should run Loading Loading @@ -925,7 +925,7 @@ public final class Choreographer { } frameTimeNanos = now - lastFrameOffset; mLastFrameTimeNanos = frameTimeNanos; frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos); mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos); } } } Loading @@ -937,7 +937,7 @@ public final class Choreographer { + ", action=" + c.action + ", token=" + c.token + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime)); } c.run(frameData); c.run(mFrameData); } } finally { synchronized (mLock) { Loading Loading @@ -1039,15 +1039,19 @@ public final class Choreographer { /** Holds data that describes one possible VSync frame event to render at. */ public static class FrameTimeline { FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) { this.mVsyncId = vsyncId; this.mExpectedPresentTimeNanos = expectedPresentTimeNanos; this.mDeadlineNanos = deadlineNanos; private long mVsyncId = FrameInfo.INVALID_VSYNC_ID; private long mExpectedPresentationTimeNanos = -1; private long mDeadlineNanos = -1; FrameTimeline() { // Intentionally empty; defined so that it is not API/public by default. } private long mVsyncId; private long mExpectedPresentTimeNanos; private long mDeadlineNanos; void update(long vsyncId, long expectedPresentationTimeNanos, long deadlineNanos) { mVsyncId = vsyncId; mExpectedPresentationTimeNanos = expectedPresentationTimeNanos; mDeadlineNanos = deadlineNanos; } /** * The id that corresponds to this frame timeline, used to correlate a frame Loading @@ -1062,7 +1066,7 @@ public final class Choreographer { * presented. */ public long getExpectedPresentationTimeNanos() { return mExpectedPresentTimeNanos; return mExpectedPresentationTimeNanos; } /** Loading @@ -1079,20 +1083,15 @@ public final class Choreographer { * information including deadline and expected present time. */ public static class FrameData { FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { this.mFrameTimeNanos = frameTimeNanos; this.mFrameTimelines = convertFrameTimelines(vsyncEventData); this.mPreferredFrameTimelineIndex = vsyncEventData.preferredFrameTimelineIndex; } private long mFrameTimeNanos; private final FrameTimeline[] mFrameTimelines; private final FrameTimeline[] mFrameTimelines = new FrameTimeline[DisplayEventReceiver.VsyncEventData.FRAME_TIMELINES_LENGTH]; private int mPreferredFrameTimelineIndex; void updateFrameData(long frameTimeNanos, int newPreferredFrameTimelineIndex) { mFrameTimeNanos = frameTimeNanos; mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex; FrameData() { for (int i = 0; i < mFrameTimelines.length; i++) { mFrameTimelines[i] = new FrameTimeline(); } } /** The time in nanoseconds when the frame started being rendered. */ Loading @@ -1113,17 +1112,24 @@ public final class Choreographer { return mFrameTimelines[mPreferredFrameTimelineIndex]; } private FrameTimeline[] convertFrameTimelines( DisplayEventReceiver.VsyncEventData vsyncEventData) { FrameTimeline[] frameTimelines = new FrameTimeline[vsyncEventData.frameTimelines.length]; /** * Update the frame data with a {@code DisplayEventReceiver.VsyncEventData} received from * native. */ void update(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { if (vsyncEventData.frameTimelines.length != mFrameTimelines.length) { throw new IllegalStateException( "Length of native frame timelines received does not match Java. Did " + "FRAME_TIMELINES_LENGTH or kFrameTimelinesLength (native) " + "change?"); } mFrameTimeNanos = frameTimeNanos; mPreferredFrameTimelineIndex = vsyncEventData.preferredFrameTimelineIndex; for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) { DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i]; frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId, frameTimeline.expectedPresentTime, frameTimeline.deadline); } return frameTimelines; mFrameTimelines[i].update(frameTimeline.vsyncId, frameTimeline.expectedPresentationTime, frameTimeline.deadline); } } Loading @@ -1132,30 +1138,32 @@ public final class Choreographer { * * @param jitterNanos currentTime - frameTime */ private FrameData getUpdatedFrameData(long frameTimeNanos, FrameData frameData, long jitterNanos) { void update( long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos) { int newPreferredIndex = 0; FrameTimeline[] frameTimelines = frameData.getFrameTimelines(); final long minimumDeadline = frameData.getPreferredFrameTimeline().getDeadlineNanos() + jitterNanos; getPreferredFrameTimeline().getDeadlineNanos() + jitterNanos; // Look for a non-past deadline timestamp in the existing frame data. Otherwise, binder // query for new frame data. Note that binder is relatively slow, O(ms), so it is // only called when the existing frame data does not hold a valid frame. while (newPreferredIndex < frameTimelines.length - 1 && frameTimelines[newPreferredIndex].getDeadlineNanos() < minimumDeadline) { while (newPreferredIndex < mFrameTimelines.length - 1 && mFrameTimelines[newPreferredIndex].getDeadlineNanos() < minimumDeadline) { newPreferredIndex++; } long newPreferredDeadline = frameData.getFrameTimelines()[newPreferredIndex].getDeadlineNanos(); long newPreferredDeadline = mFrameTimelines[newPreferredIndex].getDeadlineNanos(); if (newPreferredDeadline < minimumDeadline) { DisplayEventReceiver.VsyncEventData latestVsyncEventData = mDisplayEventReceiver.getLatestVsyncEventData(); return new FrameData(frameTimeNanos, latestVsyncEventData); displayEventReceiver.getLatestVsyncEventData(); update(frameTimeNanos, latestVsyncEventData); } else { frameData.updateFrameData(frameTimeNanos, newPreferredIndex); return frameData; update(frameTimeNanos, newPreferredIndex); } } void update(long frameTimeNanos, int newPreferredFrameTimelineIndex) { mFrameTimeNanos = frameTimeNanos; mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex; } } Loading core/java/android/view/DisplayEventReceiver.java +8 −3 Original line number Diff line number Diff line Loading @@ -145,11 +145,16 @@ public abstract class DisplayEventReceiver { static final FrameTimeline[] INVALID_FRAME_TIMELINES = {new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)}; // The amount of frame timeline choices. // Must be in sync with VsyncEventData::kFrameTimelinesLength in // frameworks/native/libs/gui/include/gui/VsyncEventData.h. If they do not match, a runtime // assertion is thrown when Choreographer is processing VsyncEventData. static final int FRAME_TIMELINES_LENGTH = 7; public static class FrameTimeline { FrameTimeline(long vsyncId, long expectedPresentTime, long deadline) { FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline) { this.vsyncId = vsyncId; this.expectedPresentTime = expectedPresentTime; this.expectedPresentationTime = expectedPresentationTime; this.deadline = deadline; } Loading @@ -158,7 +163,7 @@ public abstract class DisplayEventReceiver { public final long vsyncId; // The frame timestamp for when the frame is expected to be presented. public final long expectedPresentTime; public final long expectedPresentationTime; // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is // allotted for the frame to be completed. Loading Loading
core/java/android/view/Choreographer.java +74 −66 Original line number Diff line number Diff line Loading @@ -197,6 +197,7 @@ public final class Choreographer { private int mFPSDivisor = 1; private DisplayEventReceiver.VsyncEventData mLastVsyncEventData = new DisplayEventReceiver.VsyncEventData(); private final FrameData mFrameData = new FrameData(); /** * Contains information about the current frame for jank-tracking, Loading Loading @@ -789,7 +790,7 @@ public final class Choreographer { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId); } FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData); mFrameData.update(frameTimeNanos, vsyncEventData); synchronized (mLock) { if (!mFrameScheduled) { traceMessage("Frame not scheduled"); Loading Loading @@ -827,7 +828,7 @@ public final class Choreographer { + " ms in the past."); } } frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos); mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos); } if (frameTimeNanos < mLastFrameTimeNanos) { Loading Loading @@ -862,17 +863,16 @@ public final class Choreographer { AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); mFrameInfo.markInputHandlingStart(); doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos); mFrameInfo.markAnimationsStart(); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos); mFrameInfo.markPerformTraversalsStart(); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos); } finally { AnimationUtils.unlockAnimationClock(); Trace.traceEnd(Trace.TRACE_TAG_VIEW); Loading @@ -886,9 +886,9 @@ public final class Choreographer { } } void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) { void doCallbacks(int callbackType, long frameIntervalNanos) { CallbackRecord callbacks; long frameTimeNanos = frameData.mFrameTimeNanos; long frameTimeNanos = mFrameData.getFrameTimeNanos(); synchronized (mLock) { // We use "now" to determine when callbacks become due because it's possible // for earlier processing phases in a frame to post callbacks that should run Loading Loading @@ -925,7 +925,7 @@ public final class Choreographer { } frameTimeNanos = now - lastFrameOffset; mLastFrameTimeNanos = frameTimeNanos; frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos); mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos); } } } Loading @@ -937,7 +937,7 @@ public final class Choreographer { + ", action=" + c.action + ", token=" + c.token + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime)); } c.run(frameData); c.run(mFrameData); } } finally { synchronized (mLock) { Loading Loading @@ -1039,15 +1039,19 @@ public final class Choreographer { /** Holds data that describes one possible VSync frame event to render at. */ public static class FrameTimeline { FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) { this.mVsyncId = vsyncId; this.mExpectedPresentTimeNanos = expectedPresentTimeNanos; this.mDeadlineNanos = deadlineNanos; private long mVsyncId = FrameInfo.INVALID_VSYNC_ID; private long mExpectedPresentationTimeNanos = -1; private long mDeadlineNanos = -1; FrameTimeline() { // Intentionally empty; defined so that it is not API/public by default. } private long mVsyncId; private long mExpectedPresentTimeNanos; private long mDeadlineNanos; void update(long vsyncId, long expectedPresentationTimeNanos, long deadlineNanos) { mVsyncId = vsyncId; mExpectedPresentationTimeNanos = expectedPresentationTimeNanos; mDeadlineNanos = deadlineNanos; } /** * The id that corresponds to this frame timeline, used to correlate a frame Loading @@ -1062,7 +1066,7 @@ public final class Choreographer { * presented. */ public long getExpectedPresentationTimeNanos() { return mExpectedPresentTimeNanos; return mExpectedPresentationTimeNanos; } /** Loading @@ -1079,20 +1083,15 @@ public final class Choreographer { * information including deadline and expected present time. */ public static class FrameData { FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { this.mFrameTimeNanos = frameTimeNanos; this.mFrameTimelines = convertFrameTimelines(vsyncEventData); this.mPreferredFrameTimelineIndex = vsyncEventData.preferredFrameTimelineIndex; } private long mFrameTimeNanos; private final FrameTimeline[] mFrameTimelines; private final FrameTimeline[] mFrameTimelines = new FrameTimeline[DisplayEventReceiver.VsyncEventData.FRAME_TIMELINES_LENGTH]; private int mPreferredFrameTimelineIndex; void updateFrameData(long frameTimeNanos, int newPreferredFrameTimelineIndex) { mFrameTimeNanos = frameTimeNanos; mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex; FrameData() { for (int i = 0; i < mFrameTimelines.length; i++) { mFrameTimelines[i] = new FrameTimeline(); } } /** The time in nanoseconds when the frame started being rendered. */ Loading @@ -1113,17 +1112,24 @@ public final class Choreographer { return mFrameTimelines[mPreferredFrameTimelineIndex]; } private FrameTimeline[] convertFrameTimelines( DisplayEventReceiver.VsyncEventData vsyncEventData) { FrameTimeline[] frameTimelines = new FrameTimeline[vsyncEventData.frameTimelines.length]; /** * Update the frame data with a {@code DisplayEventReceiver.VsyncEventData} received from * native. */ void update(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { if (vsyncEventData.frameTimelines.length != mFrameTimelines.length) { throw new IllegalStateException( "Length of native frame timelines received does not match Java. Did " + "FRAME_TIMELINES_LENGTH or kFrameTimelinesLength (native) " + "change?"); } mFrameTimeNanos = frameTimeNanos; mPreferredFrameTimelineIndex = vsyncEventData.preferredFrameTimelineIndex; for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) { DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i]; frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId, frameTimeline.expectedPresentTime, frameTimeline.deadline); } return frameTimelines; mFrameTimelines[i].update(frameTimeline.vsyncId, frameTimeline.expectedPresentationTime, frameTimeline.deadline); } } Loading @@ -1132,30 +1138,32 @@ public final class Choreographer { * * @param jitterNanos currentTime - frameTime */ private FrameData getUpdatedFrameData(long frameTimeNanos, FrameData frameData, long jitterNanos) { void update( long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos) { int newPreferredIndex = 0; FrameTimeline[] frameTimelines = frameData.getFrameTimelines(); final long minimumDeadline = frameData.getPreferredFrameTimeline().getDeadlineNanos() + jitterNanos; getPreferredFrameTimeline().getDeadlineNanos() + jitterNanos; // Look for a non-past deadline timestamp in the existing frame data. Otherwise, binder // query for new frame data. Note that binder is relatively slow, O(ms), so it is // only called when the existing frame data does not hold a valid frame. while (newPreferredIndex < frameTimelines.length - 1 && frameTimelines[newPreferredIndex].getDeadlineNanos() < minimumDeadline) { while (newPreferredIndex < mFrameTimelines.length - 1 && mFrameTimelines[newPreferredIndex].getDeadlineNanos() < minimumDeadline) { newPreferredIndex++; } long newPreferredDeadline = frameData.getFrameTimelines()[newPreferredIndex].getDeadlineNanos(); long newPreferredDeadline = mFrameTimelines[newPreferredIndex].getDeadlineNanos(); if (newPreferredDeadline < minimumDeadline) { DisplayEventReceiver.VsyncEventData latestVsyncEventData = mDisplayEventReceiver.getLatestVsyncEventData(); return new FrameData(frameTimeNanos, latestVsyncEventData); displayEventReceiver.getLatestVsyncEventData(); update(frameTimeNanos, latestVsyncEventData); } else { frameData.updateFrameData(frameTimeNanos, newPreferredIndex); return frameData; update(frameTimeNanos, newPreferredIndex); } } void update(long frameTimeNanos, int newPreferredFrameTimelineIndex) { mFrameTimeNanos = frameTimeNanos; mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex; } } Loading
core/java/android/view/DisplayEventReceiver.java +8 −3 Original line number Diff line number Diff line Loading @@ -145,11 +145,16 @@ public abstract class DisplayEventReceiver { static final FrameTimeline[] INVALID_FRAME_TIMELINES = {new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)}; // The amount of frame timeline choices. // Must be in sync with VsyncEventData::kFrameTimelinesLength in // frameworks/native/libs/gui/include/gui/VsyncEventData.h. If they do not match, a runtime // assertion is thrown when Choreographer is processing VsyncEventData. static final int FRAME_TIMELINES_LENGTH = 7; public static class FrameTimeline { FrameTimeline(long vsyncId, long expectedPresentTime, long deadline) { FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline) { this.vsyncId = vsyncId; this.expectedPresentTime = expectedPresentTime; this.expectedPresentationTime = expectedPresentationTime; this.deadline = deadline; } Loading @@ -158,7 +163,7 @@ public abstract class DisplayEventReceiver { public final long vsyncId; // The frame timestamp for when the frame is expected to be presented. public final long expectedPresentTime; public final long expectedPresentationTime; // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is // allotted for the frame to be completed. Loading