From 838de0622c700345fbfde270c065fdc97f4b9428 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 4 Feb 2019 10:24:03 -0800 Subject: SurfaceFlinger: add setAllowedDisplayConfigs Add an API to ISurfaceComposer to set allowed display configurations. This API is expected to be called by DisplayManager depends on the current policy in place. Once setAllowedDisplayConfigs is called, SF can only set a new display config if it is part of the allowed configurations list. Test: call setAllowedDisplayConfigs() from backdoor and observe config change. Bug: 122905403 Change-Id: I1d0a3649bbe7a08efeb72dc270f0b2df330b021c --- libs/gui/ISurfaceComposer.cpp | 35 ++++++++ libs/gui/SurfaceComposerClient.cpp | 6 ++ libs/gui/include/gui/ISurfaceComposer.h | 10 ++- libs/gui/include/gui/SurfaceComposerClient.h | 6 ++ libs/gui/tests/Surface_test.cpp | 4 + services/surfaceflinger/AllowedDisplayConfigs.h | 62 ++++++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 104 +++++++++++++++++++++++- services/surfaceflinger/SurfaceFlinger.h | 15 ++++ 8 files changed, 237 insertions(+), 5 deletions(-) create mode 100644 services/surfaceflinger/AllowedDisplayConfigs.h diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index f77eeb246c..09f1ed700e 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -806,6 +806,32 @@ public: } return error; } + + virtual status_t setAllowedDisplayConfigs(const sp& displayToken, + const std::vector& allowedConfigs) { + Parcel data, reply; + status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (result != NO_ERROR) { + ALOGE("setAllowedDisplayConfigs failed to writeInterfaceToken: %d", result); + return result; + } + result = data.writeStrongBinder(displayToken); + if (result != NO_ERROR) { + ALOGE("setAllowedDisplayConfigs failed to writeStrongBinder: %d", result); + return result; + } + result = data.writeInt32Vector(allowedConfigs); + if (result != NO_ERROR) { + ALOGE("setAllowedDisplayConfigs failed to writeInt32Vector: %d", result); + return result; + } + result = remote()->transact(BnSurfaceComposer::SET_ALLOWED_DISPLAY_CONFIGS, data, &reply); + if (result != NO_ERROR) { + ALOGE("setAllowedDisplayConfigs failed to transact: %d", result); + return result; + } + return reply.readInt32(); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1317,6 +1343,15 @@ status_t BnSurfaceComposer::onTransact( } return removeRegionSamplingListener(listener); } + case SET_ALLOWED_DISPLAY_CONFIGS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp displayToken = data.readStrongBinder(); + std::vector allowedConfigs; + data.readInt32Vector(&allowedConfigs); + status_t result = setAllowedDisplayConfigs(displayToken, allowedConfigs); + reply->writeInt32(result); + return result; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8c2538ca19..55a2ae5905 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1382,6 +1382,12 @@ status_t SurfaceComposerClient::setActiveConfig(const sp& display, int return ComposerService::getComposerService()->setActiveConfig(display, id); } +status_t SurfaceComposerClient::setAllowedDisplayConfigs( + const sp& displayToken, const std::vector& allowedConfigs) { + return ComposerService::getComposerService()->setAllowedDisplayConfigs(displayToken, + allowedConfigs); +} + status_t SurfaceComposerClient::getDisplayColorModes(const sp& display, Vector* outColorModes) { return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e6700e77dd..0d5b7679e2 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -359,6 +359,14 @@ public: * Removes a listener that was streaming median luma updates from SurfaceFlinger. */ virtual status_t removeRegionSamplingListener(const sp& listener) = 0; + + /* + * Sets the allowed display configurations to be used. + * The allowedConfigs in a vector of indexes corresponding to the configurations + * returned from getDisplayConfigs(). + */ + virtual status_t setAllowedDisplayConfigs(const sp& displayToken, + const std::vector& allowedConfigs) = 0; }; // ---------------------------------------------------------------------------- @@ -406,7 +414,7 @@ public: GET_PHYSICAL_DISPLAY_IDS, ADD_REGION_SAMPLING_LISTENER, REMOVE_REGION_SAMPLING_LISTENER, - + SET_ALLOWED_DISPLAY_CONFIGS, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index cb38209f65..3c52b105b3 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -111,6 +111,12 @@ public: // returned by getDisplayInfo static status_t setActiveConfig(const sp& display, int id); + // Sets the allowed display configurations to be used. + // The allowedConfigs in a vector of indexes corresponding to the configurations + // returned from getDisplayConfigs(). + static status_t setAllowedDisplayConfigs(const sp& displayToken, + const std::vector& allowedConfigs); + // Gets the list of supported color modes for the given display static status_t getDisplayColorModes(const sp& display, Vector* outColorModes); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index f1278537e4..dae7736ad8 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -678,6 +678,10 @@ public: const sp& /*listener*/) override { return NO_ERROR; } + status_t setAllowedDisplayConfigs(const sp& /*displayToken*/, + const std::vector& /*allowedConfigs*/) override { + return NO_ERROR; + } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/AllowedDisplayConfigs.h b/services/surfaceflinger/AllowedDisplayConfigs.h new file mode 100644 index 0000000000..e3b9c1f1d1 --- /dev/null +++ b/services/surfaceflinger/AllowedDisplayConfigs.h @@ -0,0 +1,62 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +/* + * Used to represent the Display Configurations allowed to be set by SurfaceFlinger + */ +class AllowedDisplayConfigs { +private: + // Defining ConstructorTag as private to prevent instantiating this class from outside + // while still allowing it to be constructed by std::make_unique + struct ConstructorTag {}; + +public: + AllowedDisplayConfigs(ConstructorTag) {} + + class Builder { + public: + Builder() + : mAllowedDisplayConfigs(std::make_unique(ConstructorTag{})) {} + + std::unique_ptr build() { + return std::move(mAllowedDisplayConfigs); + } + + // add a config to the allowed config set + Builder& addConfig(int32_t config) { + mAllowedDisplayConfigs->addConfig(config); + return *this; + } + + private: + std::unique_ptr mAllowedDisplayConfigs; + }; + + bool isConfigAllowed(int32_t config) const { + return (std::find(mConfigs.begin(), mConfigs.end(), config) != mConfigs.end()); + } + +private: + // add a config to the allowed config set + void addConfig(int32_t config) { mConfigs.push_back(config); } + + std::vector mConfigs; +}; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6d10986dbb..fb59259351 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -984,9 +984,11 @@ void SurfaceFlinger::setDesiredActiveConfig(const sp& displayToken, int status_t SurfaceFlinger::setActiveConfig(const sp& displayToken, int mode) { ATRACE_CALL(); - postMessageSync(new LambdaMessage( - [&]() NO_THREAD_SAFETY_ANALYSIS { setDesiredActiveConfig(displayToken, mode); })); - return NO_ERROR; + + std::vector allowedConfig; + allowedConfig.push_back(mode); + + return setAllowedDisplayConfigs(displayToken, allowedConfig); } void SurfaceFlinger::setActiveConfigInternal() { @@ -1048,7 +1050,14 @@ bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS { return false; } - // Desired active config was set, it is different than the config currently in use. Notify HWC. + // Desired active config was set, it is different than the config currently in use, however + // allowed configs might have change by the time we process the refresh. + // Make sure the desired config is still allowed + if (!isConfigAllowed(*display->getId(), desiredActiveConfig.configId)) { + std::lock_guard lock(mActiveConfigLock); + mDesiredActiveConfig.configId = display->getActiveConfig(); + return false; + } mUpcomingActiveConfig = desiredActiveConfig; const auto displayId = display->getId(); LOG_ALWAYS_FATAL_IF(!displayId); @@ -1416,6 +1425,17 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } +bool SurfaceFlinger::isConfigAllowed(const DisplayId& displayId, int32_t config) { + std::lock_guard lock(mAllowedConfigsLock); + + // if allowed configs are not set yet for this display, every config is considered allowed + if (mAllowedConfigs.find(displayId) == mAllowedConfigs.end()) { + return true; + } + + return mAllowedConfigs[displayId]->isConfigAllowed(config); +} + void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) { mPhaseOffsets->setRefreshRateType(refreshRate); @@ -1451,6 +1471,11 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) { auto configs = getHwComposer().getConfigs(*displayId); for (int i = 0; i < configs.size(); i++) { + if (!isConfigAllowed(*displayId, i)) { + ALOGV("Skipping config %d as it is not part of allowed configs", i); + continue; + } + const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod(); if (vsyncPeriod == 0) { continue; @@ -4908,6 +4933,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_ANIMATION_FRAME_STATS: case GET_HDR_CAPABILITIES: case SET_ACTIVE_CONFIG: + case SET_ALLOWED_DISPLAY_CONFIGS: case SET_ACTIVE_COLOR_MODE: case INJECT_VSYNC: case SET_POWER_MODE: @@ -5727,6 +5753,76 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp& disp } } +void SurfaceFlinger::setAllowedDisplayConfigsInternal( + const android::sp& displayToken, + std::unique_ptr&& allowedConfigs) { + const auto displayId = getPhysicalDisplayIdLocked(displayToken); + if (!displayId) { + ALOGE("setAllowedDisplayConfigsInternal: getPhysicalDisplayId failed"); + return; + } + + ALOGV("Updating allowed configs"); + { + std::lock_guard lock(mAllowedConfigsLock); + mAllowedConfigs[*displayId] = std::move(allowedConfigs); + } + + // make sure that the current config is still allowed + int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId); + if (!isConfigAllowed(*displayId, currentConfigIndex)) { + // TODO(b/122906558): stop querying HWC for the available configs and instead use the cached + // configs queried on boot + auto configs = getHwComposer().getConfigs(*displayId); + + for (int i = 0; i < configs.size(); i++) { + if (isConfigAllowed(*displayId, i)) { + // TODO: we switch to the first allowed config. In the future + // we may want to enhance this logic to pick a similar config + // to the current one + ALOGV("Old config is not allowed - switching to config %d", i); + setDesiredActiveConfig(displayToken, i); + break; + } + } + } +} + +status_t SurfaceFlinger::setAllowedDisplayConfigs(const android::sp& displayToken, + const std::vector& allowedConfigs) { + ATRACE_CALL(); + + if (!displayToken) { + ALOGE("setAllowedDisplayConfigs: displayToken is null"); + return BAD_VALUE; + } + + if (!allowedConfigs.size()) { + ALOGE("setAllowedDisplayConfigs: empty config set provided"); + return BAD_VALUE; + } + + { + ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); + const auto displayId = getPhysicalDisplayIdLocked(displayToken); + if (!displayId) { + ALOGE("setAllowedDisplayConfigs: display not found"); + return NAME_NOT_FOUND; + } + } + + auto allowedDisplayConfigsBuilder = AllowedDisplayConfigs::Builder(); + for (int config : allowedConfigs) { + ALOGV("setAllowedDisplayConfigs: Adding config to the allowed configs = %d", config); + allowedDisplayConfigsBuilder.addConfig(config); + } + auto allowedDisplayConfigs = allowedDisplayConfigsBuilder.build(); + postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS { + setAllowedDisplayConfigsInternal(displayToken, std::move(allowedDisplayConfigs)); + })); + return NO_ERROR; +} + // ---------------------------------------------------------------------------- void SetInputWindowsListener::onSetInputWindowsFinished() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 31b4fb6232..dd03294427 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -47,6 +47,7 @@ #include #include +#include "AllowedDisplayConfigs.h" #include "Barrier.h" #include "BufferStateLayerCache.h" #include "DisplayDevice.h" @@ -490,6 +491,9 @@ private: status_t addRegionSamplingListener(const Rect& samplingArea, const sp& stopLayerHandle, const sp& listener) override; status_t removeRegionSamplingListener(const sp& listener) override; + status_t setAllowedDisplayConfigs(const sp& displayToken, + const std::vector& allowedConfigs) override; + /* ------------------------------------------------------------------------ * DeathRecipient interface */ @@ -534,6 +538,11 @@ private: // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp& display, int mode) REQUIRES(mStateLock); + // called on the main thread in response to setAllowedDisplayConfigs() + void setAllowedDisplayConfigsInternal( + const sp& displayToken, + std::unique_ptr&& allowedConfigs) REQUIRES(mStateLock); + // Returns whether the transaction actually modified any state bool handleMessageTransaction(); @@ -804,6 +813,8 @@ private: // the desired refresh rate. void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType) REQUIRES(mStateLock); + bool isConfigAllowed(const DisplayId& displayId, int32_t config); + /* * Display identification */ @@ -1098,6 +1109,10 @@ private: sp mSfConnectionHandle; std::unique_ptr mRefreshRateStats; + std::mutex mAllowedConfigsLock; + std::unordered_map> mAllowedConfigs + GUARDED_BY(mAllowedConfigsLock); + struct ActiveConfigInfo { int configId; sp displayToken; -- cgit v1.2.3-59-g8ed1b From 447052e2f69efb01023dcc0dce230dd649f0475f Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 13 Feb 2019 16:07:27 -0800 Subject: SurfaceFlinger: add DISPLAY_EVENT_CONFIG_CHANGED Add a new event to DisplayEventReceiver for display configuration change. This event is sent by SF when display config is changed. Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Bug: 122905403 Change-Id: Ibb7e0ce7b83b91259ccb0e9c982f5e378b0ebfaf --- libs/gui/include/gui/DisplayEventReceiver.h | 6 ++++++ services/surfaceflinger/Scheduler/EventThread.cpp | 15 ++++++++++++++ services/surfaceflinger/Scheduler/EventThread.h | 5 +++++ services/surfaceflinger/Scheduler/Scheduler.cpp | 6 ++++++ services/surfaceflinger/Scheduler/Scheduler.h | 4 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 23 +++++++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 9 +++++++-- .../tests/unittests/EventThreadTest.cpp | 22 +++++++++++++++++++++ .../tests/unittests/mock/MockEventThread.h | 1 + 9 files changed, 80 insertions(+), 11 deletions(-) diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 8c3f46305c..22de751498 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -52,6 +52,7 @@ public: enum { DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'), DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'), + DISPLAY_EVENT_CONFIG_CHANGED = fourcc('c', 'o', 'n', 'f'), }; struct Event { @@ -70,10 +71,15 @@ public: bool connected; }; + struct Config { + int32_t configId; + }; + Header header; union { VSync vsync; Hotplug hotplug; + Config config; }; }; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 4b500f1180..78bf7c5c49 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -97,6 +97,13 @@ DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t times return event; } +DisplayEventReceiver::Event makeConfigChanged(uint32_t displayId, int32_t configId) { + DisplayEventReceiver::Event event; + event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()}; + event.config.configId = configId; + return event; +} + } // namespace EventThreadConnection::EventThreadConnection(EventThread* eventThread, @@ -307,6 +314,13 @@ void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) mCondition.notify_all(); } +void EventThread::onConfigChanged(PhysicalDisplayId displayId, int32_t configId) { + std::lock_guard lock(mMutex); + + mPendingEvents.push_back(makeConfigChanged(displayId, configId)); + mCondition.notify_all(); +} + void EventThread::threadMain(std::unique_lock& lock) { DisplayEventConsumers consumers; @@ -404,6 +418,7 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, const sp& connection) const { switch (event.header.type) { case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: return true; case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 341143823a..d5e33490a5 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -112,6 +112,9 @@ public: virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0; + // called when SF changes the active config and apps needs to be notified about the change + virtual void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) = 0; + virtual void dump(std::string& result) const = 0; virtual void setPhaseOffset(nsecs_t phaseOffset) = 0; @@ -153,6 +156,8 @@ public: void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override; + void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) override; + void dump(std::string& result) const override; void setPhaseOffset(nsecs_t phaseOffset) override; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 4f846dbf59..990318a00a 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -153,6 +153,12 @@ void Scheduler::onScreenReleased(const sp& handle) mConnections[handle->id]->thread->onScreenReleased(); } +void Scheduler::onConfigChanged(const sp& handle, PhysicalDisplayId displayId, + int32_t configId) { + RETURN_IF_INVALID(); + mConnections[handle->id]->thread->onConfigChanged(displayId, configId); +} + void Scheduler::dump(const sp& handle, std::string& result) const { RETURN_IF_INVALID(); mConnections.at(handle->id)->thread->dump(result); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index c566922d79..7f113e717b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -105,6 +105,10 @@ public: // Should be called before the screen is turned off. void onScreenReleased(const sp& handle); + // Should be called when display config changed + void onConfigChanged(const sp& handle, PhysicalDisplayId displayId, + int32_t configId); + // Should be called when dumpsys command is received. void dump(const sp& handle, std::string& result) const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fb59259351..f651bdf4ea 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -596,11 +596,11 @@ void SurfaceFlinger::bootFinished() if (mUse90Hz) { mPhaseOffsets->setRefreshRateType( scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE); - setRefreshRateTo(RefreshRateType::PERFORMANCE); + setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None); } else { mPhaseOffsets->setRefreshRateType( scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT); - setRefreshRateTo(RefreshRateType::DEFAULT); + setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None); } })); } @@ -726,11 +726,11 @@ void SurfaceFlinger::init() { if (mUse90Hz) { mScheduler->setExpiredIdleTimerCallback([this] { Mutex::Autolock lock(mStateLock); - setRefreshRateTo(RefreshRateType::DEFAULT); + setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None); }); mScheduler->setResetIdleTimerCallback([this] { Mutex::Autolock lock(mStateLock); - setRefreshRateTo(RefreshRateType::PERFORMANCE); + setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None); }); } mRefreshRateStats = std::make_unique(getHwComposer().getConfigs( @@ -938,7 +938,8 @@ int SurfaceFlinger::getActiveConfig(const sp& displayToken) { return display->getActiveConfig(); } -void SurfaceFlinger::setDesiredActiveConfig(const sp& displayToken, int mode) { +void SurfaceFlinger::setDesiredActiveConfig(const sp& displayToken, int mode, + ConfigEvent event) { ATRACE_CALL(); Vector configs; @@ -969,7 +970,7 @@ void SurfaceFlinger::setDesiredActiveConfig(const sp& displayToken, int // Don't check against the current mode yet. Worst case we set the desired // config twice. std::lock_guard lock(mActiveConfigLock); - mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken}; + mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, event}; if (!mDesiredActiveConfigChanged) { // This is the first time we set the desired @@ -1002,6 +1003,10 @@ void SurfaceFlinger::setActiveConfigInternal() { mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); + if (mUpcomingActiveConfig.event != ConfigEvent::None) { + mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, + mUpcomingActiveConfig.configId); + } } bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS { @@ -1436,7 +1441,7 @@ bool SurfaceFlinger::isConfigAllowed(const DisplayId& displayId, int32_t config) return mAllowedConfigs[displayId]->isConfigAllowed(config); } -void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) { +void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, ConfigEvent event) { mPhaseOffsets->setRefreshRateType(refreshRate); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); @@ -1484,7 +1489,7 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) { // TODO(b/113612090): There should be a better way at determining which config // has the right refresh rate. if (std::abs(fps - newFps) <= 1) { - setDesiredActiveConfig(getInternalDisplayTokenLocked(), i); + setDesiredActiveConfig(getInternalDisplayTokenLocked(), i, event); } } } @@ -5781,7 +5786,7 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal( // we may want to enhance this logic to pick a similar config // to the current one ALOGV("Old config is not allowed - switching to config %d", i); - setDesiredActiveConfig(displayToken, i); + setDesiredActiveConfig(displayToken, i, ConfigEvent::Changed); break; } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index dd03294427..9adfb55e35 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -523,10 +523,13 @@ private: void signalLayerUpdate(); void signalRefresh(); + enum class ConfigEvent { None, Changed }; + // called on the main thread in response to initializeDisplays() void onInitializeDisplays() REQUIRES(mStateLock); // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig. - void setDesiredActiveConfig(const sp& displayToken, int mode) REQUIRES(mStateLock); + void setDesiredActiveConfig(const sp& displayToken, int mode, ConfigEvent event) + REQUIRES(mStateLock); // Once HWC has returned the present fence, this sets the active config and a new refresh // rate in SF. It also triggers HWC vsync. void setActiveConfigInternal() REQUIRES(mStateLock); @@ -811,7 +814,8 @@ private: // Sets the refresh rate by switching active configs, if they are available for // the desired refresh rate. - void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType) REQUIRES(mStateLock); + void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType, ConfigEvent event) + REQUIRES(mStateLock); bool isConfigAllowed(const DisplayId& displayId, int32_t config); @@ -1116,6 +1120,7 @@ private: struct ActiveConfigInfo { int configId; sp displayToken; + ConfigEvent event; bool operator!=(const ActiveConfigInfo& other) const { if (configId != other.configId) { diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index e499ff58f7..406ec81ce4 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -81,6 +81,8 @@ protected: void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); + void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, + int32_t expectedConfigId); AsyncCallRecorder mVSyncSetEnabledCallRecorder; AsyncCallRecorder mVSyncSetCallbackCallRecorder; @@ -212,6 +214,16 @@ void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId e EXPECT_EQ(expectedConnected, event.hotplug.connected); } +void EventThreadTest::expectConfigChangedEventReceivedByConnection( + PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId) { + auto args = mConnectionEventCallRecorder.waitForCall(); + ASSERT_TRUE(args.has_value()); + const auto& event = std::get<0>(args.value()); + EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, event.header.type); + EXPECT_EQ(expectedDisplayId, event.header.displayId); + EXPECT_EQ(expectedConfigId, event.config.configId); +} + namespace { /* ------------------------------------------------------------------------ @@ -448,5 +460,15 @@ TEST_F(EventThreadTest, postHotplugExternalConnect) { expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, true); } +TEST_F(EventThreadTest, postConfigChangedPrimary) { + mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 7); + expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7); +} + +TEST_F(EventThreadTest, postConfigChangedExternal) { + mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, 5); + expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5); +} + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 5edee6e83c..cb4a300611 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -33,6 +33,7 @@ public: MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); + MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, int32_t)); MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset)); MOCK_METHOD1(registerDisplayEventConnection, -- cgit v1.2.3-59-g8ed1b