SF: Initialize DisplayDevice with the active config index

This is a port of aosp/580542, with added unit test changes now that the
correct config is being set in the DisplayDevice.

Bug: 69807179
Test: atest libsurfaceflinger_unittest

Change-Id: I51c13678bc28c715fa116ad127478d4afa3d0349
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 3947318..61758b6 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -30,8 +30,9 @@
 
 #include <android/configuration.h>
 
-#include <algorithm>
 #include <inttypes.h>
+#include <algorithm>
+#include <iterator>
 #include <set>
 
 using android::Fence;
@@ -338,6 +339,31 @@
     return Error::None;
 }
 
+Error Display::getActiveConfigIndex(int* outIndex) const {
+    ALOGV("[%" PRIu64 "] getActiveConfigIndex", mId);
+    hwc2_config_t configId = 0;
+    auto intError = mComposer.getActiveConfig(mId, &configId);
+    auto error = static_cast<Error>(intError);
+
+    if (error != Error::None) {
+        ALOGE("Unable to get active config for mId:[%" PRIu64 "]", mId);
+        *outIndex = -1;
+        return error;
+    }
+
+    auto pos = mConfigs.find(configId);
+    if (pos != mConfigs.end()) {
+        *outIndex = std::distance(mConfigs.begin(), pos);
+    } else {
+        ALOGE("[%" PRIu64 "] getActiveConfig returned unknown config %u", mId, configId);
+        // Return no error, but the caller needs to check for a negative index
+        // to detect this case
+        *outIndex = -1;
+    }
+
+    return Error::None;
+}
+
 Error Display::getChangedCompositionTypes(
         std::unordered_map<Layer*, Composition>* outTypes)
 {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 3ac06ec..29d7a47 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -36,7 +36,6 @@
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
-#include <map>
 
 namespace android {
     class Fence;
@@ -207,6 +206,7 @@
     [[clang::warn_unused_result]] Error destroyLayer(Layer* layer);
     [[clang::warn_unused_result]] Error getActiveConfig(
             std::shared_ptr<const Config>* outConfig) const;
+    [[clang::warn_unused_result]] Error getActiveConfigIndex(int* outIndex) const;
     [[clang::warn_unused_result]] Error getChangedCompositionTypes(
             std::unordered_map<Layer*, Composition>* outTypes);
     [[clang::warn_unused_result]] Error getColorModes(
@@ -288,9 +288,7 @@
     bool mIsConnected;
     DisplayType mType;
     std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
-    // The ordering in this map matters, for getConfigs(), when it is
-    // converted to a vector
-    std::map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
+    std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
 };
 
 // Convenience C++ class to access hwc2_device_t Layer functions directly.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 96d691c..f5f7a82 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -318,6 +318,28 @@
     return config;
 }
 
+int HWComposer::getActiveConfigIndex(int32_t displayId) const {
+    if (!isValidDisplay(displayId)) {
+        ALOGV("getActiveConfigIndex: Attempted to access invalid display %d", displayId);
+        return -1;
+    }
+    int index;
+    auto error = mDisplayData[displayId].hwcDisplay->getActiveConfigIndex(&index);
+    if (error == HWC2::Error::BadConfig) {
+        ALOGE("getActiveConfigIndex: No config active, returning -1");
+        return -1;
+    } else if (error != HWC2::Error::None) {
+        ALOGE("getActiveConfigIndex failed for display %d: %s (%d)", displayId,
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        return -1;
+    } else if (index < 0) {
+        ALOGE("getActiveConfigIndex returned an unknown config for display %d", displayId);
+        return -1;
+    }
+
+    return index;
+}
+
 std::vector<ui::ColorMode> HWComposer::getColorModes(int32_t displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, {});
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index d7f3b08..f968948 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -164,6 +164,7 @@
 
     std::shared_ptr<const HWC2::Display::Config>
             getActiveConfig(int32_t displayId) const;
+    int getActiveConfigIndex(int32_t displayId) const;
 
     std::vector<ui::ColorMode> getColorModes(int32_t displayId) const;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b35b58c..9117207 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2414,6 +2414,9 @@
     }
     setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace,
                                RenderIntent::COLORIMETRIC);
+    if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
+        hw->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+    }
     hw->setLayerStack(state.layerStack);
     hw->setProjection(state.orientation, state.viewport, state.frame);
     hw->setDisplayName(state.displayName);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index d1bbb5b..cd69128 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -306,11 +306,7 @@
     static constexpr HWC2::DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
 
     // The HWC active configuration id
-    // TODO(b/69807179): SurfaceFlinger does not correctly get the active
-    // config. Once it does, change this to non-zero so that it is properly
-    // covered.
-    // static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
-    static constexpr int HWC_ACTIVE_CONFIG_ID = 0;
+    static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
 
     static void injectPendingHotplugEvent(DisplayTransactionTest* test,
                                           HWC2::Connection connection) {
@@ -362,13 +358,11 @@
     // Called by tests to set up HWC call expectations
     static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
         EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(HWC_ACTIVE_CONFIG_ID), Return(Error::NONE)));
+                .WillRepeatedly(DoAll(SetArgPointee<1>(HWC_ACTIVE_CONFIG_ID), Return(Error::NONE)));
     }
 };
 
 struct NonHwcDisplayVariant {
-    static constexpr int HWC_ACTIVE_CONFIG_ID = 0;
-
     static void injectHwcDisplay(DisplayTransactionTest*) {}
 
     static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
@@ -1033,10 +1027,7 @@
 
     // Various native window calls will be made.
     Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
-
-    // TODO(b/69807179): SurfaceFlinger does not correctly get the active config.
-    // Case::Display::setupHwcGetActiveConfigCallExpectations(this)
-
+    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
     Case::WideColorSupport::setupComposerCallExpectations(this);
     Case::HdrSupport::setupComposerCallExpectations(this);
     Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
@@ -1060,7 +1051,10 @@
     EXPECT_EQ(Case::HdrSupport::HDR10_SUPPORTED, device->hasHDR10Support());
     EXPECT_EQ(Case::HdrSupport::HDR_HLG_SUPPORTED, device->hasHLGSupport());
     EXPECT_EQ(Case::HdrSupport::HDR_DOLBY_VISION_SUPPORTED, device->hasDolbyVisionSupport());
-    EXPECT_EQ(Case::Display::HWC_ACTIVE_CONFIG_ID, device->getActiveConfig());
+    // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are
+    // remapped, and the test only ever sets up one config. If there were an error
+    // looking up the remapped index, device->getActiveConfig() would be -1 instead.
+    EXPECT_EQ(0, device->getActiveConfig());
     EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
               device->getSupportedPerFrameMetadata());
 }