Merge remote-tracking branch 'aosp/upstream-main' into HEAD am: 197c32dc5b am: 5365831dfb am: edf83fea0f am: f3da2cd345 am: 41eb3601a7

Original change: https://android-review.googlesource.com/c/platform/external/drm_hwcomposer/+/2641990

Change-Id: I52ec762c67d9cd89249809ec21e086f4dd94547f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.ci/.gitlab-ci-checkcommit.sh b/.ci/.gitlab-ci-checkcommit.sh
index c6f7c4e..f854999 100755
--- a/.ci/.gitlab-ci-checkcommit.sh
+++ b/.ci/.gitlab-ci-checkcommit.sh
@@ -1,5 +1,13 @@
 #! /usr/bin/env bash
 
+check_tool_installed() {
+	if ! command -v $1 &> /dev/null
+	then
+		echo "Please install '$1' tool"
+		exit 1
+	fi
+}
+
 echoerr() {
 	printf "ERROR: %s\n" "$*" >&2
 }
@@ -27,6 +35,9 @@
 	return 1
 }
 
+check_tool_installed bpfmt
+check_tool_installed clang-format-diff-15
+
 git fetch https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer.git
 
 git log --pretty='%h' FETCH_HEAD..HEAD | while read h; do
@@ -50,7 +61,7 @@
 		exit 1
 	fi
 
-	git show "$h" -- | clang-format-diff-14 -p 1 -style=file > /tmp/format-fixup.patch
+	git show "$h" -- | clang-format-diff-15 -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/Dockerfile b/.ci/Dockerfile
new file mode 100644
index 0000000..32c348f
--- /dev/null
+++ b/.ci/Dockerfile
@@ -0,0 +1,52 @@
+FROM ubuntu:22.10
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+ENV PATH="/home/user/bin:${PATH}"
+
+# Taking into account layer structure, everything should be done within one layer.
+RUN apt-get update && apt-get upgrade -y && \
+    apt-get install -y clang-15 clang-tidy-15 clang-format-15 git libdrm-dev blueprint-tools libgtest-dev clang \
+    llvm make python3 python3-pip wget sudo rsync lld pkg-config ninja-build && \
+    pip3 install mako meson jinja2 ply pyyaml
+
+ENV RUN_USER user
+ENV RUN_UID 1000
+
+ENV USER_HOME /home/${RUN_USER}
+
+RUN mkdir -pv ${USER_HOME}
+# Create new user
+RUN adduser \
+    --gecos 'Build User' \
+    --shell '/usr/bin/bash' \
+    --uid ${RUN_UID} \
+    --disabled-login \
+    --disabled-password ${RUN_USER} \
+    && adduser ${RUN_USER} sudo
+
+RUN chown -R ${RUN_USER}:${RUN_USER} ${USER_HOME} && chmod -R 775 ${USER_HOME}
+
+# Ensure sudo group users are not
+# asked for a password when using
+# sudo command by ammending sudoers file
+RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> \
+/etc/sudoers
+
+# Pass control to a newly created user
+USER ${RUN_USER}
+
+# Install aospless package (produced by GloDroid/aospext)
+RUN wget -P ${USER_HOME} https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/uploads/28ef9379b1a0ec1ee19a17825b0f3f3f/aospless_drm_hwcomposer_arm64.tar.xz && \
+    cd ${USER_HOME} && \
+    (echo 96b2148d04c50cf36d4151ae022e665764b8ca3317712e9467a433b62c545a43 aospless_drm_hwcomposer_arm64.tar.xz | sha256sum --check) && \
+    tar xf aospless_drm_hwcomposer_arm64.tar.xz && \
+    rm -r ${USER_HOME}/aospless/src && ln -s ../drm_hwcomposer/ ${USER_HOME}/aospless/src
+
+# Create project path
+RUN mkdir -pv ${USER_HOME}/drm_hwcomposer
+WORKDIR ${USER_HOME}/drm_hwcomposer
+
+RUN git config --global user.name "FIRST_NAME LAST_NAME" && git config --global user.email "MY_NAME@example.com"
+
+CMD [ "/bin/bash" ]
diff --git a/.ci/Makefile b/.ci/Makefile
index 581c6d9..9c82fca 100644
--- a/.ci/Makefile
+++ b/.ci/Makefile
@@ -2,12 +2,12 @@
 INCLUDE_DIRS := . ../libdrm/include/drm include ./.ci/android_headers ./tests/test_include
 SYSTEM_INCLUDE_DIRS := /usr/include/libdrm
 
-CLANG := clang++-14
-CLANG_TIDY := clang-tidy-14
+CLANG := clang++-15
+CLANG_TIDY := clang-tidy-15
 OUT_DIR := /tmp/drm_hwcomposer/build
 SRC_DIR := .
 
-CXXFLAGS := -fPIC -Wall -Wextra -Werror -DPLATFORM_SDK_VERSION=31 -D__ANDROID_API__=31
+CXXFLAGS := -fPIC -Wall -Wextra -Werror -D__ANDROID_API__=31
 CXXFLAGS += -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
 CXXFLAGS += -fvisibility-inlines-hidden -std=gnu++17 -DHWC2_USE_CPP11 -DHWC2_INCLUDE_STRINGIFICATION -fno-rtti
 
@@ -22,18 +22,11 @@
     bufferinfo/legacy/BufferInfoMaliMeson.cpp:COARSE    \
     bufferinfo/legacy/BufferInfoMinigbm.cpp:COARSE      \
     drm/DrmFbImporter.h:FINE                            \
-    drm/DrmMode.h:COARSE                                \
-    drm/DrmProperty.h:COARSE                            \
     drm/DrmUnique.h:FINE                                \
-    drm/DrmProperty.cpp:COARSE                          \
-    drm/VSyncWorker.cpp:COARSE                          \
     hwc2_device/DrmHwcTwo.cpp:COARSE                    \
     hwc2_device/DrmHwcTwo.h:COARSE                      \
     hwc2_device/HwcDisplay.cpp:COARSE                   \
     hwc2_device/HwcDisplay.h:COARSE                     \
-    tests/worker_test.cpp:COARSE                        \
-    utils/Worker.h:COARSE                               \
-    utils/UniqueFd.h:FINE                               \
     utils/log.h:FINE                                    \
     utils/properties.h:FINE                             \
 
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index eb0c265..bfc4ede 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,23 +1,40 @@
-image: ubuntu:22.04
+image: ubuntu:22.10
 
 variables:
   DEBIAN_FRONTEND: noninteractive
 
 before_script:
   - apt-get --quiet update --yes >/dev/null
-  - apt-get --quiet install --yes clang-14 clang-tidy-14 clang-format-14 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null
+  - apt-get --quiet install --yes clang-15 clang-tidy-15 clang-format-15 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null
+  - apt-get --quiet install --yes clang llvm make python3 python3-pip wget sudo rsync lld pkg-config ninja-build >/dev/null
+  - pip3 install mako meson jinja2 ply pyyaml >/dev/null
 
 stages:
   - build
+  - tidy
   - style
 
 build:
   stage: build
   script:
-    - make -f .ci/Makefile
+    - mkdir -p install/arm64
+    - cd ..
+    - wget https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/uploads/28ef9379b1a0ec1ee19a17825b0f3f3f/aospless_drm_hwcomposer_arm64.tar.xz
+    - tar xf aospless_drm_hwcomposer_arm64.tar.xz
+    - rm -r aospless/src
+    - ln -s ../drm-hwcomposer/ aospless/src
+    - make -C ./aospless all
+    - cp -r aospless/install/* drm-hwcomposer/install/arm64
+
   artifacts:
-    when: on_failure
-    untracked: true
+    paths:
+      - install/
+    expire_in: 1 week
+
+tidy:
+  stage: tidy
+  script:
+    - make -f .ci/Makefile
 
 checkstyle:
   stage: style
diff --git a/Android.bp b/Android.bp
index a7a2e94..62c7e0c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,9 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// =====================
-// libdrmhwc_utils.a
-// =====================
 package {
     default_applicable_licenses: ["external_drm_hwcomposer_license"],
 }
@@ -32,20 +29,10 @@
     ],
 }
 
-cc_library_static {
-    name: "libdrmhwc_utils",
-
-    srcs: ["utils/Worker.cpp"],
-
-    include_dirs: ["external/drm_hwcomposer"],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-
+cc_library_headers {
+    name: "drm_hwcomposer_headers",
     vendor: true,
-
+    export_include_dirs: ["."],
 }
 
 // =====================
@@ -65,9 +52,7 @@
         "libutils",
     ],
 
-    include_dirs: ["external/drm_hwcomposer"],
-
-    static_libs: ["libdrmhwc_utils"],
+    header_libs: ["drm_hwcomposer_headers"],
 
     cflags: [
         "-Wall",
@@ -80,23 +65,23 @@
         "-std=c++17",
     ],
 
-    product_variables: {
-        platform_sdk_version: {
-            cflags: ["-DPLATFORM_SDK_VERSION=%d"],
-        },
-    },
-
     relative_install_path: "hw",
     vendor: true,
 }
 
 filegroup {
+    name: "drm_hwcomposer_fd",
+    srcs: ["utils/fd.cpp"],
+}
+
+filegroup {
     name: "drm_hwcomposer_common",
     srcs: [
         "bufferinfo/BufferInfoGetter.cpp",
         "bufferinfo/BufferInfoMapperMetadata.cpp",
 
         "compositor/DrmKmsPlan.cpp",
+        "compositor/FlatteningController.cpp",
 
         "drm/DrmAtomicStateManager.cpp",
         "drm/DrmConnector.cpp",
@@ -121,6 +106,8 @@
         "hwc2_device/HwcDisplayConfigs.cpp",
         "hwc2_device/HwcLayer.cpp",
         "hwc2_device/hwc2_device.cpp",
+
+        "utils/fd.cpp",
     ],
 }
 
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..98e33af
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,95 @@
+#!/usr/bin/make
+
+DOCKER_BIN := $(shell command -v docker 2> /dev/null)
+NPROCS:=$(shell grep -c ^processor /proc/cpuinfo)
+
+DOCKERFILE := .ci/Dockerfile
+IMAGE_NAME := drmhwc_ci
+
+# We can't run style and bpfmt check in docker
+# when repo is within AOSP tree, will run it locally.
+GIT_IS_SYMLINK:=$(shell test -L .git && echo true)
+
+define print_no_docker_err
+$(warning Please install docker, e.g. for Ubuntu:)
+$(warning $$ sudo apt install docker.io)
+$(warning $$ sudo usermod -aG docker $$USER)
+$(warning and reboot your PC)
+$(error Aborting...)
+endef
+
+.PHONY : help prepare shell ci_fast ci ci_cleanup build_deploy bd local_presubmit local_cleanup
+.DEFAULT_GOAL := help
+
+help: ## Show this help
+	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
+
+PREPARE:=.out/prepare_docker.timestamp
+$(PREPARE): $(DOCKERFILE)
+	$(if $(DOCKER_BIN),,$(call print_no_docker_err))
+	mkdir -p $(dir $@)
+	$(DOCKER_BIN) build -t local/build-env -f $(DOCKERFILE) .;
+	$(DOCKER_BIN) stop $(IMAGE_NAME) || true
+	$(DOCKER_BIN) rm $(IMAGE_NAME) || true
+	$(DOCKER_BIN) run -itd --name $(IMAGE_NAME) --network="host" -v $(shell pwd):/home/user/drm_hwcomposer local/build-env
+	@touch $@
+
+prepare: $(PREPARE)
+prepare: ## Build and run Docker image
+
+shell: $(PREPARE)
+shell: ## Start shell into a container
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash
+
+ci_fast: $(PREPARE)
+ci_fast: ## Run meson build for arm64 in docker container
+	@echo "Run meson cross-build for Android:"
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -C ~/aospless all"
+
+ci: $(PREPARE)
+ci: ## Run presubmit within the docker container
+	@echo "Run native build:"
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -f .ci/Makefile -j$(NPROCS)"
+	@echo "Run meson cross-build for Android:"
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -C ~/aospless all"
+	@echo "Run style check:"
+	$(if $(GIT_IS_SYMLINK), \
+		./.ci/.gitlab-ci-checkcommit.sh, \
+		$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "./.ci/.gitlab-ci-checkcommit.sh")
+	@echo "\n\e[32m --- SUCCESS ---\n"
+
+ci_cleanup: ## Cleanup after 'make ci'
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make local_cleanup"
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "rm -rf ~/aospless/build"
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "rm -rf ~/aospless/install"
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "rm -rf ~/aospless/out_src"
+
+build_deploy: $(PREPARE)
+build_deploy: ## Build for Andoid and deploy onto the target device (require active adb device connected)
+	$(if $(filter $(shell adb shell getprop ro.bionic.arch),arm64),,$(error arm64 only is supported at the moment))
+	adb root && adb remount vendor
+	mkdir -p .out/arm64
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -C ~/aospless all"
+	$(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "cp -r ~/aospless/install/* ~/drm_hwcomposer/.out/arm64"
+	adb push .out/arm64/vendor/lib64/hw/hwcomposer.drm.so /vendor/lib64/hw/hwcomposer.drm.so
+	adb shell stop
+	adb shell stop vendor.hwcomposer-2-1 && adb shell start vendor.hwcomposer-2-1 || true
+	adb shell stop vendor.hwcomposer-2-2 && adb shell start vendor.hwcomposer-2-2 || true
+	adb shell stop vendor.hwcomposer-2-3 && adb shell start vendor.hwcomposer-2-3 || true
+	adb shell stop vendor.hwcomposer-2-4 && adb shell start vendor.hwcomposer-2-4 || true
+	bash -c '[[ "$$HWCLOG" -eq "1" ]] && adb logcat -c || true'
+	adb shell start
+	bash -c '[[ "$$HWCLOG" -eq "1" ]] && adb logcat | grep -i hwc || true'
+
+bd: build_deploy
+bd: ## Alias for build_deploy
+
+local_presubmit: ## Run local presubmit script (requires latest Ubuntu + additional packages). Consider 'make ci' instead
+	@echo "Run native build:"
+	make -f .ci/Makefile -j12
+	@echo "Run style check:"
+	./.ci/.gitlab-ci-checkcommit.sh
+	@echo "\n\e[32m --- SUCCESS ---\n"
+
+local_cleanup: ## Cleanup after 'make local_presubmit'
+	make -f .ci/Makefile clean
diff --git a/README.md b/README.md
index e98b5ae..5724b36 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
   you with formatting of your patches:
 
     ```
-    git diff | clang-format-diff-14 -p 1 -style=file
+    git diff | clang-format-diff-15 -p 1 -style=file
     ```
 
 * Hardware specific changes should be tested on relevant platforms before
diff --git a/backend/Backend.cpp b/backend/Backend.cpp
index ba0518a..3ca6e92 100644
--- a/backend/Backend.cpp
+++ b/backend/Backend.cpp
@@ -33,27 +33,36 @@
   int client_start = -1;
   size_t client_size = 0;
 
-  if (display->ProcessClientFlatteningState(layers.size() <= 1)) {
-    display->total_stats().frames_flattened_++;
+  auto flatcon = display->GetFlatCon();
+  if (flatcon) {
+    bool should_flatten = false;
+    if (layers.size() <= 1)
+      flatcon->Disable();
+    else
+      should_flatten = flatcon->NewFrame();
+
+    if (should_flatten) {
+      display->total_stats().frames_flattened_++;
+      MarkValidated(layers, 0, layers.size());
+      *num_types = layers.size();
+      return HWC2::Error::HasChanges;
+    }
+  }
+
+  std::tie(client_start, client_size) = GetClientLayers(display, layers);
+
+  MarkValidated(layers, client_start, client_size);
+
+  auto testing_needed = client_start != 0 || client_size != layers.size();
+
+  AtomicCommitArgs a_args = {.test_only = true};
+
+  if (testing_needed &&
+      display->CreateComposition(a_args) != HWC2::Error::None) {
+    ++display->total_stats().failed_kms_validate_;
     client_start = 0;
     client_size = layers.size();
-    MarkValidated(layers, client_start, client_size);
-  } else {
-    std::tie(client_start, client_size) = GetClientLayers(display, layers);
-
-    MarkValidated(layers, client_start, client_size);
-
-    bool testing_needed = !(client_start == 0 && client_size == layers.size());
-
-    AtomicCommitArgs a_args = {.test_only = true};
-
-    if (testing_needed &&
-        display->CreateComposition(a_args) != HWC2::Error::None) {
-      ++display->total_stats().failed_kms_validate_;
-      client_start = 0;
-      client_size = layers.size();
-      MarkValidated(layers, 0, client_size);
-    }
+    MarkValidated(layers, 0, client_size);
   }
 
   *num_types = client_size;
@@ -83,8 +92,7 @@
 
 bool Backend::IsClientLayer(HwcDisplay *display, HwcLayer *layer) {
   return !HardwareSupportsLayerType(layer->GetSfType()) ||
-         !layer->IsLayerUsableAsDevice() ||
-         display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY ||
+         !layer->IsLayerUsableAsDevice() || display->CtmByGpu() ||
          (layer->GetLayerData().pi.RequireScalingOrPhasing() &&
           display->GetHwc2()->GetResMan().ForcedScalingWithGpu());
 }
@@ -99,7 +107,7 @@
   uint32_t pixops = 0;
   for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
     if (z_order >= first_z && z_order < first_z + size) {
-      hwc_rect_t &df = layers[z_order]->GetLayerData().pi.display_frame;
+      auto &df = layers[z_order]->GetLayerData().pi.display_frame;
       pixops += (df.right - df.left) * (df.bottom - df.top);
     }
   }
@@ -129,16 +137,16 @@
   if (avail_planes < display->layers().size())
     avail_planes--;
 
-  int extra_client = int(layers.size() - client_size) - int(avail_planes);
+  const int extra_client = int(layers.size() - client_size) - int(avail_planes);
 
   if (extra_client > 0) {
     int start = 0;
     size_t steps = 0;
     if (client_size != 0) {
-      int prepend = std::min(client_start, extra_client);
-      int append = std::min(int(layers.size()) -
-                                int(client_start + client_size),
-                            extra_client);
+      const int prepend = std::min(client_start, extra_client);
+      const int append = std::min(int(layers.size()) -
+                                      int(client_start + client_size),
+                                  extra_client);
       start = client_start - (int)prepend;
       client_size += extra_client;
       steps = 1 + std::min(std::min(append, prepend),
@@ -150,7 +158,7 @@
 
     uint32_t gpu_pixops = UINT32_MAX;
     for (size_t i = 0; i < steps; i++) {
-      uint32_t po = CalcPixOps(layers, start + i, client_size);
+      const uint32_t po = CalcPixOps(layers, start + i, client_size);
       if (po < gpu_pixops) {
         gpu_pixops = po;
         client_start = start + int(i);
diff --git a/backend/Backend.h b/backend/Backend.h
index 82b8fca..c24e818 100644
--- a/backend/Backend.h
+++ b/backend/Backend.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_BACKEND_H
-#define ANDROID_BACKEND_H
+#pragma once
 
 #include "hwc2_device/DrmHwcTwo.h"
 
@@ -41,5 +40,3 @@
       int client_start, size_t client_size);
 };
 }  // namespace android
-
-#endif
diff --git a/backend/BackendClient.h b/backend/BackendClient.h
index 95abb0f..1333eca 100644
--- a/backend/BackendClient.h
+++ b/backend/BackendClient.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_BACKEND_CLIENT_H
-#define ANDROID_BACKEND_CLIENT_H
+#pragma once
 
 #include "Backend.h"
 
@@ -27,5 +26,3 @@
                               uint32_t *num_requests) override;
 };
 }  // namespace android
-
-#endif
diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp
index 9bf6324..c1bc0f6 100644
--- a/backend/BackendManager.cpp
+++ b/backend/BackendManager.cpp
@@ -42,7 +42,7 @@
 }
 
 int BackendManager::SetBackendForDisplay(HwcDisplay *display) {
-  std::string driver_name(display->GetPipe().device->GetName());
+  auto driver_name(display->GetPipe().device->GetName());
   char backend_override[PROPERTY_VALUE_MAX];
   property_get("vendor.hwc.backend_override", backend_override,
                driver_name.c_str());
diff --git a/backend/BackendManager.h b/backend/BackendManager.h
index 751cb78..4976744 100644
--- a/backend/BackendManager.h
+++ b/backend/BackendManager.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_BACKEND_MANAGER_H
-#define ANDROID_BACKEND_MANAGER_H
+#pragma once
 
 #include <functional>
 #include <map>
@@ -54,5 +53,3 @@
   std::map<std::string, BackendConstructorT> available_backends_;
 };
 }  // namespace android
-
-#endif
diff --git a/bufferinfo/BufferInfoGetter.cpp b/bufferinfo/BufferInfoGetter.cpp
index 95c1a23..726b4eb 100644
--- a/bufferinfo/BufferInfoGetter.cpp
+++ b/bufferinfo/BufferInfoGetter.cpp
@@ -18,7 +18,7 @@
 
 #include "BufferInfoGetter.h"
 
-#if PLATFORM_SDK_VERSION >= 30
+#if __ANDROID_API__ >= 30
 #include "BufferInfoMapperMetadata.h"
 #endif
 
@@ -38,7 +38,7 @@
 BufferInfoGetter *BufferInfoGetter::GetInstance() {
   static std::unique_ptr<BufferInfoGetter> inst;
   if (!inst) {
-#if PLATFORM_SDK_VERSION >= 30 && defined(USE_IMAPPER4_METADATA_API)
+#if __ANDROID_API__ >= 30 && defined(USE_IMAPPER4_METADATA_API)
     inst.reset(BufferInfoMapperMetadata::CreateInstance());
     if (!inst) {
       ALOGW(
@@ -68,7 +68,7 @@
 }
 
 int LegacyBufferInfoGetter::Init() {
-  int ret = hw_get_module(
+  const int ret = hw_get_module(
       GRALLOC_HARDWARE_MODULE_ID,
       // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
       reinterpret_cast<const hw_module_t **>(&gralloc_));
diff --git a/bufferinfo/BufferInfoGetter.h b/bufferinfo/BufferInfoGetter.h
index 5591296..5131c37 100644
--- a/bufferinfo/BufferInfoGetter.h
+++ b/bufferinfo/BufferInfoGetter.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_BUFFERINFOGETTER_H_
-#define ANDROID_BUFFERINFOGETTER_H_
+#pragma once
 
 #include <drm/drm_fourcc.h>
 #include <hardware/gralloc.h>
@@ -89,4 +88,3 @@
 #endif
 
 }  // namespace android
-#endif
diff --git a/bufferinfo/BufferInfoMapperMetadata.cpp b/bufferinfo/BufferInfoMapperMetadata.cpp
index bdacb74..823d28a 100644
--- a/bufferinfo/BufferInfoMapperMetadata.cpp
+++ b/bufferinfo/BufferInfoMapperMetadata.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#if PLATFORM_SDK_VERSION >= 30
+#if __ANDROID_API__ >= 30
 
 #define LOG_TAG "hwc-bufferinfo-mappermetadata"
 
diff --git a/bufferinfo/BufferInfoMapperMetadata.h b/bufferinfo/BufferInfoMapperMetadata.h
index ab269dc..ce66fe5 100644
--- a/bufferinfo/BufferInfoMapperMetadata.h
+++ b/bufferinfo/BufferInfoMapperMetadata.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef PLATFORMIMAGINATION_H
-#define PLATFORMIMAGINATION_H
+#pragma once
 
 #include "bufferinfo/BufferInfoGetter.h"
 
@@ -32,5 +31,3 @@
   static BufferInfoGetter *CreateInstance();
 };
 }  // namespace android
-
-#endif  // PLATFORMIMAGINATION_H
diff --git a/bufferinfo/legacy/BufferInfoImagination.h b/bufferinfo/legacy/BufferInfoImagination.h
index 635e3b5..3f4e13a 100644
--- a/bufferinfo/legacy/BufferInfoImagination.h
+++ b/bufferinfo/legacy/BufferInfoImagination.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef BUFFERINFOIMAGINATION_H
-#define BUFFERINFOIMAGINATION_H
+#pragma once
 
 #include <hardware/gralloc.h>
 
@@ -30,5 +29,3 @@
   auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
 };
 }  // namespace android
-
-#endif  // PLATFORMIMAGINATION_H
diff --git a/bufferinfo/legacy/BufferInfoLibdrm.cpp b/bufferinfo/legacy/BufferInfoLibdrm.cpp
index ac71ec0..b314bdc 100644
--- a/bufferinfo/legacy/BufferInfoLibdrm.cpp
+++ b/bufferinfo/legacy/BufferInfoLibdrm.cpp
@@ -154,7 +154,7 @@
   if (num_fds == 1) {
     bo->prime_fds[2] = bo->prime_fds[1] = bo->prime_fds[0];
   } else {
-    int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3;
+    const int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3;
     if (num_fds != expected_planes)
       return false;
   }
diff --git a/bufferinfo/legacy/BufferInfoLibdrm.h b/bufferinfo/legacy/BufferInfoLibdrm.h
index 7f5b08c..d913d57 100644
--- a/bufferinfo/legacy/BufferInfoLibdrm.h
+++ b/bufferinfo/legacy/BufferInfoLibdrm.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef BUFFERINFOLIBDRM_H_
-#define BUFFERINFOLIBDRM_H_
+#pragma once
 
 #include <hardware/gralloc.h>
 
@@ -35,5 +34,3 @@
 };
 
 }  // namespace android
-
-#endif
diff --git a/bufferinfo/legacy/BufferInfoMaliHisi.cpp b/bufferinfo/legacy/BufferInfoMaliHisi.cpp
index 1c7f4d0..461e2eb 100644
--- a/bufferinfo/legacy/BufferInfoMaliHisi.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliHisi.cpp
@@ -77,7 +77,7 @@
   if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
     return {};
 
-  uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
+  const uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
   if (fmt == DRM_FORMAT_INVALID)
     return {};
 
@@ -100,10 +100,10 @@
       if (hnd->usage &
           (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK))
         align = 16;
-      int adjusted_height = MALI_ALIGN(hnd->height, 2);
-      int y_size = adjusted_height * hnd->byte_stride;
-      int vu_stride = MALI_ALIGN(hnd->byte_stride / 2, align);
-      int v_size = vu_stride * (adjusted_height / 2);
+      const int adjusted_height = MALI_ALIGN(hnd->height, 2);
+      const int y_size = adjusted_height * hnd->byte_stride;
+      const int vu_stride = MALI_ALIGN(hnd->byte_stride / 2, align);
+      const int v_size = vu_stride * (adjusted_height / 2);
 
       /* V plane*/
       bi.prime_fds[1] = hnd->share_fd;
diff --git a/bufferinfo/legacy/BufferInfoMaliHisi.h b/bufferinfo/legacy/BufferInfoMaliHisi.h
index cc37491..35c7989 100644
--- a/bufferinfo/legacy/BufferInfoMaliHisi.h
+++ b/bufferinfo/legacy/BufferInfoMaliHisi.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef BUFFERINFOMALIHISI_H_
-#define BUFFERINFOMALIHISI_H_
+#pragma once
 
 #include <hardware/gralloc.h>
 
@@ -33,5 +32,3 @@
   uint64_t ConvertGrallocFormatToDrmModifiers(uint64_t flags, bool is_rgb);
 };
 }  // namespace android
-
-#endif
diff --git a/bufferinfo/legacy/BufferInfoMaliMediatek.cpp b/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
index 2e10460..6dac973 100644
--- a/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
@@ -38,7 +38,7 @@
   if (!hnd)
     return {};
 
-  uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
+  const uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
   if (fmt == DRM_FORMAT_INVALID)
     return {};
 
diff --git a/bufferinfo/legacy/BufferInfoMaliMediatek.h b/bufferinfo/legacy/BufferInfoMaliMediatek.h
index 43d987a..120a88c 100644
--- a/bufferinfo/legacy/BufferInfoMaliMediatek.h
+++ b/bufferinfo/legacy/BufferInfoMaliMediatek.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef BUFFERINFOMALIMTK_H_
-#define BUFFERINFOMALIMTK_H_
+#pragma once
 
 #include <hardware/gralloc.h>
 
@@ -30,5 +29,3 @@
   auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
 };
 }  // namespace android
-
-#endif
diff --git a/bufferinfo/legacy/BufferInfoMaliMeson.cpp b/bufferinfo/legacy/BufferInfoMaliMeson.cpp
index 8160296..536e5a6 100644
--- a/bufferinfo/legacy/BufferInfoMaliMeson.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliMeson.cpp
@@ -70,7 +70,7 @@
   if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
     return {};
 
-  uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
+  const uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
   if (fmt == DRM_FORMAT_INVALID)
     return {};
 
diff --git a/bufferinfo/legacy/BufferInfoMaliMeson.h b/bufferinfo/legacy/BufferInfoMaliMeson.h
index 3b6fab0..9a484d3 100644
--- a/bufferinfo/legacy/BufferInfoMaliMeson.h
+++ b/bufferinfo/legacy/BufferInfoMaliMeson.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef BUFFERINFOMALIHISI_H_
-#define BUFFERINFOMALIHISI_H_
+#pragma once
 
 #include <hardware/gralloc.h>
 
@@ -32,5 +31,3 @@
   uint64_t ConvertGrallocFormatToDrmModifiers(uint64_t flags);
 };
 }  // namespace android
-
-#endif
diff --git a/bufferinfo/legacy/BufferInfoMinigbm.h b/bufferinfo/legacy/BufferInfoMinigbm.h
index 40d9926..5525110 100644
--- a/bufferinfo/legacy/BufferInfoMinigbm.h
+++ b/bufferinfo/legacy/BufferInfoMinigbm.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef BUFFERINFOMINIGBM_H_
-#define BUFFERINFOMINIGBM_H_
+#pragma once
 
 #include <hardware/gralloc.h>
 
@@ -31,5 +30,3 @@
 };
 
 }  // namespace android
-
-#endif
diff --git a/bufferinfo/meson.build b/bufferinfo/meson.build
new file mode 100644
index 0000000..f53d1b9
--- /dev/null
+++ b/bufferinfo/meson.build
@@ -0,0 +1,5 @@
+src_common += files(
+    'legacy/BufferInfoLibdrm.cpp',
+    'BufferInfoGetter.cpp',
+    'BufferInfoMapperMetadata.cpp',
+)
diff --git a/build_deploy.sh b/build_deploy.sh
deleted file mode 100755
index ef25e5c..0000000
--- a/build_deploy.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/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 && adb shell start vendor.hwcomposer-2-1 || true
-adb shell stop vendor.hwcomposer-2-2 && adb shell start vendor.hwcomposer-2-2 || true
-adb shell stop vendor.hwcomposer-2-3 && adb shell start vendor.hwcomposer-2-3 || true
-adb shell stop vendor.hwcomposer-2-4 && adb shell start 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/DrmKmsPlan.h b/compositor/DrmKmsPlan.h
index 91f636e..054cd93 100644
--- a/compositor/DrmKmsPlan.h
+++ b/compositor/DrmKmsPlan.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_KMS_PLAN_H_
-#define ANDROID_DRM_KMS_PLAN_H_
+#pragma once
 
 #include <memory>
 #include <vector>
@@ -41,4 +40,3 @@
 };
 
 }  // namespace android
-#endif
diff --git a/compositor/FlatteningController.cpp b/compositor/FlatteningController.cpp
new file mode 100644
index 0000000..257f8a0
--- /dev/null
+++ b/compositor/FlatteningController.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+/*
+ * Usually, display controllers do not use intermediate buffer for composition
+ * results. Instead, they scan-out directly from the input buffers, composing
+ * the planes on the fly every VSYNC.
+ *
+ * Flattening is a technique that reduces memory bandwidth and power consumption
+ * by converting non-updating multi-plane composition into a single-plane.
+ * Additionally, flattening also makes more shared planes available for use by
+ * other CRTCs.
+ *
+ * If the client is not updating layers for 1 second, FlatCon triggers a
+ * callback to refresh the screen. The compositor should mark all layers to be
+ * composed by the client into a single framebuffer using GPU.
+ */
+
+#define LOG_TAG "hwc-flatcon"
+
+#include "FlatteningController.h"
+
+#include "utils/log.h"
+
+namespace android {
+
+auto FlatteningController::CreateInstance(FlatConCallbacks &cbks)
+    -> std::shared_ptr<FlatteningController> {
+  auto fc = std::shared_ptr<FlatteningController>(new FlatteningController());
+
+  fc->cbks_ = cbks;
+
+  std::thread(&FlatteningController::ThreadFn, fc).detach();
+
+  return fc;
+}
+
+/* Compositor should call this every frame */
+bool FlatteningController::NewFrame() {
+  bool wake_it = false;
+  auto lock = std::lock_guard<std::mutex>(mutex_);
+
+  if (flatten_next_frame_) {
+    flatten_next_frame_ = false;
+    return true;
+  }
+
+  sleep_until_ = std::chrono::system_clock::now() + kTimeout;
+  if (disabled_) {
+    wake_it = true;
+    disabled_ = false;
+  }
+
+  if (wake_it)
+    cv_.notify_all();
+
+  return false;
+}
+
+void FlatteningController::ThreadFn(
+    const std::shared_ptr<FlatteningController> &fc) {
+  for (;;) {
+    std::unique_lock<std::mutex> lock(fc->mutex_);
+    if (fc.use_count() == 1 || !fc->cbks_.trigger)
+      break;
+
+    if (fc->sleep_until_ <= std::chrono::system_clock::now() &&
+        !fc->disabled_) {
+      fc->disabled_ = true;
+      fc->flatten_next_frame_ = true;
+      ALOGV("Timeout. Sending an event to compositor");
+      fc->cbks_.trigger();
+    }
+
+    if (fc->disabled_) {
+      ALOGV("Wait");
+      fc->cv_.wait(lock);
+    } else {
+      ALOGV("Wait_until");
+      fc->cv_.wait_until(lock, fc->sleep_until_);
+    }
+  }
+}
+
+}  // namespace android
diff --git a/compositor/FlatteningController.h b/compositor/FlatteningController.h
new file mode 100644
index 0000000..2be6ce4
--- /dev/null
+++ b/compositor/FlatteningController.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <condition_variable>
+#include <functional>
+#include <thread>
+
+namespace android {
+
+// NOLINTNEXTLINE(misc-unused-using-decls): False positive
+using std::chrono_literals::operator""s;
+
+struct FlatConCallbacks {
+  std::function<void()> trigger;
+};
+
+class FlatteningController {
+ public:
+  static auto CreateInstance(FlatConCallbacks &cbks)
+      -> std::shared_ptr<FlatteningController>;
+
+  void Disable() {
+    auto lock = std::lock_guard<std::mutex>(mutex_);
+    flatten_next_frame_ = false;
+    disabled_ = true;
+  }
+
+  /* Compositor should call this every frame */
+  bool NewFrame();
+
+  auto ShouldFlatten() const {
+    return flatten_next_frame_;
+  }
+
+  void StopThread() {
+    auto lock = std::lock_guard<std::mutex>(mutex_);
+    cbks_ = {};
+    cv_.notify_all();
+  }
+
+  static constexpr auto kTimeout = 1s;
+
+ private:
+  FlatteningController() = default;
+  static void ThreadFn(const std::shared_ptr<FlatteningController> &fc);
+
+  bool flatten_next_frame_{};
+  bool disabled_{};
+  decltype(std::chrono::system_clock::now()) sleep_until_{};
+  std::mutex mutex_;
+  std::condition_variable cv_;
+  FlatConCallbacks cbks_;
+};
+
+}  // namespace android
diff --git a/compositor/LayerData.h b/compositor/LayerData.h
index d04514d..8f4b7aa 100644
--- a/compositor/LayerData.h
+++ b/compositor/LayerData.h
@@ -27,7 +27,7 @@
 
 #include "bufferinfo/BufferInfo.h"
 #include "drm/DrmFbImporter.h"
-#include "utils/UniqueFd.h"
+#include "utils/fd.h"
 
 namespace android {
 
@@ -49,33 +49,24 @@
   hwc_rect_t display_frame{};
 
   bool RequireScalingOrPhasing() const {
-    float src_width = source_crop.right - source_crop.left;
-    float src_height = source_crop.bottom - source_crop.top;
+    const float src_width = source_crop.right - source_crop.left;
+    const float src_height = source_crop.bottom - source_crop.top;
 
     auto dest_width = float(display_frame.right - display_frame.left);
     auto dest_height = float(display_frame.bottom - display_frame.top);
 
-    bool scaling = src_width != dest_width || src_height != dest_height;
-    bool phasing = (source_crop.left - std::floor(source_crop.left) != 0) ||
+    auto scaling = src_width != dest_width || src_height != dest_height;
+    auto phasing = (source_crop.left - std::floor(source_crop.left) != 0) ||
                    (source_crop.top - std::floor(source_crop.top) != 0);
     return scaling || phasing;
   }
 };
 
 struct LayerData {
-  auto Clone() {
-    LayerData clonned;
-    clonned.bi = bi;
-    clonned.fb = fb;
-    clonned.pi = pi;
-    clonned.acquire_fence = std::move(acquire_fence);
-    return clonned;
-  }
-
   std::optional<BufferInfo> bi;
   std::shared_ptr<DrmFbIdHandle> fb;
   PresentInfo pi;
-  UniqueFd acquire_fence;
+  SharedFd acquire_fence;
 };
 
 }  // namespace android
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
index 5d2eebd..4ff16e2 100644
--- a/drm/DrmAtomicStateManager.cpp
+++ b/drm/DrmAtomicStateManager.cpp
@@ -22,17 +22,10 @@
 #include "DrmAtomicStateManager.h"
 
 #include <drm/drm_mode.h>
-#include <pthread.h>
-#include <sched.h>
 #include <sync/sync.h>
 #include <utils/Trace.h>
 
-#include <array>
 #include <cassert>
-#include <cstdlib>
-#include <ctime>
-#include <sstream>
-#include <vector>
 
 #include "drm/DrmCrtc.h"
 #include "drm/DrmDevice.h"
@@ -42,8 +35,20 @@
 
 namespace android {
 
+auto DrmAtomicStateManager::CreateInstance(DrmDisplayPipeline *pipe)
+    -> std::shared_ptr<DrmAtomicStateManager> {
+  auto dasm = std::shared_ptr<DrmAtomicStateManager>(
+      new DrmAtomicStateManager());
+
+  dasm->pipe_ = pipe;
+  std::thread(&DrmAtomicStateManager::ThreadFn, dasm.get(), dasm).detach();
+
+  return dasm;
+}
+
 // NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
 auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
+  // NOLINTNEXTLINE(misc-const-correctness)
   ATRACE_CALL();
 
   if (args.active && *args.active == active_frame_state_.crtc_active_state) {
@@ -102,6 +107,20 @@
     }
   }
 
+  if (args.color_matrix && crtc->GetCtmProperty()) {
+    auto blob = drm->RegisterUserPropertyBlob(args.color_matrix.get(),
+                                              sizeof(drm_color_ctm));
+    new_frame_state.ctm_blob = std::move(blob);
+
+    if (!new_frame_state.ctm_blob) {
+      ALOGE("Failed to create CTM blob");
+      return -EINVAL;
+    }
+
+    if (!crtc->GetCtmProperty().AtomicSet(*pset, *new_frame_state.ctm_blob))
+      return -EINVAL;
+  }
+
   auto unused_planes = new_frame_state.used_planes;
 
   if (args.composition) {
@@ -136,18 +155,19 @@
   uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
 
   if (args.test_only) {
-    return drmModeAtomicCommit(drm->GetFd(), pset.get(),
+    return drmModeAtomicCommit(*drm->GetFd(), pset.get(),
                                flags | DRM_MODE_ATOMIC_TEST_ONLY, drm);
   }
 
   if (last_present_fence_) {
+    // NOLINTNEXTLINE(misc-const-correctness)
     ATRACE_NAME("WaitPriorFramePresented");
 
     constexpr int kTimeoutMs = 500;
-    int err = sync_wait(last_present_fence_.Get(), kTimeoutMs);
+    const int err = sync_wait(*last_present_fence_, kTimeoutMs);
     if (err != 0) {
-      ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)",
-            last_present_fence_.Get(), err, errno);
+      ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)", *last_present_fence_,
+            err, errno);
     }
 
     CleanupPriorFrameResources();
@@ -157,99 +177,86 @@
     flags |= DRM_MODE_ATOMIC_NONBLOCK;
   }
 
-  int err = drmModeAtomicCommit(drm->GetFd(), pset.get(), flags, drm);
+  auto err = drmModeAtomicCommit(*drm->GetFd(), pset.get(), flags, drm);
 
   if (err != 0) {
     ALOGE("Failed to commit pset ret=%d\n", err);
     return err;
   }
 
+  args.out_fence = MakeSharedFd(out_fence);
+
   if (nonblock) {
-    last_present_fence_ = UniqueFd::Dup(out_fence);
-    staged_frame_state_ = std::move(new_frame_state);
-    frames_staged_++;
-    ptt_->Notify();
+    {
+      const std::unique_lock lock(mutex_);
+      last_present_fence_ = args.out_fence;
+      staged_frame_state_ = std::move(new_frame_state);
+      frames_staged_++;
+    }
+    cv_.notify_all();
   } else {
     active_frame_state_ = std::move(new_frame_state);
   }
 
-  if (args.display_mode) {
-    /* TODO(nobody): we still need this for synthetic vsync, remove after
-     * vsync reworked */
-    connector->SetActiveMode(*args.display_mode);
-  }
-
-  args.out_fence = UniqueFd(out_fence);
-
   return 0;
 }
 
-PresentTrackerThread::PresentTrackerThread(DrmAtomicStateManager *st_man)
-    : st_man_(st_man),
-      mutex_(&st_man_->pipe_->device->GetResMan().GetMainLock()) {
-  pt_ = std::thread(&PresentTrackerThread::PresentTrackerThreadFn, this);
-}
-
-PresentTrackerThread::~PresentTrackerThread() {
-  ALOGI("PresentTrackerThread successfully destroyed");
-}
-
-void PresentTrackerThread::PresentTrackerThreadFn() {
-  /* object should be destroyed on thread exit */
-  auto self = std::unique_ptr<PresentTrackerThread>(this);
-
+void DrmAtomicStateManager::ThreadFn(
+    const std::shared_ptr<DrmAtomicStateManager> &dasm) {
   int tracking_at_the_moment = -1;
+  auto &main_mutex = pipe_->device->GetResMan().GetMainLock();
 
   for (;;) {
-    UniqueFd present_fence;
+    SharedFd present_fence;
 
     {
-      std::unique_lock lk(*mutex_);
-      cv_.wait(lk, [&] {
-        return st_man_ == nullptr ||
-               st_man_->frames_staged_ > tracking_at_the_moment;
-      });
+      std::unique_lock lk(mutex_);
+      cv_.wait(lk);
 
-      if (st_man_ == nullptr) {
+      if (exit_thread_ || dasm.use_count() == 1)
         break;
-      }
 
-      tracking_at_the_moment = st_man_->frames_staged_;
-
-      present_fence = UniqueFd::Dup(st_man_->last_present_fence_.Get());
-      if (!present_fence) {
+      if (frames_staged_ <= tracking_at_the_moment)
         continue;
-      }
+
+      tracking_at_the_moment = frames_staged_;
+
+      present_fence = last_present_fence_;
+      if (!present_fence)
+        continue;
     }
 
     {
+      // NOLINTNEXTLINE(misc-const-correctness)
       ATRACE_NAME("AsyncWaitForBuffersSwap");
       constexpr int kTimeoutMs = 500;
-      int err = sync_wait(present_fence.Get(), kTimeoutMs);
+      auto err = sync_wait(*present_fence, kTimeoutMs);
       if (err != 0) {
-        ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)", present_fence.Get(),
-              err, errno);
+        ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)", *present_fence, err,
+              errno);
       }
     }
 
     {
-      std::unique_lock lk(*mutex_);
-      if (st_man_ == nullptr) {
+      const std::unique_lock mlk(main_mutex);
+      const std::unique_lock lk(mutex_);
+      if (exit_thread_)
         break;
-      }
 
       /* If resources is already cleaned-up by main thread, skip */
-      if (tracking_at_the_moment > st_man_->frames_tracked_) {
-        st_man_->CleanupPriorFrameResources();
-      }
+      if (tracking_at_the_moment > frames_tracked_)
+        CleanupPriorFrameResources();
     }
   }
+
+  ALOGI("DrmAtomicStateManager thread exit");
 }
 
 void DrmAtomicStateManager::CleanupPriorFrameResources() {
   assert(frames_staged_ - frames_tracked_ == 1);
   assert(last_present_fence_);
 
+  // NOLINTNEXTLINE(misc-const-correctness)
   ATRACE_NAME("CleanupPriorFrameResources");
   frames_tracked_++;
   active_frame_state_ = std::move(staged_frame_state_);
@@ -257,7 +264,7 @@
 }
 
 auto DrmAtomicStateManager::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int {
-  int err = CommitFrame(args);
+  auto err = CommitFrame(args);
 
   if (!args.test_only) {
     if (err != 0) {
@@ -279,11 +286,11 @@
 }  // namespace android
 
 auto DrmAtomicStateManager::ActivateDisplayUsingDPMS() -> int {
-  return drmModeConnectorSetProperty(pipe_->device->GetFd(),
+  return drmModeConnectorSetProperty(*pipe_->device->GetFd(),
                                      pipe_->connector->Get()->GetId(),
                                      pipe_->connector->Get()
                                          ->GetDpmsProperty()
-                                         .id(),
+                                         .GetId(),
                                      DRM_MODE_DPMS_ON);
 }
 
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
index b0b85ac..6e32a37 100644
--- a/drm/DrmAtomicStateManager.h
+++ b/drm/DrmAtomicStateManager.h
@@ -14,16 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_ATOMIC_STATE_MANAGER_H_
-#define ANDROID_DRM_ATOMIC_STATE_MANAGER_H_
+#pragma once
 
 #include <pthread.h>
 
-#include <functional>
 #include <memory>
 #include <optional>
-#include <sstream>
-#include <tuple>
 
 #include "compositor/DrmKmsPlan.h"
 #include "compositor/LayerData.h"
@@ -39,9 +35,10 @@
   std::optional<DrmMode> display_mode;
   std::optional<bool> active;
   std::shared_ptr<DrmKmsPlan> composition;
+  std::shared_ptr<drm_color_ctm> color_matrix;
 
   /* out */
-  UniqueFd out_fence;
+  SharedFd out_fence;
 
   /* helpers */
   auto HasInputs() -> bool {
@@ -49,50 +46,26 @@
   }
 };
 
-class PresentTrackerThread {
- public:
-  explicit PresentTrackerThread(DrmAtomicStateManager *st_man);
-
-  ~PresentTrackerThread();
-
-  void Stop() {
-    /* Exit thread by signalling that object is no longer valid */
-    st_man_ = nullptr;
-    Notify();
-    pt_.detach();
-  }
-
-  void Notify() {
-    cv_.notify_all();
-  }
-
- private:
-  DrmAtomicStateManager *st_man_{};
-
-  void PresentTrackerThreadFn();
-
-  std::condition_variable cv_;
-  std::thread pt_;
-  std::mutex *mutex_;
-};
-
 class DrmAtomicStateManager {
-  friend class PresentTrackerThread;
-
  public:
-  explicit DrmAtomicStateManager(DrmDisplayPipeline *pipe)
-      : pipe_(pipe),
-        ptt_(std::make_unique<PresentTrackerThread>(this).release()){};
+  static auto CreateInstance(DrmDisplayPipeline *pipe)
+      -> std::shared_ptr<DrmAtomicStateManager>;
 
-  DrmAtomicStateManager(const DrmAtomicStateManager &) = delete;
-  ~DrmAtomicStateManager() {
-    ptt_->Stop();
-  }
+  ~DrmAtomicStateManager() = default;
 
   auto ExecuteAtomicCommit(AtomicCommitArgs &args) -> int;
   auto ActivateDisplayUsingDPMS() -> int;
 
+  void StopThread() {
+    {
+      const std::unique_lock lock(mutex_);
+      exit_thread_ = true;
+    }
+    cv_.notify_all();
+  }
+
  private:
+  DrmAtomicStateManager() = default;
   auto CommitFrame(AtomicCommitArgs &args) -> int;
 
   struct KmsState {
@@ -103,6 +76,7 @@
     std::vector<std::shared_ptr<DrmFbIdHandle>> used_framebuffers;
 
     DrmModeUserPropertyBlobUnique mode_blob;
+    DrmModeUserPropertyBlobUnique ctm_blob;
 
     int release_fence_pt_index{};
 
@@ -118,18 +92,19 @@
     };
   }
 
-  DrmDisplayPipeline *const pipe_;
+  DrmDisplayPipeline *pipe_{};
 
   void CleanupPriorFrameResources();
 
-  /* Present (swap) tracking */
-  PresentTrackerThread *ptt_;
   KmsState staged_frame_state_;
-  UniqueFd last_present_fence_;
+  SharedFd last_present_fence_;
   int frames_staged_{};
   int frames_tracked_{};
+
+  void ThreadFn(const std::shared_ptr<DrmAtomicStateManager> &dasm);
+  std::condition_variable cv_;
+  std::mutex mutex_;
+  bool exit_thread_{};
 };
 
 }  // namespace android
-
-#endif  // ANDROID_DRM_DISPLAY_COMPOSITOR_H_
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 4737316..f625563 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -63,7 +63,7 @@
 auto DrmConnector::CreateInstance(DrmDevice &dev, uint32_t connector_id,
                                   uint32_t index)
     -> std::unique_ptr<DrmConnector> {
-  auto conn = MakeDrmModeConnectorUnique(dev.GetFd(), connector_id);
+  auto conn = MakeDrmModeConnectorUnique(*dev.GetFd(), connector_id);
   if (!conn) {
     ALOGE("Failed to get connector %d", connector_id);
     return {};
@@ -99,18 +99,17 @@
 }
 
 auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
-  uint64_t blob_id = 0;
-  int ret = UpdateEdidProperty();
+  auto ret = UpdateEdidProperty();
   if (ret != 0) {
     return {};
   }
 
-  std::tie(ret, blob_id) = GetEdidProperty().value();
-  if (ret != 0) {
+  auto blob_id = GetEdidProperty().GetValue();
+  if (!blob_id) {
     return {};
   }
 
-  return MakeDrmModePropertyBlobUnique(drm_->GetFd(), blob_id);
+  return MakeDrmModePropertyBlobUnique(*drm_->GetFd(), *blob_id);
 }
 
 bool DrmConnector::IsInternal() const {
@@ -159,7 +158,7 @@
 }
 
 int DrmConnector::UpdateModes() {
-  auto conn = MakeDrmModeConnectorUnique(drm_->GetFd(), GetId());
+  auto conn = MakeDrmModeConnectorUnique(*drm_->GetFd(), GetId());
   if (!conn) {
     ALOGE("Failed to get connector %d", GetId());
     return -ENODEV;
@@ -177,15 +176,11 @@
     }
 
     if (!exists) {
-      modes_.emplace_back(DrmMode(&connector_->modes[i]));
+      modes_.emplace_back(&connector_->modes[i]);
     }
   }
 
   return 0;
 }
 
-void DrmConnector::SetActiveMode(DrmMode &mode) {
-  active_mode_ = mode;
-}
-
 }  // namespace android
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index 629b3cc..f21f598 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_CONNECTOR_H_
-#define ANDROID_DRM_CONNECTOR_H_
+#pragma once
 
 #include <xf86drmMode.h>
 
@@ -83,12 +82,6 @@
     return modes_;
   }
 
-  auto &GetActiveMode() const {
-    return active_mode_;
-  }
-
-  void SetActiveMode(DrmMode &mode);
-
   auto &GetDpmsProperty() const {
     return dpms_property_;
   }
@@ -124,7 +117,6 @@
 
   const uint32_t index_in_res_array_;
 
-  DrmMode active_mode_;
   std::vector<DrmMode> modes_;
 
   DrmProperty dpms_property_;
@@ -135,5 +127,3 @@
   DrmProperty writeback_out_fence_;
 };
 }  // namespace android
-
-#endif  // ANDROID_DRM_PLANE_H_
diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp
index b54f14b..948a9ac 100644
--- a/drm/DrmCrtc.cpp
+++ b/drm/DrmCrtc.cpp
@@ -35,7 +35,7 @@
 
 auto DrmCrtc::CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
     -> std::unique_ptr<DrmCrtc> {
-  auto crtc = MakeDrmModeCrtcUnique(dev.GetFd(), crtc_id);
+  auto crtc = MakeDrmModeCrtcUnique(*dev.GetFd(), crtc_id);
   if (!crtc) {
     ALOGE("Failed to get CRTC %d", crtc_id);
     return {};
@@ -61,6 +61,11 @@
     return {};
   }
 
+  ret = GetCrtcProperty(dev, *c, "CTM", &c->ctm_property_);
+  if (ret != 0) {
+    ALOGV("Missing optional CTM property");
+  }
+
   return c;
 }
 
diff --git a/drm/DrmCrtc.h b/drm/DrmCrtc.h
index ebf0a97..96443cd 100644
--- a/drm/DrmCrtc.h
+++ b/drm/DrmCrtc.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_CRTC_H_
-#define ANDROID_DRM_CRTC_H_
+#pragma once
 
 #include <xf86drmMode.h>
 
@@ -59,6 +58,10 @@
     return out_fence_ptr_property_;
   }
 
+  auto &GetCtmProperty() const {
+    return ctm_property_;
+  }
+
  private:
   DrmCrtc(DrmModeCrtcUnique crtc, uint32_t index)
       : crtc_(std::move(crtc)), index_in_res_array_(index){};
@@ -67,10 +70,10 @@
 
   const uint32_t index_in_res_array_;
 
+  DrmProperty ctm_property_;
+
   DrmProperty active_property_;
   DrmProperty mode_property_;
   DrmProperty out_fence_ptr_property_;
 };
 }  // namespace android
-
-#endif  // ANDROID_DRM_CRTC_H_
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index 0f73f1f..1d6b62e 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -55,46 +55,46 @@
 
 auto DrmDevice::Init(const char *path) -> int {
   /* TODO: Use drmOpenControl here instead */
-  fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
+  fd_ = MakeSharedFd(open(path, O_RDWR | O_CLOEXEC));
   if (!fd_) {
     // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
     ALOGE("Failed to open dri %s: %s", path, strerror(errno));
     return -ENODEV;
   }
 
-  int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+  int ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
   if (ret != 0) {
     ALOGE("Failed to set universal plane cap %d", ret);
     return ret;
   }
 
-  ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
+  ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
   if (ret != 0) {
     ALOGE("Failed to set atomic cap %d", ret);
     return ret;
   }
 
 #ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
-  ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
+  ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
   if (ret != 0) {
     ALOGI("Failed to set writeback cap %d", ret);
   }
 #endif
 
   uint64_t cap_value = 0;
-  if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
+  if (drmGetCap(*GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
     ALOGW("drmGetCap failed. Fallback to no modifier support.");
     cap_value = 0;
   }
   HasAddFb2ModifiersSupport_ = cap_value != 0;
 
-  drmSetMaster(GetFd());
-  if (drmIsMaster(GetFd()) == 0) {
+  drmSetMaster(*GetFd());
+  if (drmIsMaster(*GetFd()) == 0) {
     ALOGE("DRM/KMS master access required");
     return -EACCES;
   }
 
-  auto res = MakeDrmModeResUnique(GetFd());
+  auto res = MakeDrmModeResUnique(*GetFd());
   if (!res) {
     ALOGE("Failed to get DrmDevice resources");
     return -ENODEV;
@@ -136,7 +136,7 @@
     }
   }
 
-  auto plane_res = MakeDrmModePlaneResUnique(GetFd());
+  auto plane_res = MakeDrmModePlaneResUnique(*GetFd());
   if (!plane_res) {
     ALOGE("Failed to get plane resources");
     return -ENOENT;
@@ -161,7 +161,7 @@
   // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
   create_blob.data = (__u64)data;
 
-  int ret = drmIoctl(GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
+  auto ret = drmIoctl(*GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
   if (ret != 0) {
     ALOGE("Failed to create mode property blob %d", ret);
     return {};
@@ -171,8 +171,8 @@
       new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
         struct drm_mode_destroy_blob destroy_blob {};
         destroy_blob.blob_id = (__u32)*it;
-        int err = drmIoctl(GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
-                           &destroy_blob);
+        auto err = drmIoctl(*GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
+                            &destroy_blob);
         if (err != 0) {
           ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
                 err);
@@ -186,7 +186,7 @@
                            const char *prop_name, DrmProperty *property) const {
   drmModeObjectPropertiesPtr props = nullptr;
 
-  props = drmModeObjectGetProperties(GetFd(), obj_id, obj_type);
+  props = drmModeObjectGetProperties(*GetFd(), obj_id, obj_type);
   if (props == nullptr) {
     ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
     return -ENODEV;
@@ -195,7 +195,7 @@
   bool found = false;
   for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-    drmModePropertyPtr p = drmModeGetProperty(GetFd(), props->props[i]);
+    drmModePropertyPtr p = drmModeGetProperty(*GetFd(), props->props[i]);
     if (strcmp(p->name, prop_name) == 0) {
       // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
       property->Init(obj_id, p, props->prop_values[i]);
@@ -209,9 +209,9 @@
 }
 
 std::string DrmDevice::GetName() const {
-  auto *ver = drmGetVersion(GetFd());
+  auto *ver = drmGetVersion(*GetFd());
   if (ver == nullptr) {
-    ALOGW("Failed to get drm version for fd=%d", GetFd());
+    ALOGW("Failed to get drm version for fd=%d", *GetFd());
     return "generic";
   }
 
@@ -221,17 +221,17 @@
 }
 
 auto DrmDevice::IsKMSDev(const char *path) -> bool {
-  auto fd = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
+  auto fd = MakeUniqueFd(open(path, O_RDWR | O_CLOEXEC));
   if (!fd) {
     return false;
   }
 
-  auto res = MakeDrmModeResUnique(fd.Get());
+  auto res = MakeDrmModeResUnique(*fd);
   if (!res) {
     return false;
   }
 
-  bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
+  auto is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
                 res->count_encoders > 0;
 
   return is_kms;
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index 4cf0132..39d0c88 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_H_
-#define ANDROID_DRM_H_
+#pragma once
 
 #include <cstdint>
 #include <map>
@@ -24,8 +23,7 @@
 #include "DrmConnector.h"
 #include "DrmCrtc.h"
 #include "DrmEncoder.h"
-#include "DrmFbImporter.h"
-#include "utils/UniqueFd.h"
+#include "utils/fd.h"
 
 namespace android {
 
@@ -40,8 +38,8 @@
   static auto CreateInstance(std::string const &path, ResourceManager *res_man)
       -> std::unique_ptr<DrmDevice>;
 
-  auto GetFd() const {
-    return fd_.Get();
+  auto &GetFd() const {
+    return fd_;
   }
 
   auto &GetResMan() {
@@ -103,7 +101,7 @@
 
   static auto IsKMSDev(const char *path) -> bool;
 
-  UniqueFd fd_;
+  SharedFd fd_;
 
   std::vector<std::unique_ptr<DrmConnector>> connectors_;
   std::vector<std::unique_ptr<DrmConnector>> writeback_connectors_;
@@ -121,5 +119,3 @@
   ResourceManager *const res_man_;
 };
 }  // namespace android
-
-#endif  // ANDROID_DRM_H_
diff --git a/drm/DrmDisplayPipeline.cpp b/drm/DrmDisplayPipeline.cpp
index e81544d..1a8ad5b 100644
--- a/drm/DrmDisplayPipeline.cpp
+++ b/drm/DrmDisplayPipeline.cpp
@@ -98,7 +98,7 @@
     return {};
   }
 
-  pipe->atomic_state_manager = std::make_unique<DrmAtomicStateManager>(
+  pipe->atomic_state_manager = DrmAtomicStateManager::CreateInstance(
       pipe.get());
 
   return pipe;
@@ -171,9 +171,9 @@
   std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> planes;
   planes.emplace_back(primary_plane);
 
-  static bool use_overlay_planes = ReadUseOverlayProperty();
+  const static bool kUseOverlayPlanes = ReadUseOverlayProperty();
 
-  if (use_overlay_planes) {
+  if (kUseOverlayPlanes) {
     for (const auto &plane : device->GetPlanes()) {
       if (plane->IsCrtcSupported(*crtc->Get())) {
         if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
@@ -189,4 +189,9 @@
   return planes;
 }
 
+DrmDisplayPipeline::~DrmDisplayPipeline() {
+  if (atomic_state_manager)
+    atomic_state_manager->StopThread();
+}
+
 }  // namespace android
diff --git a/drm/DrmDisplayPipeline.h b/drm/DrmDisplayPipeline.h
index 7ec619e..cf64a36 100644
--- a/drm/DrmDisplayPipeline.h
+++ b/drm/DrmDisplayPipeline.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRMDISPLAYPIPELINE_H_
-#define ANDROID_DRMDISPLAYPIPELINE_H_
+#pragma once
 
 #include <memory>
 #include <vector>
@@ -75,6 +74,8 @@
   auto GetUsablePlanes()
       -> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>>;
 
+  ~DrmDisplayPipeline();
+
   DrmDevice *device;
 
   std::shared_ptr<BindingOwner<DrmConnector>> connector;
@@ -82,9 +83,7 @@
   std::shared_ptr<BindingOwner<DrmCrtc>> crtc;
   std::shared_ptr<BindingOwner<DrmPlane>> primary_plane;
 
-  std::unique_ptr<DrmAtomicStateManager> atomic_state_manager;
+  std::shared_ptr<DrmAtomicStateManager> atomic_state_manager;
 };
 
 }  // namespace android
-
-#endif
diff --git a/drm/DrmEncoder.cpp b/drm/DrmEncoder.cpp
index eed5b5f..21ca693 100644
--- a/drm/DrmEncoder.cpp
+++ b/drm/DrmEncoder.cpp
@@ -29,7 +29,7 @@
 
 auto DrmEncoder::CreateInstance(DrmDevice &dev, uint32_t encoder_id,
                                 uint32_t index) -> std::unique_ptr<DrmEncoder> {
-  auto e = MakeDrmModeEncoderUnique(dev.GetFd(), encoder_id);
+  auto e = MakeDrmModeEncoderUnique(*dev.GetFd(), encoder_id);
   if (!e) {
     ALOGE("Failed to get encoder %d", encoder_id);
     return {};
diff --git a/drm/DrmEncoder.h b/drm/DrmEncoder.h
index 39a695c..89e664c 100644
--- a/drm/DrmEncoder.h
+++ b/drm/DrmEncoder.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_ENCODER_H_
-#define ANDROID_DRM_ENCODER_H_
+#pragma once
 
 #include <xf86drmMode.h>
 
@@ -65,5 +64,3 @@
   const uint32_t index_in_res_array_;
 };
 }  // namespace android
-
-#endif  // ANDROID_DRM_ENCODER_H_
diff --git a/drm/DrmFbImporter.cpp b/drm/DrmFbImporter.cpp
index 585b789..a91a52b 100644
--- a/drm/DrmFbImporter.cpp
+++ b/drm/DrmFbImporter.cpp
@@ -37,6 +37,7 @@
 auto DrmFbIdHandle::CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
                                    DrmDevice &drm)
     -> std::shared_ptr<DrmFbIdHandle> {
+  // NOLINTNEXTLINE(misc-const-correctness)
   ATRACE_NAME("Import dmabufs and register FB");
 
   // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): priv. constructor usage
@@ -49,7 +50,7 @@
   for (size_t i = 1; i < local->gem_handles_.size(); i++) {
     if (bo->prime_fds[i] > 0) {
       if (bo->prime_fds[i] != bo->prime_fds[0]) {
-        err = drmPrimeFDToHandle(drm.GetFd(), bo->prime_fds[i],
+        err = drmPrimeFDToHandle(*drm.GetFd(), bo->prime_fds[i],
                                  &local->gem_handles_.at(i));
         if (err != 0) {
           ALOGE("failed to import prime fd %d errno=%d", bo->prime_fds[i],
@@ -61,7 +62,7 @@
     }
   }
 
-  bool has_modifiers = bo->modifiers[0] != DRM_FORMAT_MOD_NONE &&
+  auto has_modifiers = bo->modifiers[0] != DRM_FORMAT_MOD_NONE &&
                        bo->modifiers[0] != DRM_FORMAT_MOD_INVALID;
 
   if (!drm.HasAddFb2ModifiersSupport() && has_modifiers) {
@@ -73,11 +74,11 @@
 
   /* Create framebuffer object */
   if (!has_modifiers) {
-    err = drmModeAddFB2(drm.GetFd(), bo->width, bo->height, bo->format,
+    err = drmModeAddFB2(*drm.GetFd(), bo->width, bo->height, bo->format,
                         local->gem_handles_.data(), &bo->pitches[0],
                         &bo->offsets[0], &local->fb_id_, 0);
   } else {
-    err = drmModeAddFB2WithModifiers(drm.GetFd(), bo->width, bo->height,
+    err = drmModeAddFB2WithModifiers(*drm.GetFd(), bo->width, bo->height,
                                      bo->format, local->gem_handles_.data(),
                                      &bo->pitches[0], &bo->offsets[0],
                                      &bo->modifiers[0], &local->fb_id_,
@@ -92,10 +93,11 @@
 }
 
 DrmFbIdHandle::~DrmFbIdHandle() {
+  // NOLINTNEXTLINE(misc-const-correctness)
   ATRACE_NAME("Close FB and dmabufs");
 
   /* Destroy framebuffer object */
-  if (drmModeRmFB(drm_->GetFd(), fb_id_) != 0) {
+  if (drmModeRmFB(*drm_->GetFd(), fb_id_) != 0) {
     ALOGE("Failed to rm fb");
   }
 
@@ -116,7 +118,7 @@
       continue;
     }
     gem_close.handle = gem_handles_[i];
-    int32_t err = drmIoctl(drm_->GetFd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
+    auto err = drmIoctl(*drm_->GetFd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
     if (err != 0) {
       ALOGE("Failed to close gem handle %d, errno: %d", gem_handles_[i], errno);
     }
@@ -127,8 +129,8 @@
     -> std::shared_ptr<DrmFbIdHandle> {
   /* Lookup DrmFbIdHandle in cache first. First handle serves as a cache key. */
   GemHandle first_handle = 0;
-  int32_t err = drmPrimeFDToHandle(drm_->GetFd(), bo->prime_fds[0],
-                                   &first_handle);
+  auto err = drmPrimeFDToHandle(*drm_->GetFd(), bo->prime_fds[0],
+                                &first_handle);
 
   if (err != 0) {
     ALOGE("Failed to import prime fd %d ret=%d", bo->prime_fds[0], err);
diff --git a/drm/DrmFbImporter.h b/drm/DrmFbImporter.h
index 9e94238..9a7c335 100644
--- a/drm/DrmFbImporter.h
+++ b/drm/DrmFbImporter.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef DRM_DRMFBIMPORTER_H_
-#define DRM_DRMFBIMPORTER_H_
+#pragma once
 
 #include <drm/drm_fourcc.h>
 #include <hardware/gralloc.h>
@@ -87,5 +86,3 @@
 };
 
 }  // namespace android
-
-#endif
diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp
index 010ea1b..7cbea44 100644
--- a/drm/DrmMode.cpp
+++ b/drm/DrmMode.cpp
@@ -22,119 +22,22 @@
 
 namespace android {
 
-DrmMode::DrmMode(drmModeModeInfoPtr m)
-    : clock_(m->clock),
-      h_display_(m->hdisplay),
-      h_sync_start_(m->hsync_start),
-      h_sync_end_(m->hsync_end),
-      h_total_(m->htotal),
-      h_skew_(m->hskew),
-      v_display_(m->vdisplay),
-      v_sync_start_(m->vsync_start),
-      v_sync_end_(m->vsync_end),
-      v_total_(m->vtotal),
-      v_scan_(m->vscan),
-      v_refresh_(m->vrefresh),
-      flags_(m->flags),
-      type_(m->type),
-      name_(m->name) {
-}
+DrmMode::DrmMode(drmModeModeInfoPtr m) : mode_(*m){};
 
 bool DrmMode::operator==(const drmModeModeInfo &m) const {
-  return clock_ == m.clock && h_display_ == m.hdisplay &&
-         h_sync_start_ == m.hsync_start && h_sync_end_ == m.hsync_end &&
-         h_total_ == m.htotal && h_skew_ == m.hskew &&
-         v_display_ == m.vdisplay && v_sync_start_ == m.vsync_start &&
-         v_sync_end_ == m.vsync_end && v_total_ == m.vtotal &&
-         v_scan_ == m.vscan && flags_ == m.flags && type_ == m.type;
-}
-
-uint32_t DrmMode::clock() const {
-  return clock_;
-}
-
-uint16_t DrmMode::h_display() const {
-  return h_display_;
-}
-
-uint16_t DrmMode::h_sync_start() const {
-  return h_sync_start_;
-}
-
-uint16_t DrmMode::h_sync_end() const {
-  return h_sync_end_;
-}
-
-uint16_t DrmMode::h_total() const {
-  return h_total_;
-}
-
-uint16_t DrmMode::h_skew() const {
-  return h_skew_;
-}
-
-uint16_t DrmMode::v_display() const {
-  return v_display_;
-}
-
-uint16_t DrmMode::v_sync_start() const {
-  return v_sync_start_;
-}
-
-uint16_t DrmMode::v_sync_end() const {
-  return v_sync_end_;
-}
-
-uint16_t DrmMode::v_total() const {
-  return v_total_;
-}
-
-uint16_t DrmMode::v_scan() const {
-  return v_scan_;
-}
-
-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;
-}
-
-uint32_t DrmMode::flags() const {
-  return flags_;
-}
-
-uint32_t DrmMode::type() const {
-  return type_;
-}
-
-std::string DrmMode::name() const {
-  return name_ + "@" + std::to_string(v_refresh());
+  return memcmp(&m, &mode_, offsetof(drmModeModeInfo, name)) == 0;
 }
 
 auto DrmMode::CreateModeBlob(const DrmDevice &drm)
     -> DrmModeUserPropertyBlobUnique {
-  struct drm_mode_modeinfo drm_mode = {
-      .clock = clock_,
-      .hdisplay = h_display_,
-      .hsync_start = h_sync_start_,
-      .hsync_end = h_sync_end_,
-      .htotal = h_total_,
-      .hskew = h_skew_,
-      .vdisplay = v_display_,
-      .vsync_start = v_sync_start_,
-      .vsync_end = v_sync_end_,
-      .vtotal = v_total_,
-      .vscan = v_scan_,
-      .vrefresh = v_refresh_,
-      .flags = flags_,
-      .type = type_,
-  };
-  strncpy(drm_mode.name, name_.c_str(), DRM_DISPLAY_MODE_LEN);
+  struct drm_mode_modeinfo drm_mode = {};
+  /* drm_mode_modeinfo and drmModeModeInfo should be identical
+   * At least libdrm does the same memcpy in drmModeAttachMode();
+   */
+  memcpy(&drm_mode, &mode_, sizeof(struct drm_mode_modeinfo));
 
   return drm.RegisterUserPropertyBlob(&drm_mode,
-                                       sizeof(struct drm_mode_modeinfo));
+                                      sizeof(struct drm_mode_modeinfo));
 }
 
 }  // namespace android
diff --git a/drm/DrmMode.h b/drm/DrmMode.h
index 20515f9..c5790a5 100644
--- a/drm/DrmMode.h
+++ b/drm/DrmMode.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_MODE_H_
-#define ANDROID_DRM_MODE_H_
+#pragma once
 
 #include <xf86drmMode.h>
 
@@ -36,49 +35,26 @@
 
   bool operator==(const drmModeModeInfo &m) const;
 
-  uint32_t clock() const;
+  auto &GetRawMode() const {
+    return mode_;
+  }
 
-  uint16_t h_display() const;
-  uint16_t h_sync_start() const;
-  uint16_t h_sync_end() const;
-  uint16_t h_total() const;
-  uint16_t h_skew() const;
+  auto GetVRefresh() const {
+    if (mode_.clock == 0) {
+      return float(mode_.vrefresh);
+    }
+    // Always recalculate refresh to report correct float rate
+    return static_cast<float>(mode_.clock) /
+           (float)(mode_.vtotal * mode_.htotal) * 1000.0F;
+  }
 
-  uint16_t v_display() const;
-  uint16_t v_sync_start() const;
-  uint16_t v_sync_end() const;
-  uint16_t v_total() const;
-  uint16_t v_scan() const;
-  float v_refresh() const;
-
-  uint32_t flags() const;
-  uint32_t type() const;
-
-  std::string name() const;
+  auto GetName() const {
+    return std::string(mode_.name) + "@" + std::to_string(GetVRefresh());
+  }
 
   auto CreateModeBlob(const DrmDevice &drm) -> DrmModeUserPropertyBlobUnique;
 
  private:
-  uint32_t clock_ = 0;
-
-  uint16_t h_display_ = 0;
-  uint16_t h_sync_start_ = 0;
-  uint16_t h_sync_end_ = 0;
-  uint16_t h_total_ = 0;
-  uint16_t h_skew_ = 0;
-
-  uint16_t v_display_ = 0;
-  uint16_t v_sync_start_ = 0;
-  uint16_t v_sync_end_ = 0;
-  uint16_t v_total_ = 0;
-  uint16_t v_scan_ = 0;
-  uint16_t v_refresh_ = 0;
-
-  uint32_t flags_ = 0;
-  uint32_t type_ = 0;
-
-  std::string name_;
+  drmModeModeInfo mode_;
 };
 }  // namespace android
-
-#endif  // ANDROID_DRM_MODE_H_
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index 5051d35..228e3dd 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -31,7 +31,7 @@
 
 auto DrmPlane::CreateInstance(DrmDevice &dev, uint32_t plane_id)
     -> std::unique_ptr<DrmPlane> {
-  auto p = MakeDrmModePlaneUnique(dev.GetFd(), plane_id);
+  auto p = MakeDrmModePlaneUnique(*dev.GetFd(), plane_id);
   if (!p) {
     ALOGE("Failed to get plane %d", plane_id);
     return {};
@@ -57,21 +57,19 @@
     return -ENOTSUP;
   }
 
-  int ret = 0;
-  uint64_t type = 0;
-  std::tie(ret, type) = p.value();
-  if (ret != 0) {
+  auto type = p.GetValue();
+  if (!type) {
     ALOGE("Failed to get plane type property value");
-    return ret;
+    return -EINVAL;
   }
-  switch (type) {
+  switch (*type) {
     case DRM_PLANE_TYPE_OVERLAY:
     case DRM_PLANE_TYPE_PRIMARY:
     case DRM_PLANE_TYPE_CURSOR:
-      type_ = (uint32_t)type;
+      type_ = (uint32_t)*type;
       break;
     default:
-      ALOGE("Invalid plane type %" PRIu64, type);
+      ALOGE("Invalid plane type %" PRIu64, *type);
       return -EINVAL;
   }
 
@@ -148,9 +146,10 @@
 }
 
 bool DrmPlane::IsCrtcSupported(const DrmCrtc &crtc) const {
-  unsigned int crtc_property_value = 0;
-  std::tie(std::ignore, crtc_property_value) = crtc_property_.value();
-  if (crtc_property_value != 0 && crtc_property_value != crtc.GetId() &&
+  auto crtc_prop_optval = crtc_property_.GetValue();
+  auto crtc_prop_val = crtc_prop_optval ? *crtc_prop_optval : 0;
+
+  if (crtc_prop_val != 0 && crtc_prop_val != crtc.GetId() &&
       GetType() == DRM_PLANE_TYPE_PRIMARY) {
     // Some DRM driver such as omap_drm allows sharing primary plane between
     // CRTCs, but the primay plane could not be shared if it has been used by
@@ -158,10 +157,9 @@
     // in the kernel drivers/gpu/drm/drm_atomic.c file.
     // The current drm_hwc design is not ready to support such scenario yet,
     // so adding the CRTC status check here to workaorund for now.
-    ALOGW(
-        "%s: This Plane(id=%d) is activated for Crtc(id=%d), could not be used "
-        "for Crtc (id=%d)",
-        __FUNCTION__, GetId(), crtc_property_value, crtc.GetId());
+    ALOGW("%s: This Plane(id=%d) is activated for Crtc(id=%" PRIu64
+          "), could not be used for Crtc (id=%d)",
+          __FUNCTION__, GetId(), crtc_prop_val, crtc.GetId());
     return false;
   }
 
@@ -169,6 +167,11 @@
 }
 
 bool DrmPlane::IsValidForLayer(LayerData *layer) {
+  if (layer == nullptr || !layer->bi) {
+    ALOGE("%s: Invalid parameters", __func__);
+    return false;
+  }
+
   if (!rotation_property_) {
     if (layer->pi.transform != LayerTransform::kIdentity) {
       ALOGV("No rotation property on plane %d", GetId());
@@ -181,7 +184,7 @@
     }
   }
 
-  if (alpha_property_.id() == 0 && layer->pi.alpha != UINT16_MAX) {
+  if (!alpha_property_ && layer->pi.alpha != UINT16_MAX) {
     ALOGV("Alpha is not supported on plane %d", GetId());
     return false;
   }
@@ -193,7 +196,7 @@
     return false;
   }
 
-  uint32_t format = layer->bi->format;
+  auto format = layer->bi->format;
   if (!IsFormatSupported(format)) {
     ALOGV("Plane %d does not supports %c%c%c%c format", GetId(), format,
           format >> 8, format >> 16, format >> 24);
@@ -241,16 +244,16 @@
 
 auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, LayerData &layer,
                               uint32_t zpos, uint32_t crtc_id) -> int {
-  if (!layer.fb) {
-    ALOGE("Expected a valid framebuffer for pset");
+  if (!layer.fb || !layer.bi) {
+    ALOGE("%s: Invalid arguments", __func__);
     return -EINVAL;
   }
 
-  if (zpos_property_ && !zpos_property_.is_immutable()) {
+  if (zpos_property_ && !zpos_property_.IsImmutable()) {
     uint64_t min_zpos = 0;
 
     // Ignore ret and use min_zpos as 0 by default
-    std::tie(std::ignore, min_zpos) = zpos_property_.range_min();
+    std::tie(std::ignore, min_zpos) = zpos_property_.RangeMin();
 
     if (!zpos_property_.AtomicSet(pset, zpos + min_zpos)) {
       return -EINVAL;
@@ -258,7 +261,7 @@
   }
 
   if (layer.acquire_fence &&
-      !in_fence_fd_property_.AtomicSet(pset, layer.acquire_fence.Get())) {
+      !in_fence_fd_property_.AtomicSet(pset, *layer.acquire_fence)) {
     return -EINVAL;
   }
 
@@ -317,8 +320,8 @@
 
 auto DrmPlane::GetPlaneProperty(const char *prop_name, DrmProperty &property,
                                 Presence presence) -> bool {
-  int err = drm_->GetProperty(GetId(), DRM_MODE_OBJECT_PLANE, prop_name,
-                              &property);
+  auto err = drm_->GetProperty(GetId(), DRM_MODE_OBJECT_PLANE, prop_name,
+                               &property);
   if (err != 0) {
     if (presence == Presence::kMandatory) {
       ALOGE("Could not get mandatory property \"%s\" from plane %d", prop_name,
diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h
index 31f0a33..c26a3cc 100644
--- a/drm/DrmPlane.h
+++ b/drm/DrmPlane.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_PLANE_H_
-#define ANDROID_DRM_PLANE_H_
+#pragma once
 
 #include <xf86drmMode.h>
 
@@ -100,5 +99,3 @@
   std::map<LayerTransform, uint64_t> transform_enum_map_;
 };
 }  // namespace android
-
-#endif  // ANDROID_DRM_PLANE_H_
diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp
index 32f1c62..938b3ad 100644
--- a/drm/DrmProperty.cpp
+++ b/drm/DrmProperty.cpp
@@ -31,7 +31,7 @@
 namespace android {
 
 DrmProperty::DrmPropertyEnum::DrmPropertyEnum(drm_mode_property_enum *e)
-    : value_(e->value), name_(e->name) {
+    : value(e->value), name(e->name) {
 }
 
 DrmProperty::DrmProperty(uint32_t obj_id, drmModePropertyPtr p,
@@ -47,70 +47,43 @@
   value_ = value;
 
   for (int i = 0; i < p->count_values; ++i)
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
     values_.emplace_back(p->values[i]);
 
   for (int i = 0; i < p->count_enums; ++i)
-    enums_.emplace_back(DrmPropertyEnum(&p->enums[i]));
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
+    enums_.emplace_back(&p->enums[i]);
 
   for (int i = 0; i < p->count_blobs; ++i)
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
     blob_ids_.emplace_back(p->blob_ids[i]);
-
-  if (flags_ & DRM_MODE_PROP_RANGE)
-    type_ = DRM_PROPERTY_TYPE_INT;
-  else if (flags_ & DRM_MODE_PROP_ENUM)
-    type_ = DRM_PROPERTY_TYPE_ENUM;
-  else if (flags_ & DRM_MODE_PROP_OBJECT)
-    type_ = DRM_PROPERTY_TYPE_OBJECT;
-  else if (flags_ & DRM_MODE_PROP_BLOB)
-    type_ = DRM_PROPERTY_TYPE_BLOB;
-  else if (flags_ & DRM_MODE_PROP_BITMASK)
-    type_ = DRM_PROPERTY_TYPE_BITMASK;
 }
 
-uint32_t DrmProperty::id() const {
-  return id_;
-}
-
-std::string DrmProperty::name() const {
-  return name_;
-}
-
-std::tuple<int, uint64_t> DrmProperty::value() const {
-  if (type_ == DRM_PROPERTY_TYPE_BLOB)
-    return std::make_tuple(0, value_);
+std::optional<uint64_t> DrmProperty::GetValue() const {
+  if ((flags_ & DRM_MODE_PROP_BLOB) != 0)
+    return value_;
 
   if (values_.empty())
-    return std::make_tuple(-ENOENT, 0);
+    return {};
 
-  switch (type_) {
-    case DRM_PROPERTY_TYPE_INT:
-      return std::make_tuple(0, value_);
+  if ((flags_ & DRM_MODE_PROP_RANGE) != 0)
+    return value_;
 
-    case DRM_PROPERTY_TYPE_ENUM:
-      if (value_ >= enums_.size())
-        return std::make_tuple(-ENOENT, 0);
+  if ((flags_ & DRM_MODE_PROP_ENUM) != 0) {
+    if (value_ >= enums_.size())
+      return {};
 
-      return std::make_tuple(0, enums_[value_].value_);
-
-    case DRM_PROPERTY_TYPE_OBJECT:
-      return std::make_tuple(0, value_);
-
-    case DRM_PROPERTY_TYPE_BITMASK:
-    default:
-      return std::make_tuple(-EINVAL, 0);
+    return enums_[value_].value;
   }
+
+  if ((flags_ & DRM_MODE_PROP_OBJECT) != 0)
+    return value_;
+
+  return {};
 }
 
-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())
+std::tuple<int, uint64_t> DrmProperty::RangeMin() const {
+  if (!IsRange())
     return std::make_tuple(-EINVAL, 0);
   if (values_.empty())
     return std::make_tuple(-ENOENT, 0);
@@ -118,8 +91,8 @@
   return std::make_tuple(0, values_[0]);
 }
 
-std::tuple<int, uint64_t> DrmProperty::range_max() const {
-  if (!is_range())
+std::tuple<int, uint64_t> DrmProperty::RangeMax() const {
+  if (!IsRange())
     return std::make_tuple(-EINVAL, 0);
   if (values_.size() < 2)
     return std::make_tuple(-ENOENT, 0);
@@ -130,8 +103,8 @@
 std::tuple<uint64_t, int> DrmProperty::GetEnumValueWithName(
     const std::string &name) const {
   for (const auto &it : enums_) {
-    if (it.name_ == name) {
-      return std::make_tuple(it.value_, 0);
+    if (it.name == name) {
+      return std::make_tuple(it.value, 0);
     }
   }
 
diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h
index 26a7c38..516518b 100644
--- a/drm/DrmProperty.h
+++ b/drm/DrmProperty.h
@@ -14,27 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_PROPERTY_H_
-#define ANDROID_DRM_PROPERTY_H_
+#pragma once
 
 #include <xf86drmMode.h>
 
 #include <cstdint>
 #include <map>
+#include <optional>
 #include <string>
 #include <vector>
 
 namespace android {
 
-enum DrmPropertyType {
-  DRM_PROPERTY_TYPE_INT,
-  DRM_PROPERTY_TYPE_ENUM,
-  DRM_PROPERTY_TYPE_OBJECT,
-  DRM_PROPERTY_TYPE_BLOB,
-  DRM_PROPERTY_TYPE_BITMASK,
-  DRM_PROPERTY_TYPE_INVALID,
-};
-
 class DrmProperty {
  public:
   DrmProperty() = default;
@@ -45,15 +36,26 @@
   auto Init(uint32_t obj_id, drmModePropertyPtr p, uint64_t value) -> void;
   std::tuple<uint64_t, int> GetEnumValueWithName(const std::string &name) const;
 
-  uint32_t id() const;
-  std::string name() const;
+  auto GetId() const {
+    return id_;
+  }
 
-  std::tuple<int, uint64_t> value() const;
-  bool is_immutable() const;
+  auto GetName() const {
+    return name_;
+  }
 
-  bool is_range() const;
-  std::tuple<int, uint64_t> range_min() const;
-  std::tuple<int, uint64_t> range_max() const;
+  auto GetValue() const -> std::optional<uint64_t>;
+
+  bool IsImmutable() const {
+    return id_ != 0 && (flags_ & DRM_MODE_PROP_IMMUTABLE) != 0;
+  }
+
+  bool IsRange() const {
+    return id_ != 0 && (flags_ & DRM_MODE_PROP_RANGE) != 0;
+  }
+
+  auto RangeMin() const -> std::tuple<int, uint64_t>;
+  auto RangeMax() const -> std::tuple<int, uint64_t>;
 
   [[nodiscard]] auto AtomicSet(drmModeAtomicReq &pset, uint64_t value) const
       -> bool;
@@ -72,14 +74,13 @@
     explicit DrmPropertyEnum(drm_mode_property_enum *e);
     ~DrmPropertyEnum() = default;
 
-    uint64_t value_;
-    std::string name_;
+    uint64_t value;
+    std::string name;
   };
 
   uint32_t obj_id_ = 0;
   uint32_t id_ = 0;
 
-  DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID;
   uint32_t flags_ = 0;
   std::string name_;
   uint64_t value_ = 0;
@@ -104,5 +105,3 @@
 }
 
 }  // namespace android
-
-#endif  // ANDROID_DRM_PROPERTY_H_
diff --git a/drm/DrmUnique.h b/drm/DrmUnique.h
index 282528b..2be1eb9 100644
--- a/drm/DrmUnique.h
+++ b/drm/DrmUnique.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef DRM_UNIQUE_H_
-#define DRM_UNIQUE_H_
+#pragma once
 
 #include <xf86drmMode.h>
 
@@ -83,5 +82,3 @@
   return DrmModeResUnique(drmModeGetResources(fd),
                           [](drmModeRes *it) { drmModeFreeResources(it); });
 }
-
-#endif
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index dbf0993..577d86c 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -36,13 +36,7 @@
 ResourceManager::ResourceManager(
     PipelineToFrontendBindingInterface *p2f_bind_interface)
     : frontend_interface_(p2f_bind_interface) {
-  if (uevent_listener_.Init() != 0) {
-    ALOGE("Can't initialize event listener");
-  }
-}
-
-ResourceManager::~ResourceManager() {
-  uevent_listener_.Exit();
+  uevent_listener_ = UEventListener::CreateInstance();
 }
 
 void ResourceManager::Init() {
@@ -54,8 +48,8 @@
   char path_pattern[PROPERTY_VALUE_MAX];
   // Could be a valid path or it can have at the end of it the wildcard %
   // which means that it will try open all devices until an error is met.
-  int path_len = property_get("vendor.hwc.drm.device", path_pattern,
-                              "/dev/dri/card%");
+  auto path_len = property_get("vendor.hwc.drm.device", path_pattern,
+                               "/dev/dri/card%");
   if (path_pattern[path_len - 1] != '%') {
     auto dev = DrmDevice::CreateInstance(path_pattern, this);
     if (dev) {
@@ -78,17 +72,29 @@
     }
   }
 
-  char scale_with_gpu[PROPERTY_VALUE_MAX];
-  property_get("vendor.hwc.drm.scale_with_gpu", scale_with_gpu, "0");
-  scale_with_gpu_ = bool(strncmp(scale_with_gpu, "0", 1));
+  char proptext[PROPERTY_VALUE_MAX];
+  property_get("vendor.hwc.drm.scale_with_gpu", proptext, "0");
+  scale_with_gpu_ = bool(strncmp(proptext, "0", 1));
+
+  constexpr char kDrmOrGpu[] = "DRM_OR_GPU";
+  constexpr char kDrmOrIgnore[] = "DRM_OR_IGNORE";
+  property_get("vendor.hwc.drm.ctm", proptext, kDrmOrGpu);
+  if (strncmp(proptext, kDrmOrGpu, sizeof(kDrmOrGpu)) == 0) {
+    ctm_handling_ = CtmHandling::kDrmOrGpu;
+  } else if (strncmp(proptext, kDrmOrIgnore, sizeof(kDrmOrIgnore)) == 0) {
+    ctm_handling_ = CtmHandling::kDrmOrIgnore;
+  } else {
+    ALOGE("Invalid value for vendor.hwc.drm.ctm: %s", proptext);
+    ctm_handling_ = CtmHandling::kDrmOrGpu;
+  }
 
   if (BufferInfoGetter::GetInstance() == nullptr) {
     ALOGE("Failed to initialize BufferInfoGetter");
     return;
   }
 
-  uevent_listener_.RegisterHotplugHandler([this] {
-    const std::lock_guard<std::mutex> lock(GetMainLock());
+  uevent_listener_->RegisterHotplugHandler([this] {
+    const std::unique_lock lock(GetMainLock());
     UpdateFrontendDisplays();
   });
 
@@ -103,7 +109,7 @@
     return;
   }
 
-  uevent_listener_.RegisterHotplugHandler([] {});
+  uevent_listener_->RegisterHotplugHandler({});
 
   DetachAllFrontendDisplays();
   drms_.clear();
@@ -123,8 +129,8 @@
 
   for (auto *conn : ordered_connectors) {
     conn->UpdateModes();
-    bool connected = conn->IsConnected();
-    bool attached = attached_pipelines_.count(conn) != 0;
+    auto connected = conn->IsConnected();
+    auto attached = attached_pipelines_.count(conn) != 0;
 
     if (connected != attached) {
       ALOGI("%s connector %s", connected ? "Attaching" : "Detaching",
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 144d00e..7fa3fc6 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef RESOURCEMANAGER_H
-#define RESOURCEMANAGER_H
+#pragma once
 
 #include <cstring>
+#include <mutex>
 
 #include "DrmDevice.h"
 #include "DrmDisplayPipeline.h"
@@ -26,6 +26,11 @@
 
 namespace android {
 
+enum class CtmHandling {
+  kDrmOrGpu,    /* Handled by DRM is possible, otherwise by GPU */
+  kDrmOrIgnore, /* Handled by DRM is possible, otherwise displayed as is */
+};
+
 class PipelineToFrontendBindingInterface {
  public:
   virtual ~PipelineToFrontendBindingInterface() = default;
@@ -42,7 +47,7 @@
   ResourceManager &operator=(const ResourceManager &) = delete;
   ResourceManager(const ResourceManager &&) = delete;
   ResourceManager &&operator=(const ResourceManager &&) = delete;
-  ~ResourceManager();
+  ~ResourceManager() = default;
 
   void Init();
 
@@ -52,6 +57,10 @@
     return scale_with_gpu_;
   }
 
+  auto &GetCtmHandling() const {
+    return ctm_handling_;
+  }
+
   auto &GetMainLock() {
     return main_lock_;
   }
@@ -65,11 +74,13 @@
 
   std::vector<std::unique_ptr<DrmDevice>> drms_;
 
+  // Android properties:
   bool scale_with_gpu_{};
+  CtmHandling ctm_handling_{};
 
-  UEventListener uevent_listener_;
+  std::shared_ptr<UEventListener> uevent_listener_;
 
-  std::mutex main_lock_;
+  std::recursive_mutex main_lock_;
 
   std::map<DrmConnector *, std::unique_ptr<DrmDisplayPipeline>>
       attached_pipelines_;
@@ -79,5 +90,3 @@
   bool initialized_{};
 };
 }  // namespace android
-
-#endif  // RESOURCEMANAGER_H
diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp
index b56b8e1..a05ec65 100644
--- a/drm/UEventListener.cpp
+++ b/drm/UEventListener.cpp
@@ -18,37 +18,37 @@
 
 #include "UEventListener.h"
 
-#include <cerrno>
+#include <thread>
 
 #include "utils/log.h"
 
-/* Originally defined in system/core/libsystem/include/system/graphics.h as
- * #define HAL_PRIORITY_URGENT_DISPLAY (-8)*/
-constexpr int kHalPriorityUrgentDisplay = -8;
-
 namespace android {
 
-UEventListener::UEventListener()
-    : Worker("uevent-listener", kHalPriorityUrgentDisplay){};
+auto UEventListener::CreateInstance() -> std::shared_ptr<UEventListener> {
+  auto uel = std::shared_ptr<UEventListener>(new UEventListener());
 
-int UEventListener::Init() {
-  uevent_ = UEvent::CreateInstance();
-  if (!uevent_) {
-    return -ENODEV;
-  }
+  uel->uevent_ = UEvent::CreateInstance();
+  if (!uel->uevent_)
+    return {};
 
-  return InitWorker();
+  std::thread(&UEventListener::ThreadFn, uel.get(), uel).detach();
+
+  return uel;
 }
 
-void UEventListener::Routine() {
+void UEventListener::ThreadFn(const std::shared_ptr<UEventListener> &uel) {
+  // TODO(nobody): Rework code to allow stopping the thread (low priority)
   while (true) {
-    auto uevent_str = uevent_->ReadNext();
+    if (uel.use_count() == 1)
+      break;
+
+    auto uevent_str = uel->uevent_->ReadNext();
 
     if (!hotplug_handler_ || !uevent_str)
       continue;
 
-    bool drm_event = uevent_str->find("DEVTYPE=drm_minor") != std::string::npos;
-    bool hotplug_event = uevent_str->find("HOTPLUG=1") != std::string::npos;
+    auto drm_event = uevent_str->find("DEVTYPE=drm_minor") != std::string::npos;
+    auto hotplug_event = uevent_str->find("HOTPLUG=1") != std::string::npos;
 
     if (drm_event && hotplug_event) {
       constexpr useconds_t kDelayAfterUeventUs = 200000;
@@ -58,5 +58,7 @@
       hotplug_handler_();
     }
   }
+
+  ALOGI("UEvent thread exit");
 }
 }  // namespace android
diff --git a/drm/UEventListener.h b/drm/UEventListener.h
index c8b8582..4f2be7c 100644
--- a/drm/UEventListener.h
+++ b/drm/UEventListener.h
@@ -14,35 +14,31 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UEVENT_LISTENER_H_
-#define ANDROID_UEVENT_LISTENER_H_
+#pragma once
 
 #include <functional>
 
 #include "utils/UEvent.h"
-#include "utils/Worker.h"
 
 namespace android {
 
-class UEventListener : public Worker {
+class UEventListener {
  public:
-  UEventListener();
-  ~UEventListener() override = default;
+  ~UEventListener() = default;
 
-  int Init();
+  static auto CreateInstance() -> std::shared_ptr<UEventListener>;
 
   void RegisterHotplugHandler(std::function<void()> hotplug_handler) {
     hotplug_handler_ = std::move(hotplug_handler);
   }
 
- protected:
-  void Routine() override;
-
  private:
+  UEventListener() = default;
+
+  void ThreadFn(const std::shared_ptr<UEventListener> &uel);
+
   std::unique_ptr<UEvent> uevent_;
 
   std::function<void()> hotplug_handler_;
 };
 }  // namespace android
-
-#endif
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index ed41189..8a251c7 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -25,28 +25,48 @@
 #include <cstring>
 #include <ctime>
 
+#include "drm/ResourceManager.h"
 #include "utils/log.h"
 
 namespace android {
 
-VSyncWorker::VSyncWorker() : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY){};
+auto VSyncWorker::CreateInstance(DrmDisplayPipeline *pipe,
+                                 VSyncWorkerCallbacks &callbacks)
+    -> std::shared_ptr<VSyncWorker> {
+  auto vsw = std::shared_ptr<VSyncWorker>(new VSyncWorker());
 
-auto VSyncWorker::Init(DrmDisplayPipeline *pipe,
-                       std::function<void(uint64_t /*timestamp*/)> callback)
-    -> int {
-  pipe_ = pipe;
-  callback_ = std::move(callback);
+  vsw->callbacks_ = callbacks;
 
-  return InitWorker();
+  if (pipe != nullptr) {
+    vsw->high_crtc_ = pipe->crtc->Get()->GetIndexInResArray()
+                      << DRM_VBLANK_HIGH_CRTC_SHIFT;
+    vsw->drm_fd_ = pipe->device->GetFd();
+  }
+
+  std::thread(&VSyncWorker::ThreadFn, vsw.get(), vsw).detach();
+
+  return vsw;
 }
 
 void VSyncWorker::VSyncControl(bool enabled) {
-  Lock();
-  enabled_ = enabled;
-  last_timestamp_ = -1;
-  Unlock();
+  {
+    const std::lock_guard<std::mutex> lock(mutex_);
+    enabled_ = enabled;
+    last_timestamp_ = -1;
+  }
 
-  Signal();
+  cv_.notify_all();
+}
+
+void VSyncWorker::StopThread() {
+  {
+    const std::lock_guard<std::mutex> lock(mutex_);
+    thread_exit_ = true;
+    enabled_ = false;
+    callbacks_ = {};
+  }
+
+  cv_.notify_all();
 }
 
 /*
@@ -73,82 +93,86 @@
 static const int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
 
 int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
+  auto time_now = ResourceManager::GetTimeMonotonicNs();
+
+  // Default to 60Hz refresh rate
+  constexpr uint32_t kDefaultVSPeriodNs = 16666666;
+  auto period_ns = kDefaultVSPeriodNs;
+  if (callbacks_.get_vperiod_ns && callbacks_.get_vperiod_ns() != 0)
+    period_ns = callbacks_.get_vperiod_ns();
+
+  auto phased_timestamp = GetPhasedVSync(period_ns, time_now);
   struct timespec vsync {};
-  int ret = clock_gettime(CLOCK_MONOTONIC, &vsync);
-  if (ret)
-    return ret;
-
-  float refresh = 60.0F;  // Default to 60Hz refresh rate
-  if (pipe_ != nullptr &&
-      pipe_->connector->Get()->GetActiveMode().v_refresh() != 0.0F) {
-    refresh = pipe_->connector->Get()->GetActiveMode().v_refresh();
-  }
-
-  int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs /
-                                                static_cast<int>(refresh),
-                                            vsync.tv_sec * kOneSecondNs +
-                                                vsync.tv_nsec);
-  vsync.tv_sec = phased_timestamp / kOneSecondNs;
+  vsync.tv_sec = int(phased_timestamp / kOneSecondNs);
   vsync.tv_nsec = int(phased_timestamp - (vsync.tv_sec * kOneSecondNs));
+
+  int ret = 0;
   do {
     ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, nullptr);
   } while (ret == EINTR);
-  if (ret)
+  if (ret != 0)
     return ret;
 
-  *timestamp = (int64_t)vsync.tv_sec * kOneSecondNs + (int64_t)vsync.tv_nsec;
+  *timestamp = phased_timestamp;
   return 0;
 }
 
-void VSyncWorker::Routine() {
+void VSyncWorker::ThreadFn(const std::shared_ptr<VSyncWorker> &vsw) {
   int ret = 0;
 
-  Lock();
-  if (!enabled_) {
-    ret = WaitForSignalOrExitLocked();
-    if (ret == -EINTR) {
-      Unlock();
-      return;
+  for (;;) {
+    {
+      std::unique_lock<std::mutex> lock(vsw->mutex_);
+      if (thread_exit_)
+        break;
+
+      if (!enabled_)
+        vsw->cv_.wait(lock);
+
+      if (!enabled_)
+        continue;
     }
+
+    ret = -EAGAIN;
+    int64_t timestamp = 0;
+    drmVBlank vblank{};
+
+    if (drm_fd_) {
+      vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
+                                               (high_crtc_ &
+                                                DRM_VBLANK_HIGH_CRTC_MASK));
+      vblank.request.sequence = 1;
+
+      ret = drmWaitVBlank(*drm_fd_, &vblank);
+      if (ret == -EINTR)
+        continue;
+    }
+
+    if (ret != 0) {
+      ret = SyntheticWaitVBlank(&timestamp);
+      if (ret != 0)
+        continue;
+    } else {
+      constexpr int kUsToNsMul = 1000;
+      timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs +
+                  (int64_t)vblank.reply.tval_usec * kUsToNsMul;
+    }
+
+    decltype(callbacks_.out_event) callback;
+
+    {
+      const std::lock_guard<std::mutex> lock(mutex_);
+      if (!enabled_)
+        continue;
+      callback = callbacks_.out_event;
+    }
+
+    if (callback)
+      callback(timestamp);
+
+    last_timestamp_ = timestamp;
   }
 
-  auto *pipe = pipe_;
-  Unlock();
-
-  ret = -EAGAIN;
-  int64_t timestamp = 0;
-  drmVBlank vblank{};
-
-  if (pipe != nullptr) {
-    uint32_t high_crtc = (pipe->crtc->Get()->GetIndexInResArray()
-                          << DRM_VBLANK_HIGH_CRTC_SHIFT);
-
-    vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
-                                             (high_crtc &
-                                              DRM_VBLANK_HIGH_CRTC_MASK));
-    vblank.request.sequence = 1;
-
-    ret = drmWaitVBlank(pipe->device->GetFd(), &vblank);
-    if (ret == -EINTR)
-      return;
-  }
-
-  if (ret) {
-    ret = SyntheticWaitVBlank(&timestamp);
-    if (ret)
-      return;
-  } else {
-    timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs +
-                (int64_t)vblank.reply.tval_usec * 1000;
-  }
-
-  if (!enabled_)
-    return;
-
-  if (callback_) {
-    callback_(timestamp);
-  }
-
-  last_timestamp_ = timestamp;
+  ALOGI("VSyncWorker thread exit");
 }
 }  // namespace android
diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h
index 1e6d39f..031a561 100644
--- a/drm/VSyncWorker.h
+++ b/drm/VSyncWorker.h
@@ -14,46 +14,53 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_EVENT_WORKER_H_
-#define ANDROID_EVENT_WORKER_H_
+#pragma once
 
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-#include <hardware/hwcomposer2.h>
-
-#include <atomic>
-#include <cstdint>
+#include <condition_variable>
 #include <functional>
 #include <map>
+#include <mutex>
+#include <thread>
 
 #include "DrmDevice.h"
-#include "utils/Worker.h"
 
 namespace android {
 
-class VSyncWorker : public Worker {
- public:
-  VSyncWorker();
-  ~VSyncWorker() override = default;
+struct VSyncWorkerCallbacks {
+  std::function<void(uint64_t /*timestamp*/)> out_event;
+  std::function<uint32_t()> get_vperiod_ns;
+};
 
-  auto Init(DrmDisplayPipeline *pipe,
-            std::function<void(uint64_t /*timestamp*/)> callback) -> int;
+class VSyncWorker {
+ public:
+  ~VSyncWorker() = default;
+
+  auto static CreateInstance(DrmDisplayPipeline *pipe,
+                             VSyncWorkerCallbacks &callbacks)
+      -> std::shared_ptr<VSyncWorker>;
 
   void VSyncControl(bool enabled);
-
- protected:
-  void Routine() override;
+  void StopThread();
 
  private:
+  VSyncWorker() = default;
+
+  void ThreadFn(const std::shared_ptr<VSyncWorker> &vsw);
+
   int64_t GetPhasedVSync(int64_t frame_ns, int64_t current) const;
   int SyntheticWaitVBlank(int64_t *timestamp);
 
-  std::function<void(uint64_t /*timestamp*/)> callback_;
+  VSyncWorkerCallbacks callbacks_;
 
-  DrmDisplayPipeline *pipe_ = nullptr;
-  std::atomic_bool enabled_ = false;
+  SharedFd drm_fd_;
+  uint32_t high_crtc_ = 0;
+
+  bool enabled_ = false;
+  bool thread_exit_ = false;
   int64_t last_timestamp_ = -1;
+
+  std::condition_variable cv_;
+  std::thread vswt_;
+  std::mutex mutex_;
 };
 }  // namespace android
-
-#endif
diff --git a/drm/meson.build b/drm/meson.build
new file mode 100644
index 0000000..7bef11a
--- /dev/null
+++ b/drm/meson.build
@@ -0,0 +1,15 @@
+src_common += files(
+    'DrmAtomicStateManager.cpp',
+    'DrmConnector.cpp',
+    'DrmCrtc.cpp',
+    'DrmDevice.cpp',
+    'DrmDisplayPipeline.cpp',
+    'DrmEncoder.cpp',
+    'DrmFbImporter.cpp',
+    'DrmMode.cpp',
+    'DrmPlane.cpp',
+    'DrmProperty.cpp',
+    'ResourceManager.cpp',
+    'UEventListener.cpp',
+    'VSyncWorker.cpp',
+)
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index 4accb07..64755c3 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -61,16 +61,9 @@
   const int kTimeForSFToDisposeDisplayUs = 200000;
   usleep(kTimeForSFToDisposeDisplayUs);
   mutex.lock();
-  std::vector<std::unique_ptr<HwcDisplay>> for_disposal;
   for (auto handle : displays_for_removal_list_) {
-    for_disposal.emplace_back(
-        std::unique_ptr<HwcDisplay>(displays_[handle].release()));
     displays_.erase(handle);
   }
-  /* Destroy HwcDisplays while unlocked to avoid vsyncworker deadlocks */
-  mutex.unlock();
-  for_disposal.clear();
-  mutex.lock();
 }
 
 bool DrmHwcTwo::BindDisplay(DrmDisplayPipeline *pipeline) {
@@ -180,10 +173,7 @@
         /* 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;
@@ -196,7 +186,7 @@
       vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data);
       break;
     }
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
     case HWC2::Callback::Vsync_2_4: {
       vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
       break;
@@ -214,24 +204,15 @@
 }
 
 void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
-                                         bool connected) {
-  auto &mutex = GetResMan().GetMainLock();
-  if (mutex.try_lock()) {
-    ALOGE("FIXME!!!: Main mutex must be locked in %s", __func__);
-    mutex.unlock();
-    return;
-  }
-
+                                         bool connected) const {
   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.
+    /* For some reason HWC Service will call HWC2 API in hotplug callback
+     * handler. This is the reason we're using recursive mutex.
      */
-    mutex.unlock();
     hc.first(hc.second, displayid,
              connected == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
                                              : HWC2_CONNECTION_DISCONNECTED);
-    mutex.lock();
   }
 }
 
@@ -239,7 +220,7 @@
     hwc2_display_t displayid, int64_t timestamp,
     [[maybe_unused]] uint32_t vsync_period) const {
   /* vsync callback */
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
   if (vsync_2_4_callback_.first != nullptr &&
       vsync_2_4_callback_.second != nullptr) {
     vsync_2_4_callback_.first(vsync_2_4_callback_.second, displayid, timestamp,
@@ -255,7 +236,7 @@
 void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient(
     [[maybe_unused]] hwc2_display_t displayid,
     [[maybe_unused]] int64_t timestamp) const {
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
   hwc_vsync_period_change_timeline_t timeline = {
       .newVsyncAppliedTimeNanos = timestamp,
       .refreshRequired = false,
diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h
index 2b8a74f..81c5155 100644
--- a/hwc2_device/DrmHwcTwo.h
+++ b/hwc2_device/DrmHwcTwo.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DRM_HWC_TWO_H_
-#define ANDROID_DRM_HWC_TWO_H_
+#pragma once
 
 #include <hardware/hwcomposer2.h>
 
@@ -31,7 +30,7 @@
 
   std::pair<HWC2_PFN_HOTPLUG, hwc2_callback_data_t> hotplug_callback_{};
   std::pair<HWC2_PFN_VSYNC, hwc2_callback_data_t> vsync_callback_{};
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
   std::pair<HWC2_PFN_VSYNC_2_4, hwc2_callback_data_t> vsync_2_4_callback_{};
   std::pair<HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED, hwc2_callback_data_t>
       period_timing_changed_callback_{};
@@ -72,7 +71,7 @@
                                                  int64_t timestamp) const;
 
  private:
-  void SendHotplugEventToClient(hwc2_display_t displayid, bool connected);
+  void SendHotplugEventToClient(hwc2_display_t displayid, bool connected) const;
 
   ResourceManager resource_manager_;
   std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_;
@@ -86,5 +85,3 @@
   uint32_t last_display_handle_ = kPrimaryDisplay;
 };
 }  // namespace android
-
-#endif
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index d968ab3..efd8c14 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -31,7 +31,7 @@
 std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
   if (delta.total_pixops_ == 0)
     return "No stats yet";
-  double ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
+  auto ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
 
   std::stringstream ss;
   ss << " Total frames count: " << delta.total_frames_ << "\n"
@@ -50,32 +50,12 @@
 }
 
 std::string HwcDisplay::Dump() {
-  std::string flattening_state_str;
-  switch (flattenning_state_) {
-    case ClientFlattenningState::Disabled:
-      flattening_state_str = "Disabled";
-      break;
-    case ClientFlattenningState::NotRequired:
-      flattening_state_str = "Not needed";
-      break;
-    case ClientFlattenningState::Flattened:
-      flattening_state_str = "Active";
-      break;
-    case ClientFlattenningState::ClientRefreshRequested:
-      flattening_state_str = "Refresh requested";
-      break;
-    default:
-      flattening_state_str = std::to_string(flattenning_state_) +
-                             " VSync remains";
-  }
-
-  std::string connector_name = IsInHeadlessMode()
-                                   ? "NULL-DISPLAY"
-                                   : GetPipe().connector->Get()->GetName();
+  auto connector_name = IsInHeadlessMode()
+                            ? std::string("NULL-DISPLAY")
+                            : GetPipe().connector->Get()->GetName();
 
   std::stringstream ss;
   ss << "- Display on: " << connector_name << "\n"
-     << "  Flattening state: " << flattening_state_str << "\n"
      << "Statistics since system boot:\n"
      << DumpDelta(total_stats_) << "\n\n"
      << "Statistics since last dumpsys request:\n"
@@ -87,17 +67,18 @@
 
 HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
                        DrmHwcTwo *hwc2)
-    : hwc2_(hwc2),
-      handle_(handle),
-      type_(type),
-      client_layer_(this),
-      color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
-  // clang-format off
-  color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0,
-                             0.0, 1.0, 0.0, 0.0,
-                             0.0, 0.0, 1.0, 0.0,
-                             0.0, 0.0, 0.0, 1.0};
-  // clang-format on
+    : hwc2_(hwc2), handle_(handle), type_(type), client_layer_(this){};
+
+void HwcDisplay::SetColorMarixToIdentity() {
+  color_matrix_ = std::make_shared<drm_color_ctm>();
+  for (int i = 0; i < kCtmCols; i++) {
+    for (int j = 0; j < kCtmRows; j++) {
+      constexpr uint64_t kOne = (1ULL << 32); /* 1.0 in s31.32 format */
+      color_matrix_->matrix[i * kCtmRows + j] = (i == j) ? kOne : 0;
+    }
+  }
+
+  color_transform_hint_ = HAL_COLOR_TRANSFORM_IDENTITY;
 }
 
 HwcDisplay::~HwcDisplay() = default;
@@ -137,9 +118,17 @@
     GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
 #endif
 
-    vsync_worker_.Init(nullptr, [](int64_t) {});
     current_plan_.reset();
     backend_.reset();
+    if (flatcon_) {
+      flatcon_->StopThread();
+      flatcon_.reset();
+    }
+  }
+
+  if (vsync_worker_) {
+    vsync_worker_->StopThread();
+    vsync_worker_ = {};
   }
 
   SetClientTarget(nullptr, -1, 0, {});
@@ -148,38 +137,54 @@
 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_) {
-      uint32_t period_ns{};
-      GetDisplayVsyncPeriod(&period_ns);
-      hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
-    }
-    if (vsync_flattening_en_) {
-      ProcessFlatenningVsyncInternal();
-    }
-    if (vsync_tracking_en_) {
-      last_vsync_ts_ = timestamp;
-    }
-    if (!vsync_event_en_ && !vsync_flattening_en_ && !vsync_tracking_en_) {
-      vsync_worker_.VSyncControl(false);
-    }
-  });
-  if (ret && ret != -EALREADY) {
-    ALOGE("Failed to create event worker for d=%d %d\n", int(handle_), ret);
+  auto vsw_callbacks = (VSyncWorkerCallbacks){
+      .out_event =
+          [this](int64_t timestamp) {
+            const std::unique_lock lock(hwc2_->GetResMan().GetMainLock());
+            if (vsync_event_en_) {
+              uint32_t period_ns{};
+              GetDisplayVsyncPeriod(&period_ns);
+              hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
+            }
+            if (vsync_tracking_en_) {
+              last_vsync_ts_ = timestamp;
+            }
+            if (!vsync_event_en_ && !vsync_tracking_en_) {
+              vsync_worker_->VSyncControl(false);
+            }
+          },
+      .get_vperiod_ns = [this]() -> uint32_t {
+        uint32_t outVsyncPeriod = 0;
+        GetDisplayVsyncPeriod(&outVsyncPeriod);
+        return outVsyncPeriod;
+      },
+  };
+
+  vsync_worker_ = VSyncWorker::CreateInstance(pipeline_, vsw_callbacks);
+  if (!vsync_worker_) {
+    ALOGE("Failed to create event worker for d=%d\n", int(handle_));
     return HWC2::Error::BadDisplay;
   }
 
   if (!IsInHeadlessMode()) {
-    ret = BackendManager::GetInstance().SetBackendForDisplay(this);
+    auto ret = BackendManager::GetInstance().SetBackendForDisplay(this);
     if (ret) {
       ALOGE("Failed to set backend for d=%d %d\n", int(handle_), ret);
       return HWC2::Error::BadDisplay;
     }
+    auto flatcbk = (struct FlatConCallbacks){.trigger = [this]() {
+      if (hwc2_->refresh_callback_.first != nullptr &&
+          hwc2_->refresh_callback_.second != nullptr)
+        hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second,
+                                       handle_);
+    }};
+    flatcon_ = FlatteningController::CreateInstance(flatcbk);
   }
 
   client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
 
+  SetColorMarixToIdentity();
+
   return HWC2::Error::None;
 }
 
@@ -236,7 +241,7 @@
   }
 
   uint32_t num_changes = 0;
-  for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
+  for (auto &l : layers_) {
     if (l.second.IsTypeChanged()) {
       if (layers && num_changes < *num_elements)
         layers[num_changes] = l.first;
@@ -257,8 +262,8 @@
     return HWC2::Error::None;
   }
 
-  std::pair<uint32_t, uint32_t> min = pipeline_->device->GetMinResolution();
-  std::pair<uint32_t, uint32_t> max = pipeline_->device->GetMaxResolution();
+  auto min = pipeline_->device->GetMinResolution();
+  auto max = pipeline_->device->GetMaxResolution();
 
   if (width < min.first || height < min.second)
     return HWC2::Error::Unsupported;
@@ -296,33 +301,33 @@
   auto &hwc_config = configs_.hwc_configs[conf];
 
   static const int32_t kUmPerInch = 25400;
-  uint32_t mm_width = configs_.mm_width;
-  uint32_t mm_height = configs_.mm_height;
+  auto mm_width = configs_.mm_width;
+  auto mm_height = configs_.mm_height;
   auto attribute = static_cast<HWC2::Attribute>(attribute_in);
   switch (attribute) {
     case HWC2::Attribute::Width:
-      *value = static_cast<int>(hwc_config.mode.h_display());
+      *value = static_cast<int>(hwc_config.mode.GetRawMode().hdisplay);
       break;
     case HWC2::Attribute::Height:
-      *value = static_cast<int>(hwc_config.mode.v_display());
+      *value = static_cast<int>(hwc_config.mode.GetRawMode().vdisplay);
       break;
     case HWC2::Attribute::VsyncPeriod:
       // in nanoseconds
-      *value = static_cast<int>(1E9 / hwc_config.mode.v_refresh());
+      *value = static_cast<int>(1E9 / hwc_config.mode.GetVRefresh());
       break;
     case HWC2::Attribute::DpiX:
       // Dots per 1000 inches
-      *value = mm_width ? static_cast<int>(hwc_config.mode.h_display() *
-                                           kUmPerInch / mm_width)
+      *value = mm_width ? int(hwc_config.mode.GetRawMode().hdisplay *
+                              kUmPerInch / mm_width)
                         : -1;
       break;
     case HWC2::Attribute::DpiY:
       // Dots per 1000 inches
-      *value = mm_height ? static_cast<int>(hwc_config.mode.v_display() *
-                                            kUmPerInch / mm_height)
+      *value = mm_height ? int(hwc_config.mode.GetRawMode().vdisplay *
+                               kUmPerInch / mm_height)
                          : -1;
       break;
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
     case HWC2::Attribute::ConfigGroup:
       /* Dispite ConfigGroup is a part of HWC2.4 API, framework
        * able to request it even if service @2.1 is used */
@@ -364,8 +369,8 @@
   } else {
     stream << "display-" << GetPipe().connector->Get()->GetId();
   }
-  std::string string = stream.str();
-  size_t length = string.length();
+  auto string = stream.str();
+  auto length = string.length();
   if (!name) {
     *size = length;
     return HWC2::Error::None;
@@ -437,7 +442,7 @@
     }
 
     layers[num_layers - 1] = l.first;
-    fences[num_layers - 1] = UniqueFd::Dup(present_fence_.Get()).Release();
+    fences[num_layers - 1] = DupFd(present_fence_);
   }
   *num_elements = num_layers;
 
@@ -450,8 +455,10 @@
     return HWC2::Error::None;
   }
 
-  int PrevModeVsyncPeriodNs = static_cast<int>(
-      1E9 / GetPipe().connector->Get()->GetActiveMode().v_refresh());
+  a_args.color_matrix = color_matrix_;
+
+  uint32_t prev_vperiod_ns = 0;
+  GetDisplayVsyncPeriod(&prev_vperiod_ns);
 
   auto mode_update_commited_ = false;
   if (staged_mode_ &&
@@ -459,8 +466,8 @@
     client_layer_.SetLayerDisplayFrame(
         (hwc_rect_t){.left = 0,
                      .top = 0,
-                     .right = static_cast<int>(staged_mode_->h_display()),
-                     .bottom = static_cast<int>(staged_mode_->v_display())});
+                     .right = int(staged_mode_->GetRawMode().hdisplay),
+                     .bottom = int(staged_mode_->GetRawMode().vdisplay)});
 
     configs_.active_config_id = staged_mode_config_id_;
 
@@ -477,7 +484,7 @@
   for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
     switch (l.second.GetValidatedType()) {
       case HWC2::Composition::Device:
-        z_map.emplace(std::make_pair(l.second.GetZOrder(), &l.second));
+        z_map.emplace(l.second.GetZOrder(), &l.second);
         break;
       case HWC2::Composition::Client:
         // Place it at the z_order of the lowest client layer
@@ -489,7 +496,7 @@
     }
   }
   if (use_client_layer)
-    z_map.emplace(std::make_pair(client_z_order, &client_layer_));
+    z_map.emplace(client_z_order, &client_layer_);
 
   if (z_map.empty())
     return HWC2::Error::BadLayer;
@@ -498,7 +505,7 @@
 
   /* Import & populate */
   for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
-    l.second->PopulateLayerData(a_args.test_only);
+    l.second->PopulateLayerData();
   }
 
   // now that they're ordered by z, add them to the composition
@@ -513,7 +520,7 @@
        */
       return HWC2::Error::BadLayer;
     }
-    composition_layers.emplace_back(l.second->GetLayerData().Clone());
+    composition_layers.emplace_back(l.second->GetLayerData());
   }
 
   /* Store plan to ensure shared planes won't be stolen by other display
@@ -530,7 +537,7 @@
 
   a_args.composition = current_plan_;
 
-  int ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+  auto ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
 
   if (ret) {
     if (!a_args.test_only)
@@ -542,8 +549,9 @@
     staged_mode_.reset();
     vsync_tracking_en_ = false;
     if (last_vsync_ts_ != 0) {
-      hwc2_->SendVsyncPeriodTimingChangedEventToClient(
-          handle_, last_vsync_ts_ + PrevModeVsyncPeriodNs);
+      hwc2_->SendVsyncPeriodTimingChangedEventToClient(handle_,
+                                                       last_vsync_ts_ +
+                                                           prev_vperiod_ns);
     }
   }
 
@@ -576,8 +584,11 @@
   if (ret != HWC2::Error::None)
     return ret;
 
-  this->present_fence_ = UniqueFd::Dup(a_args.out_fence.Get());
-  *out_present_fence = a_args.out_fence.Release();
+  this->present_fence_ = a_args.out_fence;
+  *out_present_fence = DupFd(a_args.out_fence);
+
+  // Reset the color matrix so we don't apply it over and over again.
+  color_matrix_ = {};
 
   ++frame_no_;
   return HWC2::Error::None;
@@ -625,17 +636,22 @@
     return HWC2::Error::None;
   }
 
-  client_layer_.PopulateLayerData(/*test = */ true);
+  client_layer_.PopulateLayerData();
   if (!client_layer_.IsLayerUsableAsDevice()) {
     ALOGE("Client layer must be always usable by DRM/KMS");
     return HWC2::Error::BadLayer;
   }
 
   auto &bi = client_layer_.GetLayerData().bi;
-  hwc_frect_t source_crop = {.left = 0.0F,
-                             .top = 0.0F,
-                             .right = static_cast<float>(bi->width),
-                             .bottom = static_cast<float>(bi->height)};
+  if (!bi) {
+    ALOGE("%s: Invalid state", __func__);
+    return HWC2::Error::BadLayer;
+  }
+
+  auto source_crop = (hwc_frect_t){.left = 0.0F,
+                                   .top = 0.0F,
+                                   .right = static_cast<float>(bi->width),
+                                   .bottom = static_cast<float>(bi->height)};
   client_layer_.SetLayerSourceCrop(source_crop);
 
   return HWC2::Error::None;
@@ -652,6 +668,8 @@
   return HWC2::Error::None;
 }
 
+#include <xf86drmMode.h>
+
 HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) {
   if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
       hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
@@ -661,12 +679,49 @@
     return HWC2::Error::BadParameter;
 
   color_transform_hint_ = static_cast<android_color_transform_t>(hint);
-  if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
-    std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin());
+
+  if (IsInHeadlessMode())
+    return HWC2::Error::None;
+
+  if (!GetPipe().crtc->Get()->GetCtmProperty())
+    return HWC2::Error::None;
+
+  switch (color_transform_hint_) {
+    case HAL_COLOR_TRANSFORM_IDENTITY:
+      SetColorMarixToIdentity();
+      break;
+    case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
+      color_matrix_ = std::make_shared<drm_color_ctm>();
+      /* DRM expects a 3x3 matrix, but the HAL provides a 4x4 matrix. */
+      for (int i = 0; i < kCtmCols; i++) {
+        for (int j = 0; j < kCtmRows; j++) {
+          constexpr int kInCtmRows = 4;
+          /* HAL matrix type is float, but DRM expects a s31.32 fix point */
+          auto value = uint64_t(matrix[i * kInCtmRows + j] * float(1ULL << 32));
+          color_matrix_->matrix[i * kCtmRows + j] = value;
+        }
+      }
+      break;
+    default:
+      return HWC2::Error::Unsupported;
+  }
 
   return HWC2::Error::None;
 }
 
+bool HwcDisplay::CtmByGpu() {
+  if (color_transform_hint_ == HAL_COLOR_TRANSFORM_IDENTITY)
+    return false;
+
+  if (GetPipe().crtc->Get()->GetCtmProperty())
+    return false;
+
+  if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
+    return false;
+
+  return true;
+}
+
 HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/,
                                         int32_t /*release_fence*/) {
   // TODO(nobody): Need virtual display support
@@ -697,7 +752,7 @@
     return HWC2::Error::None;
   }
 
-  if (a_args.active) {
+  if (a_args.active && *a_args.active) {
     /*
      * Setting the display to active before we have a composition
      * can break some drivers, so skip setting a_args.active to
@@ -709,7 +764,7 @@
                : HWC2::Error::BadParameter;
   };
 
-  int err = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+  auto err = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
   if (err) {
     ALOGE("Failed to apply the dpms composition err=%d", err);
     return HWC2::Error::BadParameter;
@@ -720,7 +775,7 @@
 HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) {
   vsync_event_en_ = HWC2_VSYNC_ENABLE == enabled;
   if (vsync_event_en_) {
-    vsync_worker_.VSyncControl(true);
+    vsync_worker_->VSyncControl(true);
   }
   return HWC2::Error::None;
 }
@@ -767,7 +822,7 @@
                              (int32_t *)(outVsyncPeriod));
 }
 
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
 HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
   if (IsInHeadlessMode()) {
     *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
@@ -815,7 +870,7 @@
 
   last_vsync_ts_ = 0;
   vsync_tracking_en_ = true;
-  vsync_worker_.VSyncControl(true);
+  vsync_worker_->VSyncControl(true);
 
   return HWC2::Error::None;
 }
@@ -845,7 +900,7 @@
 }
 #endif
 
-#if PLATFORM_SDK_VERSION > 28
+#if __ANDROID_API__ > 28
 HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
                                                      uint32_t *outDataSize,
                                                      uint8_t *outData) {
@@ -871,12 +926,31 @@
 }
 
 HWC2::Error HwcDisplay::GetDisplayCapabilities(uint32_t *outNumCapabilities,
-                                               uint32_t * /*outCapabilities*/) {
+                                               uint32_t *outCapabilities) {
   if (outNumCapabilities == nullptr) {
     return HWC2::Error::BadParameter;
   }
 
-  *outNumCapabilities = 0;
+  bool skip_ctm = false;
+
+  // Skip client CTM if user requested DRM_OR_IGNORE
+  if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
+    skip_ctm = true;
+
+  // Skip client CTM if DRM can handle it
+  if (!skip_ctm && !IsInHeadlessMode() &&
+      GetPipe().crtc->Get()->GetCtmProperty())
+    skip_ctm = true;
+
+  if (!skip_ctm) {
+    *outNumCapabilities = 0;
+    return HWC2::Error::None;
+  }
+
+  *outNumCapabilities = 1;
+  if (outCapabilities) {
+    outCapabilities[0] = HWC2_DISPLAY_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
+  }
 
   return HWC2::Error::None;
 }
@@ -890,9 +964,9 @@
   return HWC2::Error::Unsupported;
 }
 
-#endif /* PLATFORM_SDK_VERSION > 28 */
+#endif /* __ANDROID_API__ > 28 */
 
-#if PLATFORM_SDK_VERSION > 27
+#if __ANDROID_API__ > 27
 
 HWC2::Error HwcDisplay::GetRenderIntents(
     int32_t mode, uint32_t *outNumIntents,
@@ -928,7 +1002,7 @@
   return HWC2::Error::None;
 }
 
-#endif /* PLATFORM_SDK_VERSION > 27 */
+#endif /* __ANDROID_API__ > 27 */
 
 const Backend *HwcDisplay::backend() const {
   return backend_.get();
@@ -938,37 +1012,4 @@
   backend_ = std::move(backend);
 }
 
-/* returns true if composition should be sent to client */
-bool HwcDisplay::ProcessClientFlatteningState(bool skip) {
-  int flattenning_state = flattenning_state_;
-  if (flattenning_state == ClientFlattenningState::Disabled) {
-    return false;
-  }
-
-  if (skip) {
-    flattenning_state_ = ClientFlattenningState::NotRequired;
-    return false;
-  }
-
-  if (flattenning_state == ClientFlattenningState::ClientRefreshRequested) {
-    flattenning_state_ = ClientFlattenningState::Flattened;
-    return true;
-  }
-
-  vsync_flattening_en_ = true;
-  vsync_worker_.VSyncControl(true);
-  flattenning_state_ = ClientFlattenningState::VsyncCountdownMax;
-  return false;
-}
-
-void HwcDisplay::ProcessFlatenningVsyncInternal() {
-  if (flattenning_state_ > ClientFlattenningState::ClientRefreshRequested &&
-      --flattenning_state_ == ClientFlattenningState::ClientRefreshRequested &&
-      hwc2_->refresh_callback_.first != nullptr &&
-      hwc2_->refresh_callback_.second != nullptr) {
-    hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second, handle_);
-    vsync_flattening_en_ = false;
-  }
-}
-
 }  // namespace android
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index d79efb0..bf95c3e 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_H
-#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_H
+#pragma once
 
 #include <hardware/hwcomposer2.h>
 
+#include <atomic>
 #include <optional>
+#include <sstream>
 
 #include "HwcDisplayConfigs.h"
+#include "compositor/FlatteningController.h"
 #include "compositor/LayerData.h"
 #include "drm/DrmAtomicStateManager.h"
 #include "drm/ResourceManager.h"
@@ -69,12 +71,12 @@
                                  uint32_t *num_elements, hwc2_layer_t *layers,
                                  int32_t *layer_requests);
   HWC2::Error GetDisplayType(int32_t *type);
-#if PLATFORM_SDK_VERSION > 27
+#if __ANDROID_API__ > 27
   HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents,
                                int32_t *outIntents);
   HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent);
 #endif
-#if PLATFORM_SDK_VERSION > 28
+#if __ANDROID_API__ > 28
   HWC2::Error GetDisplayIdentificationData(uint8_t *outPort,
                                            uint32_t *outDataSize,
                                            uint8_t *outData);
@@ -83,7 +85,7 @@
   HWC2::Error GetDisplayBrightnessSupport(bool *supported);
   HWC2::Error SetDisplayBrightness(float);
 #endif
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
   HWC2::Error GetDisplayConnectionType(uint32_t *outType);
 
   HWC2::Error SetActiveConfigWithConstraints(
@@ -158,18 +160,12 @@
     return *pipeline_;
   }
 
-  android_color_transform_t &color_transform_hint() {
-    return color_transform_hint_;
-  }
+  bool CtmByGpu();
 
   Stats &total_stats() {
     return total_stats_;
   }
 
-  /* returns true if composition should be sent to client */
-  bool ProcessClientFlatteningState(bool skip);
-  void ProcessFlatenningVsyncInternal();
-
   /* 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
@@ -182,24 +178,16 @@
 
   void Deinit();
 
+  auto GetFlatCon() {
+    return flatcon_;
+  }
+
  private:
-  enum ClientFlattenningState : int32_t {
-    Disabled = -3,
-    NotRequired = -2,
-    Flattened = -1,
-    ClientRefreshRequested = 0,
-    VsyncCountdownMax = 60, /* 1 sec @ 60FPS */
-  };
-
-  std::atomic_int flattenning_state_{ClientFlattenningState::NotRequired};
-
-  constexpr static size_t MATRIX_SIZE = 16;
-
   HwcDisplayConfigs configs_;
 
   DrmHwcTwo *const hwc2_;
 
-  UniqueFd present_fence_;
+  SharedFd present_fence_;
 
   std::optional<DrmMode> staged_mode_;
   int64_t staged_mode_change_time_{};
@@ -208,10 +196,10 @@
   DrmDisplayPipeline *pipeline_{};
 
   std::unique_ptr<Backend> backend_;
+  std::shared_ptr<FlatteningController> flatcon_;
 
-  VSyncWorker vsync_worker_;
+  std::shared_ptr<VSyncWorker> vsync_worker_;
   bool vsync_event_en_{};
-  bool vsync_flattening_en_{};
   bool vsync_tracking_en_{};
   int64_t last_vsync_ts_{};
 
@@ -223,8 +211,10 @@
   std::map<hwc2_layer_t, HwcLayer> layers_;
   HwcLayer client_layer_;
   int32_t color_mode_{};
-  std::array<float, MATRIX_SIZE> color_transform_matrix_{};
-  android_color_transform_t color_transform_hint_;
+  static constexpr int kCtmRows = 3;
+  static constexpr int kCtmCols = 3;
+  std::shared_ptr<drm_color_ctm> color_matrix_;
+  android_color_transform_t color_transform_hint_{};
 
   std::shared_ptr<DrmKmsPlan> current_plan_;
 
@@ -233,11 +223,11 @@
   Stats prev_stats_;
   std::string DumpDelta(HwcDisplay::Stats delta);
 
+  void SetColorMarixToIdentity();
+
   HWC2::Error Init();
 
   HWC2::Error SetActiveConfigInternal(uint32_t config, int64_t change_time);
 };
 
 }  // namespace android
-
-#endif
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
index 6a3ed5a..9727989 100644
--- a/hwc2_device/HwcDisplayConfigs.cpp
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -61,7 +61,7 @@
    * mode*/
   FillHeadless();
   /* Read real configs */
-  int ret = connector.UpdateModes();
+  auto ret = connector.UpdateModes();
   if (ret != 0) {
     ALOGE("Failed to update display modes %d", ret);
     return HWC2::Error::BadDisplay;
@@ -79,7 +79,7 @@
   preferred_config_id = 0;
   uint32_t preferred_config_group_id = 0;
 
-  uint32_t first_config_id = last_config_id;
+  auto first_config_id = last_config_id;
   uint32_t last_group_id = 1;
 
   /* Group modes */
@@ -87,8 +87,10 @@
     /* Find group for the new mode or create new group */
     uint32_t group_found = 0;
     for (auto &hwc_config : hwc_configs) {
-      if (mode.h_display() == hwc_config.second.mode.h_display() &&
-          mode.v_display() == hwc_config.second.mode.v_display()) {
+      if (mode.GetRawMode().hdisplay ==
+              hwc_config.second.mode.GetRawMode().hdisplay &&
+          mode.GetRawMode().vdisplay ==
+              hwc_config.second.mode.GetRawMode().vdisplay) {
         group_found = hwc_config.second.group_id;
       }
     }
@@ -97,9 +99,9 @@
     }
 
     bool disabled = false;
-    if ((mode.flags() & DRM_MODE_FLAG_3D_MASK) != 0) {
+    if ((mode.GetRawMode().flags & DRM_MODE_FLAG_3D_MASK) != 0) {
       ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
-            mode.name().c_str());
+            mode.GetName().c_str());
       disabled = true;
     }
 
@@ -112,7 +114,7 @@
     };
 
     /* Chwck if the mode is preferred */
-    if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 &&
+    if ((mode.GetRawMode().type & DRM_MODE_TYPE_PREFERRED) != 0 &&
         preferred_config_id == 0) {
       preferred_config_id = last_config_id;
       preferred_config_group_id = group_found;
@@ -143,7 +145,7 @@
       }
     }
 
-    bool has_both = has_interlaced && has_progressive;
+    auto has_both = has_interlaced && has_progressive;
     if (!has_both) {
       continue;
     }
@@ -159,7 +161,7 @@
         continue;
       }
 
-      bool disable = group_contains_preferred_interlaced
+      auto disable = group_contains_preferred_interlaced
                          ? !hwc_config.second.IsInterlaced()
                          : hwc_config.second.IsInterlaced();
 
@@ -167,7 +169,7 @@
         ALOGI(
             "Group %i: Disabling display mode %s (This group should consist "
             "of %s modes)",
-            group, hwc_config.second.mode.name().c_str(),
+            group, hwc_config.second.mode.GetName().c_str(),
             group_contains_preferred_interlaced ? "interlaced" : "progressive");
 
         hwc_config.second.disabled = true;
@@ -183,13 +185,13 @@
     for (uint32_t 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() -
-                hwc_configs[m2].mode.v_refresh()) < kMinFpsDelta) {
+          fabsf(hwc_configs[m1].mode.GetVRefresh() -
+                hwc_configs[m2].mode.GetVRefresh()) < kMinFpsDelta) {
         ALOGI(
             "Group %i: Disabling display mode %s (Refresh rate value is "
             "too close to existing mode %s)",
-            hwc_configs[m2].group_id, hwc_configs[m2].mode.name().c_str(),
-            hwc_configs[m1].mode.name().c_str());
+            hwc_configs[m2].group_id, hwc_configs[m2].mode.GetName().c_str(),
+            hwc_configs[m1].mode.GetName().c_str());
 
         hwc_configs[m2].disabled = true;
       }
diff --git a/hwc2_device/HwcDisplayConfigs.h b/hwc2_device/HwcDisplayConfigs.h
index 7c173d6..98067c1 100644
--- a/hwc2_device/HwcDisplayConfigs.h
+++ b/hwc2_device/HwcDisplayConfigs.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H
-#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H
+#pragma once
 
 #include <hardware/hwcomposer2.h>
 
@@ -30,11 +29,11 @@
 struct HwcDisplayConfig {
   uint32_t id{};
   uint32_t group_id{};
-  DrmMode mode;
+  DrmMode mode{};
   bool disabled{};
 
   bool IsInterlaced() const {
-    return (mode.flags() & DRM_MODE_FLAG_INTERLACE) != 0;
+    return (mode.GetRawMode().flags & DRM_MODE_FLAG_INTERLACE) != 0;
   }
 };
 
@@ -55,5 +54,3 @@
 };
 
 }  // namespace android
-
-#endif
diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp
index c278732..dd5359f 100644
--- a/hwc2_device/HwcLayer.cpp
+++ b/hwc2_device/HwcLayer.cpp
@@ -53,7 +53,7 @@
  */
 HWC2::Error HwcLayer::SetLayerBuffer(buffer_handle_t buffer,
                                      int32_t acquire_fence) {
-  acquire_fence_ = UniqueFd(acquire_fence);
+  layer_data_.acquire_fence = MakeSharedFd(acquire_fence);
   buffer_handle_ = buffer;
   buffer_handle_updated_ = true;
 
@@ -202,9 +202,14 @@
   }
 }
 
-void HwcLayer::PopulateLayerData(bool test) {
+void HwcLayer::PopulateLayerData() {
   ImportFb();
 
+  if (!layer_data_.bi) {
+    ALOGE("%s: Invalid state", __func__);
+    return;
+  }
+
   if (blend_mode_ != BufferBlendMode::kUndefined) {
     layer_data_.bi->blend_mode = blend_mode_;
   }
@@ -214,10 +219,6 @@
   if (sample_range_ != BufferSampleRange::kUndefined) {
     layer_data_.bi->sample_range = sample_range_;
   }
-
-  if (!test) {
-    layer_data_.acquire_fence = std::move(acquire_fence_);
-  }
 }
 
 /* SwapChain Cache */
@@ -227,7 +228,7 @@
     return false;
   }
 
-  int seq = swchain_lookup_table_[unique_id];
+  auto seq = swchain_lookup_table_[unique_id];
 
   if (swchain_cache_.count(seq) == 0) {
     return false;
@@ -274,7 +275,7 @@
       return;
     }
 
-    int seq = swchain_lookup_table_[unique_id];
+    auto seq = swchain_lookup_table_[unique_id];
 
     if (swchain_cache_.count(seq) == 0) {
       swchain_cache_[seq] = {};
diff --git a/hwc2_device/HwcLayer.h b/hwc2_device/HwcLayer.h
index 41b3dbb..b69ce5b 100644
--- a/hwc2_device/HwcLayer.h
+++ b/hwc2_device/HwcLayer.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HWC2_DEVICE_HWC_LAYER_H
-#define ANDROID_HWC2_DEVICE_HWC_LAYER_H
+#pragma once
 
 #include <hardware/hwcomposer2.h>
 
@@ -87,9 +86,6 @@
   uint32_t z_order_ = 0;
   LayerData layer_data_;
 
-  /* Should be populated to layer_data_.acquire_fence only before presenting */
-  UniqueFd acquire_fence_;
-
   /* The following buffer data can have 2 sources:
    * 1 - Mapper@4 metadata API
    * 2 - HWC@2 API
@@ -109,7 +105,7 @@
 
   /* Layer state */
  public:
-  void PopulateLayerData(bool test);
+  void PopulateLayerData();
 
   bool IsLayerUsableAsDevice() const {
     return !bi_get_failed_ && !fb_import_failed_ && buffer_handle_ != nullptr;
@@ -140,5 +136,3 @@
 };
 
 }  // namespace android
-
-#endif
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index a6dedb4..d4ee10d 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -35,11 +35,11 @@
  * to the short "android::HwcLayer::SetLayerBuffer" for better logs readability
  */
 static std::string GetFuncName(const char *pretty_function) {
-  std::string str(pretty_function);
+  const std::string str(pretty_function);
   const char *start = "func = &";
-  size_t p1 = str.find(start);
+  auto p1 = str.find(start);
   p1 += strlen(start);
-  size_t p2 = str.find(',', p1);
+  auto p2 = str.find(',', p1);
   return str.substr(p1, p2 - p1);
 }
 
@@ -63,7 +63,7 @@
 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());
+  const std::unique_lock lock(hwc->GetResMan().GetMainLock());
   return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...));
 }
 
@@ -73,7 +73,7 @@
   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());
+  const std::unique_lock lock(hwc->GetResMan().GetMainLock());
   auto *display = hwc->GetDisplay(display_handle);
   if (display == nullptr)
     return static_cast<int32_t>(HWC2::Error::BadDisplay);
@@ -87,7 +87,7 @@
   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());
+  const std::unique_lock lock(hwc->GetResMan().GetMainLock());
   auto *display = hwc->GetDisplay(display_handle);
   if (display == nullptr)
     return static_cast<int32_t>(HWC2::Error::BadDisplay);
@@ -102,7 +102,7 @@
 static int HookDevClose(hw_device_t *dev) {
   // NOLINTNEXTLINE (cppcoreguidelines-pro-type-reinterpret-cast): Safe
   auto *hwc2_dev = reinterpret_cast<hwc2_device_t *>(dev);
-  std::unique_ptr<DrmHwcTwo> ctx(ToDrmHwcTwo(hwc2_dev));
+  const std::unique_ptr<DrmHwcTwo> ctx(ToDrmHwcTwo(hwc2_dev));
   return 0;
 }
 
@@ -244,7 +244,7 @@
       return ToHook<HWC2_PFN_VALIDATE_DISPLAY>(
           DisplayHook<decltype(&HwcDisplay::ValidateDisplay),
                       &HwcDisplay::ValidateDisplay, uint32_t *, uint32_t *>);
-#if PLATFORM_SDK_VERSION > 27
+#if __ANDROID_API__ > 27
     case HWC2::FunctionDescriptor::GetRenderIntents:
       return ToHook<HWC2_PFN_GET_RENDER_INTENTS>(
           DisplayHook<decltype(&HwcDisplay::GetRenderIntents),
@@ -255,7 +255,7 @@
           DisplayHook<decltype(&HwcDisplay::SetColorModeWithIntent),
                       &HwcDisplay::SetColorModeWithIntent, int32_t, int32_t>);
 #endif
-#if PLATFORM_SDK_VERSION > 28
+#if __ANDROID_API__ > 28
     case HWC2::FunctionDescriptor::GetDisplayIdentificationData:
       return ToHook<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>(
           DisplayHook<decltype(&HwcDisplay::GetDisplayIdentificationData),
@@ -274,8 +274,8 @@
       return ToHook<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(
           DisplayHook<decltype(&HwcDisplay::SetDisplayBrightness),
                       &HwcDisplay::SetDisplayBrightness, float>);
-#endif /* PLATFORM_SDK_VERSION > 28 */
-#if PLATFORM_SDK_VERSION > 29
+#endif /* __ANDROID_API__ > 28 */
+#if __ANDROID_API__ > 29
     case HWC2::FunctionDescriptor::GetDisplayConnectionType:
       return ToHook<HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE>(
           DisplayHook<decltype(&HwcDisplay::GetDisplayConnectionType),
diff --git a/hwc2_device/meson.build b/hwc2_device/meson.build
new file mode 100644
index 0000000..7e6b8f4
--- /dev/null
+++ b/hwc2_device/meson.build
@@ -0,0 +1,19 @@
+src_hwc2_device = files(
+    'hwc2_device.cpp',
+    'DrmHwcTwo.cpp',
+    'HwcDisplayConfigs.cpp',
+    'HwcDisplay.cpp',
+    'HwcLayer.cpp',
+)
+
+shared_library(
+    'hwcomposer.drm',
+    src_hwc2_device,
+    name_prefix : '',
+    cpp_args : common_cpp_flags + hwc2_cpp_flags,
+    dependencies : deps,
+    install : true,
+    link_whole: drmhwc_common,
+    install_dir : get_option('libdir') / 'hw',
+    include_directories: inc_include,
+)
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..c2e5fb6
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,52 @@
+project(
+    'drm_hwcomposer',
+    ['c', 'cpp'],
+    version : '2',
+    license : 'APACHE-2.0',
+    meson_version : '>= 0.56',
+    default_options : ['buildtype=debugoptimized', 'b_ndebug=if-release', 'c_std=c11', 'cpp_std=c++17', 'cpp_rtti=false']
+)
+
+inc_include = [include_directories('.')]
+
+src_common = files(
+    'compositor/DrmKmsPlan.cpp',
+    'compositor/FlatteningController.cpp',
+    'backend/BackendManager.cpp',
+    'backend/Backend.cpp',
+    'backend/BackendClient.cpp',
+    'utils/fd.cpp',
+)
+
+deps = [
+    dependency('cutils'),
+    dependency('drm'),
+    dependency('hardware'),
+    dependency('hidlbase'),
+    dependency('log'),
+    dependency('sync'),
+    dependency('ui'),
+    dependency('utils'),
+]
+
+common_cpp_flags = [
+    '-DUSE_IMAPPER4_METADATA_API',
+]
+
+hwc2_cpp_flags = [
+    '-DHWC2_INCLUDE_STRINGIFICATION',
+    '-DHWC2_USE_CPP11',
+]
+
+subdir('drm')
+subdir('bufferinfo')
+
+drmhwc_common = static_library(
+    'drm_hwcomposer_common',
+    src_common,
+# TODO remove hwc2 flags from common code (backends needs rework)
+    cpp_args : common_cpp_flags + hwc2_cpp_flags,
+    dependencies : deps,
+)
+
+subdir('hwc2_device')
diff --git a/presubmit.sh b/presubmit.sh
deleted file mode 100755
index a551398..0000000
--- a/presubmit.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-set -e
-
-echo "Run native build:"
-
-make -f .ci/Makefile -j12
-
-echo "Run style check:"
-
-./.ci/.gitlab-ci-checkcommit.sh
-
-echo -e "\n\e[32m --- SUCCESS ---"
diff --git a/tests/Android.bp b/tests/Android.bp
index f3ebb71..43fd3fa 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -28,28 +28,19 @@
     default_applicable_licenses: ["external_drm_hwcomposer_license"],
 }
 
-cc_test {
-    name: "hwc-drm-tests",
-
-    srcs: ["worker_test.cpp"],
-
-    vendor: true,
-    header_libs: ["libhardware_headers"],
-    static_libs: ["libdrmhwc_utils"],
-    shared_libs: ["hwcomposer.drm"],
-    include_dirs: ["external/drm_hwcomposer"],
-}
-
 // Tool for listening and dumping uevents
 cc_test {
     name: "hwc-drm-uevent-print",
 
-    srcs: ["uevent_print.cpp"],
+    srcs: [
+        ":drm_hwcomposer_fd",
+        "uevent_print.cpp",
+    ],
 
     vendor: true,
-    header_libs: ["libhardware_headers"],
-    shared_libs: ["liblog"],
-    include_dirs: [
-        "external/drm_hwcomposer",
+    header_libs: [
+        "drm_hwcomposer_headers",
+        "libhardware_headers",
     ],
+    shared_libs: ["liblog"],
 }
diff --git a/tests/worker_test.cpp b/tests/worker_test.cpp
deleted file mode 100644
index d1eb2b3..0000000
--- a/tests/worker_test.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-#include "utils/Worker.h"
-
-#include <gtest/gtest.h>
-#include <hardware/hardware.h>
-
-#include <chrono>
-
-using android::Worker;
-
-struct TestWorker : public Worker {
-  TestWorker() : Worker("test-worker", HAL_PRIORITY_URGENT_DISPLAY){};
-
-  int Init() {
-    return InitWorker();
-  }
-
-  void Routine() override {
-    Lock();
-    if (!enabled_) {
-      int ret = WaitForSignalOrExitLocked();
-      if (ret == -EINTR) {
-        Unlock();
-        return;
-      }
-      // should only reached here if it was enabled
-      if (!enabled_)
-        printf("Shouldn't reach here while disabled %d %d\n", value, ret);
-    }
-    value++;
-    Unlock();
-  }
-
-  void Control(bool enable) {
-    bool changed = false;
-    Lock();
-    if (enabled_ != enable) {
-      enabled_ = enable;
-      changed = true;
-    }
-    Unlock();
-
-    if (enable && changed)
-      Signal();
-  }
-
-  // NOLINTNEXTLINE: should not be public
-  int value{};
-
- private:
-  bool enabled_{};
-};
-
-struct WorkerTest : public testing::Test {
-  TestWorker worker;
-
-  void SetUp() override {
-    worker.Init();
-  }
-
-  void small_delay() {
-    std::this_thread::sleep_for(std::chrono::milliseconds(20));
-  }
-};
-
-// NOLINTNEXTLINE: required by gtest macros
-TEST_F(WorkerTest, TestWorker) {
-  // already isInitialized so should succeed
-  ASSERT_TRUE(worker.initialized());
-
-  int val = worker.value;
-  small_delay();
-
-  // value shouldn't change when isInitialized
-  ASSERT_EQ(val, worker.value);
-
-  worker.Control(true);
-  small_delay();
-
-  // while locked, value shouldn't be changing
-  worker.Lock();
-  val = worker.value;
-  small_delay();
-  ASSERT_EQ(val, worker.value);
-  worker.Unlock();
-
-  small_delay();
-  // value should be different now
-  ASSERT_NE(val, worker.value);
-
-  worker.Control(false);
-  worker.Lock();
-  val = worker.value;
-  worker.Unlock();
-  small_delay();
-
-  // value should be same
-  ASSERT_EQ(val, worker.value);
-
-  worker.Exit();
-  ASSERT_FALSE(worker.initialized());
-}
-
-// NOLINTNEXTLINE: required by gtest macros
-TEST_F(WorkerTest, ExitWhileRunning) {
-  worker.Control(true);
-
-  std::this_thread::sleep_for(std::chrono::milliseconds(50));
-  worker.Exit();
-}
diff --git a/utils/UEvent.h b/utils/UEvent.h
index 17b3cab..5b9ecea 100644
--- a/utils/UEvent.h
+++ b/utils/UEvent.h
@@ -24,7 +24,7 @@
 #include <optional>
 #include <string>
 
-#include "UniqueFd.h"
+#include "fd.h"
 #include "log.h"
 
 namespace android {
@@ -32,7 +32,7 @@
 class UEvent {
  public:
   static auto CreateInstance() -> std::unique_ptr<UEvent> {
-    auto fd = UniqueFd(
+    auto fd = MakeUniqueFd(
         socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT));
 
     if (!fd) {
@@ -46,7 +46,7 @@
     addr.nl_groups = UINT32_MAX;
 
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
-    int ret = bind(fd.Get(), (struct sockaddr *)&addr, sizeof(addr));
+    const int ret = bind(*fd, (struct sockaddr *)&addr, sizeof(addr));
     if (ret != 0) {
       ALOGE("Failed to bind uevent socket: errno=%i", errno);
       return {};
@@ -59,7 +59,7 @@
     constexpr int kUEventBufferSize = 1024;
     char buffer[kUEventBufferSize];
     ssize_t ret = 0;
-    ret = read(fd_.Get(), &buffer, sizeof(buffer));
+    ret = read(*fd_, &buffer, sizeof(buffer));
     if (ret == 0)
       return {};
 
diff --git a/utils/UniqueFd.h b/utils/UniqueFd.h
deleted file mode 100644
index d747a7f..0000000
--- a/utils/UniqueFd.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2015, 2021 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.
- */
-
-#ifndef UNIQUEFD_H_
-#define UNIQUEFD_H_
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <memory>
-
-namespace android {
-
-/*
- * Using UniqueFd:
- * 1. Create UniqueFd object:
- *    auto fd_obj = UniqueFd(open("SomeFile", xxx));
- *
- * 2. Check whether the fd_obj is empty:
- *    if (!fd_obj) { return -errno; }
- *
- * 3. Accessing the file descriptor:
- *    int ret = read(fd_obj.Get(), buf, buf_size);
- *
- * 4. Closing the file:
- *    FD will be closed once execution leaves fd_obj scope (on any return,
- *    exception, destruction of class/struct where object is member, etc.).
- *    User can also force closing the fd_obj by calling:
- *      fd_obj = UniqueFd();
- *      // fd is closed and fd_obj is empty now.
- *
- * 5. File descriptor may be transferred to the code, which will close it after
- *    using. This can be done in 2 ways:
- *    a. Duplicate the fd, in this case both fds should be closed separately:
- *      int out_fd = dup(fd_obj.Get();
- *      ...
- *      close(out_fd);
- *    b. Transfer ownership, use this method if you do not need the fd anymore.
- *      int out_fd = fd_obj.Release();
- *      // fd_obj is empty now.
- *      ...
- *      close(out_fd);
- *
- * 6. Transferring fd into another UniqueFD object:
- *    UniqueFd fd_obj_2 = std::move(fd_obj);
- *    // fd_obj empty now
- */
-
-constexpr int kEmptyFd = -1;
-
-class UniqueFd {
- public:
-  UniqueFd() = default;
-  explicit UniqueFd(int fd) : fd_(fd){};
-
-  auto Release [[nodiscard]] () -> int {
-    return std::exchange(fd_, kEmptyFd);
-  }
-
-  auto Get [[nodiscard]] () const -> int {
-    return fd_;
-  }
-
-  static auto Dup(int fd) {
-    // NOLINTNEXTLINE(android-cloexec-dup): fcntl has issue (see issue #63)
-    return UniqueFd(dup(fd));
-  }
-
-  explicit operator bool() const {
-    return fd_ != kEmptyFd;
-  }
-
-  ~UniqueFd() {
-    Set(kEmptyFd);
-  }
-
-  /* Allow move semantics */
-  UniqueFd(UniqueFd &&rhs) noexcept {
-    Set(rhs.Release());
-  }
-
-  auto operator=(UniqueFd &&rhs) noexcept -> UniqueFd & {
-    Set(rhs.Release());
-    return *this;
-  }
-
-  /* Disable copy semantics */
-  UniqueFd(const UniqueFd &) = delete;
-  auto operator=(const UniqueFd &) = delete;
-
- private:
-  void Set(int new_fd) {
-    if (fd_ != kEmptyFd) {
-      close(fd_);
-    }
-    fd_ = new_fd;
-  }
-
-  int fd_ = kEmptyFd;
-};
-
-}  // namespace android
-
-#endif
diff --git a/utils/Worker.cpp b/utils/Worker.cpp
deleted file mode 100644
index d2b60c8..0000000
--- a/utils/Worker.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "Worker.h"
-
-#include <sys/prctl.h>
-#include <sys/resource.h>
-
-namespace android {
-
-Worker::Worker(const char *name, int priority)
-    : name_(name), priority_(priority), exit_(false), initialized_(false) {
-}
-
-Worker::~Worker() {
-  Exit();
-}
-
-int Worker::InitWorker() {
-  std::lock_guard<std::mutex> lk(mutex_);
-  if (initialized())
-    return -EALREADY;
-
-  thread_ = std::make_unique<std::thread>(&Worker::InternalRoutine, this);
-  initialized_ = true;
-  exit_ = false;
-
-  return 0;
-}
-
-void Worker::Exit() {
-  std::unique_lock<std::mutex> lk(mutex_);
-  exit_ = true;
-  if (initialized()) {
-    lk.unlock();
-    cond_.notify_all();
-    thread_->join();
-    initialized_ = false;
-  }
-}
-
-int Worker::WaitForSignalOrExitLocked(int64_t max_nanoseconds) {
-  int ret = 0;
-  if (should_exit())
-    return -EINTR;
-
-  std::unique_lock<std::mutex> lk(mutex_, std::adopt_lock);
-  if (max_nanoseconds < 0) {
-    cond_.wait(lk);
-  } else if (std::cv_status::timeout ==
-             cond_.wait_for(lk, std::chrono::nanoseconds(max_nanoseconds))) {
-    ret = -ETIMEDOUT;
-  }
-
-  // exit takes precedence on timeout
-  if (should_exit())
-    ret = -EINTR;
-
-  // release leaves mutex locked when going out of scope
-  lk.release();
-
-  return ret;
-}
-
-void Worker::InternalRoutine() {
-  setpriority(PRIO_PROCESS, 0, priority_);
-  prctl(PR_SET_NAME, name_.c_str());
-
-  std::unique_lock<std::mutex> lk(mutex_, std::defer_lock);
-
-  while (true) {
-    lk.lock();
-    if (should_exit())
-      return;
-    lk.unlock();
-
-    Routine();
-  }
-}
-}  // namespace android
diff --git a/utils/Worker.h b/utils/Worker.h
deleted file mode 100644
index 74cfdc4..0000000
--- a/utils/Worker.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef ANDROID_WORKER_H_
-#define ANDROID_WORKER_H_
-
-#include <condition_variable>
-#include <cstdint>
-#include <cstdlib>
-#include <mutex>
-#include <string>
-#include <thread>
-
-namespace android {
-
-class Worker {
- public:
-  void Lock() {
-    mutex_.lock();
-  }
-  void Unlock() {
-    mutex_.unlock();
-  }
-
-  void Signal() {
-    cond_.notify_all();
-  }
-  void Exit();
-
-  bool initialized() const {
-    return initialized_;
-  }
-
-  virtual ~Worker();
-
- protected:
-  Worker(const char *name, int priority);
-
-  int InitWorker();
-  virtual void Routine() = 0;
-
-  /*
-   * Must be called with the lock acquired. max_nanoseconds may be negative to
-   * indicate infinite timeout, otherwise it indicates the maximum time span to
-   * wait for a signal before returning.
-   * Returns -EINTR if interrupted by exit request, or -ETIMEDOUT if timed out
-   */
-  int WaitForSignalOrExitLocked(int64_t max_nanoseconds = -1);
-
-  bool should_exit() const {
-    return exit_;
-  }
-
-  std::mutex mutex_;
-  std::condition_variable cond_;
-
- private:
-  void InternalRoutine();
-
-  std::string name_;
-  int priority_;
-
-  std::unique_ptr<std::thread> thread_;
-  bool exit_;
-  bool initialized_;
-};
-}  // namespace android
-#endif
diff --git a/utils/fd.cpp b/utils/fd.cpp
new file mode 100644
index 0000000..395d3b2
--- /dev/null
+++ b/utils/fd.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 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 "fd.h"
+
+namespace android {
+
+static void CloseFd(const int *fd) {
+  if (fd != nullptr) {
+    if (*fd >= 0)
+      close(*fd);
+
+    // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
+    delete fd;
+  }
+}
+
+auto MakeUniqueFd(int fd) -> UniqueFd {
+  if (fd < 0)
+    return {nullptr, CloseFd};
+
+  return {new int(fd), CloseFd};
+}
+
+auto MakeSharedFd(int fd) -> SharedFd {
+  if (fd < 0)
+    return {};
+
+  return {new int(fd), CloseFd};
+}
+
+auto DupFd(SharedFd const &fd) -> int {
+  if (!fd)
+    return -1;
+
+  return fcntl(*fd, F_DUPFD_CLOEXEC, 0);
+}
+
+}  // namespace android
diff --git a/utils/fd.h b/utils/fd.h
new file mode 100644
index 0000000..6bfd0fa
--- /dev/null
+++ b/utils/fd.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 - 2023 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.
+ */
+
+#pragma once
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <memory>
+#include <utility>
+
+namespace android {
+
+using UniqueFd = std::unique_ptr<int, void (*)(const int *)>;
+using SharedFd = std::shared_ptr<int>;
+
+auto MakeUniqueFd(int fd) -> UniqueFd;
+
+auto MakeSharedFd(int fd) -> SharedFd;
+
+auto DupFd(SharedFd const &fd) -> int;
+
+}  // namespace android
diff --git a/utils/log.h b/utils/log.h
index a48d2e7..22200df 100644
--- a/utils/log.h
+++ b/utils/log.h
@@ -1,5 +1,20 @@
-#ifndef UTILS_LOG_H_
-#define UTILS_LOG_H_
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
 
 #ifdef ANDROID
 
@@ -22,5 +37,3 @@
 #define ALOGV(args...) printf("VERBOSE: " args)
 
 #endif
-
-#endif
\ No newline at end of file
diff --git a/utils/properties.h b/utils/properties.h
index 0b49c61..e400236 100644
--- a/utils/properties.h
+++ b/utils/properties.h
@@ -1,5 +1,20 @@
-#ifndef UTILS_PROPERTIES_H_
-#define UTILS_PROPERTIES_H_
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
 
 #ifdef ANDROID
 
@@ -25,5 +40,3 @@
 }
 
 #endif
-
-#endif
\ No newline at end of file