Loading core/api/current.txt +22 −0 Original line number Diff line number Diff line Loading @@ -51406,6 +51406,7 @@ package android.view { method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl); method public default int getBufferTransformHint(); method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.window.InputTransferToken getInputTransferToken(); method @FlaggedApi("com.android.window.flags.jank_api") @NonNull public default android.view.SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.OnJankDataListener); method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener); method public default void setChildBoundingInsets(@NonNull android.graphics.Rect); method public default void setTouchableRegion(@Nullable android.graphics.Region); Loading Loading @@ -51663,6 +51664,7 @@ package android.view { field public static final int DEADLINE = 13; // 0xd field public static final int DRAW_DURATION = 4; // 0x4 field public static final int FIRST_DRAW_FRAME = 9; // 0x9 field @FlaggedApi("com.android.window.flags.jank_api") public static final int FRAME_TIMELINE_VSYNC_ID = 14; // 0xe field public static final int GPU_DURATION = 12; // 0xc field public static final int INPUT_HANDLING_DURATION = 1; // 0x1 field public static final int INTENDED_VSYNC_TIMESTAMP = 10; // 0xa Loading Loading @@ -53100,6 +53102,26 @@ package android.view { method @NonNull public android.view.SurfaceControl.Builder setParent(@Nullable android.view.SurfaceControl); } @FlaggedApi("com.android.window.flags.jank_api") public static class SurfaceControl.JankData { method public long getActualAppFrameTimeNanos(); method public int getJankType(); method public long getScheduledAppFrameTimeNanos(); method public long getVsyncId(); field public static final int JANK_APPLICATION = 2; // 0x2 field public static final int JANK_COMPOSER = 1; // 0x1 field public static final int JANK_NONE = 0; // 0x0 field public static final int JANK_OTHER = 4; // 0x4 } @FlaggedApi("com.android.window.flags.jank_api") public static interface SurfaceControl.OnJankDataListener { method public void onJankDataAvailable(@NonNull java.util.List<android.view.SurfaceControl.JankData>); } @FlaggedApi("com.android.window.flags.jank_api") public static class SurfaceControl.OnJankDataListenerRegistration { method public void flush(); method public void removeAfter(long); } public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable { ctor public SurfaceControl.Transaction(); method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener); core/java/android/app/jank/JankDataProcessor.java +6 −6 Original line number Diff line number Diff line Loading @@ -70,8 +70,8 @@ public class JankDataProcessor { for (int j = 0; j < mPendingStates.size(); j++) { StateData pendingState = mPendingStates.get(j); // This state was active during the frame if (frame.frameVsyncId >= pendingState.mVsyncIdStart && frame.frameVsyncId <= pendingState.mVsyncIdEnd) { if (frame.getVsyncId() >= pendingState.mVsyncIdStart && frame.getVsyncId() <= pendingState.mVsyncIdEnd) { recordFrameCount(frame, pendingState, activityName, appUid); pendingState.mProcessed = true; Loading Loading @@ -131,14 +131,14 @@ public class JankDataProcessor { mPendingJankStats.put(stateData.mStateDataKey, jankStats); } // This state has already been accounted for if (jankStats.processedVsyncId == frameData.frameVsyncId) return; if (jankStats.processedVsyncId == frameData.getVsyncId()) return; jankStats.mTotalFrames += 1; if (frameData.jankType == JankData.JANK_APPLICATION) { if ((frameData.getJankType() & JankData.JANK_APPLICATION) != 0) { jankStats.mJankyFrames += 1; } jankStats.recordFrameOverrun(frameData.actualAppFrameTimeNs); jankStats.processedVsyncId = frameData.frameVsyncId; jankStats.recordFrameOverrun(frameData.getActualAppFrameTimeNanos()); jankStats.processedVsyncId = frameData.getVsyncId(); } Loading core/java/android/view/AttachedSurfaceControl.java +21 −0 Original line number Diff line number Diff line Loading @@ -15,9 +15,11 @@ */ package android.view; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UiThread; import android.content.Context; import android.graphics.Rect; Loading @@ -29,6 +31,8 @@ import android.window.SurfaceSyncGroup; import com.android.window.flags.Flags; import java.util.concurrent.Executor; /** * Provides an interface to the root-Surface of a View Hierarchy or Window. This * is used in combination with the {@link android.view.SurfaceControl} API to enable Loading Loading @@ -202,4 +206,21 @@ public interface AttachedSurfaceControl { throw new UnsupportedOperationException("The getInputTransferToken needs to be " + "implemented before making this call."); } /** * Registers a {@link OnJankDataListener} to receive jank classification data about rendered * frames. * * @param executor The executor on which the listener will be invoked. * @param listener The listener to add. * @return The {@link OnJankDataListenerRegistration} for the listener. */ @NonNull @FlaggedApi(Flags.FLAG_JANK_API) @SuppressLint("PairedRegistration") default SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener( @NonNull @CallbackExecutor Executor executor, @NonNull SurfaceControl.OnJankDataListener listener) { return SurfaceControl.OnJankDataListenerRegistration.NONE; } } core/java/android/view/FrameMetrics.java +17 −2 Original line number Diff line number Diff line Loading @@ -18,10 +18,13 @@ package android.view; import static android.graphics.FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import com.android.window.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -176,6 +179,16 @@ public final class FrameMetrics { **/ public static final int DEADLINE = 13; /** * Metric identifier for the frame's VSync identifier. * <p> * The id that corresponds to the chosen frame timeline, used to correlate a frame produced * by HWUI with the timeline data from the compositor. * </p> */ @FlaggedApi(Flags.FLAG_JANK_API) public static final int FRAME_TIMELINE_VSYNC_ID = 14; /** * Identifiers for metrics available for each frame. * Loading Loading @@ -337,7 +350,8 @@ public final class FrameMetrics { * @return the value of the metric or -1 if it is not available. */ public long getMetric(@Metric int id) { if (id < UNKNOWN_DELAY_DURATION || id > DEADLINE) { if (id < UNKNOWN_DELAY_DURATION || id > (Flags.jankApi() ? FRAME_TIMELINE_VSYNC_ID : DEADLINE)) { return -1; } Loading @@ -351,6 +365,8 @@ public final class FrameMetrics { return mTimingData[Index.INTENDED_VSYNC]; } else if (id == VSYNC_TIMESTAMP) { return mTimingData[Index.VSYNC]; } else if (id == FRAME_TIMELINE_VSYNC_ID) { return mTimingData[Index.FRAME_TIMELINE_VSYNC_ID]; } int durationsIdx = 2 * id; Loading @@ -358,4 +374,3 @@ public final class FrameMetrics { - mTimingData[DURATIONS[durationsIdx]]; } } core/java/android/view/SurfaceControl.java +139 −25 Original line number Diff line number Diff line Loading @@ -411,8 +411,19 @@ public final class SurfaceControl implements Parcelable { /** * Jank information to be fed back via {@link OnJankDataListener}. * @hide * <p> * Apps may register a {@link OnJankDataListener} to get periodic batches of jank classification * data from the (<a * href="https://source.android.com/docs/core/graphics/surfaceflinger-windowmanagersystem"> * composer</a> regarding rendered frames. A frame is considered janky if it did not reach the * display at the intended time, typically due to missing a rendering deadline. This API * provides information that can be used to identify the root cause of the scheduling misses * and provides overall frame scheduling statistics. * <p> * This API can be used in conjunction with the {@link FrameMetrics} API by associating jank * classification data with {@link FrameMetrics} data via the frame VSync id. */ @FlaggedApi(Flags.FLAG_JANK_API) public static class JankData { /** Loading @@ -429,29 +440,105 @@ public final class SurfaceControl implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface JankType {} // No Jank /** * No jank detected, the frame was on time. */ public static final int JANK_NONE = 0; // Jank caused by the composer missing a deadline /** * Bitmask for jank due to deadlines missed by the composer. */ public static final int JANK_COMPOSER = 1 << 0; // Jank caused by the application missing the composer's deadline /** * Bitmask for jank due to deadlines missed by the application. */ public static final int JANK_APPLICATION = 1 << 1; // Jank due to other unknown reasons /** * Bitmask for jank due to deadlines missed by other system components. */ public static final int JANK_OTHER = 1 << 2; private final long mFrameVsyncId; private final @JankType int mJankType; private final long mFrameIntervalNs; private final long mScheduledAppFrameTimeNs; private final long mActualAppFrameTimeNs; /** * @hide */ public JankData(long frameVsyncId, @JankType int jankType, long frameIntervalNs, long scheduledAppFrameTimeNs, long actualAppFrameTimeNs) { this.frameVsyncId = frameVsyncId; this.jankType = jankType; this.frameIntervalNs = frameIntervalNs; this.scheduledAppFrameTimeNs = scheduledAppFrameTimeNs; this.actualAppFrameTimeNs = actualAppFrameTimeNs; mFrameVsyncId = frameVsyncId; mJankType = jankType; mFrameIntervalNs = frameIntervalNs; mScheduledAppFrameTimeNs = scheduledAppFrameTimeNs; mActualAppFrameTimeNs = actualAppFrameTimeNs; } /** * Returns the id of the frame for this jank classification. * * @see FrameMetrics#FRAME_TIMELINE_VSYNC_ID * @see Choreographer.FrameTimeline#getVsyncId * @see Transaction#setFrameTimeline * @return the frame id */ public long getVsyncId() { return mFrameVsyncId; } /** * Returns the bitmask indicating the types of jank observed. * * @return the jank type bitmask */ public @JankType int getJankType() { return mJankType; } public final long frameVsyncId; public final @JankType int jankType; public final long frameIntervalNs; public final long scheduledAppFrameTimeNs; public final long actualAppFrameTimeNs; /** * Returns the time between frame VSyncs in nanoseconds. * * @return the frame interval in ns * @hide */ public long getFrameIntervalNanos() { return mFrameIntervalNs; } /** * Returns the duration in nanoseconds the application was scheduled to use to render this * frame. * <p> * Note that this may be higher than the frame interval to allow for CPU/GPU * parallelization of work. * * @return scheduled app time in ns */ public long getScheduledAppFrameTimeNanos() { return mScheduledAppFrameTimeNs; } /** * Returns the actual time in nanoseconds taken by the application to render this frame. * * @return the actual app time in ns */ public long getActualAppFrameTimeNanos() { return mActualAppFrameTimeNs; } @Override public String toString() { return "JankData{vsync=" + mFrameVsyncId + ", jankType=0x" + Integer.toHexString(mJankType) + ", frameInterval=" + mFrameIntervalNs + "ns" + ", scheduledAppTime=" + mScheduledAppFrameTimeNs + "ns" + ", actualAppTime=" + mActualAppFrameTimeNs + "ns}"; } } /** Loading @@ -459,12 +546,13 @@ public final class SurfaceControl implements Parcelable { * surface. * * @see JankData * @see #addJankDataListener * @hide * @see #addOnJankDataListener */ @FlaggedApi(Flags.FLAG_JANK_API) public interface OnJankDataListener { /** * Called when new jank classifications are available. * Called when new jank classifications are available. The listener is invoked out of band * of the rendered frames with jank classification data for a batch of frames. */ void onJankDataAvailable(@NonNull List<JankData> jankData); Loading @@ -472,9 +560,22 @@ public final class SurfaceControl implements Parcelable { /** * Handle to a registered {@link OnJankDatalistener}. * @hide */ @FlaggedApi(Flags.FLAG_JANK_API) public static class OnJankDataListenerRegistration { /** @hide */ public static final OnJankDataListenerRegistration NONE = new OnJankDataListenerRegistration() { @Override public void flush() {} @Override public void removeAfter(long afterVsync) {} @Override public void release() {} }; private final long mNativeObject; private static final NativeAllocationRegistry sRegistry = Loading @@ -485,6 +586,11 @@ public final class SurfaceControl implements Parcelable { private final Runnable mFreeNativeResources; private boolean mRemoved = false; private OnJankDataListenerRegistration() { mNativeObject = 0; mFreeNativeResources = () -> {}; } OnJankDataListenerRegistration(SurfaceControl surface, OnJankDataListener listener) { mNativeObject = nativeCreateJankDataListenerWrapper(surface.mNativeObject, listener); mFreeNativeResources = (mNativeObject == 0) ? () -> {} : Loading @@ -500,10 +606,17 @@ public final class SurfaceControl implements Parcelable { } /** * Request the removal of the registered listener after the VSync with the provided ID. Use * a value <= 0 for afterVsync to remove the listener immediately. The given listener will * not be removed before the given VSync, but may still reveive data for frames past the * provided VSync. * Schedule the removal of the registered listener after the frame with the provided id. * <p> * Because jank classification is only possible after frames have been displayed, the * callbacks are always delayed. To ensure receipt of all jank classification data, an * application can schedule the removal to happen no sooner than after the data for the * frame with the provided id has been provided. * <p> * Use a value <= 0 for afterVsync to remove the listener immediately, ensuring no future * callbacks. * * @param afterVsync the id of the Vsync after which to remove the listener */ public void removeAfter(long afterVsync) { mRemoved = true; Loading @@ -512,6 +625,7 @@ public final class SurfaceControl implements Parcelable { /** * Free the native resources associated with the listener registration. * @hide */ public void release() { if (!mRemoved) { Loading Loading
core/api/current.txt +22 −0 Original line number Diff line number Diff line Loading @@ -51406,6 +51406,7 @@ package android.view { method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl); method public default int getBufferTransformHint(); method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.window.InputTransferToken getInputTransferToken(); method @FlaggedApi("com.android.window.flags.jank_api") @NonNull public default android.view.SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.OnJankDataListener); method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener); method public default void setChildBoundingInsets(@NonNull android.graphics.Rect); method public default void setTouchableRegion(@Nullable android.graphics.Region); Loading Loading @@ -51663,6 +51664,7 @@ package android.view { field public static final int DEADLINE = 13; // 0xd field public static final int DRAW_DURATION = 4; // 0x4 field public static final int FIRST_DRAW_FRAME = 9; // 0x9 field @FlaggedApi("com.android.window.flags.jank_api") public static final int FRAME_TIMELINE_VSYNC_ID = 14; // 0xe field public static final int GPU_DURATION = 12; // 0xc field public static final int INPUT_HANDLING_DURATION = 1; // 0x1 field public static final int INTENDED_VSYNC_TIMESTAMP = 10; // 0xa Loading Loading @@ -53100,6 +53102,26 @@ package android.view { method @NonNull public android.view.SurfaceControl.Builder setParent(@Nullable android.view.SurfaceControl); } @FlaggedApi("com.android.window.flags.jank_api") public static class SurfaceControl.JankData { method public long getActualAppFrameTimeNanos(); method public int getJankType(); method public long getScheduledAppFrameTimeNanos(); method public long getVsyncId(); field public static final int JANK_APPLICATION = 2; // 0x2 field public static final int JANK_COMPOSER = 1; // 0x1 field public static final int JANK_NONE = 0; // 0x0 field public static final int JANK_OTHER = 4; // 0x4 } @FlaggedApi("com.android.window.flags.jank_api") public static interface SurfaceControl.OnJankDataListener { method public void onJankDataAvailable(@NonNull java.util.List<android.view.SurfaceControl.JankData>); } @FlaggedApi("com.android.window.flags.jank_api") public static class SurfaceControl.OnJankDataListenerRegistration { method public void flush(); method public void removeAfter(long); } public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable { ctor public SurfaceControl.Transaction(); method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener);
core/java/android/app/jank/JankDataProcessor.java +6 −6 Original line number Diff line number Diff line Loading @@ -70,8 +70,8 @@ public class JankDataProcessor { for (int j = 0; j < mPendingStates.size(); j++) { StateData pendingState = mPendingStates.get(j); // This state was active during the frame if (frame.frameVsyncId >= pendingState.mVsyncIdStart && frame.frameVsyncId <= pendingState.mVsyncIdEnd) { if (frame.getVsyncId() >= pendingState.mVsyncIdStart && frame.getVsyncId() <= pendingState.mVsyncIdEnd) { recordFrameCount(frame, pendingState, activityName, appUid); pendingState.mProcessed = true; Loading Loading @@ -131,14 +131,14 @@ public class JankDataProcessor { mPendingJankStats.put(stateData.mStateDataKey, jankStats); } // This state has already been accounted for if (jankStats.processedVsyncId == frameData.frameVsyncId) return; if (jankStats.processedVsyncId == frameData.getVsyncId()) return; jankStats.mTotalFrames += 1; if (frameData.jankType == JankData.JANK_APPLICATION) { if ((frameData.getJankType() & JankData.JANK_APPLICATION) != 0) { jankStats.mJankyFrames += 1; } jankStats.recordFrameOverrun(frameData.actualAppFrameTimeNs); jankStats.processedVsyncId = frameData.frameVsyncId; jankStats.recordFrameOverrun(frameData.getActualAppFrameTimeNanos()); jankStats.processedVsyncId = frameData.getVsyncId(); } Loading
core/java/android/view/AttachedSurfaceControl.java +21 −0 Original line number Diff line number Diff line Loading @@ -15,9 +15,11 @@ */ package android.view; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UiThread; import android.content.Context; import android.graphics.Rect; Loading @@ -29,6 +31,8 @@ import android.window.SurfaceSyncGroup; import com.android.window.flags.Flags; import java.util.concurrent.Executor; /** * Provides an interface to the root-Surface of a View Hierarchy or Window. This * is used in combination with the {@link android.view.SurfaceControl} API to enable Loading Loading @@ -202,4 +206,21 @@ public interface AttachedSurfaceControl { throw new UnsupportedOperationException("The getInputTransferToken needs to be " + "implemented before making this call."); } /** * Registers a {@link OnJankDataListener} to receive jank classification data about rendered * frames. * * @param executor The executor on which the listener will be invoked. * @param listener The listener to add. * @return The {@link OnJankDataListenerRegistration} for the listener. */ @NonNull @FlaggedApi(Flags.FLAG_JANK_API) @SuppressLint("PairedRegistration") default SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener( @NonNull @CallbackExecutor Executor executor, @NonNull SurfaceControl.OnJankDataListener listener) { return SurfaceControl.OnJankDataListenerRegistration.NONE; } }
core/java/android/view/FrameMetrics.java +17 −2 Original line number Diff line number Diff line Loading @@ -18,10 +18,13 @@ package android.view; import static android.graphics.FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import com.android.window.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -176,6 +179,16 @@ public final class FrameMetrics { **/ public static final int DEADLINE = 13; /** * Metric identifier for the frame's VSync identifier. * <p> * The id that corresponds to the chosen frame timeline, used to correlate a frame produced * by HWUI with the timeline data from the compositor. * </p> */ @FlaggedApi(Flags.FLAG_JANK_API) public static final int FRAME_TIMELINE_VSYNC_ID = 14; /** * Identifiers for metrics available for each frame. * Loading Loading @@ -337,7 +350,8 @@ public final class FrameMetrics { * @return the value of the metric or -1 if it is not available. */ public long getMetric(@Metric int id) { if (id < UNKNOWN_DELAY_DURATION || id > DEADLINE) { if (id < UNKNOWN_DELAY_DURATION || id > (Flags.jankApi() ? FRAME_TIMELINE_VSYNC_ID : DEADLINE)) { return -1; } Loading @@ -351,6 +365,8 @@ public final class FrameMetrics { return mTimingData[Index.INTENDED_VSYNC]; } else if (id == VSYNC_TIMESTAMP) { return mTimingData[Index.VSYNC]; } else if (id == FRAME_TIMELINE_VSYNC_ID) { return mTimingData[Index.FRAME_TIMELINE_VSYNC_ID]; } int durationsIdx = 2 * id; Loading @@ -358,4 +374,3 @@ public final class FrameMetrics { - mTimingData[DURATIONS[durationsIdx]]; } }
core/java/android/view/SurfaceControl.java +139 −25 Original line number Diff line number Diff line Loading @@ -411,8 +411,19 @@ public final class SurfaceControl implements Parcelable { /** * Jank information to be fed back via {@link OnJankDataListener}. * @hide * <p> * Apps may register a {@link OnJankDataListener} to get periodic batches of jank classification * data from the (<a * href="https://source.android.com/docs/core/graphics/surfaceflinger-windowmanagersystem"> * composer</a> regarding rendered frames. A frame is considered janky if it did not reach the * display at the intended time, typically due to missing a rendering deadline. This API * provides information that can be used to identify the root cause of the scheduling misses * and provides overall frame scheduling statistics. * <p> * This API can be used in conjunction with the {@link FrameMetrics} API by associating jank * classification data with {@link FrameMetrics} data via the frame VSync id. */ @FlaggedApi(Flags.FLAG_JANK_API) public static class JankData { /** Loading @@ -429,29 +440,105 @@ public final class SurfaceControl implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface JankType {} // No Jank /** * No jank detected, the frame was on time. */ public static final int JANK_NONE = 0; // Jank caused by the composer missing a deadline /** * Bitmask for jank due to deadlines missed by the composer. */ public static final int JANK_COMPOSER = 1 << 0; // Jank caused by the application missing the composer's deadline /** * Bitmask for jank due to deadlines missed by the application. */ public static final int JANK_APPLICATION = 1 << 1; // Jank due to other unknown reasons /** * Bitmask for jank due to deadlines missed by other system components. */ public static final int JANK_OTHER = 1 << 2; private final long mFrameVsyncId; private final @JankType int mJankType; private final long mFrameIntervalNs; private final long mScheduledAppFrameTimeNs; private final long mActualAppFrameTimeNs; /** * @hide */ public JankData(long frameVsyncId, @JankType int jankType, long frameIntervalNs, long scheduledAppFrameTimeNs, long actualAppFrameTimeNs) { this.frameVsyncId = frameVsyncId; this.jankType = jankType; this.frameIntervalNs = frameIntervalNs; this.scheduledAppFrameTimeNs = scheduledAppFrameTimeNs; this.actualAppFrameTimeNs = actualAppFrameTimeNs; mFrameVsyncId = frameVsyncId; mJankType = jankType; mFrameIntervalNs = frameIntervalNs; mScheduledAppFrameTimeNs = scheduledAppFrameTimeNs; mActualAppFrameTimeNs = actualAppFrameTimeNs; } /** * Returns the id of the frame for this jank classification. * * @see FrameMetrics#FRAME_TIMELINE_VSYNC_ID * @see Choreographer.FrameTimeline#getVsyncId * @see Transaction#setFrameTimeline * @return the frame id */ public long getVsyncId() { return mFrameVsyncId; } /** * Returns the bitmask indicating the types of jank observed. * * @return the jank type bitmask */ public @JankType int getJankType() { return mJankType; } public final long frameVsyncId; public final @JankType int jankType; public final long frameIntervalNs; public final long scheduledAppFrameTimeNs; public final long actualAppFrameTimeNs; /** * Returns the time between frame VSyncs in nanoseconds. * * @return the frame interval in ns * @hide */ public long getFrameIntervalNanos() { return mFrameIntervalNs; } /** * Returns the duration in nanoseconds the application was scheduled to use to render this * frame. * <p> * Note that this may be higher than the frame interval to allow for CPU/GPU * parallelization of work. * * @return scheduled app time in ns */ public long getScheduledAppFrameTimeNanos() { return mScheduledAppFrameTimeNs; } /** * Returns the actual time in nanoseconds taken by the application to render this frame. * * @return the actual app time in ns */ public long getActualAppFrameTimeNanos() { return mActualAppFrameTimeNs; } @Override public String toString() { return "JankData{vsync=" + mFrameVsyncId + ", jankType=0x" + Integer.toHexString(mJankType) + ", frameInterval=" + mFrameIntervalNs + "ns" + ", scheduledAppTime=" + mScheduledAppFrameTimeNs + "ns" + ", actualAppTime=" + mActualAppFrameTimeNs + "ns}"; } } /** Loading @@ -459,12 +546,13 @@ public final class SurfaceControl implements Parcelable { * surface. * * @see JankData * @see #addJankDataListener * @hide * @see #addOnJankDataListener */ @FlaggedApi(Flags.FLAG_JANK_API) public interface OnJankDataListener { /** * Called when new jank classifications are available. * Called when new jank classifications are available. The listener is invoked out of band * of the rendered frames with jank classification data for a batch of frames. */ void onJankDataAvailable(@NonNull List<JankData> jankData); Loading @@ -472,9 +560,22 @@ public final class SurfaceControl implements Parcelable { /** * Handle to a registered {@link OnJankDatalistener}. * @hide */ @FlaggedApi(Flags.FLAG_JANK_API) public static class OnJankDataListenerRegistration { /** @hide */ public static final OnJankDataListenerRegistration NONE = new OnJankDataListenerRegistration() { @Override public void flush() {} @Override public void removeAfter(long afterVsync) {} @Override public void release() {} }; private final long mNativeObject; private static final NativeAllocationRegistry sRegistry = Loading @@ -485,6 +586,11 @@ public final class SurfaceControl implements Parcelable { private final Runnable mFreeNativeResources; private boolean mRemoved = false; private OnJankDataListenerRegistration() { mNativeObject = 0; mFreeNativeResources = () -> {}; } OnJankDataListenerRegistration(SurfaceControl surface, OnJankDataListener listener) { mNativeObject = nativeCreateJankDataListenerWrapper(surface.mNativeObject, listener); mFreeNativeResources = (mNativeObject == 0) ? () -> {} : Loading @@ -500,10 +606,17 @@ public final class SurfaceControl implements Parcelable { } /** * Request the removal of the registered listener after the VSync with the provided ID. Use * a value <= 0 for afterVsync to remove the listener immediately. The given listener will * not be removed before the given VSync, but may still reveive data for frames past the * provided VSync. * Schedule the removal of the registered listener after the frame with the provided id. * <p> * Because jank classification is only possible after frames have been displayed, the * callbacks are always delayed. To ensure receipt of all jank classification data, an * application can schedule the removal to happen no sooner than after the data for the * frame with the provided id has been provided. * <p> * Use a value <= 0 for afterVsync to remove the listener immediately, ensuring no future * callbacks. * * @param afterVsync the id of the Vsync after which to remove the listener */ public void removeAfter(long afterVsync) { mRemoved = true; Loading @@ -512,6 +625,7 @@ public final class SurfaceControl implements Parcelable { /** * Free the native resources associated with the listener registration. * @hide */ public void release() { if (!mRemoved) { Loading