Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e40857d9 authored by Pascal Mütschard's avatar Pascal Mütschard
Browse files

Make the Jank API public.

go/jank-api

Bug: b/293949943
Flag: com.android.window.flags.jank_api
Test: FrameworksCoreTests manual
API-Coverage-Bug: b/377704581
Change-Id: I39ba49b3063d1967f5360cfaab64437824940719
parent ca7ba1eb
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -51078,6 +51078,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);
@@ -51335,6 +51336,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
@@ -52753,6 +52755,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);
+6 −6
Original line number Diff line number Diff line
@@ -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;
@@ -123,14 +123,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();

    }

+21 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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;
    }
}
+17 −2
Original line number Diff line number Diff line
@@ -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;

@@ -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.
     *
@@ -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;
        }

@@ -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;
@@ -358,4 +374,3 @@ public final class FrameMetrics {
                - mTimingData[DURATIONS[durationsIdx]];
    }
}
+139 −25
Original line number Diff line number Diff line
@@ -409,8 +409,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 {

        /**
@@ -427,29 +438,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}";
        }
    }

    /**
@@ -457,12 +544,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);

@@ -470,9 +558,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 =
@@ -483,6 +584,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) ? () -> {} :
@@ -498,10 +604,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 &lt;= 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;
@@ -510,6 +623,7 @@ public final class SurfaceControl implements Parcelable {

        /**
         * Free the native resources associated with the listener registration.
         * @hide
         */
        public void release() {
            if (!mRemoved) {
Loading