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

Commit 067dd921 authored by George Mount's avatar George Mount
Browse files

[VRR] Clear frame rate and category after 250ms idle

Fixes: 338586840

An idle app won't change its category or frame rate while idle.
Howver, that app will still vote with SurfaceFlinger if it is
on screen, even if ocluded.

This CL adds a timeout of 250ms for detecting idle time. If
the time has passed without drawing, the category and frame
rate will reset.

Test: new test, manual testing
Change-Id: Ifc6d81ee8ed97dad7dc9ed5d9a856149a40d8584
parent 025d7cd8
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -423,6 +423,12 @@ public final class ViewRootImpl implements ViewParent,
    private static final long NANOS_PER_SEC = 1000000000;
    // If the ViewRootImpl has been idle for more than 200ms, clear the preferred
    // frame rate category and frame rate.
    private static final int IDLE_TIME_MILLIS = 250;
    private static final long NANOS_PER_MILLI = 1_000_000;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
@@ -655,6 +661,8 @@ public final class ViewRootImpl implements ViewParent,
    private int mMinusOneFrameIntervalMillis = 0;
    // VRR interval between the previous and the frame before
    private int mMinusTwoFrameIntervalMillis = 0;
    // VRR has the invalidation idle message been posted?
    private boolean mInvalidationIdleMessagePosted = false;
    /**
     * Update the Choreographer's FrameInfo object with the timing information for the current
@@ -4266,6 +4274,10 @@ public final class ViewRootImpl implements ViewParent,
        // when the values are applicable.
        if (mDrawnThisFrame) {
            mDrawnThisFrame = false;
            if (!mInvalidationIdleMessagePosted) {
                mInvalidationIdleMessagePosted = true;
                mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS);
            }
            setCategoryFromCategoryCounts();
            updateInfrequentCount();
            setPreferredFrameRate(mPreferredFrameRate);
@@ -6507,6 +6519,8 @@ public final class ViewRootImpl implements ViewParent,
                    return "MSG_WINDOW_TOUCH_MODE_CHANGED";
                case MSG_KEEP_CLEAR_RECTS_CHANGED:
                    return "MSG_KEEP_CLEAR_RECTS_CHANGED";
                case MSG_CHECK_INVALIDATION_IDLE:
                    return "MSG_CHECK_INVALIDATION_IDLE";
                case MSG_REFRESH_POINTER_ICON:
                    return "MSG_REFRESH_POINTER_ICON";
                case MSG_TOUCH_BOOST_TIMEOUT:
@@ -6771,6 +6785,30 @@ public final class ViewRootImpl implements ViewParent,
                    mNumPausedForSync = 0;
                    scheduleTraversals();
                    break;
                case MSG_CHECK_INVALIDATION_IDLE: {
                    long delta;
                    if (mIsTouchBoosting || mIsFrameRateBoosting || mInsetsAnimationRunning) {
                        delta = 0;
                    } else {
                        delta = System.nanoTime() / NANOS_PER_MILLI - mLastUpdateTimeMillis;
                    }
                    if (delta >= IDLE_TIME_MILLIS) {
                        mFrameRateCategoryHighCount = 0;
                        mFrameRateCategoryHighHintCount = 0;
                        mFrameRateCategoryNormalCount = 0;
                        mFrameRateCategoryLowCount = 0;
                        mPreferredFrameRate = 0;
                        mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
                        setPreferredFrameRateCategory(FRAME_RATE_CATEGORY_NO_PREFERENCE);
                        setPreferredFrameRate(0f);
                        mInvalidationIdleMessagePosted = false;
                    } else {
                        mInvalidationIdleMessagePosted = true;
                        mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
                                IDLE_TIME_MILLIS - delta);
                    }
                    break;
                }
                case MSG_TOUCH_BOOST_TIMEOUT:
                    /**
                     * Lower the frame rate after the boosting period (FRAME_RATE_TOUCH_BOOST_TIME).
@@ -13016,6 +13054,10 @@ public final class ViewRootImpl implements ViewParent,
    private void removeVrrMessages() {
        mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT);
        mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
        if (mInvalidationIdleMessagePosted) {
            mInvalidationIdleMessagePosted = false;
            mHandler.removeMessages(MSG_CHECK_INVALIDATION_IDLE);
        }
    }
    /**
+22 −0
Original line number Diff line number Diff line
@@ -623,6 +623,28 @@ public class ViewFrameRateTest {
        assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT, mViewRoot.getLastPreferredFrameRateCategory());
    }

    @Test
    @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
            FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY
    })
    public void idleDetected() throws Throwable {
        waitForFrameRateCategoryToSettle();
        mActivityRule.runOnUiThread(() -> {
            mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_HIGH);
            mMovingView.setFrameContentVelocity(Float.MAX_VALUE);
            mMovingView.invalidate();
            runAfterDraw(() -> assertEquals(FRAME_RATE_CATEGORY_HIGH,
                    mViewRoot.getLastPreferredFrameRateCategory()));
        });
        waitForAfterDraw();

        // Wait for idle timeout
        Thread.sleep(500);
        assertEquals(0f, mViewRoot.getLastPreferredFrameRate());
        assertEquals(FRAME_RATE_CATEGORY_NO_PREFERENCE,
                mViewRoot.getLastPreferredFrameRateCategory());
    }

    private void runAfterDraw(@NonNull Runnable runnable) {
        Handler handler = new Handler(Looper.getMainLooper());
        mAfterDrawLatch = new CountDownLatch(1);