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

Commit 7a6b51ce authored by Pascal Mütschard's avatar Pascal Mütschard Committed by Android (Google) Code Review
Browse files

Merge "Make the Jank API public." into main

parents 28103fd6 e40857d9
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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
@@ -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);
+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;
@@ -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();

    }

+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
@@ -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 {

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

    /**
@@ -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);

@@ -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 =
@@ -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) ? () -> {} :
@@ -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 &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;
@@ -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