Merge remote-tracking branch 'aosp/upstream-main' into 'aosp/master'

... to pull in f0c507f16b99ff9ac30fb1a95fd1d1c1c9eaf55a to fix
crashes when display does not yet have a active mode.

Bug: b/216148216
Test: launch_cvd --gpu_mode=gfxstream --hwcomposer=drm
Change-Id: Ic75a1c8b516017d93dc9fdb1ef691b457fb61742
diff --git a/.ci/.gitlab-ci-checkcommit.sh b/.ci/.gitlab-ci-checkcommit.sh
index e59ad9f..c9c2e49 100755
--- a/.ci/.gitlab-ci-checkcommit.sh
+++ b/.ci/.gitlab-ci-checkcommit.sh
@@ -50,7 +50,7 @@
 		exit 1
 	fi
 
-	git show "$h" -- | clang-format-diff-12 -p 1 -style=file > /tmp/format-fixup.patch
+	git show "$h" -- | clang-format-diff-13 -p 1 -style=file > /tmp/format-fixup.patch
 	if [ -s  /tmp/format-fixup.patch ]; then
 		cat /tmp/format-fixup.patch >&2
 		exit 1
diff --git a/.ci/Makefile b/.ci/Makefile
index 4ca14d6..7f43a8a 100644
--- a/.ci/Makefile
+++ b/.ci/Makefile
@@ -2,8 +2,8 @@
 INCLUDE_DIRS := . ../libdrm/include/drm include ./.ci/android_headers ./tests/test_include
 SYSTEM_INCLUDE_DIRS := /usr/include/libdrm
 
-CLANG := clang++-12
-CLANG_TIDY := clang-tidy-12
+CLANG := clang++-13
+CLANG_TIDY := clang-tidy-13
 OUT_DIR := /tmp/drm_hwcomposer/build
 SRC_DIR := .
 
@@ -57,6 +57,7 @@
 TIDY_CHECKS_NORMAL :=                                   \
     $(TIDY_CHECKS_FINE)                                 \
     -hicpp*                                             \
+    -bugprone-easily-swappable-parameters               \
     -cppcoreguidelines-special-member-functions \
     -cppcoreguidelines-avoid-c-arrays \
     -cppcoreguidelines-pro-bounds-array-to-pointer-decay \
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9a54b44..89ac1b8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,11 +1,11 @@
-image: ubuntu:21.04
+image: ubuntu:21.10
 
 variables:
   DEBIAN_FRONTEND: noninteractive
 
 before_script:
   - apt-get --quiet update --yes >/dev/null
-  - apt-get --quiet install --yes clang-12 clang-tidy-12 clang-format-12 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null
+  - apt-get --quiet install --yes clang-13 clang-tidy-13 clang-format-13 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null
 
 stages:
   - build
diff --git a/Android.bp b/Android.bp
index a856594..1c3030c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -117,7 +117,6 @@
         "drm/UEventListener.cpp",
         "drm/VSyncWorker.cpp",
 
-        "utils/autolock.cpp",
         "utils/hwcutils.cpp",
 
         "backend/Backend.cpp",
diff --git a/README.md b/README.md
index c142266..05ddc79 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
   you with formatting of your patches:
 
     ```
-    git diff | clang-format-diff-12 -p 1 -style=file
+    git diff | clang-format-diff-13 -p 1 -style=file
     ```
 
 * Hardware specific changes should be tested on relevant platforms before
diff --git a/build_deploy.sh b/build_deploy.sh
new file mode 100755
index 0000000..ba9732b
--- /dev/null
+++ b/build_deploy.sh
@@ -0,0 +1,26 @@
+#!/bin/bash -e
+
+# To see logs after deploy run: $ HWCLOG=1 TESTDEV=<DEV> ./build_deploy.sh
+
+[ -z "$TESTDEV" ] && echo "Run $ TESTDEV=<Your lunch target> ./build_deploy.sh" && false
+
+cd ../..
+. build/envsetup.sh
+lunch $TESTDEV
+cd -
+
+mm
+
+adb root && adb remount && adb sync vendor
+
+adb shell stop
+adb shell stop vendor.hwcomposer-2-1 || true
+adb shell stop vendor.hwcomposer-2-2 || true
+adb shell stop vendor.hwcomposer-2-3 || true
+adb shell stop vendor.hwcomposer-2-4 || true
+
+[ $HWCLOG -eq "1" ] && adb logcat -c
+
+adb shell start
+
+[ $HWCLOG -eq "1" ] && adb logcat | grep -i hwc
diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp
index 89e7f2d..c2e51ee 100644
--- a/compositor/DrmDisplayCompositor.cpp
+++ b/compositor/DrmDisplayCompositor.cpp
@@ -35,7 +35,6 @@
 #include "drm/DrmDevice.h"
 #include "drm/DrmPlane.h"
 #include "drm/DrmUnique.h"
-#include "utils/autolock.h"
 #include "utils/log.h"
 
 namespace android {
@@ -54,18 +53,6 @@
   return 0;
 }
 
-std::unique_ptr<DrmDisplayComposition>
-DrmDisplayCompositor::CreateInitializedComposition() const {
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
-  if (!crtc) {
-    ALOGE("Failed to find crtc for display = %d", display_);
-    return std::unique_ptr<DrmDisplayComposition>();
-  }
-
-  return std::make_unique<DrmDisplayComposition>(crtc);
-}
-
 // NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
 auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int {
   ATRACE_CALL();
diff --git a/compositor/DrmDisplayCompositor.h b/compositor/DrmDisplayCompositor.h
index e7899ed..9679520 100644
--- a/compositor/DrmDisplayCompositor.h
+++ b/compositor/DrmDisplayCompositor.h
@@ -58,8 +58,6 @@
   ~DrmDisplayCompositor() = default;
   auto Init(ResourceManager *resource_manager, int display) -> int;
 
-  std::unique_ptr<DrmDisplayComposition> CreateInitializedComposition() const;
-
   auto ExecuteAtomicCommit(AtomicCommitArgs &args) -> int;
 
   DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 32b6d24..7cbec95 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -102,12 +102,12 @@
   uint64_t blob_id = 0;
   int ret = UpdateEdidProperty();
   if (ret != 0) {
-    return DrmModePropertyBlobUnique();
+    return {};
   }
 
   std::tie(ret, blob_id) = edid_property().value();
   if (ret != 0) {
-    return DrmModePropertyBlobUnique();
+    return {};
   }
 
   return MakeDrmModePropertyBlobUnique(drm_->fd(), blob_id);
@@ -175,6 +175,8 @@
     return -ENODEV;
   }
 
+  state_ = c->connection;
+
   modes_.clear();
   for (int i = 0; i < c->count_modes; ++i) {
     bool exists = false;
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index a679bf5..8245b78 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -331,9 +331,6 @@
       ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret);
       return std::make_tuple(ret, 0);
     }
-    if (!AttachWriteback(conn.get())) {
-      ALOGI("Display %d has writeback attach to it", conn->display());
-    }
   }
   return std::make_tuple(ret, displays_.size());
 }
@@ -350,39 +347,6 @@
   return nullptr;
 }
 
-DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const {
-  for (const auto &conn : writeback_connectors_) {
-    if (conn->display() == display)
-      return conn.get();
-  }
-  return nullptr;
-}
-
-// TODO(nobody): what happens when hotplugging
-DrmConnector *DrmDevice::AvailableWritebackConnector(int display) const {
-  DrmConnector *writeback_conn = GetWritebackConnectorForDisplay(display);
-  DrmConnector *display_conn = GetConnectorForDisplay(display);
-  // If we have a writeback already attached to the same CRTC just use that,
-  // if possible.
-  if (display_conn && writeback_conn &&
-      writeback_conn->encoder()->CanClone(display_conn->encoder()))
-    return writeback_conn;
-
-  // Use another CRTC if available and doesn't have any connector
-  for (const auto &crtc : crtcs_) {
-    if (crtc->display() == display)
-      continue;
-    display_conn = GetConnectorForDisplay(crtc->display());
-    // If we have a display connected don't use it for writeback
-    if (display_conn && display_conn->state() == DRM_MODE_CONNECTED)
-      continue;
-    writeback_conn = GetWritebackConnectorForDisplay(crtc->display());
-    if (writeback_conn)
-      return writeback_conn;
-  }
-  return nullptr;
-}
-
 DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
   for (const auto &crtc : crtcs_) {
     if (crtc->display() == display)
@@ -457,34 +421,6 @@
   return -ENODEV;
 }
 
-// Attach writeback connector to the CRTC linked to the display_conn
-int DrmDevice::AttachWriteback(DrmConnector *display_conn) {
-  DrmCrtc *display_crtc = display_conn->encoder()->crtc();
-  if (GetWritebackConnectorForDisplay(display_crtc->display()) != nullptr) {
-    ALOGE("Display already has writeback attach to it");
-    return -EINVAL;
-  }
-  for (auto &writeback_conn : writeback_connectors_) {
-    if (writeback_conn->display() >= 0)
-      continue;
-    for (DrmEncoder *writeback_enc : writeback_conn->possible_encoders()) {
-      for (DrmCrtc *possible_crtc : writeback_enc->possible_crtcs()) {
-        if (possible_crtc != display_crtc)
-          continue;
-        // Use just encoders which had not been bound already
-        if (writeback_enc->can_bind(display_crtc->display())) {
-          writeback_enc->set_crtc(display_crtc);
-          writeback_conn->set_encoder(writeback_enc);
-          writeback_conn->set_display(display_crtc->display());
-          writeback_conn->UpdateModes();
-          return 0;
-        }
-      }
-    }
-  }
-  return -EINVAL;
-}
-
 auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
     -> DrmModeUserPropertyBlobUnique {
   struct drm_mode_create_blob create_blob {};
@@ -494,7 +430,7 @@
   int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
   if (ret) {
     ALOGE("Failed to create mode property blob %d", ret);
-    return DrmModeUserPropertyBlobUnique();
+    return {};
   }
 
   return DrmModeUserPropertyBlobUnique(
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index d3effc2..9983d61 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -60,8 +60,6 @@
   }
 
   DrmConnector *GetConnectorForDisplay(int display) const;
-  DrmConnector *GetWritebackConnectorForDisplay(int display) const;
-  DrmConnector *AvailableWritebackConnector(int display) const;
   DrmCrtc *GetCrtcForDisplay(int display) const;
 
   int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
@@ -96,7 +94,6 @@
   int TryEncoderForDisplay(int display, DrmEncoder *enc);
 
   int CreateDisplayPipe(DrmConnector *connector);
-  int AttachWriteback(DrmConnector *display_conn);
 
   UniqueFd fd_;
   uint32_t mode_id_ = 0;
diff --git a/drm/DrmFbImporter.cpp b/drm/DrmFbImporter.cpp
index 25f32b7..6f2abe8 100644
--- a/drm/DrmFbImporter.cpp
+++ b/drm/DrmFbImporter.cpp
@@ -124,7 +124,7 @@
 
   if (err != 0) {
     ALOGE("Failed to import prime fd %d ret=%d", bo->prime_fds[0], err);
-    return std::shared_ptr<DrmFbIdHandle>();
+    return {};
   }
 
   auto drm_fb_id_cached = drm_fb_id_handle_cache_.find(first_handle);
diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp
index 1c8bd0f..010ea1b 100644
--- a/drm/DrmMode.cpp
+++ b/drm/DrmMode.cpp
@@ -94,6 +94,9 @@
 }
 
 float DrmMode::v_refresh() const {
+  if (clock_ == 0) {
+    return v_refresh_;
+  }
   // Always recalculate refresh to report correct float rate
   return static_cast<float>(clock_) / (float)(v_total_ * h_total_) * 1000.0F;
 }
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 773b350..f54d682 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -48,6 +48,10 @@
     return &uevent_listener_;
   }
 
+  auto &GetMainLock() {
+    return main_lock_;
+  }
+
  private:
   int AddDrmDevice(std::string const &path);
 
@@ -57,6 +61,8 @@
   bool scale_with_gpu_{};
 
   UEventListener uevent_listener_;
+
+  std::mutex main_lock_;
 };
 }  // namespace android
 
diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp
index 470e89a..44c503d 100644
--- a/drm/UEventListener.cpp
+++ b/drm/UEventListener.cpp
@@ -90,6 +90,10 @@
     }
 
     if (drm_event && hotplug_event && hotplug_handler_) {
+      constexpr useconds_t delay_after_uevent_us = 200000;
+      /* We need some delay to ensure DrmConnector::UpdateModes() will query
+       * correct modes list, otherwise at least RPI4 board may report 0 modes */
+      usleep(delay_after_uevent_us);
       hotplug_handler_();
     }
   }
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index 6e92838..8d1cb99 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -77,7 +77,7 @@
          last_timestamp_;
 }
 
-static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000;
+static const int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
 
 int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
   struct timespec vsync {};
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index 5bbb48a..a2a093f 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -66,8 +66,11 @@
     }
   }
 
-  resource_manager_.GetUEventListener()->RegisterHotplugHandler(
-      [this] { HandleHotplugUEvent(); });
+  resource_manager_.GetUEventListener()->RegisterHotplugHandler([this] {
+    const std::lock_guard<std::mutex> lock(GetResMan().GetMainLock());
+
+    HandleHotplugUEvent();
+  });
 
   return ret;
 }
@@ -111,12 +114,9 @@
 HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
                                         hwc2_callback_data_t data,
                                         hwc2_function_pointer_t function) {
-  std::unique_lock<std::mutex> lock(callback_lock_);
-
   switch (static_cast<HWC2::Callback>(descriptor)) {
     case HWC2::Callback::Hotplug: {
       hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
-      lock.unlock();
       const auto &drm_devices = resource_manager_.GetDrmDevices();
       for (const auto &device : drm_devices)
         HandleInitialHotplugState(device.get());
@@ -143,22 +143,36 @@
 }
 
 void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
-  const std::lock_guard<std::mutex> lock(callback_lock_);
+  auto &mutex = GetResMan().GetMainLock();
+  if (mutex.try_lock()) {
+    ALOGE("FIXME!!!: Main mutex must be locked in %s", __func__);
+    mutex.unlock();
+    return;
+  }
 
-  if (hotplug_callback_.first != nullptr &&
-      hotplug_callback_.second != nullptr) {
-    hotplug_callback_.first(hotplug_callback_.second, displayid,
-                            state == DRM_MODE_CONNECTED
-                                ? HWC2_CONNECTION_CONNECTED
-                                : HWC2_CONNECTION_DISCONNECTED);
+  auto hc = hotplug_callback_;
+  if (hc.first != nullptr && hc.second != nullptr) {
+    /* For some reason CLIENT will call HWC2 API in hotplug callback handler,
+     * which will cause deadlock . Unlock main mutex to prevent this.
+     */
+    mutex.unlock();
+    hc.first(hc.second, displayid,
+             state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
+                                         : HWC2_CONNECTION_DISCONNECTED);
+    mutex.lock();
   }
 }
 
 void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
   for (const auto &conn : drmDevice->connectors()) {
-    if (conn->state() != DRM_MODE_CONNECTED)
+    int display_id = conn->display();
+    auto &display = displays_.at(display_id);
+
+    if (conn->state() != DRM_MODE_CONNECTED && !display.IsInHeadlessMode())
       continue;
-    HandleDisplayHotplug(conn->display(), conn->state());
+    HandleDisplayHotplug(conn->display(), display.IsInHeadlessMode()
+                                              ? DRM_MODE_CONNECTED
+                                              : conn->state());
   }
 }
 
@@ -178,15 +192,15 @@
             conn->display());
 
       int display_id = conn->display();
-      if (cur_state == DRM_MODE_CONNECTED) {
-        auto &display = displays_.at(display_id);
-        display.ChosePreferredConfig();
-      } else {
-        auto &display = displays_.at(display_id);
+      auto &display = displays_.at(display_id);
+      display.ChosePreferredConfig();
+      if (cur_state != DRM_MODE_CONNECTED) {
         display.ClearDisplay();
       }
 
-      HandleDisplayHotplug(display_id, cur_state);
+      HandleDisplayHotplug(display_id, display.IsInHeadlessMode()
+                                           ? DRM_MODE_CONNECTED
+                                           : cur_state);
     }
   }
 }
diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h
index d096160..f38ba05 100644
--- a/hwc2_device/DrmHwcTwo.h
+++ b/hwc2_device/DrmHwcTwo.h
@@ -37,8 +37,6 @@
 #endif
   std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{};
 
-  std::mutex callback_lock_;
-
   static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) {
     auto it = hwc->displays_.find(display_handle);
     if (it == hwc->displays_.end())
@@ -57,6 +55,10 @@
                                hwc2_function_pointer_t function);
   HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type);
 
+  auto &GetResMan() {
+    return resource_manager_;
+  }
+
  private:
   void HandleDisplayHotplug(hwc2_display_t displayid, int state);
   void HandleInitialHotplugState(DrmDevice *drmDevice);
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 9055a9a..8936136 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -98,6 +98,11 @@
 }
 
 void HwcDisplay::ClearDisplay() {
+  if (IsInHeadlessMode()) {
+    ALOGE("%s: Headless mode, should never reach here: ", __func__);
+    return;
+  }
+
   AtomicCommitArgs a_args = {.clear_active_composition = true};
   compositor_.ExecuteAtomicCommit(a_args);
 }
@@ -136,7 +141,7 @@
   }
 
   ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) {
-    const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_);
+    const std::lock_guard<std::mutex> lock(hwc2_->GetResMan().GetMainLock());
     /* vsync callback */
 #if PLATFORM_SDK_VERSION > 29
     if (hwc2_->vsync_2_4_callback_.first != nullptr &&
@@ -160,7 +165,8 @@
 
   ret = flattening_vsync_worker_
             .Init(drm_, display, [this](int64_t /*timestamp*/) {
-              const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_);
+              const std::lock_guard<std::mutex> lock(
+                  hwc2_->GetResMan().GetMainLock());
               /* Frontend flattening */
               if (flattenning_state_ >
                       ClientFlattenningState::ClientRefreshRequested &&
@@ -191,7 +197,7 @@
 
 HWC2::Error HwcDisplay::ChosePreferredConfig() {
   HWC2::Error err = configs_.Update(*connector_);
-  if (err != HWC2::Error::None)
+  if (!IsInHeadlessMode() && err != HWC2::Error::None)
     return HWC2::Error::BadDisplay;
 
   return SetActiveConfig(configs_.preferred_config_id);
@@ -229,6 +235,11 @@
 HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements,
                                                    hwc2_layer_t *layers,
                                                    int32_t *types) {
+  if (IsInHeadlessMode()) {
+    *num_elements = 0;
+    return HWC2::Error::None;
+  }
+
   uint32_t num_changes = 0;
   for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
     if (l.second.IsTypeChanged()) {
@@ -249,6 +260,9 @@
                                                int32_t dataspace) {
   std::pair<uint32_t, uint32_t> min = drm_->min_resolution();
   std::pair<uint32_t, uint32_t> max = drm_->max_resolution();
+  if (IsInHeadlessMode()) {
+    return HWC2::Error::None;
+  }
 
   if (width < min.first || height < min.second)
     return HWC2::Error::Unsupported;
@@ -286,8 +300,8 @@
   auto &hwc_config = configs_.hwc_configs[conf];
 
   static const int32_t kUmPerInch = 25400;
-  uint32_t mm_width = connector_->mm_width();
-  uint32_t mm_height = connector_->mm_height();
+  uint32_t mm_width = configs_.mm_width;
+  uint32_t mm_height = configs_.mm_height;
   auto attribute = static_cast<HWC2::Attribute>(attribute_in);
   switch (attribute) {
     case HWC2::Attribute::Width:
@@ -328,15 +342,6 @@
 
 HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
                                           hwc2_config_t *configs) {
-  // Since this callback is normally invoked twice (once to get the count, and
-  // once to populate configs), we don't really want to read the edid
-  // redundantly. Instead, only update the modes on the first invocation. While
-  // it's possible this will result in stale modes, it'll all come out in the
-  // wash when we try to set the active config later.
-  if (!configs) {
-    configs_.Update(*connector_);
-  }
-
   uint32_t idx = 0;
   for (auto &hwc_config : configs_.hwc_configs) {
     if (hwc_config.second.disabled) {
@@ -406,6 +411,11 @@
 HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements,
                                          hwc2_layer_t *layers,
                                          int32_t *fences) {
+  if (IsInHeadlessMode()) {
+    *num_elements = 0;
+    return HWC2::Error::None;
+  }
+
   uint32_t num_layers = 0;
 
   for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
@@ -426,6 +436,11 @@
 }
 
 HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
+  if (IsInHeadlessMode()) {
+    ALOGE("%s: Display is in headless mode, should never reach here", __func__);
+    return HWC2::Error::None;
+  }
+
   // order the layers by z-order
   bool use_client_layer = false;
   uint32_t client_z_order = UINT32_MAX;
@@ -505,7 +520,11 @@
  * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805
  */
 HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) {
-  HWC2::Error ret;
+  if (IsInHeadlessMode()) {
+    *present_fence = -1;
+    return HWC2::Error::None;
+  }
+  HWC2::Error ret{};
 
   ++total_stats_.total_frames_;
 
@@ -619,6 +638,10 @@
 }
 
 HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
+  if (IsInHeadlessMode()) {
+    return HWC2::Error::None;
+  }
+
   auto mode = static_cast<HWC2::PowerMode>(mode_in);
   AtomicCommitArgs a_args{};
 
@@ -660,6 +683,10 @@
 
 HWC2::Error HwcDisplay::ValidateDisplay(uint32_t *num_types,
                                         uint32_t *num_requests) {
+  if (IsInHeadlessMode()) {
+    *num_types = *num_requests = 0;
+    return HWC2::Error::None;
+  }
   return backend_->ValidateDisplay(this, num_types, num_requests);
 }
 
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 6f46f5d..c3e0f6e 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -200,6 +200,16 @@
     return false;
   }
 
+  /* Headless mode required to keep SurfaceFlinger alive when all display are
+   * disconnected, Without headless mode Android will continuously crash.
+   * Only single internal (primary) display is required to be in HEADLESS mode
+   * to prevent the crash. See:
+   * https://source.android.com/devices/graphics/hotplug#handling-common-scenarios
+   */
+  bool IsInHeadlessMode() {
+    return handle_ == 0 && connector_->state() != DRM_MODE_CONNECTED;
+  }
+
  private:
   enum ClientFlattenningState : int32_t {
     Disabled = -3,
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
index d1a8d4c..16f1ed0 100644
--- a/hwc2_device/HwcDisplayConfigs.cpp
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -23,26 +23,57 @@
 #include "drm/DrmConnector.h"
 #include "utils/log.h"
 
+constexpr uint32_t kHeadlessModeDisplayWidthMm = 163;
+constexpr uint32_t kHeadlessModeDisplayHeightMm = 122;
+constexpr uint32_t kHeadlessModeDisplayWidthPx = 1024;
+constexpr uint32_t kHeadlessModeDisplayHeightPx = 768;
+constexpr uint32_t kHeadlessModeDisplayVRefresh = 60;
+
 namespace android {
 
 // NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
 HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
+  /* In case UpdateModes will fail we will still have one mode for headless
+   * mode*/
+  hwc_configs.clear();
+
+  last_config_id++;
+  preferred_config_id = active_config_id = last_config_id;
+  auto headless_drm_mode_info = (drmModeModeInfo){
+      .hdisplay = kHeadlessModeDisplayWidthPx,
+      .vdisplay = kHeadlessModeDisplayHeightPx,
+      .vrefresh = kHeadlessModeDisplayVRefresh,
+      .name = "HEADLESS-MODE",
+  };
+  hwc_configs[active_config_id] = (HwcDisplayConfig){
+      .id = active_config_id,
+      .group_id = 1,
+      .mode = DrmMode(&headless_drm_mode_info),
+  };
+
+  mm_width = kHeadlessModeDisplayWidthMm;
+  mm_height = kHeadlessModeDisplayHeightMm;
+
+  /* Read real configs */
   int ret = connector.UpdateModes();
   if (ret != 0) {
     ALOGE("Failed to update display modes %d", ret);
     return HWC2::Error::BadDisplay;
   }
 
-  hwc_configs.clear();
-  preferred_config_id = 0;
-  int preferred_config_group_id = 0;
-
   if (connector.modes().empty()) {
     ALOGE("No modes reported by KMS");
     return HWC2::Error::BadDisplay;
   }
 
-  int last_config_id = 1;
+  hwc_configs.clear();
+  mm_width = connector.mm_width();
+  mm_height = connector.mm_height();
+
+  preferred_config_id = 0;
+  int preferred_config_group_id = 0;
+
+  int first_config_id = last_config_id;
   int last_group_id = 1;
 
   /* Group modes */
@@ -87,7 +118,7 @@
   /* We must have preferred mode. Set first mode as preferred
    * in case KMS haven't reported anything. */
   if (preferred_config_id == 0) {
-    preferred_config_id = 1;
+    preferred_config_id = first_config_id;
     preferred_config_group_id = 1;
   }
 
@@ -142,8 +173,8 @@
    * otherwise android.graphics.cts.SetFrameRateTest CTS will fail
    */
   constexpr float kMinFpsDelta = 1.0;  // FPS
-  for (int m1 = 1; m1 < last_config_id; m1++) {
-    for (int m2 = 1; m2 < last_config_id; m2++) {
+  for (int m1 = first_config_id; m1 < last_config_id; m1++) {
+    for (int m2 = first_config_id; m2 < last_config_id; m2++) {
       if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
           !hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
           fabsf(hwc_configs[m1].mode.v_refresh() -
@@ -159,6 +190,8 @@
     }
   }
 
+  /* Set active mode to be valid mode */
+  active_config_id = preferred_config_id;
   return HWC2::Error::None;
 }
 
diff --git a/hwc2_device/HwcDisplayConfigs.h b/hwc2_device/HwcDisplayConfigs.h
index cb38625..5bcf696 100644
--- a/hwc2_device/HwcDisplayConfigs.h
+++ b/hwc2_device/HwcDisplayConfigs.h
@@ -45,6 +45,11 @@
 
   int active_config_id = 0;
   int preferred_config_id = 0;
+
+  int last_config_id = 1;
+
+  uint32_t mm_width = 0;
+  uint32_t mm_height = 0;
 };
 
 }  // namespace android
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index 22e4589..6d258e8 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -14,14 +14,35 @@
  * limitations under the License.
  */
 
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+// #define LOG_NDEBUG 0 // Uncomment to see HWC2 API calls in logcat
+
 #define LOG_TAG "hwc2-device"
 
+#include <cinttypes>
+
 #include "DrmHwcTwo.h"
 #include "backend/Backend.h"
 #include "utils/log.h"
 
 namespace android {
 
+/* Converts long __PRETTY_FUNCTION__ result, e.g.:
+ * "int32_t android::LayerHook(hwc2_device_t *, hwc2_display_t, hwc2_layer_t,"
+ * "Args...) [HookType = HWC2::Error (android::HwcLayer::*)(const native_handle"
+ * "*,int), func = &android::HwcLayer::SetLayerBuffer, Args = <const
+ * "native_handle, int>"
+ * to the short "android::HwcLayer::SetLayerBuffer" for better logs readability
+ */
+static std::string GetFuncName(const char *pretty_function) {
+  std::string str(pretty_function);
+  const char *start = "func = &";
+  size_t p1 = str.find(start);
+  p1 += strlen(start);
+  size_t p2 = str.find(',', p1);
+  return str.substr(p1, p2 - p1);
+}
+
 struct Drmhwc2Device : hwc2_device {
   DrmHwcTwo drmhwctwo;
 };
@@ -40,14 +61,20 @@
 
 template <typename T, typename HookType, HookType func, typename... Args>
 static T DeviceHook(hwc2_device_t *dev, Args... args) {
+  ALOGV("Device hook: %s", GetFuncName(__PRETTY_FUNCTION__).c_str());
   DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
+  const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
   return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...));
 }
 
 template <typename HookType, HookType func, typename... Args>
 static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle,
                            Args... args) {
-  HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), display_handle);
+  ALOGV("Display #%" PRIu64 " hook: %s", display_handle,
+        GetFuncName(__PRETTY_FUNCTION__).c_str());
+  DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
+  const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+  HwcDisplay *display = DrmHwcTwo::GetDisplay(hwc, display_handle);
   if (!display)
     return static_cast<int32_t>(HWC2::Error::BadDisplay);
 
@@ -57,7 +84,11 @@
 template <typename HookType, HookType func, typename... Args>
 static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle,
                          hwc2_layer_t layer_handle, Args... args) {
-  HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), display_handle);
+  ALOGV("Display #%" PRIu64 " Layer: #%" PRIu64 " hook: %s", display_handle,
+        layer_handle, GetFuncName(__PRETTY_FUNCTION__).c_str());
+  DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
+  const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+  HwcDisplay *display = DrmHwcTwo::GetDisplay(hwc, display_handle);
   if (!display)
     return static_cast<int32_t>(HWC2::Error::BadDisplay);
 
diff --git a/utils/autolock.cpp b/utils/autolock.cpp
deleted file mode 100644
index 3afe488..0000000
--- a/utils/autolock.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#define LOG_TAG "hwc-drm-auto-lock"
-
-#include "autolock.h"
-
-#include <pthread.h>
-
-#include <cerrno>
-
-#include "utils/log.h"
-
-namespace android {
-
-int AutoLock::Lock() {
-  if (locked_) {
-    ALOGE("Invalid attempt to double lock AutoLock %s", name_);
-    return -EINVAL;
-  }
-  int ret = pthread_mutex_lock(mutex_);
-  if (ret != 0) {
-    ALOGE("Failed to acquire %s lock %d", name_, ret);
-    return ret;
-  }
-  locked_ = true;
-  return 0;
-}
-
-int AutoLock::Unlock() {
-  if (!locked_) {
-    ALOGE("Invalid attempt to unlock unlocked AutoLock %s", name_);
-    return -EINVAL;
-  }
-  int ret = pthread_mutex_unlock(mutex_);
-  if (ret != 0) {
-    ALOGE("Failed to release %s lock %d", name_, ret);
-    return ret;
-  }
-  locked_ = false;
-  return 0;
-}
-}  // namespace android
diff --git a/utils/autolock.h b/utils/autolock.h
deleted file mode 100644
index 006406a..0000000
--- a/utils/autolock.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <pthread.h>
-
-namespace android {
-
-class AutoLock {
- public:
-  AutoLock(pthread_mutex_t *mutex, const char *const name)
-      : mutex_(mutex), name_(name) {
-  }
-  ~AutoLock() {
-    if (locked_)
-      Unlock();
-  }
-
-  AutoLock(const AutoLock &rhs) = delete;
-  AutoLock &operator=(const AutoLock &rhs) = delete;
-
-  int Lock();
-  int Unlock();
-
- private:
-  pthread_mutex_t *const mutex_;
-  bool locked_ = false;
-  const char *const name_;
-};
-}  // namespace android