Merge "sdm: Save debug logs on pingpong timeout"
diff --git a/Android.mk b/Android.mk
index 226e8a0..1a285bf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -3,7 +3,7 @@
 
 ifneq ($(TARGET_IS_HEADLESS), true)
     display-hals += libcopybit liblight libmemtrack hdmi_cec \
-                    $(sdm-libs)/hwc $(sdm-libs)/hwc2 gpu_tonemapper libdrmutils
+                    $(sdm-libs)/hwc $(sdm-libs)/hwc2 gpu_tonemapper libdrmutils libdisplayconfig
 endif
 
 ifneq ($(TARGET_USES_GRALLOC1), true)
diff --git a/common.mk b/common.mk
index 66f0a11..18ee72f 100644
--- a/common.mk
+++ b/common.mk
@@ -3,7 +3,7 @@
 
 #Common C flags
 common_flags := -DDEBUG_CALC_FPS -Wno-missing-field-initializers
-common_flags += -Wconversion -Wall -Werror -std=c++11
+common_flags += -Wconversion -Wall -Werror -std=c++14
 ifeq ($(TARGET_IS_HEADLESS), true)
     common_flags += -DTARGET_HEADLESS
     LOCAL_CLANG := false
diff --git a/libdisplayconfig/Android.mk b/libdisplayconfig/Android.mk
new file mode 100644
index 0000000..fae7f85
--- /dev/null
+++ b/libdisplayconfig/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE                  := libdisplayconfig
+LOCAL_MODULE_TAGS             := optional
+LOCAL_HEADER_LIBRARIES        := display_headers
+LOCAL_COPY_HEADERS            := DisplayConfig.h
+LOCAL_SRC_FILES               := DisplayConfig.cpp
+LOCAL_SHARED_LIBRARIES        := libhidlbase libhidltransport libutils \
+                                 vendor.display.config@1.0 android.hidl.base@1.0
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libdisplayconfig/DisplayConfig.cpp b/libdisplayconfig/DisplayConfig.cpp
new file mode 100644
index 0000000..c55715b
--- /dev/null
+++ b/libdisplayconfig/DisplayConfig.cpp
@@ -0,0 +1,363 @@
+/*
+* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <vendor/display/config/1.0/IDisplayConfig.h>
+
+#include "DisplayConfig.h"
+
+namespace display {
+
+using vendor::display::config::V1_0::IDisplayConfig;
+
+//=============================================================================
+// The functions below run in the client process and wherever necessary
+// do a binder call to HWC to get/set data.
+
+IDisplayConfig::DisplayType MapDisplayType(int dpy) {
+    switch (dpy) {
+        case DISPLAY_PRIMARY:
+            return IDisplayConfig::DisplayType::DISPLAY_PRIMARY;
+
+        case DISPLAY_EXTERNAL:
+            return IDisplayConfig::DisplayType::DISPLAY_EXTERNAL;
+
+        case DISPLAY_VIRTUAL:
+            return IDisplayConfig::DisplayType::DISPLAY_VIRTUAL;
+
+        default:
+            break;
+    }
+
+    return IDisplayConfig::DisplayType::INVALID;
+}
+
+IDisplayConfig::DisplayExternalStatus MapExternalStatus(uint32_t status) {
+    switch (status) {
+        case EXTERNAL_OFFLINE:
+            return IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE;
+
+        case EXTERNAL_ONLINE:
+            return IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE;
+
+        case EXTERNAL_PAUSE:
+            return IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE;
+
+        case EXTERNAL_RESUME:
+            return IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME;
+
+        default:
+            break;
+    }
+
+    return IDisplayConfig::DisplayExternalStatus::INVALID;
+}
+
+IDisplayConfig::DisplayDynRefreshRateOp MapDynRefreshRateOp(uint32_t op) {
+    switch (op) {
+        case DISABLE_METADATA_DYN_REFRESH_RATE:
+            return IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE;
+
+        case ENABLE_METADATA_DYN_REFRESH_RATE:
+            return IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE;
+
+        case SET_BINDER_DYN_REFRESH_RATE:
+            return IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE;
+
+        default:
+            break;
+    }
+
+    return IDisplayConfig::DisplayDynRefreshRateOp::INVALID;
+}
+
+int MapDisplayPortType(IDisplayConfig::DisplayPortType panelType) {
+    switch (panelType) {
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT:
+            return DISPLAY_PORT_DEFAULT;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DSI:
+            return DISPLAY_PORT_DSI;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DTV:
+            return DISPLAY_PORT_DTV;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_WRITEBACK:
+            return DISPLAY_PORT_WRITEBACK;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_LVDS:
+            return DISPLAY_PORT_LVDS;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_EDP:
+            return DISPLAY_PORT_EDP;
+
+        case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DP:
+            return DISPLAY_PORT_DP;
+
+        default:
+            break;
+    }
+
+    return -1;
+}
+
+int isExternalConnected() {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return 0;
+    }
+
+    int connected = 0;
+    intf->isDisplayConnected(IDisplayConfig::DisplayType::DISPLAY_EXTERNAL,
+        [&](const auto &tmpError, const auto &tmpStatus) {
+            if (tmpError) {
+                return;
+            }
+
+            connected = tmpStatus;
+        });
+
+    return connected;
+}
+
+int setSecondayDisplayStatus(int dpy, uint32_t status) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setSecondayDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status));
+}
+
+int configureDynRefeshRate(uint32_t op, uint32_t refreshRate) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->configureDynRefeshRate(MapDynRefreshRateOp(op), refreshRate);
+}
+
+int getConfigCount(int dpy) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    int count = 0;
+    intf->getActiveConfig(MapDisplayType(dpy),
+        [&](const auto &tmpError, const auto &tmpCount) {
+            if (tmpError) {
+                return;
+            }
+
+            count = tmpCount;
+        });
+
+    return count;
+}
+
+int getActiveConfig(int dpy) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    int config = 0;
+    intf->getActiveConfig(MapDisplayType(dpy),
+        [&](const auto &tmpError, const auto &tmpConfig) {
+            if (tmpError) {
+                return;
+            }
+
+            config = tmpConfig;
+        });
+
+    return config;
+}
+
+int setActiveConfig(int dpy, uint32_t config) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setActiveConfig(MapDisplayType(dpy), config);
+}
+
+DisplayAttributes getDisplayAttributes(uint32_t configIndex, int dpy) {
+    DisplayAttributes attributes;
+
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return attributes;
+    }
+
+    intf->getDisplayAttributes(configIndex, MapDisplayType(dpy),
+        [&](const auto &tmpError, const auto &tmpAttributes) {
+            if (tmpError) {
+                return;
+            }
+
+            attributes.vsync_period = tmpAttributes.vsyncPeriod;
+            attributes.xres = tmpAttributes.xRes;
+            attributes.yres = tmpAttributes.yRes;
+            attributes.xdpi = tmpAttributes.xDpi;
+            attributes.ydpi = tmpAttributes.yDpi;
+            attributes.panel_type = MapDisplayPortType(tmpAttributes.panelType);
+            attributes.is_yuv = tmpAttributes.isYuv;
+        });
+
+    return attributes;
+}
+
+int setPanelBrightness(uint32_t level) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setPanelBrightness(level);
+}
+
+uint32_t getPanelBrightness() {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return 0;
+    }
+
+    int level = 0;
+    intf->getPanelBrightness(
+        [&](const auto &tmpError, const auto &tmpLevel) {
+            if (tmpError) {
+                return;
+            }
+
+            level = tmpLevel;
+        });
+
+    return level;
+}
+
+int minHdcpEncryptionLevelChanged(int dpy, uint32_t min_enc_level) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->minHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
+}
+
+int refreshScreen() {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->refreshScreen();
+}
+
+int controlPartialUpdate(int dpy, bool enable) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->controlPartialUpdate(MapDisplayType(dpy), enable);
+}
+
+int toggleScreenUpdate(uint32_t on) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->toggleScreenUpdate(on == 1);
+}
+
+int setIdleTimeout(uint32_t value) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setIdleTimeout(value);
+}
+
+int getHDRCapabilities(int dpy, DisplayHDRCapabilities *caps) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL || caps == NULL) {
+        return -1;
+    }
+
+    int error = -1;
+    intf->getHDRCapabilities(MapDisplayType(dpy),
+        [&](const auto &tmpError, const auto &tmpCaps) {
+            error = tmpError;
+            if (error) {
+                return;
+            }
+
+            caps->supported_hdr_types = tmpCaps.supportedHdrTypes;
+            caps->max_luminance = tmpCaps.maxLuminance;
+            caps->max_avg_luminance = tmpCaps.maxAvgLuminance;
+            caps->min_luminance = tmpCaps.minLuminance;
+        });
+
+    return error;
+}
+
+int setCameraLaunchStatus(uint32_t on) {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return -1;
+    }
+
+    return intf->setCameraLaunchStatus(on);
+}
+
+bool displayBWTransactionPending() {
+    android::sp<IDisplayConfig> intf = IDisplayConfig::getService();
+    if (intf == NULL) {
+        return 0;
+    }
+
+    int status = 0;
+    intf->displayBWTransactionPending(
+        [&](const auto &tmpError, const auto &tmpStatus) {
+            if (tmpError) {
+                return;
+            }
+
+            status = tmpStatus;
+        });
+
+    return status;
+}
+
+} // namespace display
diff --git a/libdisplayconfig/DisplayConfig.h b/libdisplayconfig/DisplayConfig.h
new file mode 100644
index 0000000..69a542a
--- /dev/null
+++ b/libdisplayconfig/DisplayConfig.h
@@ -0,0 +1,110 @@
+/*
+ * Copyight (c) 2017 The Linux Foundation. All ights reserved.
+ *
+ * Redistibution and use in souce and binary forms, with or without
+ * modification, ae pemitted provided that the following conditions are
+ * met:
+ *    * Redistibutions of souce code must retain the above copyright
+ *      notice, this list of conditions and the following disclaime.
+ *    * Redistibutions in binay form must reproduce the above
+ *      copyight notice, this list of conditions and the following
+ *      disclaime in the documentation and/o other materials provided
+ *      with the distibution.
+ *    * Neither the name of The Linux Foundation. no the names of its
+ *      contibutos may be used to endorse or promote products derived
+ *      fom this softwae without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DISPLAY_CONFIG_H__
+#define __DISPLAY_CONFIG_H__
+
+#include <stdint.h>
+#include <vector>
+
+// This header is for clients to use to set/get global display configuration.
+
+namespace display {
+
+enum {
+    DISPLAY_PRIMARY = 0,
+    DISPLAY_EXTERNAL,
+    DISPLAY_VIRTUAL,
+};
+
+enum {
+    EXTERNAL_OFFLINE = 0,
+    EXTERNAL_ONLINE,
+    EXTERNAL_PAUSE,
+    EXTERNAL_RESUME,
+};
+
+enum {
+    DISABLE_METADATA_DYN_REFRESH_RATE = 0,
+    ENABLE_METADATA_DYN_REFRESH_RATE,
+    SET_BINDER_DYN_REFRESH_RATE,
+};
+
+enum {
+    DISPLAY_PORT_DEFAULT = 0,
+    DISPLAY_PORT_DSI,
+    DISPLAY_PORT_DTV,
+    DISPLAY_PORT_WRITEBACK,
+    DISPLAY_PORT_LVDS,
+    DISPLAY_PORT_EDP,
+    DISPLAY_PORT_DP,
+};
+
+struct DisplayAttributes {
+    uint32_t vsync_period = 0; //nanoseconds
+    uint32_t xres = 0;
+    uint32_t yres = 0;
+    float xdpi = 0.0f;
+    float ydpi = 0.0f;
+    int panel_type = DISPLAY_PORT_DEFAULT;
+    bool is_yuv = false;
+};
+
+struct DisplayHDRCapabilities {
+    std::vector<int32_t> supported_hdr_types;
+    float max_luminance = 0.0f;
+    float max_avg_luminance = 0.0f;
+    float min_luminance = 0.0f;
+};
+
+//=============================================================================
+// The functions below run in the client pocess and wherever necessary
+// do a binder call to HWC to get/set data.
+
+int isExternalConnected();
+int setSecondayDisplayStatus(int dpy, uint32_t status);
+int configureDynRefeshRate(uint32_t op, uint32_t refreshRate);
+int getConfigCount(int dpy);
+int getActiveConfig(int dpy);
+int setActiveConfig(int dpy, uint32_t config);
+DisplayAttributes getDisplayAttributes(uint32_t configIndex, int dpy);
+int setPanelBrightness(uint32_t level);
+uint32_t getPanelBrightness();
+int minHdcpEncryptionLevelChanged(int dpy, uint32_t min_enc_level);
+int refreshScreen();
+int controlPartialUpdate(int dpy, bool enable);
+int toggleScreenUpdate(uint32_t on);
+int setIdleTimeout(uint32_t value);
+int getHDRCapabilities(int dpy, DisplayHDRCapabilities *caps);
+int setCameraLaunchStatus(uint32_t on);
+bool displayBWTransactionPending();
+
+} // namespace display
+
+#endif  // __DISPLAY_CONFIG_H__
diff --git a/libgralloc1/gr_buf_mgr.cpp b/libgralloc1/gr_buf_mgr.cpp
index 2d8a558..16f5635 100644
--- a/libgralloc1/gr_buf_mgr.cpp
+++ b/libgralloc1/gr_buf_mgr.cpp
@@ -214,7 +214,9 @@
   private_handle_t * handle = const_cast<private_handle_t *>(hnd);
   handle->fd = -1;
   handle->fd_metadata = -1;
-  delete handle;
+  if (!(handle->flags & private_handle_t::PRIV_FLAGS_CLIENT_ALLOCATED)) {
+      delete handle;
+  }
   return GRALLOC1_ERROR_NONE;
 }
 
@@ -277,10 +279,6 @@
 }
 
 gralloc1_error_t BufferManager::RetainBuffer(private_handle_t const *hnd) {
-  if (hnd->flags & private_handle_t::PRIV_FLAGS_CLIENT_ALLOCATED) {
-    return GRALLOC1_ERROR_NONE;
-  }
-
   ALOGD_IF(DEBUG, "Retain buffer handle:%p id: %" PRIu64, hnd, hnd->id);
   gralloc1_error_t err = GRALLOC1_ERROR_NONE;
   std::lock_guard<std::mutex> lock(buffer_lock_);
@@ -302,10 +300,6 @@
 }
 
 gralloc1_error_t BufferManager::ReleaseBuffer(private_handle_t const *hnd) {
-  if (hnd->flags & private_handle_t::PRIV_FLAGS_CLIENT_ALLOCATED) {
-    return GRALLOC1_ERROR_NONE;
-  }
-
   ALOGD_IF(DEBUG, "Release buffer handle:%p id: %" PRIu64, hnd, hnd->id);
   std::lock_guard<std::mutex> lock(buffer_lock_);
   auto buf = GetBufferFromHandleLocked(hnd);
diff --git a/liblight/Android.mk b/liblight/Android.mk
index f627286..2f2e1ca 100644
--- a/liblight/Android.mk
+++ b/liblight/Android.mk
@@ -22,7 +22,7 @@
 
 LOCAL_SRC_FILES := lights.c lights_prv.cpp
 LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SHARED_LIBRARIES := liblog libcutils libsdm-disp-apis
+LOCAL_SHARED_LIBRARIES := liblog libcutils libsdm-disp-vndapis
 LOCAL_CFLAGS := -DLOG_TAG=\"qdlights\"
 LOCAL_CLANG  := true
 LOCAL_MODULE := lights.$(TARGET_BOARD_PLATFORM)
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 78dbfad..8cf1922 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -38,8 +38,6 @@
 
 const int kMaxSDELayers = 16;   // Maximum number of layers that can be handled by MDP5 hardware
                                 // in a given layer stack.
-const int kMaxBlitLayers = 32;   // Maximum number of layers that can be handled by MDP3 hardware
-                                // in a given layer stack.
 #define MAX_PLANES 4
 
 #define MAX_DETAIL_ENHANCE_CURVE 3
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index f6540cd..7228169 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -1331,10 +1331,6 @@
 
       sdm_layer->input_buffer.release_fence_fd = temp;
     }
-
-    // Reset the sync fence fds of HWLayer
-    hw_layer.input_buffer.acquire_fence_fd = -1;
-    hw_layer.input_buffer.release_fence_fd = -1;
   }
 
   return;
diff --git a/sdm/libs/hwc/hwc_color_manager.h b/sdm/libs/hwc/hwc_color_manager.h
index 0f4247d..20d2b39 100644
--- a/sdm/libs/hwc/hwc_color_manager.h
+++ b/sdm/libs/hwc/hwc_color_manager.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -42,7 +42,7 @@
 
 // This macro defines name for display APIs interface wrapper library.
 // This macro shall be used to load library using dlopen().
-#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-apis.so"
+#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-vndapis.so"
 
 // This macro defines variable name of display color APIs function tables
 // This macro shall be used to specify name of the variable in dlsym().
diff --git a/sdm/libs/hwc2/Android.mk b/sdm/libs/hwc2/Android.mk
index 81271b0..9f1f3c7 100644
--- a/sdm/libs/hwc2/Android.mk
+++ b/sdm/libs/hwc2/Android.mk
@@ -19,14 +19,15 @@
 
 LOCAL_SHARED_LIBRARIES        := libsdmcore libqservice libbinder libhardware libhardware_legacy \
                                  libutils libcutils libsync libqdutils libqdMetaData libdl \
-                                 libsdmutils libc++ liblog libgrallocutils \
-                                 libui libgpu_tonemapper
+                                 libsdmutils libc++ liblog libgrallocutils libui libgpu_tonemapper \
+                                 libhidlbase libhidltransport vendor.display.config@1.0
 
 ifneq ($(TARGET_USES_GRALLOC1), true)
     LOCAL_SHARED_LIBRARIES += libmemalloc
 endif
 
 LOCAL_SRC_FILES               := hwc_session.cpp \
+                                 hwc_session_services.cpp \
                                  hwc_display.cpp \
                                  hwc_display_primary.cpp \
                                  hwc_display_external.cpp \
@@ -38,7 +39,8 @@
                                  hwc_callbacks.cpp \
                                  ../hwc/cpuhint.cpp \
                                  ../hwc/hwc_socket_handler.cpp \
-                                 hwc_tonemapper.cpp
+                                 hwc_tonemapper.cpp \
+                                 display_null.cpp
 
 ifneq ($(TARGET_USES_GRALLOC1), true)
     LOCAL_SRC_FILES += ../hwc/hwc_buffer_allocator.cpp
diff --git a/sdm/libs/hwc2/display_null.cpp b/sdm/libs/hwc2/display_null.cpp
new file mode 100644
index 0000000..16f4da6
--- /dev/null
+++ b/sdm/libs/hwc2/display_null.cpp
@@ -0,0 +1,68 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "display_null.h"
+
+#define __CLASS__ "DisplayNull"
+
+namespace sdm {
+
+DisplayError DisplayNull::Commit(LayerStack *layer_stack) {
+  for (Layer *layer : layer_stack->layers) {
+    if (layer->composition != kCompositionGPUTarget) {
+      layer->composition = kCompositionSDE;
+      layer->input_buffer.release_fence_fd = -1;
+    }
+  }
+  layer_stack->retire_fence_fd = -1;
+
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetDisplayState(DisplayState *state) {
+  *state = state_;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::SetDisplayState(DisplayState state) {
+  state_ = state;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info) {
+  fb_config_ = variable_info;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info) {
+  *variable_info = fb_config_;
+  return kErrorNone;
+}
+
+}  // namespace sdm
diff --git a/sdm/libs/hwc2/display_null.h b/sdm/libs/hwc2/display_null.h
new file mode 100644
index 0000000..fa88c28
--- /dev/null
+++ b/sdm/libs/hwc2/display_null.h
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __DISPLAY_NULL_H__
+#define __DISPLAY_NULL_H__
+
+#include <core/display_interface.h>
+#include <string>
+#include <vector>
+
+namespace sdm {
+
+#define MAKE_NO_OP(virtual_method_name) \
+      virtual DisplayError virtual_method_name { return kErrorNone; }
+
+class DisplayNull : public DisplayInterface {
+ public:
+  virtual ~DisplayNull() { }
+  virtual DisplayError Commit(LayerStack *layer_stack);
+  virtual DisplayError GetDisplayState(DisplayState *state);
+  virtual DisplayError SetDisplayState(DisplayState state);
+  virtual DisplayError SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info);
+  virtual DisplayError GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info);
+  virtual bool IsUnderscanSupported() { return true; }
+  virtual void SetIdleTimeoutMs(uint32_t active_ms) { }
+  virtual bool IsPrimaryDisplay() { return true; }
+
+  void SetActive(bool active) {
+    active_ = active;
+  }
+
+  bool IsActive() {
+    return active_;
+  }
+
+  MAKE_NO_OP(Prepare(LayerStack *))
+  MAKE_NO_OP(Flush())
+  MAKE_NO_OP(GetNumVariableInfoConfigs(uint32_t *))
+  MAKE_NO_OP(GetConfig(uint32_t, DisplayConfigVariableInfo *))
+  MAKE_NO_OP(GetConfig(DisplayConfigFixedInfo *))
+  MAKE_NO_OP(GetActiveConfig(uint32_t *))
+  MAKE_NO_OP(GetVSyncState(bool *))
+  MAKE_NO_OP(SetActiveConfig(uint32_t))
+  MAKE_NO_OP(SetActiveConfig(DisplayConfigVariableInfo *))
+  MAKE_NO_OP(SetMaxMixerStages(uint32_t))
+  MAKE_NO_OP(ControlPartialUpdate(bool, uint32_t *))
+  MAKE_NO_OP(DisablePartialUpdateOneFrame())
+  MAKE_NO_OP(SetDisplayMode(uint32_t))
+  MAKE_NO_OP(SetPanelBrightness(int))
+  MAKE_NO_OP(CachePanelBrightness(int))
+  MAKE_NO_OP(OnMinHdcpEncryptionLevelChange(uint32_t))
+  MAKE_NO_OP(ColorSVCRequestRoute(const PPDisplayAPIPayload &, PPDisplayAPIPayload *,
+                                  PPPendingParams *))
+  MAKE_NO_OP(GetColorModeCount(uint32_t *))
+  MAKE_NO_OP(GetColorModes(uint32_t *, std::vector<std::string> *))
+  MAKE_NO_OP(GetColorModeAttr(const std::string &, AttrVal *))
+  MAKE_NO_OP(SetColorMode(const std::string &))
+  MAKE_NO_OP(SetColorModeById(int32_t))
+  MAKE_NO_OP(SetColorTransform(const uint32_t, const double *))
+  MAKE_NO_OP(GetDefaultColorMode(std::string *))
+  MAKE_NO_OP(ApplyDefaultDisplayMode())
+  MAKE_NO_OP(SetCursorPosition(int, int))
+  MAKE_NO_OP(GetRefreshRateRange(uint32_t *, uint32_t *))
+  MAKE_NO_OP(SetRefreshRate(uint32_t, bool))
+  MAKE_NO_OP(GetPanelBrightness(int *))
+  MAKE_NO_OP(SetVSyncState(bool))
+  MAKE_NO_OP(SetMixerResolution(uint32_t, uint32_t))
+  MAKE_NO_OP(GetMixerResolution(uint32_t *, uint32_t *))
+  MAKE_NO_OP(SetDetailEnhancerData(const DisplayDetailEnhancerData &))
+  MAKE_NO_OP(GetDisplayPort(DisplayPort *))
+  MAKE_NO_OP(SetCompositionState(LayerComposition, bool))
+
+ private:
+  bool active_ = false;
+  DisplayState state_ = kStateOff;
+  DisplayConfigVariableInfo fb_config_ = {};
+};
+
+}  // namespace sdm
+
+#endif  // __DISPLAY_NULL_H__
diff --git a/sdm/libs/hwc2/hwc_color_manager.h b/sdm/libs/hwc2/hwc_color_manager.h
index 0bfd29f..f88a5bb 100644
--- a/sdm/libs/hwc2/hwc_color_manager.h
+++ b/sdm/libs/hwc2/hwc_color_manager.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -40,7 +40,7 @@
 
 // This macro defines name for display APIs interface wrapper library.
 // This macro shall be used to load library using dlopen().
-#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-apis.so"
+#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-vndapis.so"
 
 // This macro defines variable name of display color APIs function tables
 // This macro shall be used to specify name of the variable in dlsym().
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 4f623ce..f3c81f2 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -1523,7 +1523,7 @@
   *y_pixels = display_config.y_pixels;
 }
 
-int HWCDisplay::SetDisplayStatus(uint32_t display_status) {
+int HWCDisplay::SetDisplayStatus(DisplayStatus display_status) {
   int status = 0;
 
   switch (display_status) {
@@ -1598,6 +1598,7 @@
     auto layer = hwc_layer->GetSDMLayer();
     layer->composition = kCompositionSDE;
   }
+  validated_ = true;
 }
 
 void HWCDisplay::MarkLayersForClientComposition() {
@@ -1726,8 +1727,8 @@
   return;
 }
 
-int HWCDisplay::SetActiveDisplayConfig(int config) {
-  return display_intf_->SetActiveConfig(UINT32(config)) == kErrorNone ? 0 : -1;
+int HWCDisplay::SetActiveDisplayConfig(uint32_t config) {
+  return display_intf_->SetActiveConfig(config) == kErrorNone ? 0 : -1;
 }
 
 int HWCDisplay::GetActiveDisplayConfig(uint32_t *config) {
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 1b04c84..b70f160 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -20,6 +20,7 @@
 #ifndef __HWC_DISPLAY_H__
 #define __HWC_DISPLAY_H__
 
+#include <sys/stat.h>
 #include <QService.h>
 #include <core/core_interface.h>
 #include <hardware/hwcomposer.h>
@@ -92,6 +93,14 @@
 
 class HWCDisplay : public DisplayEventHandler {
  public:
+  enum DisplayStatus {
+    kDisplayStatusInvalid = -1,
+    kDisplayStatusOffline,
+    kDisplayStatusOnline,
+    kDisplayStatusPause,
+    kDisplayStatusResume,
+  };
+
   virtual ~HWCDisplay() {}
   virtual int Init();
   virtual int Deinit();
@@ -106,7 +115,7 @@
   virtual HWC2::PowerMode GetLastPowerMode();
   virtual int SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels);
   virtual void GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels);
-  virtual int SetDisplayStatus(uint32_t display_status);
+  virtual int SetDisplayStatus(DisplayStatus display_status);
   virtual int OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level);
   virtual int Perform(uint32_t operation, ...);
   virtual void SetSecureDisplay(bool secure_display_active);
@@ -132,7 +141,7 @@
   }
 
   // Display Configurations
-  virtual int SetActiveDisplayConfig(int config);
+  virtual int SetActiveDisplayConfig(uint32_t config);
   virtual int GetActiveDisplayConfig(uint32_t *config);
   virtual int GetDisplayConfigCount(uint32_t *count);
   virtual int GetDisplayAttributesForConfig(int config,
@@ -150,6 +159,9 @@
     return INT32(status);
   }
 
+  virtual int SetState(bool connected) {
+    return kErrorNotSupported;
+  }
   int SetPanelBrightness(int level);
   int GetPanelBrightness(int *level);
   int ToggleScreenUpdates(bool enable);
@@ -211,13 +223,6 @@
                                          float* out_min_luminance);
 
  protected:
-  enum DisplayStatus {
-    kDisplayStatusOffline = 0,
-    kDisplayStatusOnline,
-    kDisplayStatusPause,
-    kDisplayStatusResume,
-  };
-
   // Maximum number of layers supported by display manager.
   static const uint32_t kMaxLayerCount = 32;
 
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index a8f8480..e89451d 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -64,6 +64,7 @@
 
   error = hwc_display_external->GetMixerResolution(&external_width, &external_height);
   if (error != kErrorNone) {
+    Destroy(hwc_display_external);
     return -EINVAL;
   }
 
@@ -215,4 +216,65 @@
   }
 }
 
+int HWCDisplayExternal::SetState(bool connected) {
+  DisplayError error = kErrorNone;
+  DisplayState state = kStateOff;
+  DisplayConfigVariableInfo fb_config = {};
+
+  if (connected) {
+    if (display_null_.IsActive()) {
+      error = core_intf_->CreateDisplay(type_, this, &display_intf_);
+      if (error != kErrorNone) {
+        DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p",
+              error, type_, this, &display_intf_);
+        return -EINVAL;
+      }
+
+      // Restore HDMI attributes when display is reconnected.
+      // This is to ensure that surfaceflinger & sdm are in sync.
+      display_null_.GetFrameBufferConfig(&fb_config);
+      int status = SetFrameBufferResolution(fb_config.x_pixels, fb_config.y_pixels);
+      if (status) {
+        DLOGW("Set frame buffer config failed. Error = %d", error);
+        return -1;
+      }
+
+      display_null_.GetDisplayState(&state);
+      display_intf_->SetDisplayState(state);
+
+      SetVsyncEnabled(HWC2::Vsync::Enable);
+
+      display_null_.SetActive(false);
+      DLOGI("Display is connected successfully.");
+    } else {
+      DLOGI("Display is already connected.");
+    }
+  } else {
+    if (!display_null_.IsActive()) {
+      // Preserve required attributes of HDMI display that surfaceflinger sees.
+      // Restore HDMI attributes when display is reconnected.
+      display_intf_->GetDisplayState(&state);
+      display_null_.SetDisplayState(state);
+
+      error = display_intf_->GetFrameBufferConfig(&fb_config);
+      if (error != kErrorNone) {
+        DLOGW("Get frame buffer config failed. Error = %d", error);
+        return -1;
+      }
+      display_null_.SetFrameBufferConfig(fb_config);
+
+      SetVsyncEnabled(HWC2::Vsync::Disable);
+      core_intf_->DestroyDisplay(display_intf_);
+      display_intf_ = &display_null_;
+
+      display_null_.SetActive(true);
+      DLOGI("Display is disconnected successfully.");
+    } else {
+      DLOGI("Display is already disconnected.");
+    }
+  }
+
+  return 0;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_external.h b/sdm/libs/hwc2/hwc_display_external.h
index 802a77c..7aa84b2 100644
--- a/sdm/libs/hwc2/hwc_display_external.h
+++ b/sdm/libs/hwc2/hwc_display_external.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -31,6 +31,7 @@
 #define __HWC_DISPLAY_EXTERNAL_H__
 
 #include "hwc_display.h"
+#include "display_null.h"
 
 namespace sdm {
 
@@ -47,6 +48,7 @@
   virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error Present(int32_t *out_retire_fence);
   virtual void SetSecureDisplay(bool secure_display_active);
+  virtual int SetState(bool connected);
 
  private:
   HWCDisplayExternal(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
@@ -54,6 +56,8 @@
   void ApplyScanAdjustment(hwc_rect_t *display_frame);
   static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
                                      uint32_t *virtual_width, uint32_t *virtual_height);
+
+  DisplayNull display_null_;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 2fcf2a9..b82a46e 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -521,12 +521,12 @@
   GetPanelResolution(&panel_width, &panel_height);
   GetFrameBufferResolution(&fb_width, &fb_height);
 
-  if (post_processed_output && (output_buffer_info_.buffer_config.width < panel_width ||
-                                output_buffer_info_.buffer_config.height < panel_height)) {
+  if (post_processed_output && (output_buffer_info.buffer_config.width < panel_width ||
+                                output_buffer_info.buffer_config.height < panel_height)) {
     DLOGE("Buffer dimensions should not be less than panel resolution");
     return -1;
-  } else if (!post_processed_output && (output_buffer_info_.buffer_config.width < fb_width ||
-                                        output_buffer_info_.buffer_config.height < fb_height)) {
+  } else if (!post_processed_output && (output_buffer_info.buffer_config.width < fb_width ||
+                                        output_buffer_info.buffer_config.height < fb_height)) {
     DLOGE("Buffer dimensions should not be less than FB resolution");
     return -1;
   }
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 7b68eb8..b305a9a 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -94,9 +94,9 @@
     return -EINVAL;
   }
 
-  buffer_allocator_ = new HWCBufferAllocator();
+  StartServices();
 
-  DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), buffer_allocator_,
+  DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_,
                                                  &buffer_sync_handler_, &socket_handler_,
                                                  &core_intf_);
   if (error != kErrorNone) {
@@ -104,20 +104,31 @@
     return -EINVAL;
   }
 
-  // Read which display is first, and create it and store it in primary slot
-  // TODO(user): This will need to be redone for HWC2 - right now we validate only
-  // the primary physical path
-  HWDisplayInterfaceInfo hw_disp_info;
+  // If HDMI display is primary display, defer display creation until hotplug event is received.
+  HWDisplayInterfaceInfo hw_disp_info = {};
   error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
-  if (error == kErrorNone && hw_disp_info.type == kHDMI && hw_disp_info.is_connected) {
-    // HDMI is primary display. If already connected, then create it and store in
-    // primary display slot. If not connected, create a NULL display for now.
-    status = HWCDisplayExternal::Create(core_intf_, buffer_allocator_, &callbacks_, qservice_,
-                                        &hwc_display_[HWC_DISPLAY_PRIMARY]);
+  if (error != kErrorNone) {
+    CoreInterface::DestroyCore();
+    DLOGE("Primary display type not recognized. Error = %d", error);
+    return -EINVAL;
+  }
+
+  if (hw_disp_info.type == kHDMI) {
+    status = 0;
+    hdmi_is_primary_ = true;
+    // Create display if it is connected, else wait for hotplug connect event.
+    if (hw_disp_info.is_connected) {
+      status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, qservice_,
+                                          &hwc_display_[HWC_DISPLAY_PRIMARY]);
+    }
   } else {
     // Create and power on primary display
-    status = HWCDisplayPrimary::Create(core_intf_, buffer_allocator_, &callbacks_, qservice_,
+    status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &callbacks_, qservice_,
                                        &hwc_display_[HWC_DISPLAY_PRIMARY]);
+    color_mgr_ = HWCColorManager::CreateColorManager(&buffer_allocator_);
+    if (!color_mgr_) {
+      DLOGW("Failed to load HWCColorManager.");
+    }
   }
 
   if (status) {
@@ -125,19 +136,6 @@
     return status;
   }
 
-  color_mgr_ = HWCColorManager::CreateColorManager(buffer_allocator_);
-  if (!color_mgr_) {
-    DLOGW("Failed to load HWCColorManager.");
-  }
-
-  if (pthread_create(&uevent_thread_, NULL, &HWCUeventThread, this) < 0) {
-    DLOGE("Failed to start = %s, error = %s", uevent_thread_name_, strerror(errno));
-    HWCDisplayPrimary::Destroy(hwc_display_[HWC_DISPLAY_PRIMARY]);
-    hwc_display_[HWC_DISPLAY_PRIMARY] = 0;
-    CoreInterface::DestroyCore();
-    return -errno;
-  }
-
   struct rlimit fd_limit = {};
   getrlimit(RLIMIT_NOFILE, &fd_limit);
   fd_limit.rlim_cur = fd_limit.rlim_cur * 2;
@@ -147,31 +145,38 @@
       DLOGW("Unable to increase fd limit -  err:%d, %s", errno, strerror(errno));
     }
   }
+
+  std::thread uevent_thread(HWCUeventThread, this);
+  uevent_thread_.swap(uevent_thread);
+
   return 0;
 }
 
 int HWCSession::Deinit() {
-  HWCDisplayPrimary::Destroy(hwc_display_[HWC_DISPLAY_PRIMARY]);
-  hwc_display_[HWC_DISPLAY_PRIMARY] = 0;
+  HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+  if (primary_display) {
+    if (hdmi_is_primary_) {
+      HWCDisplayExternal::Destroy(primary_display);
+    } else {
+      HWCDisplayPrimary::Destroy(primary_display);
+    }
+  }
+  hwc_display_[HWC_DISPLAY_PRIMARY] = nullptr;
+
   if (color_mgr_) {
     color_mgr_->DestroyColorManager();
   }
-  uevent_thread_exit_ = true;
+
   DLOGD("Terminating uevent thread");
-  // TODO(user): on restarting HWC in the same process, the uevent thread does not restart
-  // cleanly.
-  Sys::pthread_cancel_(uevent_thread_);
+  uevent_thread_exit_ = true;
+  // todo(user): add a local event to interrupt thread execution and join.
+  uevent_thread_.detach();
 
   DisplayError error = CoreInterface::DestroyCore();
   if (error != kErrorNone) {
     DLOGE("Display core de-initialization failed. Error = %d", error);
   }
 
-  if (buffer_allocator_ != nullptr) {
-    delete buffer_allocator_;
-  }
-  buffer_allocator_ = nullptr;
-
   return 0;
 }
 
@@ -434,8 +439,13 @@
   auto desc = static_cast<HWC2::Callback>(descriptor);
   auto error = hwc_session->callbacks_.Register(desc, callback_data, pointer);
   DLOGD("Registering callback: %s", to_string(desc).c_str());
-  if (descriptor == HWC2_CALLBACK_HOTPLUG)
-    hwc_session->callbacks_.Hotplug(HWC_DISPLAY_PRIMARY, HWC2::Connection::Connected);
+  if (descriptor == HWC2_CALLBACK_HOTPLUG) {
+    // If primary display (HDMI) is not created yet, wait for it to be hotplugged.
+    if (hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY]) {
+      hwc_session->callbacks_.Hotplug(HWC_DISPLAY_PRIMARY, HWC2::Connection::Connected);
+    }
+  }
+
   return INT32(error);
 }
 
@@ -717,7 +727,7 @@
   if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
     return HWC2::Error::NoResources;
   }
-  auto status = HWCDisplayVirtual::Create(core_intf_, buffer_allocator_, &callbacks_, width,
+  auto status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_, width,
                                           height, format, &hwc_display_[HWC_DISPLAY_VIRTUAL]);
   // TODO(user): validate width and height support
   if (status)
@@ -736,7 +746,7 @@
   hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
 
   if (disp == HWC_DISPLAY_EXTERNAL) {
-    status = HWCDisplayExternal::Create(core_intf_, buffer_allocator_, &callbacks_, primary_width,
+    status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, primary_width,
                                         primary_height, qservice_, false, &hwc_display_[disp]);
   } else {
     DLOGE("Invalid display type");
@@ -770,8 +780,6 @@
 // Qclient methods
 android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
                                              android::Parcel *output_parcel) {
-  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
-
   android::status_t status = 0;
 
   switch (command) {
@@ -780,14 +788,11 @@
       break;
 
     case qService::IQService::SCREEN_REFRESH:
-      callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
+      refreshScreen();
       break;
 
     case qService::IQService::SET_IDLE_TIMEOUT:
-      if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-        uint32_t timeout = UINT32(input_parcel->readInt32());
-        hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(timeout);
-      }
+      setIdleTimeout(UINT32(input_parcel->readInt32()));
       break;
 
     case qService::IQService::SET_FRAME_DUMP_CONFIG:
@@ -802,8 +807,13 @@
       status = SetDisplayMode(input_parcel);
       break;
 
-    case qService::IQService::SET_SECONDARY_DISPLAY_STATUS:
-      status = SetSecondaryDisplayStatus(input_parcel, output_parcel);
+    case qService::IQService::SET_SECONDARY_DISPLAY_STATUS: {
+        int disp_id = INT(input_parcel->readInt32());
+        HWCDisplay::DisplayStatus disp_status =
+              static_cast<HWCDisplay::DisplayStatus>(input_parcel->readInt32());
+        status = SetSecondaryDisplayStatus(disp_id, disp_status);
+        output_parcel->writeInt32(status);
+      }
       break;
 
     case qService::IQService::CONFIGURE_DYN_REFRESH_RATE:
@@ -813,56 +823,89 @@
     case qService::IQService::SET_VIEW_FRAME:
       break;
 
-    case qService::IQService::TOGGLE_SCREEN_UPDATES:
-      status = ToggleScreenUpdates(input_parcel, output_parcel);
+    case qService::IQService::TOGGLE_SCREEN_UPDATES: {
+        int32_t input = input_parcel->readInt32();
+        status = toggleScreenUpdate(input == 1);
+        output_parcel->writeInt32(status);
+      }
       break;
 
     case qService::IQService::QDCM_SVC_CMDS:
       status = QdcmCMDHandler(input_parcel, output_parcel);
       break;
 
-    case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED:
-      status = OnMinHdcpEncryptionLevelChange(input_parcel, output_parcel);
+    case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED: {
+        int disp_id = input_parcel->readInt32();
+        uint32_t min_enc_level = UINT32(input_parcel->readInt32());
+        status = MinHdcpEncryptionLevelChanged(disp_id, min_enc_level);
+        output_parcel->writeInt32(status);
+      }
       break;
 
-    case qService::IQService::CONTROL_PARTIAL_UPDATE:
-      status = ControlPartialUpdate(input_parcel, output_parcel);
+    case qService::IQService::CONTROL_PARTIAL_UPDATE: {
+        int disp_id = input_parcel->readInt32();
+        uint32_t enable = UINT32(input_parcel->readInt32());
+        status = ControlPartialUpdate(disp_id, enable == 1);
+        output_parcel->writeInt32(status);
+      }
       break;
 
-    case qService::IQService::SET_ACTIVE_CONFIG:
-      status = HandleSetActiveDisplayConfig(input_parcel, output_parcel);
+    case qService::IQService::SET_ACTIVE_CONFIG: {
+        uint32_t config = UINT32(input_parcel->readInt32());
+        int disp_id = input_parcel->readInt32();
+        status = SetActiveConfigIndex(disp_id, config);
+      }
       break;
 
-    case qService::IQService::GET_ACTIVE_CONFIG:
-      status = HandleGetActiveDisplayConfig(input_parcel, output_parcel);
+    case qService::IQService::GET_ACTIVE_CONFIG: {
+        int disp_id = input_parcel->readInt32();
+        uint32_t config = 0;
+        status = GetActiveConfigIndex(disp_id, &config);
+        output_parcel->writeInt32(INT(config));
+      }
       break;
 
-    case qService::IQService::GET_CONFIG_COUNT:
-      status = HandleGetDisplayConfigCount(input_parcel, output_parcel);
+    case qService::IQService::GET_CONFIG_COUNT: {
+        int disp_id = input_parcel->readInt32();
+        uint32_t count = 0;
+        status = GetConfigCount(disp_id, &count);
+        output_parcel->writeInt32(INT(count));
+      }
       break;
 
     case qService::IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
       status = HandleGetDisplayAttributesForConfig(input_parcel, output_parcel);
       break;
 
-    case qService::IQService::GET_PANEL_BRIGHTNESS:
-      status = GetPanelBrightness(input_parcel, output_parcel);
+    case qService::IQService::GET_PANEL_BRIGHTNESS: {
+        int level = 0;
+        status = GetPanelBrightness(&level);
+        output_parcel->writeInt32(level);
+      }
       break;
 
-    case qService::IQService::SET_PANEL_BRIGHTNESS:
-      status = SetPanelBrightness(input_parcel, output_parcel);
+    case qService::IQService::SET_PANEL_BRIGHTNESS: {
+        uint32_t level = UINT32(input_parcel->readInt32());
+        status = setPanelBrightness(level);
+        output_parcel->writeInt32(status);
+      }
       break;
 
     case qService::IQService::GET_DISPLAY_VISIBLE_REGION:
       status = GetVisibleDisplayRect(input_parcel, output_parcel);
       break;
 
-    case qService::IQService::SET_CAMERA_STATUS:
-      status = SetDynamicBWForCamera(input_parcel, output_parcel);
+    case qService::IQService::SET_CAMERA_STATUS: {
+        uint32_t camera_status = UINT32(input_parcel->readInt32());
+        status = setCameraLaunchStatus(camera_status);
+      }
       break;
 
-    case qService::IQService::GET_BW_TRANSACTION_STATUS:
-      status = GetBWTransactionStatus(input_parcel, output_parcel);
+    case qService::IQService::GET_BW_TRANSACTION_STATUS: {
+        bool state = true;
+        status = DisplayBWTransactionPending(&state);
+        output_parcel->writeInt32(state);
+      }
       break;
 
     case qService::IQService::SET_LAYER_MIXER_RESOLUTION:
@@ -885,167 +928,11 @@
   return status;
 }
 
-android::status_t HWCSession::ToggleScreenUpdates(const android::Parcel *input_parcel,
-                                                  android::Parcel *output_parcel) {
-  int input = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY] && (input <= 1) && (input >= 0)) {
-    error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(input == 1);
-    if (error != 0) {
-      DLOGE("Failed to toggle screen updates = %d. Error = %d", input, error);
-    }
-  }
-  output_parcel->writeInt32(error);
-
-  return error;
-}
-
-android::status_t HWCSession::SetPanelBrightness(const android::Parcel *input_parcel,
-                                                 android::Parcel *output_parcel) {
-  int level = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(level);
-    if (error != 0) {
-      DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
-    }
-  }
-  output_parcel->writeInt32(error);
-
-  return error;
-}
-
-android::status_t HWCSession::GetPanelBrightness(const android::Parcel *input_parcel,
-                                                 android::Parcel *output_parcel) {
-  int error = android::BAD_VALUE;
-  int ret = error;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(&ret);
-    if (error != 0) {
-      ret = error;
-      DLOGE("Failed to get the panel brightness. Error = %d", error);
-    }
-  }
-  output_parcel->writeInt32(ret);
-
-  return error;
-}
-
-android::status_t HWCSession::ControlPartialUpdate(const android::Parcel *input_parcel,
-                                                   android::Parcel *out) {
-  DisplayError error = kErrorNone;
-  int ret = 0;
-  uint32_t disp_id = UINT32(input_parcel->readInt32());
-  uint32_t enable = UINT32(input_parcel->readInt32());
-
-  if (disp_id != HWC_DISPLAY_PRIMARY) {
-    DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
-    ret = -EINVAL;
-    out->writeInt32(ret);
-    return ret;
-  }
-
-  if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    DLOGE("primary display object is not instantiated");
-    ret = -EINVAL;
-    out->writeInt32(ret);
-    return ret;
-  }
-
-  uint32_t pending = 0;
-  error = hwc_display_[HWC_DISPLAY_PRIMARY]->ControlPartialUpdate(enable, &pending);
-
-  if (error == kErrorNone) {
-    if (!pending) {
-      out->writeInt32(ret);
-      return ret;
-    }
-  } else if (error == kErrorNotSupported) {
-    out->writeInt32(ret);
-    return ret;
-  } else {
-    ret = -EINVAL;
-    out->writeInt32(ret);
-    return ret;
-  }
-
-  // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
-  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
-
-  // Wait until partial update control is complete
-  ret = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
-
-  out->writeInt32(ret);
-
-  return ret;
-}
-
-android::status_t HWCSession::HandleSetActiveDisplayConfig(const android::Parcel *input_parcel,
-                                                           android::Parcel *output_parcel) {
-  int config = input_parcel->readInt32();
-  int dpy = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (dpy > HWC_DISPLAY_VIRTUAL) {
-    return android::BAD_VALUE;
-  }
-
-  if (hwc_display_[dpy]) {
-    error = hwc_display_[dpy]->SetActiveDisplayConfig(config);
-    if (error == 0) {
-      callbacks_.Refresh(0);
-    }
-  }
-
-  return error;
-}
-
-android::status_t HWCSession::HandleGetActiveDisplayConfig(const android::Parcel *input_parcel,
-                                                           android::Parcel *output_parcel) {
-  int dpy = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (dpy > HWC_DISPLAY_VIRTUAL) {
-    return android::BAD_VALUE;
-  }
-
-  if (hwc_display_[dpy]) {
-    uint32_t config = 0;
-    error = hwc_display_[dpy]->GetActiveDisplayConfig(&config);
-    if (error == 0) {
-      output_parcel->writeInt32(INT(config));
-    }
-  }
-
-  return error;
-}
-
-android::status_t HWCSession::HandleGetDisplayConfigCount(const android::Parcel *input_parcel,
-                                                          android::Parcel *output_parcel) {
-  int dpy = input_parcel->readInt32();
-  int error = android::BAD_VALUE;
-
-  if (dpy > HWC_DISPLAY_VIRTUAL) {
-    return android::BAD_VALUE;
-  }
-
-  uint32_t count = 0;
-  if (hwc_display_[dpy]) {
-    error = hwc_display_[dpy]->GetDisplayConfigCount(&count);
-    if (error == 0) {
-      output_parcel->writeInt32(INT(count));
-    }
-  }
-
-  return error;
-}
-
 android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel
                                                                   *input_parcel,
                                                                   android::Parcel *output_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   int config = input_parcel->readInt32();
   int dpy = input_parcel->readInt32();
   int error = android::BAD_VALUE;
@@ -1070,44 +957,24 @@
   return error;
 }
 
-android::status_t HWCSession::SetSecondaryDisplayStatus(const android::Parcel *input_parcel,
-                                                        android::Parcel *output_parcel) {
-  int ret = -EINVAL;
-
-  uint32_t display_id = UINT32(input_parcel->readInt32());
-  uint32_t display_status = UINT32(input_parcel->readInt32());
-
-  DLOGI("Display = %d, Status = %d", display_id, display_status);
-
-  if (display_id >= HWC_NUM_DISPLAY_TYPES) {
-    DLOGE("Invalid display_id");
-  } else if (display_id == HWC_DISPLAY_PRIMARY) {
-    DLOGE("Not supported for this display");
-  } else if (!hwc_display_[display_id]) {
-    DLOGW("Display is not connected");
-  } else {
-    ret = hwc_display_[display_id]->SetDisplayStatus(display_status);
-  }
-
-  output_parcel->writeInt32(ret);
-
-  return ret;
-}
-
 android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   uint32_t operation = UINT32(input_parcel->readInt32());
+  HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+
   switch (operation) {
     case qdutils::DISABLE_METADATA_DYN_REFRESH_RATE:
-      return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
-          HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
+      return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
+
     case qdutils::ENABLE_METADATA_DYN_REFRESH_RATE:
-      return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
-          HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
+      return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
+
     case qdutils::SET_BINDER_DYN_REFRESH_RATE: {
       uint32_t refresh_rate = UINT32(input_parcel->readInt32());
-      return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
-          HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refresh_rate);
+      return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refresh_rate);
     }
+
     default:
       DLOGW("Invalid operation %d", operation);
       return -EINVAL;
@@ -1117,11 +984,15 @@
 }
 
 android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   uint32_t mode = UINT32(input_parcel->readInt32());
   return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(HWCDisplayPrimary::SET_DISPLAY_MODE, mode);
 }
 
 android::status_t HWCSession::SetMaxMixerStages(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   DisplayError error = kErrorNone;
   std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
   uint32_t max_mixer_stages = UINT32(input_parcel->readInt32());
@@ -1156,42 +1027,9 @@
   return 0;
 }
 
-android::status_t HWCSession::SetDynamicBWForCamera(const android::Parcel *input_parcel,
-                                                    android::Parcel *output_parcel) {
-  DisplayError error = kErrorNone;
-  uint32_t camera_status = UINT32(input_parcel->readInt32());
-  HWBwModes mode = camera_status > 0 ? kBwCamera : kBwDefault;
-
-  // trigger invalidate to apply new bw caps.
-  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
-
-  error = core_intf_->SetMaxBandwidthMode(mode);
-  if (error != kErrorNone) {
-    return -EINVAL;
-  }
-
-  new_bw_mode_ = true;
-  need_invalidate_ = true;
-
-  return 0;
-}
-
-android::status_t HWCSession::GetBWTransactionStatus(const android::Parcel *input_parcel,
-                                                     android::Parcel *output_parcel) {
-  bool state = true;
-
-  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    if (sync_wait(bw_mode_release_fd_, 0) < 0) {
-      DLOGI("bw_transaction_release_fd is not yet signalled: err= %s", strerror(errno));
-      state = false;
-    }
-    output_parcel->writeInt32(state);
-  }
-
-  return 0;
-}
-
 void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
   std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
   uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32());
@@ -1216,6 +1054,8 @@
 }
 
 android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   DisplayError error = kErrorNone;
   uint32_t dpy = UINT32(input_parcel->readInt32());
 
@@ -1241,6 +1081,8 @@
 }
 
 android::status_t HWCSession::SetColorModeOverride(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   auto display = static_cast<hwc2_display_t >(input_parcel->readInt32());
   auto mode = static_cast<android_color_mode_t>(input_parcel->readInt32());
   auto device = static_cast<hwc2_device_t *>(this);
@@ -1261,6 +1103,8 @@
 }
 
 void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   int type = input_parcel->readInt32();
   bool enable = (input_parcel->readInt32() > 0);
   DLOGI("type = %d enable = %d", type, enable);
@@ -1301,6 +1145,8 @@
 
 android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel,
                                              android::Parcel *output_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   int ret = 0;
   int32_t *brightness_value = NULL;
   uint32_t display_id(0);
@@ -1392,29 +1238,6 @@
   return (ret ? -EINVAL : 0);
 }
 
-android::status_t HWCSession::OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
-                                                             android::Parcel *output_parcel) {
-  int ret = -EINVAL;
-  uint32_t display_id = UINT32(input_parcel->readInt32());
-  uint32_t min_enc_level = UINT32(input_parcel->readInt32());
-
-  DLOGI("Display %d", display_id);
-
-  if (display_id >= HWC_NUM_DISPLAY_TYPES) {
-    DLOGE("Invalid display_id");
-  } else if (display_id != HWC_DISPLAY_EXTERNAL) {
-    DLOGE("Not supported for display");
-  } else if (!hwc_display_[display_id]) {
-    DLOGW("Display is not connected");
-  } else {
-    ret = hwc_display_[display_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
-  }
-
-  output_parcel->writeInt32(ret);
-
-  return ret;
-}
-
 void *HWCSession::HWCUeventThread(void *context) {
   if (context) {
     return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
@@ -1526,34 +1349,35 @@
 int HWCSession::HotPlugHandler(bool connected) {
   int status = 0;
   bool notify_hotplug = false;
-  bool hdmi_primary = false;
 
   // To prevent sending events to client while a lock is held, acquire scope locks only within
   // below scope so that those get automatically unlocked after the scope ends.
-  {
+  do {
     SEQUENCE_WAIT_SCOPE_LOCK(locker_);
 
+    // If HDMI is primary but not created yet (first time), create it and notify surfaceflinger.
+    //    if it is already created, but got disconnected/connected again,
+    //    just toggle display status and do not notify surfaceflinger.
+    // If HDMI is not primary, create/destroy external display normally.
+    if (hdmi_is_primary_) {
+      if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+        status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetState(connected);
+      } else {
+        status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_,
+                                            qservice_, &hwc_display_[HWC_DISPLAY_PRIMARY]);
+        notify_hotplug = true;
+      }
+
+      break;
+    }
+
+    // Primary display must be connected for HDMI as secondary cases.
     if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
       DLOGE("Primary display is not connected.");
       return -1;
     }
 
-    HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
-    HWCDisplay *external_display = NULL;
-
-    if (primary_display->GetDisplayClass() == DISPLAY_CLASS_EXTERNAL) {
-      external_display = static_cast<HWCDisplayExternal *>(hwc_display_[HWC_DISPLAY_PRIMARY]);
-      hdmi_primary = true;
-    }
-
-    // If primary display connected is a NULL display, then replace it with the external display
     if (connected) {
-      // If we are in HDMI as primary and the primary display just got plugged in
-      if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-        DLOGE("HDMI is already connected");
-        return -1;
-      }
-
       // Connect external display if virtual display is not connected.
       // Else, defer external display connection and process it when virtual display
       // tears down; Do not notify SurfaceFlinger since connection is deferred now.
@@ -1571,39 +1395,28 @@
       // Do not return error if external display is not in connected status.
       // Due to virtual display concurrency, external display connection might be still pending
       // but hdmi got disconnected before pending connection could be processed.
-
-      if (hdmi_primary) {
-        assert(external_display != NULL);
-        uint32_t x_res, y_res;
-        external_display->GetFrameBufferResolution(&x_res, &y_res);
-        // Need to manually disable VSYNC as SF is not aware of connect/disconnect cases
-        // for HDMI as primary
-        external_display->SetVsyncEnabled(HWC2::Vsync::Disable);
-        HWCDisplayExternal::Destroy(external_display);
-
-        // In HWC2, primary displays can be hotplugged out
+      if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
+        status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL);
         notify_hotplug = true;
-      } else {
-        if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-          status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL);
-          notify_hotplug = true;
-        }
-        external_pending_connect_ = false;
       }
+      external_pending_connect_ = false;
+    }
+  } while (0);
+
+  if (connected) {
+    callbacks_.Refresh(0);
+
+    if (!hdmi_is_primary_) {
+      // wait for sufficient time to ensure sufficient resources are available to process new
+      // new display connection.
+      uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY));
+      usleep(vsync_period * 2 / 1000);
     }
   }
 
-  if (connected && notify_hotplug) {
-    // trigger screen refresh to ensure sufficient resources are available to process new
-    // new display connection.
-    callbacks_.Refresh(0);
-    uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY));
-    usleep(vsync_period * 2 / 1000);
-  }
   // notify client
-  // Handle HDMI as primary here
   if (notify_hotplug) {
-    callbacks_.Hotplug(HWC_DISPLAY_EXTERNAL,
+    callbacks_.Hotplug(hdmi_is_primary_ ? HWC_DISPLAY_PRIMARY : HWC_DISPLAY_EXTERNAL,
                        connected ? HWC2::Connection::Connected : HWC2::Connection::Disconnected);
   }
 
@@ -1627,6 +1440,8 @@
 
 android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel,
                                                     android::Parcel *output_parcel) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   int dpy = input_parcel->readInt32();
 
   if (dpy < HWC_DISPLAY_PRIMARY || dpy > HWC_DISPLAY_VIRTUAL) {
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index c4c38a5..cd9831d 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -20,8 +20,10 @@
 #ifndef __HWC_SESSION_H__
 #define __HWC_SESSION_H__
 
+#include <vendor/display/config/1.0/IDisplayConfig.h>
 #include <core/core_interface.h>
 #include <utils/locker.h>
+#include <thread>
 
 #include "hwc_callbacks.h"
 #include "hwc_layers.h"
@@ -34,7 +36,10 @@
 
 namespace sdm {
 
-class HWCSession : hwc2_device_t, public qClient::BnQClient {
+using ::vendor::display::config::V1_0::IDisplayConfig;
+using ::android::hardware::Return;
+
+class HWCSession : hwc2_device_t, public IDisplayConfig, public qClient::BnQClient {
  public:
   struct HWCModuleMethods : public hw_module_methods_t {
     HWCModuleMethods() { hw_module_methods_t::open = HWCSession::Open; }
@@ -125,6 +130,44 @@
   int32_t ConnectDisplay(int disp);
   int DisconnectDisplay(int disp);
   int GetVsyncPeriod(int disp);
+  int32_t GetConfigCount(int disp_id, uint32_t *count);
+  int32_t GetActiveConfigIndex(int disp_id, uint32_t *config);
+  int32_t SetActiveConfigIndex(int disp_id, uint32_t config);
+  int32_t ControlPartialUpdate(int dpy, bool enable);
+  int32_t DisplayBWTransactionPending(bool *status);
+  int32_t SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status);
+  int32_t GetPanelBrightness(int *level);
+  int32_t MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level);
+
+  // service methods
+  void StartServices();
+
+  // Methods from ::android::hardware::display::config::V1_0::IDisplayConfig follow.
+  Return<void> isDisplayConnected(IDisplayConfig::DisplayType dpy,
+                                  isDisplayConnected_cb _hidl_cb) override;
+  Return<int32_t> setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,
+                                  IDisplayConfig::DisplayExternalStatus status) override;
+  Return<int32_t> configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,
+                                  uint32_t refreshRate) override;
+  Return<void> getConfigCount(IDisplayConfig::DisplayType dpy,
+                              getConfigCount_cb _hidl_cb) override;
+  Return<void> getActiveConfig(IDisplayConfig::DisplayType dpy,
+                               getActiveConfig_cb _hidl_cb) override;
+  Return<int32_t> setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) override;
+  Return<void> getDisplayAttributes(uint32_t configIndex, IDisplayConfig::DisplayType dpy,
+                                    getDisplayAttributes_cb _hidl_cb) override;
+  Return<int32_t> setPanelBrightness(uint32_t level) override;
+  Return<void> getPanelBrightness(getPanelBrightness_cb _hidl_cb) override;
+  Return<int32_t> minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,
+                                                uint32_t min_enc_level) override;
+  Return<int32_t> refreshScreen() override;
+  Return<int32_t> controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) override;
+  Return<int32_t> toggleScreenUpdate(bool on) override;
+  Return<int32_t> setIdleTimeout(uint32_t value) override;
+  Return<void> getHDRCapabilities(IDisplayConfig::DisplayType dpy,
+                                  getHDRCapabilities_cb _hidl_cb) override;
+  Return<int32_t> setCameraLaunchStatus(uint32_t on) override;
+  Return<void> displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) override;
 
   // QClient methods
   virtual android::status_t notifyCallback(uint32_t command, const android::Parcel *input_parcel,
@@ -133,60 +176,37 @@
   void SetFrameDumpConfig(const android::Parcel *input_parcel);
   android::status_t SetMaxMixerStages(const android::Parcel *input_parcel);
   android::status_t SetDisplayMode(const android::Parcel *input_parcel);
-  android::status_t SetSecondaryDisplayStatus(const android::Parcel *input_parcel,
-                                              android::Parcel *output_parcel);
-  android::status_t ToggleScreenUpdates(const android::Parcel *input_parcel,
-                                        android::Parcel *output_parcel);
   android::status_t ConfigureRefreshRate(const android::Parcel *input_parcel);
   android::status_t QdcmCMDHandler(const android::Parcel *input_parcel,
                                    android::Parcel *output_parcel);
-  android::status_t ControlPartialUpdate(const android::Parcel *input_parcel, android::Parcel *out);
-  android::status_t OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
-                                                   android::Parcel *output_parcel);
-  android::status_t SetPanelBrightness(const android::Parcel *input_parcel,
-                                       android::Parcel *output_parcel);
-  android::status_t GetPanelBrightness(const android::Parcel *input_parcel,
-                                       android::Parcel *output_parcel);
-  // These functions return the actual display config info as opposed to FB
-  android::status_t HandleSetActiveDisplayConfig(const android::Parcel *input_parcel,
-                                                 android::Parcel *output_parcel);
-  android::status_t HandleGetActiveDisplayConfig(const android::Parcel *input_parcel,
-                                                 android::Parcel *output_parcel);
-  android::status_t HandleGetDisplayConfigCount(const android::Parcel *input_parcel,
-                                                android::Parcel *output_parcel);
   android::status_t HandleGetDisplayAttributesForConfig(const android::Parcel *input_parcel,
                                                         android::Parcel *output_parcel);
   android::status_t GetVisibleDisplayRect(const android::Parcel *input_parcel,
                                           android::Parcel *output_parcel);
-
-  android::status_t SetDynamicBWForCamera(const android::Parcel *input_parcel,
-                                          android::Parcel *output_parcel);
-  android::status_t GetBWTransactionStatus(const android::Parcel *input_parcel,
-                                           android::Parcel *output_parcel);
   android::status_t SetMixerResolution(const android::Parcel *input_parcel);
-
   android::status_t SetColorModeOverride(const android::Parcel *input_parcel);
 
   android::status_t SetColorModeById(const android::Parcel *input_parcel);
 
   static Locker locker_;
-  CoreInterface *core_intf_ = NULL;
-  HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {NULL};
+  CoreInterface *core_intf_ = nullptr;
+  HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {nullptr};
   HWCCallbacks callbacks_;
-  pthread_t uevent_thread_;
+  std::thread uevent_thread_;
   bool uevent_thread_exit_ = false;
   const char *uevent_thread_name_ = "HWC_UeventThread";
-  HWCBufferAllocator *buffer_allocator_;
+  HWCBufferAllocator buffer_allocator_;
   HWCBufferSyncHandler buffer_sync_handler_;
-  HWCColorManager *color_mgr_ = NULL;
+  HWCColorManager *color_mgr_ = nullptr;
   bool reset_panel_ = false;
   bool secure_display_active_ = false;
   bool external_pending_connect_ = false;
   bool new_bw_mode_ = false;
   bool need_invalidate_ = false;
   int bw_mode_release_fd_ = -1;
-  qService::QService *qservice_ = NULL;
+  qService::QService *qservice_ = nullptr;
   HWCSocketHandler socket_handler_;
+  bool hdmi_is_primary_ = false;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_session_services.cpp b/sdm/libs/hwc2/hwc_session_services.cpp
new file mode 100644
index 0000000..4b5374f
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_session_services.cpp
@@ -0,0 +1,483 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*    * Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer.
+*    * Redistributions in binary form must reproduce the above
+*      copyright notice, this list of conditions and the following
+*      disclaimer in the documentation and/or other materials provided
+*      with the distribution.
+*    * Neither the name of The Linux Foundation. nor the names of its
+*      contributors may be used to endorse or promote products derived
+*      from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <core/buffer_allocator.h>
+#include <utils/debug.h>
+#include <sync/sync.h>
+#include <profiler.h>
+
+#include "hwc_buffer_sync_handler.h"
+#include "hwc_session.h"
+
+#define __CLASS__ "HWCSession"
+
+namespace sdm {
+
+using ::android::hardware::Void;
+
+void HWCSession::StartServices() {
+  status_t status = IDisplayConfig::registerAsService();
+  if (status != OK) {
+    DLOGW("Could not register IDisplayConfig as service (%d).", status);
+  } else {
+    DLOGI("IDisplayConfig service registration completed.");
+  }
+}
+
+int MapDisplayType(IDisplayConfig::DisplayType dpy) {
+  switch (dpy) {
+    case IDisplayConfig::DisplayType::DISPLAY_PRIMARY:
+      return HWC_DISPLAY_PRIMARY;
+
+    case IDisplayConfig::DisplayType::DISPLAY_EXTERNAL:
+      return HWC_DISPLAY_EXTERNAL;
+
+    case IDisplayConfig::DisplayType::DISPLAY_VIRTUAL:
+      return HWC_DISPLAY_VIRTUAL;
+
+    default:
+      break;
+  }
+
+  return -EINVAL;
+}
+
+HWCDisplay::DisplayStatus MapExternalStatus(IDisplayConfig::DisplayExternalStatus status) {
+  switch (status) {
+    case IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE:
+      return HWCDisplay::kDisplayStatusOffline;
+
+    case IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE:
+      return HWCDisplay::kDisplayStatusOnline;
+
+    case IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE:
+      return HWCDisplay::kDisplayStatusPause;
+
+    case IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME:
+      return HWCDisplay::kDisplayStatusResume;
+
+    default:
+      break;
+  }
+
+  return HWCDisplay::kDisplayStatusInvalid;
+}
+
+// Methods from ::vendor::hardware::display::config::V1_0::IDisplayConfig follow.
+Return<void> HWCSession::isDisplayConnected(IDisplayConfig::DisplayType dpy,
+                                            isDisplayConnected_cb _hidl_cb) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  bool connected = false;
+
+  int disp_id = MapDisplayType(dpy);
+  if (disp_id >= 0) {
+    connected = hwc_display_[disp_id];
+    error = 0;
+  }
+
+  _hidl_cb(error, connected);
+
+  return Void();
+}
+
+int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
+
+  DLOGI("Display = %d, Status = %d", disp_id, status);
+
+  if (disp_id == HWC_DISPLAY_PRIMARY) {
+    DLOGE("Not supported for this display");
+  } else if (!hwc_display_[disp_id]) {
+    DLOGW("Display is not connected");
+  } else {
+    return hwc_display_[disp_id]->SetDisplayStatus(status);
+  }
+
+  return -EINVAL;
+}
+
+Return<int32_t> HWCSession::setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,
+                                                  IDisplayConfig::DisplayExternalStatus status) {
+  return SetSecondaryDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status));
+}
+
+Return<int32_t> HWCSession::configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,
+                                                   uint32_t refreshRate) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+
+  switch (op) {
+    case IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE:
+      return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
+
+    case IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE:
+      return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
+
+    case IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE:
+      return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refreshRate);
+
+    default:
+      DLOGW("Invalid operation %d", op);
+      return -EINVAL;
+  }
+
+  return 0;
+}
+
+int32_t HWCSession::GetConfigCount(int disp_id, uint32_t *count) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id >= 0 && hwc_display_[disp_id]) {
+    return hwc_display_[disp_id]->GetDisplayConfigCount(count);
+  }
+
+  return -EINVAL;
+}
+
+Return<void> HWCSession::getConfigCount(IDisplayConfig::DisplayType dpy,
+                                        getConfigCount_cb _hidl_cb) {
+  uint32_t count = 0;
+  int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &count);
+
+  _hidl_cb(error, count);
+
+  return Void();
+}
+
+int32_t HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id >= 0 && hwc_display_[disp_id]) {
+    return hwc_display_[disp_id]->GetActiveDisplayConfig(config);
+  }
+
+  return -EINVAL;
+}
+
+Return<void> HWCSession::getActiveConfig(IDisplayConfig::DisplayType dpy,
+                                         getActiveConfig_cb _hidl_cb) {
+  uint32_t config = 0;
+  int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &config);
+
+  _hidl_cb(error, config);
+
+  return Void();
+}
+
+int32_t HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
+
+  int32_t error = -EINVAL;
+  if (hwc_display_[disp_id]) {
+    error = hwc_display_[disp_id]->SetActiveDisplayConfig(config);
+    if (!error) {
+      callbacks_.Refresh(0);
+    }
+  }
+
+  return error;
+}
+
+Return<int32_t> HWCSession::setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) {
+  return SetActiveConfigIndex(MapDisplayType(dpy), config);
+}
+
+Return<void> HWCSession::getDisplayAttributes(uint32_t configIndex,
+                                              IDisplayConfig::DisplayType dpy,
+                                              getDisplayAttributes_cb _hidl_cb) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  IDisplayConfig::DisplayAttributes display_attributes = {};
+
+  int disp_id = MapDisplayType(dpy);
+  if (disp_id >= 0 && hwc_display_[disp_id]) {
+    DisplayConfigVariableInfo hwc_display_attributes;
+    error = hwc_display_[disp_id]->GetDisplayAttributesForConfig(static_cast<int>(configIndex),
+                                                                 &hwc_display_attributes);
+    if (!error) {
+      display_attributes.vsyncPeriod = hwc_display_attributes.vsync_period_ns;
+      display_attributes.xRes = hwc_display_attributes.x_pixels;
+      display_attributes.yRes = hwc_display_attributes.y_pixels;
+      display_attributes.xDpi = hwc_display_attributes.x_dpi;
+      display_attributes.yDpi = hwc_display_attributes.y_dpi;
+      display_attributes.panelType = IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT;
+      display_attributes.isYuv = hwc_display_attributes.is_yuv;
+    }
+  }
+
+  return Void();
+}
+
+Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(static_cast<int>(level));
+    if (error) {
+      DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
+    }
+  }
+
+  return error;
+}
+
+int32_t HWCSession::GetPanelBrightness(int *level) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(level);
+    if (error) {
+      DLOGE("Failed to get the panel brightness. Error = %d", error);
+    }
+  }
+
+  return error;
+}
+
+Return<void> HWCSession::getPanelBrightness(getPanelBrightness_cb _hidl_cb) {
+  int level = 0;
+  int32_t error = GetPanelBrightness(&level);
+
+  _hidl_cb(error, static_cast<uint32_t>(level));
+
+  return Void();
+}
+
+int32_t HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  DLOGI("Display %d", disp_id);
+
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
+
+  if (disp_id != HWC_DISPLAY_EXTERNAL) {
+    DLOGE("Not supported for display");
+  } else if (!hwc_display_[disp_id]) {
+    DLOGW("Display is not connected");
+  } else {
+    return hwc_display_[disp_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
+  }
+
+  return -EINVAL;
+}
+
+Return<int32_t> HWCSession::minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,
+                                                          uint32_t min_enc_level) {
+  return MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
+}
+
+Return<int32_t> HWCSession::refreshScreen() {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
+
+  return 0;
+}
+
+int32_t HWCSession::ControlPartialUpdate(int disp_id, bool enable) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (disp_id < 0) {
+    return -EINVAL;
+  }
+
+  if (disp_id != HWC_DISPLAY_PRIMARY) {
+    DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
+    return -EINVAL;
+  }
+
+  HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+  if (!hwc_display) {
+    DLOGE("primary display object is not instantiated");
+    return -EINVAL;
+  }
+
+  uint32_t pending = 0;
+  DisplayError hwc_error = hwc_display->ControlPartialUpdate(enable, &pending);
+
+  if (hwc_error == kErrorNone) {
+    if (!pending) {
+      return 0;
+    }
+  } else if (hwc_error == kErrorNotSupported) {
+    return 0;
+  } else {
+    return -EINVAL;
+  }
+
+  // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
+  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
+
+  // Wait until partial update control is complete
+  int32_t error = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
+
+  return error;
+}
+
+Return<int32_t> HWCSession::controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) {
+  return ControlPartialUpdate(MapDisplayType(dpy), enable);
+}
+
+Return<int32_t> HWCSession::toggleScreenUpdate(bool on) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(on);
+    if (error) {
+      DLOGE("Failed to toggle screen updates = %d. Error = %d", on, error);
+    }
+  }
+
+  return error;
+}
+
+Return<int32_t> HWCSession::setIdleTimeout(uint32_t value) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(value);
+    return 0;
+  }
+
+  return -EINVAL;
+}
+
+Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy,
+                                            getHDRCapabilities_cb _hidl_cb) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  int32_t error = -EINVAL;
+  IDisplayConfig::DisplayHDRCapabilities hdr_caps = {};
+
+  do {
+    int disp_id = MapDisplayType(dpy);
+    if (disp_id < 0) {
+      DLOGE("Invalid display id = %d", disp_id);
+      break;
+    }
+
+    HWCDisplay *hwc_display = hwc_display_[disp_id];
+    if (!hwc_display) {
+      DLOGE("Display = %d is not connected.", disp_id);
+      break;
+    }
+
+    // query number of hdr types
+    uint32_t out_num_types = 0;
+    if (hwc_display->GetHdrCapabilities(&out_num_types, nullptr, nullptr, nullptr, nullptr)
+        != HWC2::Error::None) {
+      break;
+    }
+
+    if (!out_num_types) {
+      error = 0;
+      break;
+    }
+
+    // query hdr caps
+    hdr_caps.supportedHdrTypes.resize(out_num_types);
+
+    float out_max_luminance = 0.0f;
+    float out_max_average_luminance = 0.0f;
+    float out_min_luminance = 0.0f;
+    if (hwc_display->GetHdrCapabilities(&out_num_types, hdr_caps.supportedHdrTypes.data(),
+                                        &out_max_luminance, &out_max_average_luminance,
+                                        &out_min_luminance)
+        == HWC2::Error::None) {
+      error = 0;
+    }
+  } while (false);
+
+  _hidl_cb(error, hdr_caps);
+
+  return Void();
+}
+
+Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  HWBwModes mode = on > 0 ? kBwCamera : kBwDefault;
+
+  // trigger invalidate to apply new bw caps.
+  callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
+
+  if (core_intf_->SetMaxBandwidthMode(mode) != kErrorNone) {
+    return -EINVAL;
+  }
+
+  new_bw_mode_ = true;
+  need_invalidate_ = true;
+
+  return 0;
+}
+
+int32_t HWCSession::DisplayBWTransactionPending(bool *status) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+  if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    if (sync_wait(bw_mode_release_fd_, 0) < 0) {
+      DLOGI("bw_transaction_release_fd is not yet signaled: err= %s", strerror(errno));
+      *status = false;
+    }
+
+    return 0;
+  }
+
+  return -EINVAL;
+}
+
+Return<void> HWCSession::displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) {
+  bool status = true;
+
+  int32_t error = DisplayBWTransactionPending(&status);
+
+  _hidl_cb(error, status);
+
+  return Void();
+}
+
+}  // namespace sdm