Add display finder DRM flow

... so that downstream devices of Cuttlefish that run without
Cuttlefish's config server can still initialize displays.

Eventually, we want to enable this on Cuttlefish as well once
Crosvm fully supports the display properties we use (it looks like
it doesn't support DPI and refresh rate yet).

Bug: b/239855014
Test: cvd start --gpu_mode=gfxstream
                --display0=width=320,height=480
                --display1=width=640,height=500
      `adb shell getprop | grep "hwcomposer"`
      (to confirm mode)
      `adb shell dumpsys SurfaceFlinger`
      (to confirm display props)
      and interact with all displays.
Test: cvd start --gpu_mode=guest_swiftshader
                --display0=width=320,height=480
                --display1=width=640,height=500
                --display2=width=700,height=700
                --display3=width=800,height=600
      `adb shell getprop | grep "hwcomposer"`
      (to confirm mode)
      `adb shell dumpsys SurfaceFlinger`
      (to confirm display props)
      and interact with all displays.
Change-Id: Ifff742e5fc3fe12a1d81d294882bbb3d8b1560d2
diff --git a/system/hwc3/ClientFrameComposer.cpp b/system/hwc3/ClientFrameComposer.cpp
index d7f8b55..284a46f 100644
--- a/system/hwc3/ClientFrameComposer.cpp
+++ b/system/hwc3/ClientFrameComposer.cpp
@@ -146,6 +146,11 @@
   }
 
   DisplayInfo& displayInfo = displayInfoIt->second;
+  if (!displayInfo.clientTargetDrmBuffer) {
+    ALOGW("%s: display:%" PRIu64 " no client target set, nothing to present.",
+          __FUNCTION__, displayId);
+    return HWC3::Error::None;
+  }
 
   ::android::base::unique_fd fence = display->getClientTarget().getFence();
 
diff --git a/system/hwc3/ClientFrameComposer.h b/system/hwc3/ClientFrameComposer.h
index 3fb0ba8..6961354 100644
--- a/system/hwc3/ClientFrameComposer.h
+++ b/system/hwc3/ClientFrameComposer.h
@@ -64,6 +64,10 @@
       std::unordered_map<int64_t, ::android::base::unique_fd>* outLayerFences)
       override;
 
+  const DrmPresenter* getDrmPresenter() const override {
+    return &mDrmPresenter;
+  }
+
  private:
   struct DisplayInfo {
     std::unique_ptr<DrmBuffer> clientTargetDrmBuffer;;
diff --git a/system/hwc3/Common.cpp b/system/hwc3/Common.cpp
index 497f764..e9ac507 100644
--- a/system/hwc3/Common.cpp
+++ b/system/hwc3/Common.cpp
@@ -30,18 +30,34 @@
              std::string::npos;
 }
 
-bool IsNoOpMode() {
+bool IsInNoOpCompositionMode() {
   const std::string mode = ::android::base::GetProperty("ro.vendor.hwcomposer.mode", "");
   DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.mode is %s", __FUNCTION__, mode.c_str());
   return mode == "noop";
 }
 
-bool IsClientCompositionMode() {
+bool IsInClientCompositionMode() {
   const std::string mode = ::android::base::GetProperty("ro.vendor.hwcomposer.mode", "");
   DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.mode is %s", __FUNCTION__, mode.c_str());
   return mode == "client";
 }
 
+bool IsInNoOpDisplayFinderMode() {
+  const std::string mode =
+    ::android::base::GetProperty("ro.vendor.hwcomposer.display_finder_mode", "");
+  DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.display_finder_mode is %s",
+            __FUNCTION__, mode.c_str());
+  return mode == "noop";
+}
+
+bool IsInDrmDisplayFinderMode() {
+  const std::string mode =
+    ::android::base::GetProperty("ro.vendor.hwcomposer.display_finder_mode", "");
+  DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.display_finder_mode is %s",
+            __FUNCTION__, mode.c_str());
+  return mode == "drm";
+}
+
 std::string toString(HWC3::Error error) {
   switch (error) {
     case HWC3::Error::None:
diff --git a/system/hwc3/Common.h b/system/hwc3/Common.h
index 5b6587e..493e5d0 100644
--- a/system/hwc3/Common.h
+++ b/system/hwc3/Common.h
@@ -44,8 +44,12 @@
 
 bool IsCuttlefish();
 bool IsCuttlefishFoldable();
-bool IsNoOpMode();
-bool IsClientCompositionMode();
+
+bool IsInNoOpCompositionMode();
+bool IsInClientCompositionMode();
+
+bool IsInNoOpDisplayFinderMode();
+bool IsInDrmDisplayFinderMode();
 
 namespace HWC3 {
 enum class Error : int32_t {
diff --git a/system/hwc3/ComposerClient.cpp b/system/hwc3/ComposerClient.cpp
index db05383..2098435 100644
--- a/system/hwc3/ComposerClient.cpp
+++ b/system/hwc3/ComposerClient.cpp
@@ -1237,7 +1237,7 @@
 
   std::vector<DisplayMultiConfigs> displays;
 
-  HWC3::Error error = findDisplays(displays);
+  HWC3::Error error = findDisplays(mComposer->getDrmPresenter(), &displays);
   if (error != HWC3::Error::None) {
     ALOGE("%s failed to find display configs", __FUNCTION__);
     return error;
diff --git a/system/hwc3/Device.cpp b/system/hwc3/Device.cpp
index cf4be42..894d48b 100644
--- a/system/hwc3/Device.cpp
+++ b/system/hwc3/Device.cpp
@@ -94,10 +94,10 @@
   std::unique_lock<std::mutex> lock(mMutex);
 
   if (mComposer == nullptr) {
-    if (IsNoOpMode()) {
+    if (IsInNoOpCompositionMode()) {
       DEBUG_LOG("%s: using NoOpFrameComposer", __FUNCTION__);
       mComposer = std::make_unique<NoOpFrameComposer>();
-    } else if (IsClientCompositionMode()) {
+    } else if (IsInClientCompositionMode()) {
       DEBUG_LOG("%s: using ClientFrameComposer", __FUNCTION__);
       mComposer = std::make_unique<ClientFrameComposer>();
     } else if (shouldUseGuestComposer()) {
diff --git a/system/hwc3/DisplayFinder.cpp b/system/hwc3/DisplayFinder.cpp
index 8e252cb..10bd5fd 100644
--- a/system/hwc3/DisplayFinder.cpp
+++ b/system/hwc3/DisplayFinder.cpp
@@ -31,7 +31,7 @@
   return 1000 * 1000 * 1000 / hertz;
 }
 
-HWC3::Error findCuttlefishDisplays(std::vector<DisplayMultiConfigs>& displays) {
+HWC3::Error findCuttlefishDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
   DEBUG_LOG("%s", __FUNCTION__);
 
   // TODO: replace with initializing directly from DRM info.
@@ -55,7 +55,7 @@
                               vsyncPeriodNanos),
             },
     };
-    displays.push_back(display);
+    outDisplays->push_back(display);
     ++displayId;
   }
 
@@ -79,7 +79,7 @@
 }
 
 HWC3::Error findGoldfishPrimaryDisplay(
-    std::vector<DisplayMultiConfigs>& displays) {
+    std::vector<DisplayMultiConfigs>* outDisplays) {
   DEBUG_LOG("%s", __FUNCTION__);
 
   DEFINE_AND_VALIDATE_HOST_CONNECTION
@@ -118,13 +118,13 @@
   }
   hostCon->unlock();
 
-  displays.push_back(display);
+  outDisplays->push_back(display);
 
   return HWC3::Error::None;
 }
 
 HWC3::Error findGoldfishSecondaryDisplays(
-    std::vector<DisplayMultiConfigs>& displays) {
+    std::vector<DisplayMultiConfigs>* outDisplays) {
   DEBUG_LOG("%s", __FUNCTION__);
 
   static constexpr const char kExternalDisplayProp[] =
@@ -170,7 +170,7 @@
         /*dpiYh=*/propIntParts[3],               //
         /*vsyncPeriod=*/HertzToPeriodNanos(160)  //
         ));
-    displays.push_back(display);
+    outDisplays->push_back(display);
 
     ++secondaryDisplayId;
 
@@ -180,14 +180,14 @@
   return HWC3::Error::None;
 }
 
-HWC3::Error findGoldfishDisplays(std::vector<DisplayMultiConfigs>& displays) {
-  HWC3::Error error = findGoldfishPrimaryDisplay(displays);
+HWC3::Error findGoldfishDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
+  HWC3::Error error = findGoldfishPrimaryDisplay(outDisplays);
   if (error != HWC3::Error::None) {
     ALOGE("%s failed to find Goldfish primary display", __FUNCTION__);
     return error;
   }
 
-  error = findGoldfishSecondaryDisplays(displays);
+  error = findGoldfishSecondaryDisplays(outDisplays);
   if (error != HWC3::Error::None) {
     ALOGE("%s failed to find Goldfish secondary displays", __FUNCTION__);
   }
@@ -197,8 +197,8 @@
 
 // This is currently only used for Gem5 bring-up where virtio-gpu and drm
 // are not currently available. For now, just return a placeholder display.
-HWC3::Error findNoOpDisplays(std::vector<DisplayMultiConfigs>& displays) {
-  displays.push_back(DisplayMultiConfigs{
+HWC3::Error findNoOpDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
+  outDisplays->push_back(DisplayMultiConfigs{
       .displayId = 0,
       .activeConfigId = 0,
       .configs = {DisplayConfig(0,
@@ -213,16 +213,54 @@
   return HWC3::Error::None;
 }
 
+HWC3::Error findDrmDisplays(const DrmPresenter& drm,
+                            std::vector<DisplayMultiConfigs>* outDisplays) {
+  outDisplays->clear();
+
+  std::vector<DrmPresenter::DisplayConfig> drmDisplayConfigs;
+
+  HWC3::Error error = drm.getDisplayConfigs(&drmDisplayConfigs);
+  if (error != HWC3::Error::None) {
+    ALOGE("%s failed to find displays from DRM.", __FUNCTION__);
+    return error;
+  }
+
+  for (const DrmPresenter::DisplayConfig drmDisplayConfig : drmDisplayConfigs) {
+    outDisplays->push_back(DisplayMultiConfigs{
+      .displayId = drmDisplayConfig.id,
+      .activeConfigId = static_cast<int32_t>(drmDisplayConfig.id),
+      .configs = {
+        DisplayConfig(static_cast<int32_t>(drmDisplayConfig.id),
+                      drmDisplayConfig.width,
+                      drmDisplayConfig.height,
+                      drmDisplayConfig.dpiX,
+                      drmDisplayConfig.dpiY,
+                      HertzToPeriodNanos(drmDisplayConfig.refreshRateHz)),
+      },
+    });
+  }
+
+  return HWC3::Error::None;
+}
+
 }  // namespace
 
-HWC3::Error findDisplays(std::vector<DisplayMultiConfigs>& displays) {
+HWC3::Error findDisplays(const DrmPresenter* drm,
+                         std::vector<DisplayMultiConfigs>* outDisplays) {
   HWC3::Error error = HWC3::Error::None;
-  if (IsNoOpMode()) {
-    error = findNoOpDisplays(displays);
+  if (IsInNoOpCompositionMode()) {
+    error = findNoOpDisplays(outDisplays);
+  } else if (IsInDrmDisplayFinderMode()) {
+    if (drm == nullptr) {
+      ALOGE("%s asked to find displays from DRM, but DRM not available.",
+            __FUNCTION__);
+      return HWC3::Error::NoResources;
+    }
+    error = findDrmDisplays(*drm, outDisplays);
   } else if (IsCuttlefish()) {
-    error = findCuttlefishDisplays(displays);
+    error = findCuttlefishDisplays(outDisplays);
   } else {
-    error = findGoldfishDisplays(displays);
+    error = findGoldfishDisplays(outDisplays);
   }
 
   if (error != HWC3::Error::None) {
@@ -230,7 +268,7 @@
     return error;
   }
 
-  for (auto& display : displays) {
+  for (auto& display : *outDisplays) {
     DisplayConfig::addConfigGroups(&display.configs);
   }
 
diff --git a/system/hwc3/DisplayFinder.h b/system/hwc3/DisplayFinder.h
index 8197a82..171d204 100644
--- a/system/hwc3/DisplayFinder.h
+++ b/system/hwc3/DisplayFinder.h
@@ -17,10 +17,12 @@
 #ifndef ANDROID_HWC_DISPLAYFINDER_H
 #define ANDROID_HWC_DISPLAYFINDER_H
 
+#include <optional>
 #include <vector>
 
 #include "Common.h"
 #include "DisplayConfig.h"
+#include "DrmPresenter.h"
 
 namespace aidl::android::hardware::graphics::composer3::impl {
 
@@ -31,7 +33,8 @@
   std::vector<DisplayConfig> configs;
 };
 
-HWC3::Error findDisplays(std::vector<DisplayMultiConfigs>& displays);
+HWC3::Error findDisplays(const DrmPresenter* drm,
+                         std::vector<DisplayMultiConfigs>* outDisplays);
 
 }  // namespace aidl::android::hardware::graphics::composer3::impl
 
diff --git a/system/hwc3/DrmPresenter.cpp b/system/hwc3/DrmPresenter.cpp
index 6e13209..a62e17b 100644
--- a/system/hwc3/DrmPresenter.cpp
+++ b/system/hwc3/DrmPresenter.cpp
@@ -93,6 +93,31 @@
   return HWC3::Error::None;
 }
 
+HWC3::Error DrmPresenter::getDisplayConfigs(std::vector<DisplayConfig>* configs) const {
+  AutoReadLock lock(mStateMutex);
+
+  configs->clear();
+
+  for (uint32_t i = 0; i < mConnectors.size(); i++) {
+    const auto& connector = mConnectors[i];
+
+    if (connector.connection != DRM_MODE_CONNECTED) {
+      continue;
+    }
+
+    configs->emplace_back(DisplayConfig{
+        .id = i,
+        .width = connector.mMode.hdisplay,
+        .height = connector.mMode.vdisplay,
+        .dpiX = 160, //static_cast<uint32_t>(connector.dpiX),
+        .dpiY = 160, //static_cast<uint32_t>(connector.dpiY),
+        .refreshRateHz = connector.mRefreshRateAsInteger,
+    });
+  }
+
+  return HWC3::Error::None;
+}
+
 HWC3::Error DrmPresenter::registerOnHotplugCallback(const HotplugCallback& cb) {
   mHotplugCallback = cb;
   return HWC3::Error::None;
diff --git a/system/hwc3/DrmPresenter.h b/system/hwc3/DrmPresenter.h
index 61e546a..c87e5aa 100644
--- a/system/hwc3/DrmPresenter.h
+++ b/system/hwc3/DrmPresenter.h
@@ -77,6 +77,17 @@
 
   HWC3::Error init();
 
+  struct DisplayConfig {
+    uint32_t id;
+    uint32_t width;
+    uint32_t height;
+    uint32_t dpiX;
+    uint32_t dpiY;
+    uint32_t refreshRateHz;
+  };
+
+  HWC3::Error getDisplayConfigs(std::vector<DisplayConfig>* configs) const;
+
   using HotplugCallback = std::function<void(bool /*connected*/,   //
                                              uint32_t /*id*/,      //
                                              uint32_t /*width*/,   //
@@ -117,7 +128,7 @@
   std::optional<HotplugCallback> mHotplugCallback;
 
   // Protects access to the below drm structs.
-  ::android::base::guest::ReadWriteLock mStateMutex;
+  mutable ::android::base::guest::ReadWriteLock mStateMutex;
 
   struct DrmPlane {
     uint32_t mId = -1;
diff --git a/system/hwc3/FrameComposer.h b/system/hwc3/FrameComposer.h
index fdb6db3..794855b 100644
--- a/system/hwc3/FrameComposer.h
+++ b/system/hwc3/FrameComposer.h
@@ -26,6 +26,7 @@
 
 #include "Common.h"
 #include "DisplayChanges.h"
+#include "DrmPresenter.h"
 
 namespace aidl::android::hardware::graphics::composer3::impl {
 
@@ -68,6 +69,10 @@
           outLayerFences) = 0;
 
   virtual HWC3::Error onActiveConfigChange(Display* display) = 0;
+
+  virtual const DrmPresenter* getDrmPresenter() const {
+    return nullptr;
+  }
 };
 
 }  // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/GuestFrameComposer.h b/system/hwc3/GuestFrameComposer.h
index af46b3d..2ab1a82 100644
--- a/system/hwc3/GuestFrameComposer.h
+++ b/system/hwc3/GuestFrameComposer.h
@@ -62,6 +62,10 @@
 
   HWC3::Error onActiveConfigChange(Display* /*display*/) override;
 
+  const DrmPresenter* getDrmPresenter() const override {
+    return &mDrmPresenter;
+  }
+
  private:
   struct DisplayConfig {
     int width;
diff --git a/system/hwc3/HostFrameComposer.h b/system/hwc3/HostFrameComposer.h
index e99e6f2..b2b042c 100644
--- a/system/hwc3/HostFrameComposer.h
+++ b/system/hwc3/HostFrameComposer.h
@@ -65,6 +65,13 @@
 
   HWC3::Error onActiveConfigChange(Display* display) override;
 
+  const DrmPresenter* getDrmPresenter() const override {
+    if (mDrmPresenter) {
+      return &*mDrmPresenter;
+    }
+    return nullptr;
+  }
+
  private:
   HWC3::Error createHostComposerDisplayInfo(Display* display,
                                             uint32_t hostDisplayId);