diff options
| -rw-r--r-- | libs/gui/ISurfaceComposer.cpp | 46 | ||||
| -rw-r--r-- | libs/gui/include/gui/ISurfaceComposer.h | 9 | ||||
| -rw-r--r-- | libs/gui/tests/Surface_test.cpp | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp | 86 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/RefreshRateConfigs.h | 65 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 155 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 14 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp | 49 |
8 files changed, 334 insertions, 92 deletions
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8d79cf8723..bd4d62c4f7 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -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); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 09487eab8b..3cef25639f 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -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. }; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 8c0f8f8de9..ef1fd026f2 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -859,6 +859,8 @@ public: return NO_ERROR; } + status_t acquireFrameRateFlexibilityToken(sp<IBinder>* /*outToken*/) { return NO_ERROR; } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 02d0b5359c..14ef73335e 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -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) { - std::lock_guard lock(mLock); - bool policyChanged = defaultConfigId != mDefaultConfig || - minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps; - if (outPolicyChanged) { - *outPolicyChanged = policyChanged; +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; } - if (!policyChanged) { - return NO_ERROR; + const RefreshRate& refreshRate = *iter->second; + if (!refreshRate.inPolicy(policy.minRefreshRate, policy.maxRefreshRate)) { + return false; } - // defaultConfigId must be a valid config ID, and within the given refresh rate range. - if (mRefreshRates.count(defaultConfigId) == 0) { + return true; +} + +status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { + std::lock_guard lock(mLock); + if (!isPolicyValid(policy)) { return BAD_VALUE; } - const RefreshRate& refreshRate = *mRefreshRates.at(defaultConfigId); - if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) { + Policy previousPolicy = *getCurrentPolicyLocked(); + mDisplayManagerPolicy = policy; + if (*getCurrentPolicyLocked() == previousPolicy) { + return CURRENT_POLICY_UNCHANGED; + } + constructAvailableRefreshRates(); + return NO_ERROR; +} + +status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& policy) { + std::lock_guard lock(mLock); + if (policy && !isPolicyValid(*policy)) { return BAD_VALUE; } - mDefaultConfig = defaultConfigId; - mMinRefreshRateFps = minRefreshRate; - mMaxRefreshRateFps = maxRefreshRate; + Policy previousPolicy = *getCurrentPolicyLocked(); + mOverridePolicy = policy; + if (*getCurrentPolicyLocked() == previousPolicy) { + return CURRENT_POLICY_UNCHANGED; + } 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); + return *getCurrentPolicyLocked(); +} + +RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const { std::lock_guard lock(mLock); - *defaultConfigId = mDefaultConfig; - *minRefreshRate = mMinRefreshRateFps; - *maxRefreshRate = mMaxRefreshRateFps; + 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) { - return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; + 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(); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 87d43898d9..e749f8fb93 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -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. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index eb624ca737..4ceac4ef7e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -200,6 +200,15 @@ bool validateCompositionDataspace(Dataspace dataspace) { return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3; } +class FrameRateFlexibilityToken : public BBinder { +public: + FrameRateFlexibilityToken(std::function<void()> callback) : mCallback(callback) {} + virtual ~FrameRateFlexibilityToken() { mCallback(); } + +private: + std::function<void()> mCallback; +}; + } // namespace anonymous // --------------------------------------------------------------------------- @@ -977,8 +986,11 @@ status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mo } else { HwcConfigIndexType config(mode); const auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(config); - result = setDesiredDisplayConfigSpecsInternal(display, config, refreshRate.fps, - refreshRate.fps); + result = setDesiredDisplayConfigSpecsInternal(display, + scheduler::RefreshRateConfigs:: + Policy{config, refreshRate.fps, + refreshRate.fps}, + /*overridePolicy=*/false); } })); @@ -3505,12 +3517,13 @@ uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) { return flags; } -bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess() { +bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache) { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && - !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { + (usePermissionCache ? !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid) + : !checkPermission(sAccessSurfaceFlinger, pid, uid))) { return false; } return true; @@ -4382,13 +4395,11 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", dispSyncPresentTimeOffset, getVsyncPeriod()); - HwcConfigIndexType defaultConfig; - float minFps, maxFps; - mRefreshRateConfigs->getPolicy(&defaultConfig, &minFps, &maxFps); + scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy(); StringAppendF(&result, "DesiredDisplayConfigSpecs: default config ID: %d" ", min: %.2f Hz, max: %.2f Hz", - defaultConfig.value(), minFps, maxFps); + policy.defaultConfig.value(), policy.minRefreshRate, policy.maxRefreshRate); StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); @@ -4827,8 +4838,12 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: case GET_DISPLAYED_CONTENT_SAMPLE: case NOTIFY_POWER_HINT: - case SET_GLOBAL_SHADOW_SETTINGS: { - if (!callingThreadHasUnscopedSurfaceFlingerAccess()) { + case SET_GLOBAL_SHADOW_SETTINGS: + case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { + // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is used by CTS tests, which acquire the + // necessary permission dynamically. Don't use the permission cache for this check. + bool usePermissionCache = code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN; + if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(), ipc->getCallingUid()); @@ -5917,12 +5932,15 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& disp } } -status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const sp<DisplayDevice>& display, - HwcConfigIndexType defaultConfig, - float minRefreshRate, - float maxRefreshRate) { +status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( + const sp<DisplayDevice>& display, + const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) { Mutex::Autolock lock(mStateLock); + LOG_ALWAYS_FATAL_IF(!display->isPrimary() && overridePolicy, + "Can only set override policy on the primary display"); + LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy"); + if (!display->isPrimary()) { // TODO(b/144711714): For non-primary displays we should be able to set an active config // as well. For now, just call directly to setActiveConfigWithConstraints but ideally @@ -5936,7 +5954,8 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const sp<DisplayDe constraints.seamlessRequired = false; HWC2::VsyncPeriodChangeTimeline timeline = {0, 0, 0}; - if (getHwComposer().setActiveConfigWithConstraints(*displayId, defaultConfig.value(), + if (getHwComposer().setActiveConfigWithConstraints(*displayId, + policy->defaultConfig.value(), constraints, &timeline) < 0) { return BAD_VALUE; } @@ -5944,11 +5963,12 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const sp<DisplayDe repaintEverythingForHWC(); } - display->setActiveConfig(defaultConfig); - const nsecs_t vsyncPeriod = - getHwComposer().getConfigs(*displayId)[defaultConfig.value()]->getVsyncPeriod(); - mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, defaultConfig, - vsyncPeriod); + display->setActiveConfig(policy->defaultConfig); + const nsecs_t vsyncPeriod = getHwComposer() + .getConfigs(*displayId)[policy->defaultConfig.value()] + ->getVsyncPeriod(); + mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, + policy->defaultConfig, vsyncPeriod); return NO_ERROR; } @@ -5957,17 +5977,20 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const sp<DisplayDe return NO_ERROR; } - bool policyChanged; - if (mRefreshRateConfigs->setPolicy(defaultConfig, minRefreshRate, maxRefreshRate, - &policyChanged) < 0) { + status_t setPolicyResult = overridePolicy + ? mRefreshRateConfigs->setOverridePolicy(policy) + : mRefreshRateConfigs->setDisplayManagerPolicy(*policy); + if (setPolicyResult < 0) { return BAD_VALUE; } - if (!policyChanged) { + if (setPolicyResult == scheduler::RefreshRateConfigs::CURRENT_POLICY_UNCHANGED) { return NO_ERROR; } + scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy(); ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f", - defaultConfig.value(), minRefreshRate, maxRefreshRate); + currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate, + currentPolicy.maxRefreshRate); // TODO(b/140204874): This hack triggers a notification that something has changed, so // that listeners that care about a change in allowed configs can get the notification. @@ -5981,7 +6004,7 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const sp<DisplayDe auto& preferredRefreshRate = configId ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId) // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind. - : mRefreshRateConfigs->getRefreshRateFromConfigId(defaultConfig); + : mRefreshRateConfigs->getRefreshRateFromConfigId(currentPolicy.defaultConfig); ALOGV("trying to switch to Scheduler preferred config %d (%s)", preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str()); @@ -6016,9 +6039,13 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& display result = BAD_VALUE; ALOGW("Attempt to set desired display configs for virtual display"); } else { - result = - setDesiredDisplayConfigSpecsInternal(display, HwcConfigIndexType(defaultConfig), - minRefreshRate, maxRefreshRate); + result = setDesiredDisplayConfigSpecsInternal(display, + scheduler::RefreshRateConfigs:: + Policy{HwcConfigIndexType( + defaultConfig), + minRefreshRate, + maxRefreshRate}, + /*overridePolicy=*/false); } })); @@ -6042,9 +6069,11 @@ status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& display } if (display->isPrimary()) { - HwcConfigIndexType defaultConfig; - mRefreshRateConfigs->getPolicy(&defaultConfig, outMinRefreshRate, outMaxRefreshRate); - *outDefaultConfig = defaultConfig.value(); + scheduler::RefreshRateConfigs::Policy policy = + mRefreshRateConfigs->getDisplayManagerPolicy(); + *outDefaultConfig = policy.defaultConfig.value(); + *outMinRefreshRate = policy.minRefreshRate; + *outMaxRefreshRate = policy.maxRefreshRate; return NO_ERROR; } else if (display->isVirtual()) { return BAD_VALUE; @@ -6164,6 +6193,68 @@ status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, return NO_ERROR; } +status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) { + if (!outToken) { + return BAD_VALUE; + } + status_t result = NO_ERROR; + postMessageSync(new LambdaMessage([&]() { + if (mFrameRateFlexibilityTokenCount == 0) { + // |mStateLock| not needed as we are on the main thread + const auto display = getDefaultDisplayDeviceLocked(); + + // This is a little racy, but not in a way that hurts anything. As we grab the + // defaultConfig from the display manager policy, we could be setting a new display + // manager policy, leaving us using a stale defaultConfig. The defaultConfig doesn't + // matter for the override policy though, since we set allowGroupSwitching to true, so + // it's not a problem. + scheduler::RefreshRateConfigs::Policy overridePolicy; + overridePolicy.defaultConfig = + mRefreshRateConfigs->getDisplayManagerPolicy().defaultConfig; + overridePolicy.allowGroupSwitching = true; + result = setDesiredDisplayConfigSpecsInternal(display, overridePolicy, + /*overridePolicy=*/true); + } + + if (result == NO_ERROR) { + mFrameRateFlexibilityTokenCount++; + // Handing out a reference to the SurfaceFlinger object, as we're doing in the line + // below, is something to consider carefully. The lifetime of the + // FrameRateFlexibilityToken isn't tied to SurfaceFlinger object lifetime, so if this + // SurfaceFlinger object were to be destroyed while the token still exists, the token + // destructor would be accessing a stale SurfaceFlinger reference, and crash. This is ok + // in this case, for two reasons: + // 1. Once SurfaceFlinger::run() is called by main_surfaceflinger.cpp, the only way + // the program exits is via a crash. So we won't have a situation where the + // SurfaceFlinger object is dead but the process is still up. + // 2. The frame rate flexibility token is acquired/released only by CTS tests, so even + // if condition 1 were changed, the problem would only show up when running CTS tests, + // not on end user devices, so we could spot it and fix it without serious impact. + *outToken = new FrameRateFlexibilityToken( + [this]() { onFrameRateFlexibilityTokenReleased(); }); + ALOGD("Frame rate flexibility token acquired. count=%d", + mFrameRateFlexibilityTokenCount); + } + })); + return result; +} + +void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() { + postMessageAsync(new LambdaMessage([&]() { + LOG_ALWAYS_FATAL_IF(mFrameRateFlexibilityTokenCount == 0, + "Failed tracking frame rate flexibility tokens"); + mFrameRateFlexibilityTokenCount--; + ALOGD("Frame rate flexibility token released. count=%d", mFrameRateFlexibilityTokenCount); + if (mFrameRateFlexibilityTokenCount == 0) { + // |mStateLock| not needed as we are on the main thread + const auto display = getDefaultDisplayDeviceLocked(); + status_t result = + setDesiredDisplayConfigSpecsInternal(display, {}, /*overridePolicy=*/true); + LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token"); + } + })); +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 78c9206f61..12efca1873 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -407,7 +407,8 @@ private: */ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override; status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); } - bool callingThreadHasUnscopedSurfaceFlingerAccess() EXCLUDES(mStateLock); + bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true) + EXCLUDES(mStateLock); /* ------------------------------------------------------------------------ * ISurfaceComposer interface @@ -503,6 +504,7 @@ private: float lightPosY, float lightPosZ, float lightRadius) override; status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, int8_t compatibility) override; + status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override; /* ------------------------------------------------------------------------ * DeathRecipient interface */ @@ -574,9 +576,9 @@ private: void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock); // Sets the desired display configs. - status_t setDesiredDisplayConfigSpecsInternal(const sp<DisplayDevice>& display, - HwcConfigIndexType defaultConfig, - float minRefreshRate, float maxRefreshRate) + status_t setDesiredDisplayConfigSpecsInternal( + const sp<DisplayDevice>& display, + const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) EXCLUDES(mStateLock); // called on the main thread in response to setAutoLowLatencyMode() @@ -968,6 +970,8 @@ private: return doDump(fd, args, asProto); } + void onFrameRateFlexibilityTokenReleased(); + /* ------------------------------------------------------------------------ * VrFlinger */ @@ -1276,6 +1280,8 @@ private: std::atomic<bool> mInputDirty = true; void dirtyInput() { mInputDirty = true; } bool inputDirty() { return mInputDirty; } + + int mFrameRateFlexibilityTokenCount = 0; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index dd04076644..ce41291813 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -83,8 +83,8 @@ TEST_F(RefreshRateConfigsTest, invalidPolicy) { {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}}; auto refreshRateConfigs = std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); - ASSERT_LT(refreshRateConfigs->setPolicy(HwcConfigIndexType(10), 60, 60, nullptr), 0); - ASSERT_LT(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 20, 40, nullptr), 0); + ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), 60, 60}), 0); + ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 20, 40}), 0); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { @@ -126,7 +126,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe ASSERT_EQ(expectedDefaultConfig, minRate60); ASSERT_EQ(expectedDefaultConfig, performanceRate60); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0); refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy(); @@ -155,7 +155,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { 90}; ASSERT_EQ(expectedPerformanceConfig, performanceRate); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0); auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); @@ -180,7 +180,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) { EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); } - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0); { auto& current = refreshRateConfigs->getCurrentRefreshRate(); EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); @@ -212,7 +212,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0); EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f))); EXPECT_EQ(expected60Config, @@ -224,7 +224,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0); EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f))); EXPECT_EQ(expected90Config, @@ -235,7 +235,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f))); EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0); EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f))); EXPECT_EQ(expected60Config, @@ -332,7 +332,7 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { &ignored)); lr.name = ""; - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(expected60Config, @@ -370,7 +370,7 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, &ignored)); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(expected90Config, @@ -408,7 +408,7 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, &ignored)); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, @@ -1218,6 +1218,33 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_ExplicitDefault) { } } +TEST_F(RefreshRateConfigsTest, groupSwitching) { + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_1, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); + + auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitDefault; + layer.desiredRefreshRate = 90.0f; + layer.name = "90Hz ExplicitDefault"; + + bool touchConsidered; + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered) + .configId); + + RefreshRateConfigs::Policy policy; + policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig; + policy.allowGroupSwitching = true; + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); + ASSERT_EQ(HWC_CONFIG_ID_90, + refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered) + .configId); +} + } // namespace } // namespace scheduler } // namespace android |