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

Commit d407190b authored by Steven Thomas's avatar Steven Thomas
Browse files

Add frame rate flexibility token

Add support for temporarily relaxing frame rate restrictions in surface
flinger. This is used by CTS tests to get a consistent device state
while running frame rate tests.

Bug: 148033900

Test: - On a Pixel 4, I turned the brightness down and covered the
ambient light sensor, causing the display manager to set a frame rate
restriction. I ran the frame rate CTS test without these CLs applied,
and confirmed the test failed because surface flinger couldn't switch
frame rates, as expected. Then I ran the tests with the CLs applied, and
confirmed the tests pass.

- I confirmed that, without adopting shell permission identity, the CTS
test is denied the request to acquire a frame rate flexibility token. So
normal apps won't be able to access this.

Change-Id: I6685edc4bc07c7888b79a9dd72a90f56b74e7604
parent 4e2936c2
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -1145,6 +1145,42 @@ public:
            ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err);
            return err;
        }

        return reply.readInt32();
    }

    virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) {
        if (!outToken) return BAD_VALUE;

        Parcel data, reply;
        status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
        if (err != NO_ERROR) {
            ALOGE("acquireFrameRateFlexibilityToken: failed writing interface token: %s (%d)",
                  strerror(-err), -err);
            return err;
        }

        err = remote()->transact(BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, data,
                                 &reply);
        if (err != NO_ERROR) {
            ALOGE("acquireFrameRateFlexibilityToken: failed to transact: %s (%d)", strerror(-err),
                  err);
            return err;
        }

        err = reply.readInt32();
        if (err != NO_ERROR) {
            ALOGE("acquireFrameRateFlexibilityToken: call failed: %s (%d)", strerror(-err), err);
            return err;
        }

        err = reply.readStrongBinder(outToken);
        if (err != NO_ERROR) {
            ALOGE("acquireFrameRateFlexibilityToken: failed reading binder token: %s (%d)",
                  strerror(-err), err);
            return err;
        }

        return NO_ERROR;
    }
};
@@ -1945,6 +1981,16 @@ status_t BnSurfaceComposer::onTransact(
            reply->writeInt32(result);
            return NO_ERROR;
        }
        case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<IBinder> token;
            status_t result = acquireFrameRateFlexibilityToken(&token);
            reply->writeInt32(result);
            if (result == NO_ERROR) {
                reply->writeStrongBinder(token);
            }
            return NO_ERROR;
        }
        default: {
            return BBinder::onTransact(code, data, reply, flags);
        }
+9 −0
Original line number Diff line number Diff line
@@ -508,6 +508,14 @@ public:
     */
    virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
                                  int8_t compatibility) = 0;

    /*
     * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired,
     * surface flinger will freely switch between frame rates in any way it sees fit, regardless of
     * the current restrictions applied by DisplayManager. This is useful to get consistent behavior
     * for tests. Release the token by releasing the returned IBinder reference.
     */
    virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) = 0;
};

// ----------------------------------------------------------------------------
@@ -566,6 +574,7 @@ public:
        GET_GAME_CONTENT_TYPE_SUPPORT,
        SET_GAME_CONTENT_TYPE,
        SET_FRAME_RATE,
        ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
        // Always append new enum to the end.
    };

+2 −0
Original line number Diff line number Diff line
@@ -859,6 +859,8 @@ public:
        return NO_ERROR;
    }

    status_t acquireFrameRateFlexibilityToken(sp<IBinder>* /*outToken*/) { return NO_ERROR; }

protected:
    IBinder* onAsBinder() override { return nullptr; }

+57 −29
Original line number Diff line number Diff line
@@ -301,7 +301,7 @@ const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() con
                  mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
        return *mCurrentRefreshRate;
    }
    return *mRefreshRates.at(mDefaultConfig);
    return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig);
}

void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
@@ -326,38 +326,59 @@ RefreshRateConfigs::RefreshRateConfigs(
    init(inputConfigs, currentConfigId);
}

status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
                                       float maxRefreshRate, bool* outPolicyChanged) {
bool RefreshRateConfigs::isPolicyValid(const Policy& policy) {
    // defaultConfig must be a valid config, and within the given refresh rate range.
    auto iter = mRefreshRates.find(policy.defaultConfig);
    if (iter == mRefreshRates.end()) {
        return false;
    }
    const RefreshRate& refreshRate = *iter->second;
    if (!refreshRate.inPolicy(policy.minRefreshRate, policy.maxRefreshRate)) {
        return false;
    }
    return true;
}

status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
    std::lock_guard lock(mLock);
    bool policyChanged = defaultConfigId != mDefaultConfig ||
            minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps;
    if (outPolicyChanged) {
        *outPolicyChanged = policyChanged;
    if (!isPolicyValid(policy)) {
        return BAD_VALUE;
    }
    if (!policyChanged) {
    Policy previousPolicy = *getCurrentPolicyLocked();
    mDisplayManagerPolicy = policy;
    if (*getCurrentPolicyLocked() == previousPolicy) {
        return CURRENT_POLICY_UNCHANGED;
    }
    constructAvailableRefreshRates();
    return NO_ERROR;
}
    // defaultConfigId must be a valid config ID, and within the given refresh rate range.
    if (mRefreshRates.count(defaultConfigId) == 0) {

status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& policy) {
    std::lock_guard lock(mLock);
    if (policy && !isPolicyValid(*policy)) {
        return BAD_VALUE;
    }
    const RefreshRate& refreshRate = *mRefreshRates.at(defaultConfigId);
    if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
        return BAD_VALUE;
    Policy previousPolicy = *getCurrentPolicyLocked();
    mOverridePolicy = policy;
    if (*getCurrentPolicyLocked() == previousPolicy) {
        return CURRENT_POLICY_UNCHANGED;
    }
    mDefaultConfig = defaultConfigId;
    mMinRefreshRateFps = minRefreshRate;
    mMaxRefreshRateFps = maxRefreshRate;
    constructAvailableRefreshRates();
    return NO_ERROR;
}

void RefreshRateConfigs::getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
                                   float* maxRefreshRate) const {
const RefreshRateConfigs::Policy* RefreshRateConfigs::getCurrentPolicyLocked() const {
    return mOverridePolicy ? &mOverridePolicy.value() : &mDisplayManagerPolicy;
}

RefreshRateConfigs::Policy RefreshRateConfigs::getCurrentPolicy() const {
    std::lock_guard lock(mLock);
    *defaultConfigId = mDefaultConfig;
    *minRefreshRate = mMinRefreshRateFps;
    *maxRefreshRate = mMaxRefreshRateFps;
    return *getCurrentPolicyLocked();
}

RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const {
    std::lock_guard lock(mLock);
    return mDisplayManagerPolicy;
}

bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
@@ -385,19 +406,25 @@ void RefreshRateConfigs::getSortedRefreshRateList(

    std::sort(outRefreshRates->begin(), outRefreshRates->end(),
              [](const auto refreshRate1, const auto refreshRate2) {
                  if (refreshRate1->vsyncPeriod != refreshRate2->vsyncPeriod) {
                      return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
                  } else {
                      return refreshRate1->configGroup > refreshRate2->configGroup;
                  }
              });
}

void RefreshRateConfigs::constructAvailableRefreshRates() {
    // Filter configs based on current policy and sort based on vsync period
    HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig)->configGroup;
    const Policy* policy = getCurrentPolicyLocked();
    HwcConfigGroupType group = mRefreshRates.at(policy->defaultConfig)->configGroup;
    ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
          mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
          policy->defaultConfig.value(), group.value(), policy->minRefreshRate,
          policy->maxRefreshRate);
    getSortedRefreshRateList(
            [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
                return refreshRate.configGroup == group &&
                        refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps);
                return (policy->allowGroupSwitching || refreshRate.configGroup == group) &&
                        refreshRate.inPolicy(policy->minRefreshRate, policy->maxRefreshRate);
            },
            &mAvailableRefreshRates);

@@ -409,7 +436,8 @@ void RefreshRateConfigs::constructAvailableRefreshRates() {
    ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
    LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
                        "No compatible display configs for default=%d min=%.0f max=%.0f",
                        mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
                        policy->defaultConfig.value(), policy->minRefreshRate,
                        policy->maxRefreshRate);
}

// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor
@@ -432,7 +460,7 @@ void RefreshRateConfigs::init(const std::vector<InputConfig>& configs,

    std::vector<const RefreshRate*> sortedConfigs;
    getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
    mDefaultConfig = currentHwcConfig;
    mDisplayManagerPolicy.defaultConfig = currentHwcConfig;
    mMinSupportedRefreshRate = sortedConfigs.front();
    mMaxSupportedRefreshRate = sortedConfigs.back();
    constructAvailableRefreshRates();
+49 −16
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include <algorithm>
#include <numeric>
#include <optional>
#include <type_traits>

#include "DisplayHardware/HWComposer.h"
@@ -90,14 +91,47 @@ public:
    using AllRefreshRatesMapType =
            std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;

    // Sets the current policy to choose refresh rates. Returns NO_ERROR if the requested policy is
    // valid, or a negative error value otherwise. policyChanged, if non-null, will be set to true
    // if the new policy is different from the old policy.
    status_t setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
                       float maxRefreshRate, bool* policyChanged) EXCLUDES(mLock);
    // Gets the current policy.
    void getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
                   float* maxRefreshRate) const EXCLUDES(mLock);
    struct Policy {
        // The default config, used to ensure we only initiate display config switches within the
        // same config group as defaultConfigId's group.
        HwcConfigIndexType defaultConfig;
        // The min and max FPS allowed by the policy.
        float minRefreshRate = 0;
        float maxRefreshRate = std::numeric_limits<float>::max();
        // Whether or not we switch config groups to get the best frame rate. Only used by tests.
        bool allowGroupSwitching = false;

        bool operator==(const Policy& other) const {
            return defaultConfig == other.defaultConfig && minRefreshRate == other.minRefreshRate &&
                    maxRefreshRate == other.maxRefreshRate &&
                    allowGroupSwitching == other.allowGroupSwitching;
        }

        bool operator!=(const Policy& other) const { return !(*this == other); }
    };

    // Return code set*Policy() to indicate the current policy is unchanged.
    static constexpr int CURRENT_POLICY_UNCHANGED = 1;

    // We maintain the display manager policy and the override policy separately. The override
    // policy is used by CTS tests to get a consistent device state for testing. While the override
    // policy is set, it takes precedence over the display manager policy. Once the override policy
    // is cleared, we revert to using the display manager policy.

    // Sets the display manager policy to choose refresh rates. The return value will be:
    //   - A negative value if the policy is invalid or another error occurred.
    //   - NO_ERROR if the policy was successfully updated, and the current policy is different from
    //     what it was before the call.
    //   - CURRENT_POLICY_UNCHANGED if the policy was successfully updated, but the current policy
    //     is the same as it was before the call.
    status_t setDisplayManagerPolicy(const Policy& policy) EXCLUDES(mLock);
    // Sets the override policy. See setDisplayManagerPolicy() for the meaning of the return value.
    status_t setOverridePolicy(const std::optional<Policy>& policy) EXCLUDES(mLock);
    // Gets the current policy, which will be the override policy if active, and the display manager
    // policy otherwise.
    Policy getCurrentPolicy() const EXCLUDES(mLock);
    // Gets the display manager policy, regardless of whether an override policy is active.
    Policy getDisplayManagerPolicy() const EXCLUDES(mLock);

    // Returns true if config is allowed by the current policy.
    bool isConfigAllowed(HwcConfigIndexType config) const EXCLUDES(mLock);
@@ -208,6 +242,9 @@ private:
    // the policy.
    const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock);

    const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
    bool isPolicyValid(const Policy& policy);

    // The list of refresh rates, indexed by display config ID. This must not change after this
    // object is initialized.
    AllRefreshRatesMapType mRefreshRates;
@@ -220,14 +257,10 @@ private:
    // the main thread, and read by the Scheduler (and other objects) on other threads.
    const RefreshRate* mCurrentRefreshRate GUARDED_BY(mLock);

    // The default config. This will change at runtime. This is set by SurfaceFlinger on
    // the main thread, and read by the Scheduler (and other objects) on other threads.
    HwcConfigIndexType mDefaultConfig GUARDED_BY(mLock);

    // The min and max FPS allowed by the policy. This will change at runtime and set by
    // SurfaceFlinger on the main thread.
    float mMinRefreshRateFps GUARDED_BY(mLock) = 0;
    float mMaxRefreshRateFps GUARDED_BY(mLock) = std::numeric_limits<float>::max();
    // The policy values will change at runtime. They're set by SurfaceFlinger on the main thread,
    // and read by the Scheduler (and other objects) on other threads.
    Policy mDisplayManagerPolicy GUARDED_BY(mLock);
    std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);

    // The min and max refresh rates supported by the device.
    // This will not change at runtime.
Loading