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

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

Add the expected and actual frame duration to the SF jank data.

Adds the expected and actual frame duration, that is the frame durations
as shown in the frame timeline in Perfetto, to the jank data exposed by
SurfaceFlinger.

This reverts commit e0af07b8.

Bug: b/354763298
Test: FrameworksCoreTests manual
Flag: com.android.internal.jank.use_sf_frame_duration
Change-Id: I0b7a2baeb20cac2e0c012c3a54a79d43652c60fa
parent 5ff76a1a
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -445,16 +445,20 @@ public final class SurfaceControl implements Parcelable {
        // Jank due to unknown reasons.
        public static final int UNKNOWN = 0x80;

        public JankData(long frameVsyncId, @JankType int jankType, long frameIntervalNs) {
        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;
        }

        public final long frameVsyncId;
        public final @JankType int jankType;
        public final long frameIntervalNs;
        public final long scheduledAppFrameTimeNs;
        public final long actualAppFrameTimeNs;
    }

    /**
+28 −26
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
    private Runnable mWaitForFinishTimedOut;

    private static class JankInfo {
        long frameVsyncId;
        final long frameVsyncId;
        long totalDurationNanos;
        boolean isFirstFrame;
        boolean hwuiCallbackFired;
@@ -135,29 +135,37 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
        @JankType int jankType;
        @RefreshRate int refreshRate;

        static JankInfo createFromHwuiCallback(long frameVsyncId, long totalDurationNanos,
                boolean isFirstFrame) {
            return new JankInfo(frameVsyncId, true, false, JANK_NONE, UNKNOWN_REFRESH_RATE,
                    totalDurationNanos, isFirstFrame);
        static JankInfo createFromHwuiCallback(
                long frameVsyncId, long totalDurationNanos, boolean isFirstFrame) {
            return new JankInfo(frameVsyncId).update(totalDurationNanos, isFirstFrame);
        }

        static JankInfo createFromSurfaceControlCallback(long frameVsyncId,
                @JankType int jankType, @RefreshRate int refreshRate) {
            return new JankInfo(
                    frameVsyncId, false, true, jankType, refreshRate, 0, false /* isFirstFrame */);
        static JankInfo createFromSurfaceControlCallback(SurfaceControl.JankData jankStat) {
            return new JankInfo(jankStat.frameVsyncId).update(jankStat);
        }

        private JankInfo(long frameVsyncId, boolean hwuiCallbackFired,
                boolean surfaceControlCallbackFired, @JankType int jankType,
                @RefreshRate int refreshRate,
                long totalDurationNanos, boolean isFirstFrame) {
        private JankInfo(long frameVsyncId) {
            this.frameVsyncId = frameVsyncId;
            this.hwuiCallbackFired = hwuiCallbackFired;
            this.surfaceControlCallbackFired = surfaceControlCallbackFired;
            this.jankType = jankType;
            this.refreshRate = refreshRate;
            this.hwuiCallbackFired = false;
            this.surfaceControlCallbackFired = false;
            this.jankType = JANK_NONE;
            this.refreshRate = UNKNOWN_REFRESH_RATE;
            this.totalDurationNanos = 0;
            this.isFirstFrame = false;
        }

        private JankInfo update(SurfaceControl.JankData jankStat) {
            this.surfaceControlCallbackFired = true;
            this.jankType = jankStat.jankType;
            this.refreshRate = DisplayRefreshRate.getRefreshRate(jankStat.frameIntervalNs);
            return this;
        }

        private JankInfo update(long totalDurationNanos, boolean isFirstFrame) {
            this.hwuiCallbackFired = true;
            this.totalDurationNanos = totalDurationNanos;
            this.isFirstFrame = isFirstFrame;
            return this;
        }

        @Override
@@ -457,16 +465,12 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
                if (!isInRange(jankStat.frameVsyncId)) {
                    continue;
                }
                int refreshRate = DisplayRefreshRate.getRefreshRate(jankStat.frameIntervalNs);
                JankInfo info = findJankInfo(jankStat.frameVsyncId);
                if (info != null) {
                    info.surfaceControlCallbackFired = true;
                    info.jankType = jankStat.jankType;
                    info.refreshRate = refreshRate;
                    info.update(jankStat);
                } else {
                    mJankInfos.put((int) jankStat.frameVsyncId,
                            JankInfo.createFromSurfaceControlCallback(
                                    jankStat.frameVsyncId, jankStat.jankType, refreshRate));
                            JankInfo.createFromSurfaceControlCallback(jankStat));
                }
            }
            processJankInfos();
@@ -513,9 +517,7 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
            }
            JankInfo info = findJankInfo(frameVsyncId);
            if (info != null) {
                info.hwuiCallbackFired = true;
                info.totalDurationNanos = totalDurationNanos;
                info.isFirstFrame = isFirstFrame;
                info.update(totalDurationNanos, isFirstFrame);
            } else {
                mJankInfos.put((int) frameVsyncId, JankInfo.createFromHwuiCallback(
                        frameVsyncId, totalDurationNanos, isFirstFrame));
+6 −4
Original line number Diff line number Diff line
@@ -2089,9 +2089,11 @@ public:
        jobjectArray jJankDataArray = env->NewObjectArray(jankData.size(),
                gJankDataClassInfo.clazz, nullptr);
        for (size_t i = 0; i < jankData.size(); i++) {
            jobject jJankData = env->NewObject(gJankDataClassInfo.clazz, gJankDataClassInfo.ctor,
            jobject jJankData =
                    env->NewObject(gJankDataClassInfo.clazz, gJankDataClassInfo.ctor,
                                   jankData[i].frameVsyncId, jankData[i].jankType,
                                               jankData[i].frameIntervalNs);
                                   jankData[i].frameIntervalNs, jankData[i].scheduledAppFrameTimeNs,
                                   jankData[i].actualAppFrameTimeNs);
            env->SetObjectArrayElement(jJankDataArray, i, jJankData);
            env->DeleteLocalRef(jJankData);
        }
@@ -2727,7 +2729,7 @@ int register_android_view_SurfaceControl(JNIEnv* env)
    jclass jankDataClazz =
                FindClassOrDie(env, "android/view/SurfaceControl$JankData");
    gJankDataClassInfo.clazz = MakeGlobalRefOrDie(env, jankDataClazz);
    gJankDataClassInfo.ctor = GetMethodIDOrDie(env, gJankDataClassInfo.clazz, "<init>", "(JIJ)V");
    gJankDataClassInfo.ctor = GetMethodIDOrDie(env, gJankDataClassInfo.clazz, "<init>", "(JIJJJ)V");
    jclass onJankDataListenerClazz =
            FindClassOrDie(env, "android/view/SurfaceControl$OnJankDataListener");
    gJankDataListenerClassInfo.clazz = MakeGlobalRefOrDie(env, onJankDataListenerClazz);
+6 −4
Original line number Diff line number Diff line
@@ -359,7 +359,7 @@ public class FrameTrackerTest {
        tracker.end(FrameTracker.REASON_END_NORMAL);

        // Send incomplete callback for 102L
        sendSfFrame(tracker, 102L, JANK_NONE);
        sendSfFrame(tracker, 4, 102L, JANK_NONE);

        // Send janky but complete callbck fo 103L
        sendFrame(tracker, 50, JANK_APP_DEADLINE_MISSED, 103L);
@@ -629,7 +629,7 @@ public class FrameTrackerTest {
        if (!tracker.mSurfaceOnly) {
            sendHwuiFrame(tracker, durationMillis, vsyncId, firstWindowFrame);
        }
        sendSfFrame(tracker, vsyncId, jankType);
        sendSfFrame(tracker, durationMillis, vsyncId, jankType);
    }

    private void sendHwuiFrame(FrameTracker tracker, long durationMillis, long vsyncId,
@@ -645,11 +645,13 @@ public class FrameTrackerTest {
        captor.getValue().run();
    }

    private void sendSfFrame(FrameTracker tracker, long vsyncId, @JankType int jankType) {
    private void sendSfFrame(
            FrameTracker tracker, long durationMillis, long vsyncId, @JankType int jankType) {
        final ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
        doNothing().when(tracker).postCallback(captor.capture());
        mListenerCapture.getValue().onJankDataAvailable(new JankData[] {
                new JankData(vsyncId, jankType, FRAME_TIME_60Hz)
                new JankData(vsyncId, jankType, FRAME_TIME_60Hz, FRAME_TIME_60Hz,
                TimeUnit.MILLISECONDS.toNanos(durationMillis))
        });
        captor.getValue().run();
    }