Merge master@5406228 into git_qt-dev-plus-aosp.

Change-Id: Ibaeaf918de950d67dcd5eb3a0633a85dbdccb460
BUG: 129345239
diff --git a/.gitlab-ci-checkcommit.sh b/.gitlab-ci-checkcommit.sh
index d76baf7..c1c524d 100755
--- a/.gitlab-ci-checkcommit.sh
+++ b/.gitlab-ci-checkcommit.sh
@@ -38,13 +38,13 @@
 
 	commit_body=$(git show -s --pretty=%b "$h")
 
-	author=$(git show -s --format='%an <%ae>')
+	author=$(git show -s --format='%an <%ae>' "$h")
 	if findtag "$commit_body" "Signed-off-by" "$author"; then
 		echoerr "Author SoB tag is missing from commit $h"
 		exit 1
 	fi
 
-	committer=$(git show -s --format='%cn <%ce>')
+	committer=$(git show -s --format='%cn <%ce>' "$h")
 	if findtag "$commit_body" "Signed-off-by" "$committer"; then
 		echoerr "Committer SoB tag is missing from commit $h"
 		exit 1
diff --git a/drmconnector.cpp b/drmconnector.cpp
index 756791f..f272024 100644
--- a/drmconnector.cpp
+++ b/drmconnector.cpp
@@ -122,6 +122,7 @@
 
   state_ = c->connection;
 
+  bool preferred_mode_found = false;
   std::vector<DrmMode> new_modes;
   for (int i = 0; i < c->count_modes; ++i) {
     bool exists = false;
@@ -132,14 +133,20 @@
         break;
       }
     }
-    if (exists)
-      continue;
-
-    DrmMode m(&c->modes[i]);
-    m.set_id(drm_->next_mode_id());
-    new_modes.push_back(m);
+    if (!exists) {
+      DrmMode m(&c->modes[i]);
+      m.set_id(drm_->next_mode_id());
+      new_modes.push_back(m);
+    }
+    if (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED) {
+      preferred_mode_id_ = new_modes.back().id();
+      preferred_mode_found = true;
+    }
   }
   modes_.swap(new_modes);
+  if ((!preferred_mode_found) && (modes_.size() != 0)) {
+    preferred_mode_id_ = modes_[0].id();
+  }
   return 0;
 }
 
diff --git a/drmconnector.h b/drmconnector.h
index 4f7f6a8..9c526c8 100644
--- a/drmconnector.h
+++ b/drmconnector.h
@@ -74,6 +74,10 @@
   uint32_t mm_width() const;
   uint32_t mm_height() const;
 
+  uint32_t get_preferred_mode_id() const {
+    return preferred_mode_id_;
+  }
+
  private:
   DrmDevice *drm_;
 
@@ -97,6 +101,8 @@
   DrmProperty writeback_out_fence_;
 
   std::vector<DrmEncoder *> possible_encoders_;
+
+  uint32_t preferred_mode_id_;
 };
 }  // namespace android
 
diff --git a/drmdevice.h b/drmdevice.h
index da1b961..91dd38b 100644
--- a/drmdevice.h
+++ b/drmdevice.h
@@ -76,6 +76,9 @@
   int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id);
   int DestroyPropertyBlob(uint32_t blob_id);
   bool HandlesDisplay(int display) const;
+  void RegisterHotplugHandler(DrmEventHandler *handler) {
+    event_listener_.RegisterHotplugHandler(handler);
+  }
 
  private:
   int TryEncoderForDisplay(int display, DrmEncoder *enc);
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index a1ccdc7..e6f6922 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -359,10 +359,16 @@
         }
       }
 
-      if (plane->zpos_property().id() && !plane->zpos_property().immutable()) {
+      if (plane->zpos_property().id() &&
+          !plane->zpos_property().is_immutable()) {
+        uint64_t min_zpos = 0;
+
+        // Ignore ret and use min_zpos as 0 by default
+        std::tie(std::ignore, min_zpos) = plane->zpos_property().range_min();
+
         ret = drmModeAtomicAddProperty(pset, plane->id(),
                                        plane->zpos_property().id(),
-                                       source_layers.front()) < 0;
+                                       source_layers.front() + min_zpos) < 0;
         if (ret) {
           ALOGE("Failed to add zpos property %d to plane %d",
                 plane->zpos_property().id(), plane->id());
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 67f6334..1005598 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -55,6 +55,7 @@
   int Composite();
   void Dump(std::ostringstream *out) const;
   void Vsync(int display, int64_t timestamp);
+  void ClearDisplay();
 
   std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution();
 
@@ -82,7 +83,6 @@
   int ApplyDpms(DrmDisplayComposition *display_comp);
   int DisablePlanes(DrmDisplayComposition *display_comp);
 
-  void ClearDisplay();
   void ApplyFrame(std::unique_ptr<DrmDisplayComposition> composition,
                   int status, bool writeback = false);
   int FlattenActiveComposition();
diff --git a/drmeventlistener.cpp b/drmeventlistener.cpp
index 6aab6fb..8f655a7 100644
--- a/drmeventlistener.cpp
+++ b/drmeventlistener.cpp
@@ -64,7 +64,7 @@
 
 void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) {
   assert(!hotplug_handler_);
-  hotplug_handler_ = handler;
+  hotplug_handler_.reset(handler);
 }
 
 void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */,
diff --git a/drmeventlistener.h b/drmeventlistener.h
index d8a61a5..95672ee 100644
--- a/drmeventlistener.h
+++ b/drmeventlistener.h
@@ -58,7 +58,7 @@
   int max_fd_ = -1;
 
   DrmDevice *drm_;
-  DrmEventHandler *hotplug_handler_ = NULL;
+  std::unique_ptr<DrmEventHandler> hotplug_handler_;
 };
 }  // namespace android
 
diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp
index cf4ec11..3123b29 100644
--- a/drmhwctwo.cpp
+++ b/drmhwctwo.cpp
@@ -57,43 +57,55 @@
   getFunction = HookDevGetFunction;
 }
 
-HWC2::Error DrmHwcTwo::Init() {
-  int ret = resource_manager_.Init();
-  if (ret) {
-    ALOGE("Can't initialize the resource manager %d", ret);
-    return HWC2::Error::NoResources;
-  }
-
-  DrmDevice *drm = resource_manager_.GetDrmDevice(HWC_DISPLAY_PRIMARY);
-  std::shared_ptr<Importer> importer = resource_manager_.GetImporter(
-      HWC_DISPLAY_PRIMARY);
+HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ,
+                                     HWC2::DisplayType type) {
+  DrmDevice *drm = resource_manager_.GetDrmDevice(displ);
+  std::shared_ptr<Importer> importer = resource_manager_.GetImporter(displ);
   if (!drm || !importer) {
     ALOGE("Failed to get a valid drmresource and importer");
     return HWC2::Error::NoResources;
   }
-
-  displays_.emplace(std::piecewise_construct,
-                    std::forward_as_tuple(HWC_DISPLAY_PRIMARY),
+  displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ),
                     std::forward_as_tuple(&resource_manager_, drm, importer,
-                                          HWC_DISPLAY_PRIMARY,
-                                          HWC2::DisplayType::Physical));
+                                          displ, type));
 
-  DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(HWC_DISPLAY_PRIMARY));
+  DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ));
   if (!crtc) {
-    ALOGE("Failed to get crtc for display %d",
-          static_cast<int>(HWC_DISPLAY_PRIMARY));
+    ALOGE("Failed to get crtc for display %d", static_cast<int>(displ));
     return HWC2::Error::BadDisplay;
   }
-
   std::vector<DrmPlane *> display_planes;
   for (auto &plane : drm->planes()) {
     if (plane->GetCrtcSupported(*crtc))
       display_planes.push_back(plane.get());
   }
-  displays_.at(HWC_DISPLAY_PRIMARY).Init(&display_planes);
+  displays_.at(displ).Init(&display_planes);
   return HWC2::Error::None;
 }
 
+HWC2::Error DrmHwcTwo::Init() {
+  int rv = resource_manager_.Init();
+  if (rv) {
+    ALOGE("Can't initialize the resource manager %d", rv);
+    return HWC2::Error::NoResources;
+  }
+
+  HWC2::Error ret = HWC2::Error::None;
+  for (int i = 0; i < resource_manager_.getDisplayCount(); i++) {
+    ret = CreateDisplay(i, HWC2::DisplayType::Physical);
+    if (ret != HWC2::Error::None) {
+      ALOGE("Failed to create display %d with error %d", i, ret);
+      return ret;
+    }
+  }
+
+  auto &drmDevices = resource_manager_.getDrmDevices();
+  for (auto &device : drmDevices) {
+    device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get()));
+  }
+  return ret;
+}
+
 template <typename... Args>
 static inline HWC2::Error unsupported(char const *func, Args... /*args*/) {
   ALOGV("Unsupported function: %s", func);
@@ -132,6 +144,12 @@
                                         hwc2_function_pointer_t function) {
   supported(__func__);
   auto callback = static_cast<HWC2::Callback>(descriptor);
+
+  if (!function) {
+    callbacks_.erase(callback);
+    return HWC2::Error::None;
+  }
+
   callbacks_.emplace(callback, HwcCallback(data, function));
 
   switch (callback) {
@@ -139,6 +157,9 @@
       auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(function);
       hotplug(data, HWC_DISPLAY_PRIMARY,
               static_cast<int32_t>(HWC2::Connection::Connected));
+      auto &drmDevices = resource_manager_.getDrmDevices();
+      for (auto &device : drmDevices)
+        HandleInitialHotplugState(device.get());
       break;
     }
     case HWC2::Callback::Vsync: {
@@ -165,6 +186,10 @@
   supported(__func__);
 }
 
+void DrmHwcTwo::HwcDisplay::ClearDisplay() {
+  compositor_.ClearDisplay();
+}
+
 HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
   supported(__func__);
   planner_ = Planner::CreateInstance(drm_);
@@ -204,27 +229,23 @@
     return HWC2::Error::BadDisplay;
   }
 
-  // Fetch the number of modes from the display
-  uint32_t num_configs;
-  HWC2::Error err = GetDisplayConfigs(&num_configs, NULL);
-  if (err != HWC2::Error::None || !num_configs)
-    return err;
-
-  // Grab the first mode, we'll choose this as the active mode
-  // TODO: Should choose the preferred mode here
-  hwc2_config_t default_config;
-  num_configs = 1;
-  err = GetDisplayConfigs(&num_configs, &default_config);
-  if (err != HWC2::Error::None)
-    return err;
-
   ret = vsync_worker_.Init(drm_, display);
   if (ret) {
     ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
     return HWC2::Error::BadDisplay;
   }
 
-  return SetActiveConfig(default_config);
+  return ChosePreferredConfig();
+}
+
+HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() {
+  // Fetch the number of modes from the display
+  uint32_t num_configs;
+  HWC2::Error err = GetDisplayConfigs(&num_configs, NULL);
+  if (err != HWC2::Error::None || !num_configs)
+    return err;
+
+  return SetActiveConfig(connector_->get_preferred_mode_id());
 }
 
 HWC2::Error DrmHwcTwo::HwcDisplay::RegisterVsyncCallback(
@@ -617,8 +638,8 @@
     ALOGE("Failed to queue dpms composition on %d", ret);
     return HWC2::Error::BadConfig;
   }
-  if (connector_->active_mode().id() == 0)
-    connector_->set_active_mode(*mode);
+
+  connector_->set_active_mode(*mode);
 
   // Setup the client layer's dimensions
   hwc_rect_t display_frame = {.left = 0,
@@ -702,7 +723,7 @@
 
 HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) {
   supported(__func__);
-  vsync_worker_.VSyncControl(enabled);
+  vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled);
   return HWC2::Error::None;
 }
 
@@ -880,6 +901,52 @@
   layer->SetTransform(static_cast<int32_t>(transform_));
 }
 
+void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
+  auto cb = callbacks_.find(HWC2::Callback::Hotplug);
+  if (cb == callbacks_.end())
+    return;
+
+  auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(cb->second.func);
+  hotplug(cb->second.data, displayid,
+          (state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
+                                       : HWC2_CONNECTION_DISCONNECTED));
+}
+
+void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
+  for (auto &conn : drmDevice->connectors()) {
+    if (conn->state() != DRM_MODE_CONNECTED)
+      continue;
+    HandleDisplayHotplug(conn->display(), conn->state());
+  }
+}
+
+void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) {
+  for (auto &conn : drm_->connectors()) {
+    drmModeConnection old_state = conn->state();
+    drmModeConnection cur_state = conn->UpdateModes()
+                                      ? DRM_MODE_UNKNOWNCONNECTION
+                                      : conn->state();
+
+    if (cur_state == old_state)
+      continue;
+
+    ALOGI("%s event @%" PRIu64 " for connector %u on display %d",
+          cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us,
+          conn->id(), conn->display());
+
+    int display_id = conn->display();
+    if (cur_state == DRM_MODE_CONNECTED) {
+      auto &display = hwc2_->displays_.at(display_id);
+      display.ChosePreferredConfig();
+    } else {
+      auto &display = hwc2_->displays_.at(display_id);
+      display.ClearDisplay();
+    }
+
+    hwc2_->HandleDisplayHotplug(display_id, cur_state);
+  }
+}
+
 // static
 int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) {
   unsupported(__func__);
diff --git a/drmhwctwo.h b/drmhwctwo.h
index d9ced9b..a71d7cc 100644
--- a/drmhwctwo.h
+++ b/drmhwctwo.h
@@ -143,6 +143,7 @@
 
     HWC2::Error RegisterVsyncCallback(hwc2_callback_data_t data,
                                       hwc2_function_pointer_t func);
+    void ClearDisplay();
 
     // HWC Hooks
     HWC2::Error AcceptDisplayChanges();
@@ -173,6 +174,7 @@
                                  int32_t *fences);
     HWC2::Error PresentDisplay(int32_t *retire_fence);
     HWC2::Error SetActiveConfig(hwc2_config_t config);
+    HWC2::Error ChosePreferredConfig();
     HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
                                 int32_t dataspace, hwc_region_t damage);
     HWC2::Error SetColorMode(int32_t mode);
@@ -213,6 +215,18 @@
     uint32_t frame_no_ = 0;
   };
 
+  class DrmHotplugHandler : public DrmEventHandler {
+   public:
+    DrmHotplugHandler(DrmHwcTwo *hwc2, DrmDevice *drm)
+        : hwc2_(hwc2), drm_(drm) {
+    }
+    void HandleEvent(uint64_t timestamp_us);
+
+   private:
+    DrmHwcTwo *hwc2_;
+    DrmDevice *drm_;
+  };
+
   static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) {
     return static_cast<DrmHwcTwo *>(dev);
   }
@@ -261,6 +275,9 @@
   uint32_t GetMaxVirtualDisplayCount();
   HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
                                hwc2_function_pointer_t function);
+  HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type);
+  void HandleDisplayHotplug(hwc2_display_t displayid, int state);
+  void HandleInitialHotplugState(DrmDevice *drmDevice);
 
   ResourceManager resource_manager_;
   std::map<hwc2_display_t, HwcDisplay> displays_;
diff --git a/drmplane.cpp b/drmplane.cpp
index 35f91b4..6f1bf9b 100644
--- a/drmplane.cpp
+++ b/drmplane.cpp
@@ -42,7 +42,7 @@
   }
 
   uint64_t type;
-  ret = p.value(&type);
+  std::tie(ret, type) = p.value();
   if (ret) {
     ALOGE("Failed to get plane type property value");
     return ret;
diff --git a/drmproperty.cpp b/drmproperty.cpp
index 9faa37e..3aeed13 100644
--- a/drmproperty.cpp
+++ b/drmproperty.cpp
@@ -70,40 +70,57 @@
   return name_;
 }
 
-int DrmProperty::value(uint64_t *value) const {
-  if (type_ == DRM_PROPERTY_TYPE_BLOB) {
-    *value = value_;
-    return 0;
-  }
+std::tuple<int, uint64_t> DrmProperty::value() const {
+  if (type_ == DRM_PROPERTY_TYPE_BLOB)
+    return std::make_tuple(0, value_);
 
   if (values_.size() == 0)
-    return -ENOENT;
+    return std::make_tuple(-ENOENT, 0);
 
   switch (type_) {
     case DRM_PROPERTY_TYPE_INT:
-      *value = value_;
-      return 0;
+      return std::make_tuple(0, value_);
 
     case DRM_PROPERTY_TYPE_ENUM:
       if (value_ >= enums_.size())
-        return -ENOENT;
+        return std::make_tuple(-ENOENT, 0);
 
-      *value = enums_[value_].value_;
-      return 0;
+      return std::make_tuple(0, enums_[value_].value_);
 
     case DRM_PROPERTY_TYPE_OBJECT:
-      *value = value_;
-      return 0;
+      return std::make_tuple(0, value_);
 
     default:
-      return -EINVAL;
+      return std::make_tuple(-EINVAL, 0);
   }
 }
 
-bool DrmProperty::immutable() const {
+bool DrmProperty::is_immutable() const {
   return id_ && (flags_ & DRM_MODE_PROP_IMMUTABLE);
 }
 
+bool DrmProperty::is_range() const {
+  return id_ && (flags_ & DRM_MODE_PROP_RANGE);
+}
+
+std::tuple<int, uint64_t> DrmProperty::range_min() const {
+  if (!is_range())
+    return std::make_tuple(-EINVAL, 0);
+  if (values_.size() < 1)
+    return std::make_tuple(-ENOENT, 0);
+
+  return std::make_tuple(0, values_[0]);
+}
+
+std::tuple<int, uint64_t> DrmProperty::range_max() const {
+  if (!is_range())
+    return std::make_tuple(-EINVAL, 0);
+  if (values_.size() < 2)
+    return std::make_tuple(-ENOENT, 0);
+
+  return std::make_tuple(0, values_[1]);
+}
+
 std::tuple<uint64_t, int> DrmProperty::GetEnumValueWithName(
     std::string name) const {
   for (auto it : enums_) {
diff --git a/drmproperty.h b/drmproperty.h
index f1328fe..2d92ca1 100644
--- a/drmproperty.h
+++ b/drmproperty.h
@@ -45,8 +45,12 @@
   uint32_t id() const;
   std::string name() const;
 
-  int value(uint64_t *value) const;
-  bool immutable() const;
+  std::tuple<int, uint64_t> value() const;
+  bool is_immutable() const;
+
+  bool is_range() const;
+  std::tuple<int, uint64_t> range_min() const;
+  std::tuple<int, uint64_t> range_max() const;
 
  private:
   class DrmPropertyEnum {
diff --git a/platform.h b/platform.h
index a58d62e..6fdece2 100644
--- a/platform.h
+++ b/platform.h
@@ -90,7 +90,7 @@
         ret = ValidatePlane(plane, layer.second);
         if (!ret)
           break;
-        if (!plane->zpos_property().immutable())
+        if (!plane->zpos_property().is_immutable())
           unused_planes.push_back(plane);
         plane = PopPlane(planes);
       }
diff --git a/resourcemanager.h b/resourcemanager.h
index 463739b..f10af45 100644
--- a/resourcemanager.h
+++ b/resourcemanager.h
@@ -34,6 +34,12 @@
   std::shared_ptr<Importer> GetImporter(int display);
   const gralloc_module_t *gralloc();
   DrmConnector *AvailableWritebackConnector(int display);
+  const std::vector<std::unique_ptr<DrmDevice>> &getDrmDevices() const {
+    return drms_;
+  }
+  int getDisplayCount() const {
+    return num_displays_;
+  }
 
  private:
   int AddDrmDevice(std::string path);