Runtime multidsplay handling through virtio gpu

Bug: 184849633

* Display change listener
* Add/Del/Modify secondary displays at runtime. When hotplug is called
with DISCONNECTED, surfaceFlinger will call hwc2 to destroy layer, stop
vsync.

Test: add/modify/del display at runtime

Change-Id: Ia8a1230c615ef6359213d6297d43dfd5eec37bc2
diff --git a/system/hwc2/Android.mk b/system/hwc2/Android.mk
index 29eff18..2254d2f 100644
--- a/system/hwc2/Android.mk
+++ b/system/hwc2/Android.mk
@@ -46,6 +46,7 @@
 
 emulator_hwcomposer_c_includes += \
     device/generic/goldfish-opengl/host/include/libOpenglRender \
+    device/generic/goldfish-opengl/android-emu \
     device/generic/goldfish-opengl/shared/OpenglCodecCommon \
     device/generic/goldfish-opengl/system/OpenglSystemCommon \
     device/generic/goldfish-opengl/system/include \
diff --git a/system/hwc2/Common.h b/system/hwc2/Common.h
index 4313a78..949708d 100644
--- a/system/hwc2/Common.h
+++ b/system/hwc2/Common.h
@@ -25,7 +25,7 @@
 #include <log/log.h>
 
 // Uncomment to enable additional debug logging.
-// #define DEBUG_RANCHU_HWC
+//#define DEBUG_RANCHU_HWC
 
 #if defined(DEBUG_RANCHU_HWC)
 #define DEBUG_LOG ALOGE
@@ -39,4 +39,4 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
-#endif
\ No newline at end of file
+#endif
diff --git a/system/hwc2/Composer.h b/system/hwc2/Composer.h
index 795504f..1b65f3a 100644
--- a/system/hwc2/Composer.h
+++ b/system/hwc2/Composer.h
@@ -24,7 +24,6 @@
 #include "Common.h"
 
 namespace android {
-
 class Device;
 class Display;
 
@@ -32,7 +31,13 @@
  public:
   virtual ~Composer() {}
 
-  virtual HWC2::Error init() = 0;
+  using HotplugCallback =
+    std::function<void(bool /*connected*/, uint32_t /*id*/,
+                       uint32_t /*width*/, uint32_t /*height*/,
+                       uint32_t /*dpiX*/, uint32_t /*dpiY*/,
+                       uint32_t /*refreshRate*/)>;
+
+  virtual HWC2::Error init(const HotplugCallback& cb) = 0;
 
   using AddDisplayToDeviceFunction =
       std::function<HWC2::Error(std::unique_ptr<Display>)>;
@@ -43,6 +48,11 @@
       Device* device,
       const AddDisplayToDeviceFunction& addDisplayToDeviceFn) = 0;
 
+  virtual HWC2::Error createDisplay(
+      Device* device, uint32_t displayId, uint32_t width, uint32_t height,
+      uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+      const AddDisplayToDeviceFunction& addDisplayToDeviceFn) = 0;
+
   virtual HWC2::Error onDisplayDestroy(Display* display) = 0;
 
   virtual HWC2::Error onDisplayClientTargetSet(Display* display) = 0;
@@ -61,4 +71,4 @@
 
 }  // namespace android
 
-#endif
\ No newline at end of file
+#endif
diff --git a/system/hwc2/Device.cpp b/system/hwc2/Device.cpp
index fa6362f..29ae17f 100644
--- a/system/hwc2/Device.cpp
+++ b/system/hwc2/Device.cpp
@@ -61,7 +61,14 @@
     mComposer = std::make_unique<HostComposer>();
   }
 
-  HWC2::Error error = mComposer->init();
+  HWC2::Error error = mComposer->init(
+    [this](bool connected, uint32_t id,
+           uint32_t width, uint32_t height,
+           uint32_t dpiX, uint32_t dpiY,
+           uint32_t refreshRate) {
+    handleHotplug(connected, id, width, height, dpiX, dpiY, refreshRate);
+  });
+
   if (error != HWC2::Error::None) {
     ALOGE("%s failed to initialize Composer", __FUNCTION__);
     return HWC2::Error::NoResources;
@@ -107,6 +114,32 @@
   return HWC2::Error::None;
 }
 
+HWC2::Error Device::createDisplay(uint32_t displayId, uint32_t width,
+                                           uint32_t height, uint32_t dpiX, uint32_t dpiY,
+                                           uint32_t refreshRate) {
+  if (!mComposer) {
+    ALOGE("%s composer not initialized!", __FUNCTION__);
+    return HWC2::Error::NoResources;
+  }
+
+  auto addDisplayLockedFn = [this](std::unique_ptr<Display> display) {
+    auto displayId = display->getId();
+    DEBUG_LOG("%s: adding display:%" PRIu64, __FUNCTION__, displayId);
+    mDisplays.emplace(displayId, std::move(display));
+    return HWC2::Error::None;
+  };
+
+  HWC2::Error error = mComposer->createDisplay(this, displayId, width, height,
+                                                        dpiX, dpiY, refreshRate,
+                                                        addDisplayLockedFn);
+  if (error != HWC2::Error::None) {
+    ALOGE("%s composer failed to create displays", __FUNCTION__);
+    return error;
+  }
+
+  return HWC2::Error::None;
+}
+
 HWC2::Error Device::destroyDisplays() {
   DEBUG_LOG("%s", __FUNCTION__);
 
@@ -472,10 +505,38 @@
   return HWC2::Error::None;
 }
 
+bool Device::handleHotplug(bool connected, uint32_t id, uint32_t width,
+                           uint32_t height, uint32_t dpiX, uint32_t dpiY,
+                           uint32_t refreshRate) {
+  std::unique_lock<std::mutex> lock(mStateMutex);
+  if (mCallbacks[HWC2::Callback::Hotplug].pointer == nullptr) {
+    return false;
+  }
+  auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(mCallbacks[HWC2::Callback::Hotplug].pointer);
+  auto hotplugConnect = static_cast<int32_t>(HWC2::Connection::Connected);
+  auto hotplugDisconnect = static_cast<int32_t>(HWC2::Connection::Disconnected);
+  Display* display = getDisplay(id);
+  if (display) {
+    // if existed, disconnect first
+    ALOGD("callback hotplugDisconnect display %" PRIu32, id);
+    hotplug(mCallbacks[HWC2::Callback::Hotplug].data, id, hotplugDisconnect);
+    display->lock();
+    mComposer->onDisplayDestroy(display);
+    display->unlock();
+  }
+  if (connected) {
+    createDisplay(id, width, height, dpiX, dpiY, refreshRate);
+    ALOGD("callback hotplugConnect display %" PRIu32, id);
+    hotplug(mCallbacks[HWC2::Callback::Hotplug].data, id, hotplugConnect);
+  };
+
+  return true;
+}
+
 Display* Device::getDisplay(hwc2_display_t id) {
   auto display = mDisplays.find(id);
   if (display == mDisplays.end()) {
-    ALOGE("Failed to get display for id=%d", (uint32_t)id);
+    ALOGW("Failed to get display for id=%d", (uint32_t)id);
     return nullptr;
   }
   return display->second.get();
diff --git a/system/hwc2/Device.h b/system/hwc2/Device.h
index 7dae04b0..1b9cf50 100644
--- a/system/hwc2/Device.h
+++ b/system/hwc2/Device.h
@@ -53,9 +53,19 @@
 
   HWC2::Error createDisplays();
 
+  HWC2::Error createDisplay(uint32_t displayId, uint32_t width,
+                                     uint32_t height, uint32_t dpiX, uint32_t dpiY,
+                                     uint32_t refreshRate);
+
+  Display* getDisplay(hwc2_display_t displayId);
+
  private:
   HWC2::Error destroyDisplays();
 
+  bool handleHotplug(bool connected, uint32_t id, uint32_t width,
+                     uint32_t height, uint32_t dpiX, uint32_t dpiY,
+                     uint32_t refreshRate);
+
   void getCapabilities(uint32_t* outCount, int32_t* outCapabilities);
   static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
                                   int32_t* outCapabilities);
@@ -71,8 +81,6 @@
     return static_cast<T>(((*device).*func)(std::forward<Args>(args)...));
   }
 
-  Display* getDisplay(hwc2_display_t displayId);
-
   // Wrapper to call a specific function on a specific display.
   template <typename HookType, HookType func, typename... Args>
   static int32_t displayHook(hwc2_device_t* dev, hwc2_display_t displayId,
diff --git a/system/hwc2/Display.cpp b/system/hwc2/Display.cpp
index 786ce2a..f97dbc2 100644
--- a/system/hwc2/Display.cpp
+++ b/system/hwc2/Display.cpp
@@ -27,7 +27,6 @@
 namespace {
 
 std::atomic<hwc2_config_t> sNextConfigId{0};
-std::atomic<hwc2_display_t> sNextDisplayId{0};
 
 bool IsValidColorMode(android_color_mode_t mode) {
   switch (mode) {
@@ -61,10 +60,10 @@
 
 }  // namespace
 
-Display::Display(Device& device, Composer* composer)
+Display::Display(Device& device, Composer* composer, hwc2_display_t id)
     : mDevice(device),
       mComposer(composer),
-      mId(sNextDisplayId++),
+      mId(id),
       mVsyncThread(new VsyncThread(*this)) {}
 
 Display::~Display() {}
@@ -97,6 +96,30 @@
   return HWC2::Error::None;
 }
 
+HWC2::Error Display::updateParameters(uint32_t width, uint32_t height, uint32_t dpiX,
+                                      uint32_t dpiY, uint32_t refreshRateHz) {
+  DEBUG_LOG("%s updating display:%" PRIu64
+            " width:%d height:%d dpiX:%d dpiY:%d refreshRateHz:%d",
+            __FUNCTION__, mId, width, height, dpiX, dpiY, refreshRateHz);
+
+  std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+  mVsyncPeriod = 1000 * 1000 * 1000 / refreshRateHz;
+
+  auto it = mConfigs.find(*mActiveConfigId);
+  if (it == mConfigs.end()) {
+    ALOGE("%s: failed to find config %" PRIu32, __func__, *mActiveConfigId);
+    return HWC2::Error::NoResources;
+  }
+  it->second.setAttribute(HWC2::Attribute::VsyncPeriod, mVsyncPeriod);
+  it->second.setAttribute(HWC2::Attribute::Width, width);
+  it->second.setAttribute(HWC2::Attribute::Height, height);
+  it->second.setAttribute(HWC2::Attribute::DpiX, dpiX * 1000);
+  it->second.setAttribute(HWC2::Attribute::DpiY, dpiY * 1000);
+
+  return HWC2::Error::None;
+}
+
 Layer* Display::getLayer(hwc2_layer_t layerId) {
   auto it = mLayers.find(layerId);
   if (it == mLayers.end()) {
@@ -216,6 +239,8 @@
 
   const Config& config = it->second;
   *outValue = config.getAttribute(attribute);
+  DEBUG_LOG("%s: display:%" PRIu64 " attribute:%s value is %" PRIi32,
+            __FUNCTION__, mId, attributeString.c_str(), *outValue);
   return HWC2::Error::None;
 }
 
diff --git a/system/hwc2/Display.h b/system/hwc2/Display.h
index 910cf5a..277933a 100644
--- a/system/hwc2/Display.h
+++ b/system/hwc2/Display.h
@@ -37,7 +37,7 @@
 
 class Display {
  public:
-  Display(Device& device, Composer* composer);
+  Display(Device& device, Composer* composer, hwc2_display_t id);
   ~Display();
 
   Display(const Display& display) = delete;
@@ -49,6 +49,9 @@
   HWC2::Error init(uint32_t width, uint32_t height, uint32_t dpiX,
                    uint32_t dpiY, uint32_t refreshRateHz);
 
+  HWC2::Error updateParameters(uint32_t width, uint32_t height, uint32_t dpiX,
+                               uint32_t dpiY, uint32_t refreshRateHz);
+
   hwc2_display_t getId() const { return mId; }
 
   Layer* getLayer(hwc2_layer_t layerHandle);
@@ -108,6 +111,8 @@
                                      uint32_t* outCapabilities);
   HWC2::Error getDisplayBrightnessSupport(bool* out_support);
   HWC2::Error setDisplayBrightness(float brightness);
+  void lock() { mStateMutex.lock(); }
+  void unlock() { mStateMutex.unlock(); }
 
  private:
   class Config {
diff --git a/system/hwc2/DrmPresenter.cpp b/system/hwc2/DrmPresenter.cpp
index 56eee8e..b31e73c 100644
--- a/system/hwc2/DrmPresenter.cpp
+++ b/system/hwc2/DrmPresenter.cpp
@@ -17,14 +17,21 @@
 #include "DrmPresenter.h"
 
 #include <cros_gralloc_handle.h>
+#include <linux/netlink.h>
+#include <sys/socket.h>
+
+using android::base::guest::ReadWriteLock;
+using android::base::guest::AutoReadLock;
+using android::base::guest::AutoWriteLock;
 
 namespace android {
 
 DrmPresenter::DrmPresenter() {}
 
-bool DrmPresenter::init() {
+bool DrmPresenter::init(const HotplugCallback& cb) {
   DEBUG_LOG("%s", __FUNCTION__);
 
+  mHotplugCallback = cb;
   mFd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
   if (mFd < 0) {
     ALOGE("%s HWC2::Error opening DrmPresenter device: %d", __FUNCTION__,
@@ -35,33 +42,49 @@
   int univRet = drmSetClientCap(mFd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
   if (univRet) {
     ALOGE("%s: fail to set universal plane %d\n", __FUNCTION__, univRet);
+    return false;
   }
 
   int atomicRet = drmSetClientCap(mFd, DRM_CLIENT_CAP_ATOMIC, 1);
   if (atomicRet) {
     ALOGE("%s: fail to set atomic operation %d, %d\n", __FUNCTION__, atomicRet,
           errno);
-  }
-  ALOGD("%s: Did set universal planes and atomic cap\n", __FUNCTION__);
-
-  bool configRet = configDrmElements();
-  if (configRet) {
-    ALOGD("%s: Successfully initialized DRM backend", __FUNCTION__);
-  } else {
-    ALOGD("%s: Failed to initialize DRM backend", __FUNCTION__);
+    return false;
   }
 
-  return configRet;
+  {
+    AutoWriteLock lock(mStateMutex);
+    bool configRet = configDrmElementsLocked();
+    if (configRet) {
+      ALOGD("%s: Successfully initialized DRM backend", __FUNCTION__);
+    } else {
+      ALOGE("%s: Failed to initialize DRM backend", __FUNCTION__);
+      return false;
+    }
+  }
+
+  mDrmEventListener.reset(new DrmEventListener(*this));
+  mDrmEventListener->run("", ANDROID_PRIORITY_URGENT_DISPLAY);
+
+  return true;
 }
 
-void DrmPresenter::clearDrmElements() {
+void DrmPresenter::clearDrmElementsLocked() {
+  for (auto& c : mConnectors) {
+    if (c.mModeBlobId) {
+      if (drmModeDestroyPropertyBlob(mFd, c.mModeBlobId)) {
+        ALOGE("%s: Error destroy PropertyBlob %" PRIu32, __func__, c.mModeBlobId);
+      }
+    }
+  }
   mConnectors.clear();
   mCrtcs.clear();
   mPlanes.clear();
 }
 
-bool DrmPresenter::configDrmElements() {
+bool DrmPresenter::configDrmElementsLocked() {
   drmModeRes* res;
+  static const int32_t kUmPerInch = 25400;
 
   res = drmModeGetResources(mFd);
   if (res == nullptr) {
@@ -71,7 +94,7 @@
     return false;
   }
 
-  ALOGI(
+  ALOGD(
       "drmModeRes count fbs %d crtc %d connector %d encoder %d min w %d max w "
       "%d min h %d max h %d",
       res->count_fbs, res->count_crtcs, res->count_connectors,
@@ -94,16 +117,10 @@
 
       if (!strcmp(crtcProp->name, "OUT_FENCE_PTR")) {
         crtc.mFencePropertyId = crtcProp->prop_id;
-        ALOGI("%s: Crtc %" PRIu32 " fence property id: %" PRIu32, __FUNCTION__,
-              crtc.mId, crtcProp->prop_id);
       } else if (!strcmp(crtcProp->name, "ACTIVE")) {
         crtc.mActivePropertyId = crtcProp->prop_id;
-        ALOGI("%s: Crtc %" PRIu32 " active property id: %" PRIu32, __FUNCTION__,
-              crtc.mId, crtcProp->prop_id);
       } else if (!strcmp(crtcProp->name, "MODE_ID")) {
         crtc.mModePropertyId = crtcProp->prop_id;
-        ALOGI("%s: Crtc %" PRIu32 " mode property id: %" PRIu32, __FUNCTION__,
-              crtc.mId, crtcProp->prop_id);
       }
 
       drmModeFreeProperty(crtcProp);
@@ -121,7 +138,7 @@
     drmModePlanePtr p = drmModeGetPlane(mFd, planeRes->planes[i]);
     plane.mId = p->plane_id;
 
-    ALOGI(
+    ALOGD(
         "%s: plane id: %u crtcid %u fbid %u crtc xy %d %d xy %d %d "
         "possible ctrcs 0x%x",
         __FUNCTION__, p->plane_id, p->crtc_id, p->fb_id, p->crtc_x, p->crtc_y,
@@ -137,48 +154,26 @@
 
       if (!strcmp(planeProp->name, "CRTC_ID")) {
         plane.mCrtcPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " crtc property %u", __FUNCTION__, plane.mId,
-              planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "FB_ID")) {
         plane.mFbPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " fb property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "CRTC_X")) {
         plane.mCrtcXPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " crtc X property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "CRTC_Y")) {
         plane.mCrtcYPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " crtc Y property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "CRTC_W")) {
         plane.mCrtcWPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " crtc W property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "CRTC_H")) {
         plane.mCrtcHPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " crtc H property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "SRC_X")) {
         plane.mSrcXPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " src X property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "SRC_Y")) {
         plane.mSrcYPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " src Y property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "SRC_W")) {
         plane.mSrcWPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " src W property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "SRC_H")) {
         plane.mSrcHPropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " src H property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
       } else if (!strcmp(planeProp->name, "type")) {
         plane.mTypePropertyId = planeProp->prop_id;
-        ALOGD("%s: plane %" PRIu32 " type property id %" PRIu32, __FUNCTION__,
-              plane.mId, planeProp->prop_id);
         uint64_t type = planeProp->values[0];
         switch (type) {
           case DRM_PLANE_TYPE_OVERLAY:
@@ -203,27 +198,22 @@
 
     bool isPrimaryOrOverlay = plane.mType == DRM_PLANE_TYPE_OVERLAY ||
                               plane.mType == DRM_PLANE_TYPE_PRIMARY;
-    if (isPrimaryOrOverlay && ((1 << 0) & p->possible_crtcs)) {
-      ALOGD("%s: plane %" PRIu32 " compatible with crtc mask %" PRIu32,
-            __FUNCTION__, plane.mId, p->possible_crtcs);
-    }
-
-    if (plane.mType == DRM_PLANE_TYPE_OVERLAY ||
-        plane.mType == DRM_PLANE_TYPE_PRIMARY) {
-      // TODO: correctly convert mask.
-      uint32_t crtcIndex = p->possible_crtcs - 1;
-
-      DrmCrtc& crtc = mCrtcs[crtcIndex];
-
-      if (crtc.mPlaneId == -1) {
-        crtc.mPlaneId = plane.mId;
-        ALOGE("%s: plane %" PRIu32 " associated with crtc %" PRIu32,
-              __FUNCTION__, plane.mId, crtc.mId);
+    if (isPrimaryOrOverlay) {
+      for (uint32_t j = 0; j < mCrtcs.size(); j++) {
+        if ((0x1 << j) & p->possible_crtcs) {
+          ALOGD("%s: plane %" PRIu32 " compatible with crtc mask %" PRIu32,
+                __FUNCTION__, plane.mId, p->possible_crtcs);
+          if (mCrtcs[j].mPlaneId == -1) {
+            mCrtcs[j].mPlaneId = plane.mId;
+            ALOGD("%s: plane %" PRIu32 " associated with crtc %" PRIu32,
+                  __FUNCTION__, plane.mId, j);
+            break;
+          }
+        }
       }
     }
 
     drmModeFreePlane(p);
-
     mPlanes[plane.mId] = plane;
   }
   drmModeFreePlaneResources(planeRes);
@@ -243,8 +233,6 @@
             drmModeGetProperty(mFd, connectorProps->props[connectorPropIndex]);
         if (!strcmp(connectorProp->name, "CRTC_ID")) {
           connector.mCrtcPropertyId = connectorProp->prop_id;
-          ALOGD("%s: connector %" PRIu32 " crtc prop id %" PRIu32, __FUNCTION__,
-                connector.mId, connectorProp->prop_id);
         }
         drmModeFreeProperty(connectorProp);
       }
@@ -258,14 +246,22 @@
               connector.mId, errno);
         return false;
       }
+      connector.connection = c->connection;
+      if (c->count_modes > 0) {
+        memcpy(&connector.mMode, &c->modes[0], sizeof(drmModeModeInfo));
+        drmModeCreatePropertyBlob(mFd, &connector.mMode, sizeof(connector.mMode),
+                                  &connector.mModeBlobId);
 
-      memcpy(&connector.mMode, &c->modes[0], sizeof(drmModeModeInfo));
+        // Dots per 1000 inches
+        connector.dpiX = c->mmWidth ? (c->mmWidth * kUmPerInch * 10) / c->modes[0].hdisplay : -1;
+        // Dots per 1000 inches
+        connector.dpiY = c->mmHeight ? (c->mmHeight * kUmPerInch * 10) / c->modes[0].vdisplay : -1;
+      }
+      ALOGD("%s connector %" PRIu32 " dpiX %" PRIi32 " dpiY %" PRIi32 " connection %d",
+            __FUNCTION__, connector.mId, connector.dpiX, connector.dpiY, connector.connection);
 
       drmModeFreeConnector(c);
 
-      drmModeCreatePropertyBlob(mFd, &connector.mMode, sizeof(connector.mMode),
-                                &connector.mModeBlobId);
-
       connector.mRefreshRateAsFloat =
           1000.0f * connector.mMode.clock /
           ((float)connector.mMode.vtotal * (float)connector.mMode.htotal);
@@ -296,7 +292,6 @@
           strerror(errno), errno);
     return -1;
   }
-  ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
   return 0;
 }
 
@@ -322,10 +317,49 @@
   return ret;
 }
 
-bool DrmPresenter::supportComposeWithoutPost() { return true; }
+bool DrmPresenter::handleHotPlug() {
+  std::vector<DrmConnector> oldConnectors(mConnectors);
+  {
+    AutoReadLock lock(mStateMutex);
+    oldConnectors.assign(mConnectors.begin(), mConnectors.end());
+  }
+  {
+    AutoWriteLock lock(mStateMutex);
+    clearDrmElementsLocked();
+    configDrmElementsLocked();
+  }
 
-HWC2::Error DrmPresenter::flushToDisplay(int display, hwc_drm_bo_t& bo,
-                                         int* outSyncFd) {
+  AutoReadLock lock(mStateMutex);
+  for (int i = 0; i < mConnectors.size(); i++) {
+    bool changed = oldConnectors[i].dpiX != mConnectors[i].dpiX ||
+                   oldConnectors[i].dpiY != mConnectors[i].dpiY ||
+                   oldConnectors[i].connection != mConnectors[i].connection ||
+                   oldConnectors[i].mMode.hdisplay != mConnectors[i].mMode.hdisplay ||
+                   oldConnectors[i].mMode.vdisplay != mConnectors[i].mMode.vdisplay;
+    if (changed) {
+      if (i == 0) {
+        ALOGE("%s: Ignoring changes to display:0 which is not configurable by "
+              "multi-display interface.", __FUNCTION__);
+        continue;
+      }
+
+      bool connected = mConnectors[i].connection == DRM_MODE_CONNECTED ? true : false;
+      if (mHotplugCallback) {
+        mHotplugCallback(connected, i,
+                         mConnectors[i].mMode.hdisplay,
+                         mConnectors[i].mMode.vdisplay,
+                         mConnectors[i].dpiX,
+                         mConnectors[i].dpiY,
+                         mConnectors[i].mRefreshRateAsInteger);
+      }
+    }
+  }
+  return true;
+}
+
+HWC2::Error DrmPresenter::flushToDisplay(int display, hwc_drm_bo_t& bo, int* outSyncFd) {
+  AutoReadLock lock(mStateMutex);
+
   DrmConnector& connector = mConnectors[display];
   DrmCrtc& crtc = mCrtcs[display];
 
@@ -470,4 +504,95 @@
   return mDrmPresenter.flushToDisplay(display, mBo, outFlushDoneSyncFd);
 }
 
+DrmPresenter::DrmEventListener::DrmEventListener(DrmPresenter& presenter)
+  : mPresenter(presenter) {
+  mEventFd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+  if (mEventFd < 0) {
+    ALOGE("Failed to open uevent socket: %s", strerror(errno));
+    return;
+  }
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  addr.nl_pid = 0;
+  addr.nl_groups = 0xFFFFFFFF;
+
+  int ret = bind(mEventFd, (struct sockaddr *)&addr, sizeof(addr));
+  if (ret) {
+    ALOGE("Failed to bind uevent socket: %s", strerror(errno));
+    return;
+  }
+
+  FD_ZERO(&mFds);
+  FD_SET(mPresenter.mFd, &mFds);
+  FD_SET(mEventFd, &mFds);
+  mMaxFd = std::max(mPresenter.mFd, mEventFd);
+}
+
+DrmPresenter::DrmEventListener::~DrmEventListener() {
+  if (mEventFd >= 0) {
+    close(mEventFd);
+  }
+}
+
+bool DrmPresenter::DrmEventListener::threadLoop() {
+  int ret;
+  do {
+    ret = select(mMaxFd + 1, &mFds, NULL, NULL, NULL);
+  } while (ret == -1 && errno == EINTR);
+
+  // if (FD_ISSET(mPresenter.mFd, &mFds)) {
+  //   TODO: handle drm related events
+  // }
+
+  if (FD_ISSET(mEventFd, &mFds)) {
+    UEventHandler();
+  }
+  return true;
+}
+
+void DrmPresenter::DrmEventListener::UEventHandler() {
+  char buffer[1024];
+  int ret;
+
+  struct timespec ts;
+  uint64_t timestamp = 0;
+  ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+  if (!ret) {
+    timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+  } else {
+    ALOGE("Failed to get monotonic clock on hotplug %d", ret);
+  }
+
+  while (true) {
+    ret = read(mEventFd, &buffer, sizeof(buffer));
+    if (ret == 0) {
+      return;
+    } else if (ret < 0) {
+      ALOGE("Got error reading uevent %d", ret);
+      return;
+    }
+
+    bool drmEvent = false, hotplugEvent = false;
+    for (int i = 0; i < ret;) {
+      char *event = buffer + i;
+      if (strcmp(event, "DEVTYPE=drm_minor")) {
+        drmEvent = true;
+      } else if (strcmp(event, "HOTPLUG=1")) {
+        hotplugEvent = true;
+      }
+
+      i += strlen(event) + 1;
+    }
+
+    if (drmEvent && hotplugEvent) {
+      processHotplug(timestamp);
+    }
+  }
+}
+
+void DrmPresenter::DrmEventListener::processHotplug(uint64_t timestamp) {
+  ALOGD("hotplug event %" PRIu64, timestamp);
+  mPresenter.handleHotPlug();
+}
 }  // namespace android
diff --git a/system/hwc2/DrmPresenter.h b/system/hwc2/DrmPresenter.h
index 0c3b5b1..26d3d94 100644
--- a/system/hwc2/DrmPresenter.h
+++ b/system/hwc2/DrmPresenter.h
@@ -17,13 +17,16 @@
 #ifndef ANDROID_HWC_DRMPRESENTER_H
 #define ANDROID_HWC_DRMPRESENTER_H
 
+#include <map>
+#include <memory>
+#include <vector>
+
 #include <include/drmhwcgralloc.h>
+#include <utils/Thread.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
-#include <map>
-#include <vector>
-
+#include "android/base/synchronization/AndroidLock.h"
 #include "Common.h"
 
 namespace android {
@@ -63,21 +66,29 @@
   DrmPresenter(DrmPresenter&&) = delete;
   DrmPresenter& operator=(DrmPresenter&&) = delete;
 
-  bool init();
-  void clearDrmElements();
-  bool configDrmElements();
+  using HotplugCallback =
+    std::function<void(bool /*connected*/, uint32_t /*id*/,
+                       uint32_t /*width*/, uint32_t /*height*/,
+                       uint32_t /*dpiX*/, uint32_t /*dpiY*/,
+                       uint32_t /*refreshRate*/)>;
+
+  bool init(const HotplugCallback& cb);
+
+  void clearDrmElementsLocked();
+  bool configDrmElementsLocked();
 
   int getDrmFB(hwc_drm_bo_t& bo);
   int clearDrmFB(hwc_drm_bo_t& bo);
-  bool supportComposeWithoutPost();
+
   uint32_t refreshRate() const { return mConnectors[0].mRefreshRateAsInteger; }
+  bool handleHotPlug();
 
   HWC2::Error flushToDisplay(int display, hwc_drm_bo_t& fb, int* outSyncFd);
 
  private:
   // Drm device.
   int32_t mFd = -1;
-
+  HotplugCallback mHotplugCallback;
   struct DrmPlane {
     uint32_t mId = -1;
     uint32_t mCrtcPropertyId = -1;
@@ -110,11 +121,30 @@
     uint32_t mId = -1;
     uint32_t mCrtcPropertyId = -1;
     drmModeModeInfo mMode;
-    uint32_t mModeBlobId;
+    int32_t dpiX;
+    int32_t dpiY;
+    drmModeConnection connection;
+    uint32_t mModeBlobId = 0;
     float mRefreshRateAsFloat;
     uint32_t mRefreshRateAsInteger;
   };
   std::vector<DrmConnector> mConnectors;
+
+  class DrmEventListener : public Thread {
+    public:
+      DrmEventListener(DrmPresenter& presenter);
+      virtual ~DrmEventListener();
+    private:
+      bool threadLoop() final;
+      void UEventHandler();
+      void processHotplug(uint64_t timestamp);
+      DrmPresenter& mPresenter;
+      int mEventFd;
+      int mMaxFd;
+      fd_set mFds;
+  };
+  std::unique_ptr<DrmEventListener> mDrmEventListener;
+  android::base::guest::ReadWriteLock mStateMutex;
 };
 
 }  // namespace android
diff --git a/system/hwc2/GuestComposer.cpp b/system/hwc2/GuestComposer.cpp
index cf4bc52..d4db808 100644
--- a/system/hwc2/GuestComposer.cpp
+++ b/system/hwc2/GuestComposer.cpp
@@ -380,10 +380,10 @@
 
 }  // namespace
 
-HWC2::Error GuestComposer::init() {
+HWC2::Error GuestComposer::init(const HotplugCallback& cb) {
   DEBUG_LOG("%s", __FUNCTION__);
 
-  if (!mDrmPresenter.init()) {
+  if (!mDrmPresenter.init(cb)) {
     ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
     return HWC2::Error::NoResources;
   }
@@ -410,81 +410,101 @@
     ALOGE("%s failed to get display configs from system prop", __FUNCTION__);
     return error;
   }
-
+  uint32_t id = 0;
   for (const auto& displayConfig : displayConfigs) {
-    auto display = std::make_unique<Display>(*device, this);
-    if (display == nullptr) {
-      ALOGE("%s failed to allocate display", __FUNCTION__);
-      return HWC2::Error::NoResources;
-    }
-
-    auto displayId = display->getId();
-
-    error = display->init(displayConfig.width,   //
-                          displayConfig.height,  //
-                          displayConfig.dpiX,    //
-                          displayConfig.dpiY,    //
-                          displayConfig.refreshRateHz);
+    error = createDisplay(device,
+                          id,
+                          displayConfig.width,
+                          displayConfig.height,
+                          displayConfig.dpiX,
+                          displayConfig.dpiY,
+                          displayConfig.refreshRateHz,
+                          addDisplayToDeviceFn);
     if (error != HWC2::Error::None) {
-      ALOGE("%s failed to initialize display:%" PRIu64, __FUNCTION__,
-            displayId);
+      ALOGE("%s: failed to create display %d", __FUNCTION__, id);
       return error;
     }
 
-    auto it = mDisplayInfos.find(displayId);
-    if (it != mDisplayInfos.end()) {
-      ALOGE("%s: display:%" PRIu64 " already created?", __FUNCTION__,
-            displayId);
+    ++id;
+  }
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error GuestComposer::createDisplay(
+    Device* device, uint32_t id, uint32_t width, uint32_t height,
+    uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+    const AddDisplayToDeviceFunction& addDisplayToDeviceFn) {
+
+
+  auto display = std::make_unique<Display>(*device, this, id);
+  if (display == nullptr) {
+    ALOGE("%s failed to allocate display", __FUNCTION__);
+    return HWC2::Error::NoResources;
+  }
+
+  auto displayId = display->getId();
+
+  HWC2::Error error = display->init(width, height, dpiX, dpiY, refreshRateHz);
+  if (error != HWC2::Error::None) {
+    ALOGE("%s failed to initialize display:%" PRIu64, __FUNCTION__,
+          displayId);
+    return error;
+  }
+
+  auto it = mDisplayInfos.find(displayId);
+  if (it != mDisplayInfos.end()) {
+    ALOGE("%s: display:%" PRIu64 " already created?", __FUNCTION__,
+          displayId);
+  }
+
+  GuestComposerDisplayInfo& displayInfo = mDisplayInfos[displayId];
+
+  uint32_t bufferStride;
+  buffer_handle_t bufferHandle;
+
+  auto status = GraphicBufferAllocator::get().allocate(
+      width,     //
+      height,    //
+      PIXEL_FORMAT_RGBA_8888,  //
+      /*layerCount=*/1,        //
+      GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_SW_READ_OFTEN |
+          GraphicBuffer::USAGE_SW_WRITE_OFTEN,  //
+      &bufferHandle,                            //
+      &bufferStride,                            //
+      "RanchuHwc");
+  if (status != OK) {
+    ALOGE("%s failed to allocate composition buffer for display:%" PRIu64,
+          __FUNCTION__, displayId);
+    return HWC2::Error::NoResources;
+  }
+
+  displayInfo.compositionResultBuffer = bufferHandle;
+
+  displayInfo.compositionResultDrmBuffer = std::make_unique<DrmBuffer>(
+      displayInfo.compositionResultBuffer, mDrmPresenter);
+
+  if (displayId == 0) {
+    int flushSyncFd = -1;
+
+    HWC2::Error flushError =
+        displayInfo.compositionResultDrmBuffer->flushToDisplay(displayId,
+                                                               &flushSyncFd);
+    if (flushError != HWC2::Error::None) {
+      ALOGW(
+          "%s: Initial display flush failed. HWComposer assuming that we are "
+          "running in QEMU without a display and disabling presenting.",
+          __FUNCTION__);
+      mPresentDisabled = true;
+    } else {
+      close(flushSyncFd);
     }
+  }
 
-    GuestComposerDisplayInfo& displayInfo = mDisplayInfos[displayId];
-
-    uint32_t bufferStride;
-    buffer_handle_t bufferHandle;
-
-    auto status = GraphicBufferAllocator::get().allocate(
-        displayConfig.width,     //
-        displayConfig.height,    //
-        PIXEL_FORMAT_RGBA_8888,  //
-        /*layerCount=*/1,        //
-        GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_SW_READ_OFTEN |
-            GraphicBuffer::USAGE_SW_WRITE_OFTEN,  //
-        &bufferHandle,                            //
-        &bufferStride,                            //
-        "RanchuHwc");
-    if (status != OK) {
-      ALOGE("%s failed to allocate composition buffer for display:%" PRIu64,
-            __FUNCTION__, displayId);
-      return HWC2::Error::NoResources;
-    }
-
-    displayInfo.compositionResultBuffer = bufferHandle;
-
-    displayInfo.compositionResultDrmBuffer = std::make_unique<DrmBuffer>(
-        displayInfo.compositionResultBuffer, mDrmPresenter);
-
-    if (displayId == 0) {
-      int flushSyncFd = -1;
-
-      HWC2::Error flushError =
-          displayInfo.compositionResultDrmBuffer->flushToDisplay(displayId,
-                                                                 &flushSyncFd);
-      if (flushError != HWC2::Error::None) {
-        ALOGW(
-            "%s: Initial display flush failed. HWComposer assuming that we are "
-            "running in QEMU without a display and disabling presenting.",
-            __FUNCTION__);
-        mPresentDisabled = true;
-      } else {
-        close(flushSyncFd);
-      }
-    }
-
-    error = addDisplayToDeviceFn(std::move(display));
-    if (error != HWC2::Error::None) {
-      ALOGE("%s failed to add display:%" PRIu64, __FUNCTION__, displayId);
-      return error;
-    }
+  error = addDisplayToDeviceFn(std::move(display));
+  if (error != HWC2::Error::None) {
+    ALOGE("%s failed to add display:%" PRIu64, __FUNCTION__, displayId);
+    return error;
   }
 
   return HWC2::Error::None;
diff --git a/system/hwc2/GuestComposer.h b/system/hwc2/GuestComposer.h
index c3e6eae..930cbee 100644
--- a/system/hwc2/GuestComposer.h
+++ b/system/hwc2/GuestComposer.h
@@ -35,12 +35,17 @@
   GuestComposer(GuestComposer&&) = delete;
   GuestComposer& operator=(GuestComposer&&) = delete;
 
-  HWC2::Error init() override;
+  HWC2::Error init(const HotplugCallback& cb) override;
 
   HWC2::Error createDisplays(
       Device* device,
       const AddDisplayToDeviceFunction& addDisplayToDeviceFn) override;
 
+  HWC2::Error createDisplay(
+      Device* device, uint32_t displayId, uint32_t width, uint32_t height,
+      uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+      const AddDisplayToDeviceFunction& addDisplayToDeviceFn) override;
+
   HWC2::Error onDisplayDestroy(Display*) override;
 
   HWC2::Error onDisplayClientTargetSet(Display*) override {
@@ -110,4 +115,4 @@
 
 }  // namespace android
 
-#endif
\ No newline at end of file
+#endif
diff --git a/system/hwc2/HostComposer.cpp b/system/hwc2/HostComposer.cpp
index ad7f663..f280eb3 100644
--- a/system/hwc2/HostComposer.cpp
+++ b/system/hwc2/HostComposer.cpp
@@ -172,13 +172,13 @@
 
 }  // namespace
 
-HWC2::Error HostComposer::init() {
+HWC2::Error HostComposer::init(const HotplugCallback& cb) {
   mIsMinigbm = isMinigbmFromProperty();
   if (!mIsMinigbm) {
     mSyncDeviceFd = goldfish_sync_open();
   }
 
-  if (!mDrmPresenter.init()) {
+  if (!mDrmPresenter.init(cb)) {
     ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
 
     // Non-fatal for HostComposer.
@@ -221,7 +221,7 @@
 
   int refreshRateHz = getVsyncHzFromProperty();
 
-  auto display = std::make_unique<Display>(*device, this);
+  auto display = std::make_unique<Display>(*device, this, 0);
   if (display == nullptr) {
     ALOGE("%s failed to allocate display", __FUNCTION__);
     return HWC2::Error::NoResources;
@@ -251,6 +251,81 @@
   return HWC2::Error::None;
 }
 
+HWC2::Error HostComposer::createDisplay(
+    Device* device, uint32_t displayId, uint32_t width, uint32_t height,
+    uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+    const AddDisplayToDeviceFunction& addDisplayToDeviceFn) {
+
+  HWC2::Error error;
+  Display* display = device->getDisplay(displayId);
+  if (display) {
+    ALOGD("%s display %d already existed, then update", __func__, displayId);
+  }
+
+  uint32_t actualHostDisplayId = displayId;
+  DEFINE_AND_VALIDATE_HOST_CONNECTION
+  hostCon->lock();
+  rcEnc->rcCreateDisplay(rcEnc, &actualHostDisplayId);
+  rcEnc->rcSetDisplayPose(rcEnc, actualHostDisplayId, -1, -1, width, height);
+  hostCon->unlock();
+
+  if (actualHostDisplayId != displayId) {
+    ALOGW(
+        "Something wrong with host displayId allocation, expected %d "
+        "but received %d",
+        displayId, actualHostDisplayId);
+  }
+
+  if (!display) {
+    auto newDisplay = std::make_unique<Display>(*device, this, displayId);
+    if (newDisplay == nullptr) {
+      ALOGE("%s failed to allocate display", __FUNCTION__);
+      return HWC2::Error::NoResources;
+    }
+
+    error = newDisplay->init(width, height, dpiX, dpiY, refreshRateHz);
+    if (error != HWC2::Error::None) {
+      ALOGE("%s failed to initialize display:%" PRIu32, __FUNCTION__,
+            displayId);
+      return error;
+    }
+
+    error = createHostComposerDisplayInfo(newDisplay.get(), actualHostDisplayId);
+    if (error != HWC2::Error::None) {
+      ALOGE("%s failed to initialize host info for display:%" PRIu32,
+            __FUNCTION__, displayId);
+      return error;
+    }
+
+    error = addDisplayToDeviceFn(std::move(newDisplay));
+    if (error != HWC2::Error::None) {
+      ALOGE("%s failed to add display:%" PRIu32, __FUNCTION__, displayId);
+      return error;
+    }
+  } else {
+    display->lock();
+    // update display parameters
+    error = display->updateParameters(width, height, dpiX, dpiY, refreshRateHz);
+    if (error != HWC2::Error::None) {
+      ALOGE("%s failed to update display:%" PRIu32, __FUNCTION__,
+            displayId);
+      display->unlock();
+      return error;
+    }
+
+    error = createHostComposerDisplayInfo(display, actualHostDisplayId);
+    if (error != HWC2::Error::None) {
+      ALOGE("%s failed to initialize host info for display:%" PRIu32,
+            __FUNCTION__, displayId);
+      display->unlock();
+      return error;
+    }
+    display->unlock();
+  }
+
+  return HWC2::Error::None;
+}
+
 HWC2::Error HostComposer::createSecondaryDisplays(
     Device* device, const AddDisplayToDeviceFunction& addDisplayToDeviceFn) {
   HWC2::Error error = HWC2::Error::None;
@@ -286,7 +361,7 @@
 
   static constexpr const uint32_t kHostDisplayIdStart = 6;
 
-  uint32_t secondaryDisplayIndex = 0;
+  uint32_t secondaryDisplayIndex = 1;
   while (!propIntParts.empty()) {
     int width = propIntParts[1];
     int height = propIntParts[2];
@@ -297,7 +372,7 @@
     propIntParts.erase(propIntParts.begin(), propIntParts.begin() + 5);
 
     uint32_t expectedHostDisplayId =
-        kHostDisplayIdStart + secondaryDisplayIndex;
+        kHostDisplayIdStart + secondaryDisplayIndex - 1;
     uint32_t actualHostDisplayId = 0;
 
     DEFINE_AND_VALIDATE_HOST_CONNECTION
@@ -314,7 +389,7 @@
           expectedHostDisplayId, actualHostDisplayId);
     }
 
-    auto display = std::make_unique<Display>(*device, this);
+    auto display = std::make_unique<Display>(*device, this, secondaryDisplayIndex++);
     if (display == nullptr) {
       ALOGE("%s failed to allocate display", __FUNCTION__);
       return HWC2::Error::NoResources;
@@ -423,6 +498,13 @@
 
   HostComposerDisplayInfo& displayInfo = mDisplayInfos[displayId];
 
+  if (displayId != 0 ) {
+    DEFINE_AND_VALIDATE_HOST_CONNECTION
+    hostCon->lock();
+    rcEnc->rcDestroyDisplay(rcEnc, displayInfo.hostDisplayId);
+    hostCon->unlock();
+  }
+
   FreeDisplayColorBuffer(displayInfo.compositionResultBuffer);
 
   mDisplayInfos.erase(it);
@@ -466,6 +548,8 @@
   if (hostCompositionV1 || hostCompositionV2) {
     // Support Device and SolidColor, otherwise, fallback all layers to Client.
     bool fallBack = false;
+    //TODO: use local var compositiontype, avoid call getCompositionType() many
+    //times
     for (auto& layer : layers) {
       if (layer->getCompositionType() == HWC2::Composition::Invalid) {
         // Log error for unused layers, layer leak?
@@ -554,7 +638,7 @@
       if (displayClientTarget.getBuffer() != nullptr) {
         if (mIsMinigbm) {
           int retireFence;
-          displayInfo.clientTargetDrmBuffer->flushToDisplay(0, &retireFence);
+          displayInfo.clientTargetDrmBuffer->flushToDisplay(display->getId(), &retireFence);
           *outRetireFence = dup(retireFence);
           close(retireFence);
         } else {
@@ -589,6 +673,7 @@
 
     int releaseLayersCount = 0;
     for (auto layer : layers) {
+      //TODO: use local var composisitonType to store getCompositionType()
       if (layer->getCompositionType() != HWC2::Composition::Device &&
           layer->getCompositionType() != HWC2::Composition::SolidColor) {
         ALOGE("%s: Unsupported composition types %d layer %u", __FUNCTION__,
@@ -714,7 +799,7 @@
     hostCon->unlock();
 
     if (mIsMinigbm) {
-      displayInfo.compositionResultDrmBuffer->flushToDisplay(0, &retire_fd);
+        displayInfo.compositionResultDrmBuffer->flushToDisplay(display->getId(), &retire_fd);
     } else {
       goldfish_sync_queue_work(mSyncDeviceFd, sync_handle, thread_handle,
                                &retire_fd);
@@ -738,7 +823,7 @@
     // we set all layers Composition::Client, so do nothing.
     if (mIsMinigbm) {
       int retireFence;
-      displayInfo.clientTargetDrmBuffer->flushToDisplay(0, &retireFence);
+      displayInfo.clientTargetDrmBuffer->flushToDisplay(display->getId(), &retireFence);
       *outRetireFence = dup(retireFence);
       close(retireFence);
     } else {
@@ -763,4 +848,4 @@
   hostCon->unlock();
 }
 
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/system/hwc2/HostComposer.h b/system/hwc2/HostComposer.h
index 31188d3..fe4a49f 100644
--- a/system/hwc2/HostComposer.h
+++ b/system/hwc2/HostComposer.h
@@ -34,12 +34,17 @@
   HostComposer(HostComposer&&) = delete;
   HostComposer& operator=(HostComposer&&) = delete;
 
-  HWC2::Error init() override;
+  HWC2::Error init(const HotplugCallback& cb) override;
 
   HWC2::Error createDisplays(
       Device* device,
       const AddDisplayToDeviceFunction& addDisplayToDeviceFn) override;
 
+  HWC2::Error createDisplay(
+      Device* device, uint32_t displayId, uint32_t width, uint32_t height,
+      uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz,
+      const AddDisplayToDeviceFunction& addDisplayToDeviceFn) override;
+
   HWC2::Error onDisplayDestroy(Display* display) override;
 
   HWC2::Error onDisplayClientTargetSet(Display* display) override;
@@ -92,4 +97,4 @@
 
 }  // namespace android
 
-#endif
\ No newline at end of file
+#endif