diff options
| -rw-r--r-- | libs/gui/ISurfaceComposer.cpp | 35 | ||||
| -rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 6 | ||||
| -rw-r--r-- | libs/gui/include/gui/DisplayEventReceiver.h | 6 | ||||
| -rw-r--r-- | libs/gui/include/gui/ISurfaceComposer.h | 10 | ||||
| -rw-r--r-- | libs/gui/include/gui/SurfaceComposerClient.h | 6 | ||||
| -rw-r--r-- | libs/gui/tests/Surface_test.cpp | 4 | ||||
| -rw-r--r-- | services/surfaceflinger/AllowedDisplayConfigs.h | 62 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/EventThread.cpp | 15 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/EventThread.h | 5 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.cpp | 6 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.h | 4 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 125 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 24 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/EventThreadTest.cpp | 22 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/mock/MockEventThread.h | 1 |
15 files changed, 316 insertions, 15 deletions
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index d549346276..d2f2539e8e 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -807,6 +807,32 @@ public: } return error; } + + virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken, + const std::vector<int32_t>& 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 @@ -1319,6 +1345,15 @@ status_t BnSurfaceComposer::onTransact( } return removeRegionSamplingListener(listener); } + case SET_ALLOWED_DISPLAY_CONFIGS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> displayToken = data.readStrongBinder(); + std::vector<int32_t> 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 7770518cf6..d583e6db9d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1382,6 +1382,12 @@ status_t SurfaceComposerClient::setActiveConfig(const sp<IBinder>& display, int return ComposerService::getComposerService()->setActiveConfig(display, id); } +status_t SurfaceComposerClient::setAllowedDisplayConfigs( + const sp<IBinder>& displayToken, const std::vector<int32_t>& allowedConfigs) { + return ComposerService::getComposerService()->setAllowedDisplayConfigs(displayToken, + allowedConfigs); +} + status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display, Vector<ColorMode>* outColorModes) { return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes); 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/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 8654f5ef0a..eedd5f583a 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -360,6 +360,14 @@ public: * Removes a listener that was streaming median luma updates from SurfaceFlinger. */ virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& 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<IBinder>& displayToken, + const std::vector<int32_t>& allowedConfigs) = 0; }; // ---------------------------------------------------------------------------- @@ -407,7 +415,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 6d21bff1f7..4621a34781 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<IBinder>& 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<IBinder>& displayToken, + const std::vector<int32_t>& allowedConfigs); + // Gets the list of supported color modes for the given display static status_t getDisplayColorModes(const sp<IBinder>& display, Vector<ui::ColorMode>* outColorModes); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e14c698088..7f1dc84b1c 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -679,6 +679,10 @@ public: const sp<IRegionSamplingListener>& /*listener*/) override { return NO_ERROR; } + status_t setAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/, + const std::vector<int32_t>& /*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 <log/log.h> +#include <vector> + +/* + * 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<AllowedDisplayConfigs>(ConstructorTag{})) {} + + std::unique_ptr<const AllowedDisplayConfigs> 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<AllowedDisplayConfigs> 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<int32_t> mConfigs; +}; 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<std::mutex> lock(mMutex); + + mPendingEvents.push_back(makeConfigChanged(displayId, configId)); + mCondition.notify_all(); +} + void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { DisplayEventConsumers consumers; @@ -404,6 +418,7 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, const sp<EventThreadConnection>& 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<Scheduler::ConnectionHandle>& handle) mConnections[handle->id]->thread->onScreenReleased(); } +void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId, + int32_t configId) { + RETURN_IF_INVALID(); + mConnections[handle->id]->thread->onConfigChanged(displayId, configId); +} + void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& 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<ConnectionHandle>& handle); + // Should be called when display config changed + void onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId, + int32_t configId); + // Should be called when dumpsys command is received. void dump(const sp<ConnectionHandle>& handle, std::string& result) const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 68fa04c7a0..daa9ff9047 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -575,11 +575,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); } })); } @@ -706,11 +706,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<scheduler::RefreshRateStats>(getHwComposer().getConfigs( @@ -918,7 +918,8 @@ int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) { return display->getActiveConfig(); } -void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) { +void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode, + ConfigEvent event) { ATRACE_CALL(); Vector<DisplayInfo> configs; @@ -949,7 +950,7 @@ void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int // Don't check against the current mode yet. Worst case we set the desired // config twice. std::lock_guard<std::mutex> lock(mActiveConfigLock); - mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken}; + mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, event}; if (!mDesiredActiveConfigChanged) { // This is the first time we set the desired @@ -964,9 +965,11 @@ void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) { ATRACE_CALL(); - postMessageSync(new LambdaMessage( - [&]() NO_THREAD_SAFETY_ANALYSIS { setDesiredActiveConfig(displayToken, mode); })); - return NO_ERROR; + + std::vector<int32_t> allowedConfig; + allowedConfig.push_back(mode); + + return setAllowedDisplayConfigs(displayToken, allowedConfig); } void SurfaceFlinger::setActiveConfigInternal() { @@ -980,6 +983,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 { @@ -1028,7 +1035,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<std::mutex> lock(mActiveConfigLock); + mDesiredActiveConfig.configId = display->getActiveConfig(); + return false; + } mUpcomingActiveConfig = desiredActiveConfig; const auto displayId = display->getId(); LOG_ALWAYS_FATAL_IF(!displayId); @@ -1396,7 +1410,18 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) { +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, ConfigEvent event) { mPhaseOffsets->setRefreshRateType(refreshRate); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); @@ -1431,6 +1456,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; @@ -1439,7 +1469,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); } } } @@ -4873,6 +4903,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: @@ -5693,6 +5724,76 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& disp } } +void SurfaceFlinger::setAllowedDisplayConfigsInternal( + const android::sp<android::IBinder>& displayToken, + std::unique_ptr<const AllowedDisplayConfigs>&& 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, ConfigEvent::Changed); + break; + } + } + } +} + +status_t SurfaceFlinger::setAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken, + const std::vector<int32_t>& 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 6ca9720a32..4fb1c0e258 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -47,6 +47,7 @@ #include <utils/Trace.h> #include <utils/threads.h> +#include "AllowedDisplayConfigs.h" #include "Barrier.h" #include "BufferStateLayerCache.h" #include "DisplayDevice.h" @@ -491,6 +492,9 @@ private: status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, const sp<IRegionSamplingListener>& listener) override; status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override; + status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken, + const std::vector<int32_t>& allowedConfigs) override; + /* ------------------------------------------------------------------------ * DeathRecipient interface */ @@ -520,10 +524,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<IBinder>& displayToken, int mode) REQUIRES(mStateLock); + void setDesiredActiveConfig(const sp<IBinder>& 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); @@ -535,6 +542,11 @@ private: // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock); + // called on the main thread in response to setAllowedDisplayConfigs() + void setAllowedDisplayConfigsInternal( + const sp<IBinder>& displayToken, + std::unique_ptr<const AllowedDisplayConfigs>&& allowedConfigs) REQUIRES(mStateLock); + // Returns whether the transaction actually modified any state bool handleMessageTransaction(); @@ -799,7 +811,10 @@ 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); /* * Display identification @@ -1095,9 +1110,14 @@ private: sp<Scheduler::ConnectionHandle> mSfConnectionHandle; std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats; + std::mutex mAllowedConfigsLock; + std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs + GUARDED_BY(mAllowedConfigsLock); + struct ActiveConfigInfo { int configId; sp<IBinder> 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<void (*)(bool)> mVSyncSetEnabledCallRecorder; AsyncCallRecorder<void (*)(VSyncSource::Callback*)> 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, |