Merge "libgui: disable RegionSamplingTest"
diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c
index 3b8955b..71f0837 100644
--- a/cmds/ip-up-vpn/ip-up-vpn.c
+++ b/cmds/ip-up-vpn/ip-up-vpn.c
@@ -95,6 +95,7 @@
         strncpy(ifr.ifr_name, interface, IFNAMSIZ);
         if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
             ALOGE("Cannot bring up %s: %s", interface, strerror(errno));
+            fclose(state);
             return 1;
         }
 
@@ -102,6 +103,7 @@
         if (!set_address(&ifr.ifr_addr, address) ||
                 ioctl(s, SIOCSIFADDR, &ifr)) {
             ALOGE("Cannot set address: %s", strerror(errno));
+            fclose(state);
             return 1;
         }
 
@@ -109,6 +111,7 @@
         if (set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4"))) {
             if (ioctl(s, SIOCSIFNETMASK, &ifr)) {
                 ALOGE("Cannot set netmask: %s", strerror(errno));
+                fclose(state);
                 return 1;
             }
         }
@@ -123,6 +126,7 @@
         fprintf(state, "%s\n", env("REMOTE_ADDR"));
     } else {
         ALOGE("Cannot parse parameters");
+        fclose(state);
         return 1;
     }
 
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 962d263..84ba644 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -100,6 +100,7 @@
 
     output.writeFloat(bgColorAlpha);
     output.writeUint32(static_cast<uint32_t>(bgColorDataspace));
+    output.writeBool(colorSpaceAgnostic);
 
     return NO_ERROR;
 }
@@ -177,6 +178,7 @@
 
     bgColorAlpha = input.readFloat();
     bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32());
+    colorSpaceAgnostic = input.readBool();
 
     return NO_ERROR;
 }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 050ba87..0a4ad46 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -989,6 +989,20 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorSpaceAgnostic(
+        const sp<SurfaceControl>& sc, const bool agnostic) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eColorSpaceAgnosticChanged;
+    s->colorSpaceAgnostic = agnostic;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
 SurfaceComposerClient::Transaction&
 SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
         TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 32d7391..35e795c 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -88,6 +88,7 @@
         eCachedBufferChanged = 0x2'00000000,
         eBackgroundColorChanged = 0x4'00000000,
         eMetadataChanged = 0x8'00000000,
+        eColorSpaceAgnosticChanged = 0x10'00000000,
     };
 
     layer_state_t()
@@ -115,7 +116,8 @@
             api(-1),
             colorTransform(mat4()),
             bgColorAlpha(0),
-            bgColorDataspace(ui::Dataspace::UNKNOWN) {
+            bgColorDataspace(ui::Dataspace::UNKNOWN),
+            colorSpaceAgnostic(false) {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
         hdrMetadata.validTypes = 0;
@@ -192,6 +194,10 @@
     // the background color layer
     float bgColorAlpha;
     ui::Dataspace bgColorDataspace;
+
+    // A color space agnostic layer means the color of this layer can be
+    // interpreted in any color space.
+    bool colorSpaceAgnostic;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e062339..2c483ee 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -360,6 +360,7 @@
         Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
                                        const sp<NativeHandle>& sidebandStream);
         Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
+        Transaction& setColorSpaceAgnostic(const sp<SurfaceControl>& sc, const bool agnostic);
 
         Transaction& addTransactionCompletedCallback(
                 TransactionCompletedCallbackTakesContext callback, void* callbackContext);
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 756ca42..7884362 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -239,7 +239,8 @@
 
 void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
                                   const ui::Transform& transform, const Rect& viewport,
-                                  int32_t supportedPerFrameMetadata) {
+                                  int32_t supportedPerFrameMetadata,
+                                  const ui::Dataspace targetDataspace) {
     RETURN_IF_NO_HWC_LAYER(displayDevice);
 
     // Apply this display's projection's viewport to the visible region
@@ -291,10 +292,10 @@
         setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
     }
 
-    ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
-    error = hwcLayer->setDataspace(mCurrentDataSpace);
+    ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+    error = hwcLayer->setDataspace(dataspace);
     if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index e9dbdea..8149cba 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -81,7 +81,8 @@
     bool isHdrY410() const override;
 
     void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
-                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+                         const Rect& viewport, int32_t supportedPerFrameMetadata,
+                         const ui::Dataspace targetDataspace) override;
 
     bool onPreComposition(nsecs_t refreshStartTime) override;
     bool onPostComposition(const std::optional<DisplayId>& displayId,
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 2aeece7..a2692bc 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -81,7 +81,8 @@
 
 void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
                                  const ui::Transform& transform, const Rect& viewport,
-                                 int32_t /* supportedPerFrameMetadata */) {
+                                 int32_t /* supportedPerFrameMetadata */,
+                                 const ui::Dataspace targetDataspace) {
     RETURN_IF_NO_HWC_LAYER(display);
 
     Region visible = transform.transform(visibleRegion.intersect(viewport));
@@ -101,9 +102,10 @@
 
     setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
 
-    error = hwcLayer->setDataspace(mCurrentDataSpace);
+    const ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+    error = hwcLayer->setDataspace(dataspace);
     if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 9786419..9a72b40 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -36,7 +36,8 @@
     bool setColor(const half3& color) override;
 
     void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
-                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+                         const Rect& viewport, int32_t supportedPerFrameMetadata,
+                         const ui::Dataspace targetDataspace) override;
 
     bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
 
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 738f4b6..7927fa9 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -40,6 +40,6 @@
 }
 
 void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
-                                     const Rect&, int32_t) {}
+                                     const Rect&, int32_t, const ui::Dataspace) {}
 
 } // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index c7cfdcd..7222a3e 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -34,7 +34,8 @@
     bool canReceiveInput() const override;
 
     void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
-                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+                         const Rect& viewport, int32_t supportedPerFrameMetadata,
+                         const ui::Dataspace targetDataspace) override;
 
     bool isCreatedFromMainThread() const override { return true; }
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5ab4523..5c3fb05 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -103,6 +103,7 @@
     mCurrentState.cornerRadius = 0.0f;
     mCurrentState.api = -1;
     mCurrentState.hasColorTransform = false;
+    mCurrentState.colorSpaceAgnostic = false;
 
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
@@ -1355,6 +1356,17 @@
     return true;
 }
 
+bool Layer::setColorSpaceAgnostic(const bool agnostic) {
+    if (mCurrentState.colorSpaceAgnostic == agnostic) {
+        return false;
+    }
+    mCurrentState.sequence++;
+    mCurrentState.colorSpaceAgnostic = agnostic;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 uint32_t Layer::getLayerStack() const {
     auto p = mDrawingParent.promote();
     if (p == nullptr) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 143ac94..1afb917 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -210,6 +210,7 @@
         // The deque of callback handles for this frame. The back of the deque contains the most
         // recent callback handle.
         std::deque<sp<CallbackHandle>> callbackHandles;
+        bool colorSpaceAgnostic;
     };
 
     explicit Layer(const LayerCreationArgs& args);
@@ -297,6 +298,7 @@
     virtual bool setColorTransform(const mat4& matrix);
     virtual mat4 getColorTransform() const;
     virtual bool hasColorTransform() const;
+    virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
 
     // Used only to set BufferStateLayer state
     virtual bool setTransform(uint32_t /*transform*/) { return false; };
@@ -315,6 +317,7 @@
         return false;
     };
     virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
+    virtual bool setColorSpaceAgnostic(const bool agnostic);
 
     ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
 
@@ -450,7 +453,8 @@
     bool getForceClientComposition(const sp<DisplayDevice>& display);
     virtual void setPerFrameData(const sp<const DisplayDevice>& display,
                                  const ui::Transform& transform, const Rect& viewport,
-                                 int32_t supportedPerFrameMetadata) = 0;
+                                 int32_t supportedPerFrameMetadata,
+                                 const ui::Dataspace targetDataspace) = 0;
 
     // callIntoHwc exists so we can update our local state and call
     // acceptDisplayChanges without unnecessarily updating the device's state
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 026f7c7..cbcc031 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -28,7 +28,7 @@
 namespace scheduler {
 
 /**
- * This class is used to encapsulate configuration for refresh rates. It holds infomation
+ * This class is used to encapsulate configuration for refresh rates. It holds information
  * about available refresh rates on the device, and the mapping between the numbers and human
  * readable names.
  */
@@ -40,8 +40,6 @@
     enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
 
     struct RefreshRate {
-        // Type of the refresh rate.
-        RefreshRateType type;
         // This config ID corresponds to the position of the config in the vector that is stored
         // on the device.
         int configId;
@@ -59,13 +57,16 @@
     }
     ~RefreshRateConfigs() = default;
 
-    const std::vector<RefreshRate>& getRefreshRates() { return mRefreshRates; }
+    const std::unordered_map<RefreshRateType, RefreshRate>& getRefreshRates() {
+        return mRefreshRates;
+    }
+    const RefreshRate& getRefreshRate(RefreshRateType type) { return mRefreshRates[type]; }
 
 private:
     void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
         // This is the rate that HWC encapsulates right now when the device is in DOZE mode.
-        mRefreshRates.push_back(
-                RefreshRate{RefreshRateType::POWER_SAVING, SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
+        mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
+                              RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
 
         if (configs.size() < 1) {
             ALOGE("Device does not have valid configs. Config size is 0.");
@@ -88,9 +89,10 @@
         nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
         if (vsyncPeriod != 0) {
             const float fps = 1e9 / vsyncPeriod;
-            mRefreshRates.push_back(
-                    RefreshRate{RefreshRateType::DEFAULT, configIdToVsyncPeriod[0].first,
-                                base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
+            mRefreshRates.emplace(RefreshRateType::DEFAULT,
+                                  RefreshRate{configIdToVsyncPeriod[0].first,
+                                              base::StringPrintf("%2.ffps", fps),
+                                              static_cast<uint32_t>(fps)});
         }
 
         if (configs.size() < 2) {
@@ -102,13 +104,14 @@
         vsyncPeriod = configIdToVsyncPeriod[1].second;
         if (vsyncPeriod != 0) {
             const float fps = 1e9 / vsyncPeriod;
-            mRefreshRates.push_back(
-                    RefreshRate{RefreshRateType::PERFORMANCE, configIdToVsyncPeriod[1].first,
-                                base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
+            mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
+                                  RefreshRate{configIdToVsyncPeriod[1].first,
+                                              base::StringPrintf("%2.ffps", fps),
+                                              static_cast<uint32_t>(fps)});
         }
     }
 
-    std::vector<RefreshRate> mRefreshRates;
+    std::unordered_map<RefreshRateType, RefreshRate> mRefreshRates;
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index dcb2988..2491081 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -41,10 +41,9 @@
     static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
 
 public:
-    explicit RefreshRateStats(
-            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
-            const std::shared_ptr<TimeStats>& timeStats)
-          : mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)),
+    explicit RefreshRateStats(const std::shared_ptr<RefreshRateConfigs>& refreshRateConfigs,
+                              const std::shared_ptr<TimeStats>& timeStats)
+          : mRefreshRateConfigs(refreshRateConfigs),
             mTimeStats(timeStats),
             mPreviousRecordedTime(systemTime()) {}
     ~RefreshRateStats() = default;
@@ -84,7 +83,7 @@
         flushTime();
 
         std::unordered_map<std::string, int64_t> totalTime;
-        for (auto config : mRefreshRateConfigs->getRefreshRates()) {
+        for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) {
             int64_t totalTimeForConfig = 0;
             if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
                 totalTimeForConfig = mConfigModesTotalTime.at(config.configId);
@@ -124,7 +123,7 @@
         mPreviousRecordedTime = currentTime;
 
         mConfigModesTotalTime[mode] += timeElapsedMs;
-        for (const auto& config : mRefreshRateConfigs->getRefreshRates()) {
+        for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) {
             if (config.configId == mode) {
                 mTimeStats->recordRefreshRate(config.fps, timeElapsed);
             }
@@ -143,7 +142,7 @@
     }
 
     // Keeps information about refresh rate configs that device has.
-    std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+    std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs;
 
     // Aggregate refresh rate statistics for telemetry.
     std::shared_ptr<TimeStats> mTimeStats;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 128ebf9..b90bd53 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -201,9 +201,6 @@
 const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
 const String16 sDump("android.permission.DUMP");
 
-constexpr float kDefaultRefreshRate = 60.f;
-constexpr float kPerformanceRefreshRate = 90.f;
-
 // ---------------------------------------------------------------------------
 int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
 bool SurfaceFlinger::useHwcForRgbToYuv;
@@ -712,9 +709,11 @@
             setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
         });
     }
-    mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
-                                                                              *display->getId()),
-                                                                      mTimeStats);
+    mRefreshRateConfigs[*display->getId()] = std::make_shared<scheduler::RefreshRateConfigs>(
+            getHwComposer().getConfigs(*display->getId()));
+    mRefreshRateStats =
+            std::make_unique<scheduler::RefreshRateStats>(mRefreshRateConfigs[*display->getId()],
+                                                          mTimeStats);
 
     ALOGV("Done initializing");
 }
@@ -921,14 +920,6 @@
                                             ConfigEvent event) {
     ATRACE_CALL();
 
-    Vector<DisplayInfo> configs;
-    // Lock is acquired by setRefreshRateTo.
-    getDisplayConfigsLocked(displayToken, &configs);
-    if (mode < 0 || mode >= static_cast<int>(configs.size())) {
-        ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
-        return;
-    }
-
     // Lock is acquired by setRefreshRateTo.
     const auto display = getDisplayDeviceLocked(displayToken);
     if (!display) {
@@ -1426,6 +1417,8 @@
 }
 
 void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, ConfigEvent event) {
+    ATRACE_CALL();
+
     mPhaseOffsets->setRefreshRateType(refreshRate);
 
     const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
@@ -1435,47 +1428,23 @@
         return;
     }
 
-    // TODO(b/113612090): There should be a message queue flush here. Because this esentially
-    // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
-    // manner, once the setActiveConfig is synchronous, and is executed at a known time in a
-    // refresh cycle.
-
     // Don't do any updating if the current fps is the same as the new one.
-    const nsecs_t currentVsyncPeriod = getVsyncPeriod();
-    if (currentVsyncPeriod == 0) {
-        return;
-    }
-
-    // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
-    // floating numbers.
-    const float currentFps = 1e9 / currentVsyncPeriod;
-    const float newFps = refreshRate == RefreshRateType::PERFORMANCE ? kPerformanceRefreshRate
-                                                                     : kDefaultRefreshRate;
-    if (std::abs(currentFps - newFps) <= 1) {
-        return;
-    }
-
     const auto displayId = getInternalDisplayIdLocked();
     LOG_ALWAYS_FATAL_IF(!displayId);
+    const auto displayToken = getInternalDisplayTokenLocked();
 
-    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;
-        }
-        const float fps = 1e9 / vsyncPeriod;
-        // 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, event);
-        }
+    auto desiredConfigId = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate).configId;
+    const auto display = getDisplayDeviceLocked(displayToken);
+    if (desiredConfigId == display->getActiveConfig()) {
+        return;
     }
+
+    if (!isConfigAllowed(*displayId, desiredConfigId)) {
+        ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
+        return;
+    }
+
+    setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
 }
 
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -1789,6 +1758,13 @@
         if (mDrawingState.colorMatrixChanged) {
             display->setColorTransform(mDrawingState.colorMatrix);
         }
+        Dataspace targetDataspace = Dataspace::UNKNOWN;
+        if (useColorManagement) {
+            ColorMode colorMode;
+            RenderIntent renderIntent;
+            pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
+            display->setColorMode(colorMode, targetDataspace, renderIntent);
+        }
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             if (layer->isHdrY410()) {
                 layer->forceClientComposition(displayDevice);
@@ -1820,15 +1796,7 @@
 
             const auto& displayState = display->getState();
             layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
-                                   displayDevice->getSupportedPerFrameMetadata());
-        }
-
-        if (useColorManagement) {
-            ColorMode  colorMode;
-            Dataspace dataSpace;
-            RenderIntent renderIntent;
-            pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
-            display->setColorMode(colorMode, dataSpace, renderIntent);
+                                   displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
         }
     }
 
@@ -3919,6 +3887,11 @@
     if (what & layer_state_t::eMetadataChanged) {
         if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded;
     }
+    if (what & layer_state_t::eColorSpaceAgnosticChanged) {
+        if (layer->setColorSpaceAgnostic(s.colorSpaceAgnostic)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     std::vector<sp<CallbackHandle>> callbackHandles;
     if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
         mTransactionCompletedThread.run();
@@ -5677,17 +5650,13 @@
     // 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)) {
+        for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) {
+            if (isConfigAllowed(*displayId, config.configId)) {
                 // 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);
+                ALOGV("Old config is not allowed - switching to config %d", config.configId);
+                setDesiredActiveConfig(displayToken, config.configId, ConfigEvent::Changed);
                 break;
             }
         }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 57dab7f..75947ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1116,6 +1116,9 @@
     sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
     std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
 
+    std::unordered_map<DisplayId, std::shared_ptr<scheduler::RefreshRateConfigs>>
+            mRefreshRateConfigs;
+
     std::mutex mAllowedConfigsLock;
     std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
             GUARDED_BY(mAllowedConfigsLock);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 3d887ea..4342dc9 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -45,6 +45,7 @@
 
     std::unique_ptr<RefreshRateStats> mRefreshRateStats;
     std::shared_ptr<android::mock::TimeStats> mTimeStats;
+    std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs;
 };
 
 RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -61,7 +62,8 @@
 
 void RefreshRateStatsTest::init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs) {
     mTimeStats = std::make_shared<android::mock::TimeStats>();
-    mRefreshRateStats = std::make_unique<RefreshRateStats>(configs, mTimeStats);
+    mRefreshRateConfigs = std::make_shared<RefreshRateConfigs>(configs);
+    mRefreshRateStats = std::make_unique<RefreshRateStats>(mRefreshRateConfigs, mTimeStats);
 }
 
 namespace {