drm_hwcomposer: Fixes for display hotplug / headless mode

Further testing showed that several issues is still present:
1. Boot without display doesn't work.
2. Unplug/plug primary display has some flaws due to incomplete
   HwcDisplay disposal.
3. In case creation of the pipeline fails, hwcomposer crashes.

This commit aims to address them.

Fixes: bb594baa1c68 ("drm_hwcomposer: Rework HwcDisplay disposal to avoid races")
Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index c8235e9..ddf59dd 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -136,8 +136,10 @@
 
       if (connected) {
         auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
-        frontend_interface_->BindDisplay(pipeline.get());
-        attached_pipelines_[conn] = std::move(pipeline);
+        if (pipeline) {
+          frontend_interface_->BindDisplay(pipeline.get());
+          attached_pipelines_[conn] = std::move(pipeline);
+        }
       } else {
         auto &pipeline = attached_pipelines_[conn];
         frontend_interface_->UnbindDisplay(pipeline.get());
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index e689419..4accb07 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -177,8 +177,14 @@
         resource_manager_.Init();
       } else {
         resource_manager_.DeInit();
-        /* Headless display may still be here, remove it */
-        displays_.erase(kPrimaryDisplay);
+        /* Headless display may still be here. Remove it! */
+        if (displays_.count(kPrimaryDisplay) != 0) {
+          displays_[kPrimaryDisplay]->Deinit();
+          auto &mutex = GetResMan().GetMainLock();
+          mutex.unlock();
+          displays_.erase(kPrimaryDisplay);
+          mutex.lock();
+        }
       }
       break;
     }
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index cedac19..0f957a7 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -102,24 +102,36 @@
 HwcDisplay::~HwcDisplay() = default;
 
 void HwcDisplay::SetPipeline(DrmDisplayPipeline *pipeline) {
+  Deinit();
+
   pipeline_ = pipeline;
 
-  if (pipeline != nullptr) {
-    ChosePreferredConfig();
+  if (pipeline != nullptr || handle_ == kPrimaryDisplay) {
     Init();
-
     hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
   } else {
-    backend_.reset();
-    vsync_worker_.Init(nullptr, [](int64_t) {});
-    SetClientTarget(nullptr, -1, 0, {});
-    if (handle_ != kPrimaryDisplay) {
-      hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
-    }
+    hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
   }
 }
 
+void HwcDisplay::Deinit() {
+  if (pipeline_ != nullptr) {
+    AtomicCommitArgs a_args{};
+    a_args.active = false;
+    a_args.composition = std::make_shared<DrmKmsPlan>();
+    GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+
+    vsync_worker_.Init(nullptr, [](int64_t) {});
+    current_plan_.reset();
+    backend_.reset();
+  }
+
+  SetClientTarget(nullptr, -1, 0, {});
+}
+
 HWC2::Error HwcDisplay::Init() {
+  ChosePreferredConfig();
+
   int ret = vsync_worker_.Init(pipeline_, [this](int64_t timestamp) {
     const std::lock_guard<std::mutex> lock(hwc2_->GetResMan().GetMainLock());
     if (vsync_event_en_) {
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 98d8e9b..8ff9a92 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -180,6 +180,8 @@
     return !pipeline_;
   }
 
+  void Deinit();
+
  private:
   enum ClientFlattenningState : int32_t {
     Disabled = -3,