Merge "Don't depend on String8 cast to C string" into main
diff --git a/BoardConfigCFlags.mk b/BoardConfigCFlags.mk
index 0b567a9..679f44f 100644
--- a/BoardConfigCFlags.mk
+++ b/BoardConfigCFlags.mk
@@ -9,8 +9,8 @@
 
 LOCAL_CFLAGS += -DUSES_GSCALER
 
-ifeq ($(HWC_SKIP_VALIDATE),true)
-	LOCAL_CFLAGS += -DHWC_SKIP_VALIDATE
+ifeq ($(HWC_NO_SUPPORT_SKIP_VALIDATE),true)
+	LOCAL_CFLAGS += -DHWC_NO_SUPPORT_SKIP_VALIDATE
 endif
 
 ifeq ($(HWC_SUPPORT_COLOR_TRANSFORM), true)
diff --git a/hwc3/Android.mk b/hwc3/Android.mk
index 43538d3..28ed88d 100644
--- a/hwc3/Android.mk
+++ b/hwc3/Android.mk
@@ -28,14 +28,14 @@
 
 LOCAL_CFLAGS += \
 	-DSOC_VERSION=$(soc_ver) \
-	-DLOG_TAG=\"hwc3\"
+	-DLOG_TAG=\"hwc-3\"
 
 # hwc3 re-uses hwc2.2 ComposerResource and libexynosdisplay
-LOCAL_SHARED_LIBRARIES := android.hardware.graphics.composer3-V1-ndk \
+LOCAL_SHARED_LIBRARIES := android.hardware.graphics.composer3-V2-ndk \
 	android.hardware.graphics.composer@2.1-resources \
         android.hardware.graphics.composer@2.2-resources \
 	android.hardware.graphics.composer@2.4 \
-	com.google.hardware.pixel.display-V7-ndk \
+	com.google.hardware.pixel.display-V8-ndk \
 	libbase \
 	libbinder \
 	libbinder_ndk \
@@ -66,6 +66,7 @@
 	$(TOP)/hardware/google/graphics/common/libhwc2.1/libresource \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/include \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1 \
+	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libcolormanager \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libmaindisplay \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index b576b68..c34b13a 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -33,25 +33,11 @@
         return false;
     }
 
-    mCommandEngine = std::make_unique<ComposerCommandEngine>(mHal, mResources.get());
-    if (mCommandEngine == nullptr) {
-        return false;
-    }
-    if (!mCommandEngine->init()) {
-        mCommandEngine = nullptr;
-        return false;
-    }
-
     return true;
 }
 
 ComposerClient::~ComposerClient() {
     DEBUG_FUNC();
-    // not initialized
-    if (!mCommandEngine) {
-        return;
-    }
-
     LOG(DEBUG) << "destroying composer client";
 
     mHal->unregisterEventCallback();
@@ -67,7 +53,7 @@
 // no need to check nullptr for output parameter, the aidl stub code won't pass nullptr
 ndk::ScopedAStatus ComposerClient::createLayer(int64_t display, int32_t bufferSlotCount,
                                                int64_t* layer) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->createLayer(display, layer);
     if (!err) {
         err = mResources->addLayer(display, *layer, bufferSlotCount);
@@ -91,7 +77,7 @@
 }
 
 ndk::ScopedAStatus ComposerClient::destroyLayer(int64_t display, int64_t layer) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->destroyLayer(display, layer);
     if (!err) {
         err = mResources->removeLayer(display, layer);
@@ -100,7 +86,7 @@
 }
 
 ndk::ScopedAStatus ComposerClient::destroyVirtualDisplay(int64_t display) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->destroyVirtualDisplay(display);
     if (!err) {
         err = mResources->removeDisplay(display);
@@ -110,20 +96,33 @@
 
 ndk::ScopedAStatus ComposerClient::executeCommands(const std::vector<DisplayCommand>& commands,
                                                    std::vector<CommandResultPayload>* results) {
-    DEBUG_FUNC();
-    auto err = mCommandEngine->execute(commands, results);
+    int64_t display = commands.empty() ? -1 : commands[0].display;
+    DEBUG_DISPLAY_FUNC(display);
+    ComposerCommandEngine engine(mHal, mResources.get());
+
+    auto err = engine.init();
+    if (err != ::android::NO_ERROR) {
+        LOG(ERROR) << "executeCommands(): init ComposerCommandEngine failed " << err;
+        return TO_BINDER_STATUS(err);
+    }
+
+    err = engine.execute(commands, results);
+    if (err != ::android::NO_ERROR) {
+        LOG(ERROR) << "executeCommands(): execute failed " << err;
+        return TO_BINDER_STATUS(err);
+    }
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getActiveConfig(int64_t display, int32_t* config) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getActiveConfig(display, config);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getColorModes(int64_t display,
                                                  std::vector<ColorMode>* colorModes) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getColorModes(display, colorModes);
     return TO_BINDER_STATUS(err);
 }
@@ -149,14 +148,14 @@
 
 ndk::ScopedAStatus ComposerClient::getDisplayAttribute(int64_t display, int32_t config,
                                                        DisplayAttribute attribute, int32_t* value) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayAttribute(display, config, attribute, value);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayCapabilities(int64_t display,
                                                           std::vector<DisplayCapability>* caps) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayCapabilities(display, caps);
     if (err) {
         return TO_BINDER_STATUS(err);
@@ -177,33 +176,33 @@
 
 ndk::ScopedAStatus ComposerClient::getDisplayConfigs(int64_t display,
                                                      std::vector<int32_t>* configs) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayConfigs(display, configs);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayConnectionType(int64_t display,
                                                             DisplayConnectionType* type) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayConnectionType(display, type);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayIdentificationData(int64_t display,
                                                                 DisplayIdentification* id) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayIdentificationData(display, id);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayName(int64_t display, std::string* name) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayName(display, name);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayVsyncPeriod(int64_t display, int32_t* vsyncPeriod) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayVsyncPeriod(display, vsyncPeriod);
     return TO_BINDER_STATUS(err);
 }
@@ -211,31 +210,37 @@
 ndk::ScopedAStatus ComposerClient::getDisplayedContentSample(int64_t display, int64_t maxFrames,
                                                              int64_t timestamp,
                                                              DisplayContentSample* samples) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayedContentSample(display, maxFrames, timestamp, samples);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayedContentSamplingAttributes(
         int64_t display, DisplayContentSamplingAttributes* attrs) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayedContentSamplingAttributes(display, attrs);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayPhysicalOrientation(int64_t display,
                                                                  common::Transform* orientation) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getDisplayPhysicalOrientation(display, orientation);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getHdrCapabilities(int64_t display, HdrCapabilities* caps) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getHdrCapabilities(display, caps);
     return TO_BINDER_STATUS(err);
 }
 
+ndk::ScopedAStatus ComposerClient::getOverlaySupport(OverlayProperties* caps) {
+    DEBUG_FUNC();
+    auto err = mHal->getOverlaySupport(caps);
+    return TO_BINDER_STATUS(err);
+}
+
 ndk::ScopedAStatus ComposerClient::getMaxVirtualDisplayCount(int32_t* count) {
     DEBUG_FUNC();
     auto err = mHal->getMaxVirtualDisplayCount(count);
@@ -244,42 +249,42 @@
 
 ndk::ScopedAStatus ComposerClient::getPerFrameMetadataKeys(int64_t display,
                                                            std::vector<PerFrameMetadataKey>* keys) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getPerFrameMetadataKeys(display, keys);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getReadbackBufferAttributes(int64_t display,
                                                                ReadbackBufferAttributes* attrs) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getReadbackBufferAttributes(display, attrs);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getReadbackBufferFence(int64_t display,
                                                           ndk::ScopedFileDescriptor* acquireFence) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getReadbackBufferFence(display, acquireFence);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getRenderIntents(int64_t display, ColorMode mode,
                                                     std::vector<RenderIntent>* intents) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getRenderIntents(display, mode, intents);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getSupportedContentTypes(int64_t display,
                                                             std::vector<ContentType>* types) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getSupportedContentTypes(display, types);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getDisplayDecorationSupport(
         int64_t display, std::optional<common::DisplayDecorationSupport>* supportStruct) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     bool support = false;
     auto err = mHal->getRCDLayerSupport(display, support);
     if (err != ::android::OK) {
@@ -306,7 +311,7 @@
 }
 
 ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display, int32_t config) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setActiveConfig(display, config);
     return TO_BINDER_STATUS(err);
 }
@@ -314,63 +319,78 @@
 ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints(
         int64_t display, int32_t config, const VsyncPeriodChangeConstraints& constraints,
         VsyncPeriodChangeTimeline* timeline) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setActiveConfigWithConstraints(display, config, constraints, timeline);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t display, int32_t config) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setBootDisplayConfig(display, config);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::clearBootDisplayConfig(int64_t display) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->clearBootDisplayConfig(display);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::getPreferredBootDisplayConfig(int64_t display, int32_t* config) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->getPreferredBootDisplayConfig(display, config);
     return TO_BINDER_STATUS(err);
 }
 
-ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t display, bool on) {
+ndk::ScopedAStatus ComposerClient::getHdrConversionCapabilities(
+        std::vector<common::HdrConversionCapability>* hdrConversionCapabilities) {
     DEBUG_FUNC();
+    auto err = mHal->getHdrConversionCapabilities(hdrConversionCapabilities);
+    return TO_BINDER_STATUS(err);
+}
+
+ndk::ScopedAStatus ComposerClient::setHdrConversionStrategy(
+        const common::HdrConversionStrategy& hdrConversionStrategy,
+        common::Hdr* preferredHdrOutputType) {
+    DEBUG_FUNC();
+    auto err = mHal->setHdrConversionStrategy(hdrConversionStrategy, preferredHdrOutputType);
+    return TO_BINDER_STATUS(err);
+}
+
+ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t display, bool on) {
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setAutoLowLatencyMode(display, on);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(int64_t display, int32_t count) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mResources->setDisplayClientTargetCacheSize(display, count);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::setColorMode(int64_t display, ColorMode mode,
                                                 RenderIntent intent) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setColorMode(display, mode, intent);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::setContentType(int64_t display, ContentType type) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setContentType(display, type);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::setDisplayedContentSamplingEnabled(
         int64_t display, bool enable, FormatColorComponent componentMask, int64_t maxFrames) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::setPowerMode(int64_t display, PowerMode mode) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setPowerMode(display, mode);
     return TO_BINDER_STATUS(err);
 }
@@ -378,7 +398,7 @@
 ndk::ScopedAStatus ComposerClient::setReadbackBuffer(
         int64_t display, const AidlNativeHandle& aidlBuffer,
         const ndk::ScopedFileDescriptor& releaseFence) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     buffer_handle_t readbackBuffer;
     // Note ownership of the buffer is not passed to resource manager.
     buffer_handle_t buffer = ::android::makeFromAidl(aidlBuffer);
@@ -392,19 +412,35 @@
 }
 
 ndk::ScopedAStatus ComposerClient::setVsyncEnabled(int64_t display, bool enabled) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setVsyncEnabled(display, enabled);
     return TO_BINDER_STATUS(err);
 }
 
 ndk::ScopedAStatus ComposerClient::setIdleTimerEnabled(int64_t display, int32_t timeout) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto err = mHal->setIdleTimerEnabled(display, timeout);
     return TO_BINDER_STATUS(err);
 }
 
+ndk::ScopedAStatus ComposerClient::setRefreshRateChangedCallbackDebugEnabled(int64_t display,
+                                                                             bool enabled) {
+    DEBUG_DISPLAY_FUNC(display);
+    auto err = mHal->setRefreshRateChangedCallbackDebugEnabled(display, enabled);
+    return TO_BINDER_STATUS(err);
+}
+
+void ComposerClient::HalEventCallback::onRefreshRateChangedDebug(
+        const RefreshRateChangedDebugData& data) {
+    DEBUG_DISPLAY_FUNC(data.display);
+    auto ret = mCallback->onRefreshRateChangedDebug(data);
+    if (!ret.isOk()) {
+        LOG(ERROR) << "failed to send onRefreshRateChangedDebug:" << ret.getDescription();
+    }
+}
+
 void ComposerClient::HalEventCallback::onHotplug(int64_t display, bool connected) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     if (connected) {
         if (mResources->hasDisplay(display)) {
             // This is a subsequent hotplug "connected" for a display. This signals a
@@ -426,7 +462,7 @@
 }
 
 void ComposerClient::HalEventCallback::onRefresh(int64_t display) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     mResources->setDisplayMustValidateState(display, true);
     auto ret = mCallback->onRefresh(display);
     if (!ret.isOk()) {
@@ -436,7 +472,7 @@
 
 void ComposerClient::HalEventCallback::onVsync(int64_t display, int64_t timestamp,
                                                int32_t vsyncPeriodNanos) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto ret = mCallback->onVsync(display, timestamp, vsyncPeriodNanos);
     if (!ret.isOk()) {
         LOG(ERROR) << "failed to send onVsync:" << ret.getDescription();
@@ -445,7 +481,7 @@
 
 void ComposerClient::HalEventCallback::onVsyncPeriodTimingChanged(
         int64_t display, const VsyncPeriodChangeTimeline& timeline) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto ret = mCallback->onVsyncPeriodTimingChanged(display, timeline);
     if (!ret.isOk()) {
         LOG(ERROR) << "failed to send onVsyncPeriodTimingChanged:" << ret.getDescription();
@@ -453,7 +489,7 @@
 }
 
 void ComposerClient::HalEventCallback::onVsyncIdle(int64_t display) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto ret = mCallback->onVsyncIdle(display);
     if (!ret.isOk()) {
         LOG(ERROR) << "failed to send onVsyncIdle:" << ret.getDescription();
@@ -461,7 +497,7 @@
 }
 
 void ComposerClient::HalEventCallback::onSeamlessPossible(int64_t display) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     auto ret = mCallback->onSeamlessPossible(display);
     if (!ret.isOk()) {
         LOG(ERROR) << "failed to send onSealmessPossible:" << ret.getDescription();
@@ -469,7 +505,7 @@
 }
 
 void ComposerClient::HalEventCallback::cleanDisplayResources(int64_t display) {
-    DEBUG_FUNC();
+    DEBUG_DISPLAY_FUNC(display);
     size_t cacheSize;
     auto err = mResources->getDisplayClientTargetCacheSize(display, &cacheSize);
     if (!err) {
diff --git a/hwc3/ComposerClient.h b/hwc3/ComposerClient.h
index 855fb8b..7a76fa4 100644
--- a/hwc3/ComposerClient.h
+++ b/hwc3/ComposerClient.h
@@ -49,6 +49,7 @@
                                           const VsyncPeriodChangeTimeline& timeline) override;
           void onVsyncIdle(int64_t display) override;
           void onSeamlessPossible(int64_t display) override;
+          void onRefreshRateChangedDebug(const RefreshRateChangedDebugData& data) override;
 
       private:
         void cleanDisplayResources(int64_t display);
@@ -92,6 +93,7 @@
     ndk::ScopedAStatus getDisplayPhysicalOrientation(int64_t display,
                                                      common::Transform* orientation) override;
     ndk::ScopedAStatus getHdrCapabilities(int64_t display, HdrCapabilities* caps) override;
+    ndk::ScopedAStatus getOverlaySupport(OverlayProperties* caps) override;
     ndk::ScopedAStatus getMaxVirtualDisplayCount(int32_t* count) override;
     ndk::ScopedAStatus getPerFrameMetadataKeys(int64_t display,
                                                std::vector<PerFrameMetadataKey>* keys) override;
@@ -114,6 +116,10 @@
     ndk::ScopedAStatus setBootDisplayConfig(int64_t display, int32_t config) override;
     ndk::ScopedAStatus clearBootDisplayConfig(int64_t display) override;
     ndk::ScopedAStatus getPreferredBootDisplayConfig(int64_t display, int32_t* config) override;
+    ndk::ScopedAStatus getHdrConversionCapabilities(
+            std::vector<common::HdrConversionCapability>*) override;
+    ndk::ScopedAStatus setHdrConversionStrategy(const common::HdrConversionStrategy&,
+                                                common::Hdr* preferredHdrOutputType) override;
     ndk::ScopedAStatus setAutoLowLatencyMode(int64_t display, bool on) override;
     ndk::ScopedAStatus setClientTargetSlotCount(int64_t display, int32_t count) override;
     ndk::ScopedAStatus setColorMode(int64_t display, ColorMode mode, RenderIntent intent) override;
@@ -126,6 +132,8 @@
                                          const ndk::ScopedFileDescriptor& releaseFence) override;
     ndk::ScopedAStatus setVsyncEnabled(int64_t display, bool enabled) override;
     ndk::ScopedAStatus setIdleTimerEnabled(int64_t display, int32_t timeout) override;
+    ndk::ScopedAStatus setRefreshRateChangedCallbackDebugEnabled(int64_t /* display */,
+                                                                 bool /* enabled */) override;
 
 protected:
     ::ndk::SpAIBinder createBinder() override;
@@ -135,7 +143,6 @@
 
     IComposerHal* mHal;
     std::unique_ptr<IResourceManager> mResources;
-    std::unique_ptr<ComposerCommandEngine> mCommandEngine;
     std::function<void()> mOnClientDestroyed;
     std::unique_ptr<HalEventCallback> mHalEventCallback;
 };
diff --git a/hwc3/ComposerCommandEngine.cpp b/hwc3/ComposerCommandEngine.cpp
index 4b3a1a3..8b0f005 100644
--- a/hwc3/ComposerCommandEngine.cpp
+++ b/hwc3/ComposerCommandEngine.cpp
@@ -55,9 +55,9 @@
         }                                                                         \
     } while (0)
 
-bool ComposerCommandEngine::init() {
+int32_t ComposerCommandEngine::init() {
     mWriter = std::make_unique<ComposerServiceWriter>();
-    return (mWriter != nullptr);
+    return (mWriter != nullptr) ? ::android::NO_ERROR : ::android::NO_MEMORY;
 }
 
 int32_t ComposerCommandEngine::execute(const std::vector<DisplayCommand>& commands,
@@ -232,16 +232,12 @@
 void ComposerCommandEngine::executePresentOrValidateDisplay(
         int64_t display, const std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
     executeSetExpectedPresentTimeInternal(display, expectedPresentTime);
-
-    int err;
     // First try to Present as is.
-    if (mHal->hasCapability(Capability::SKIP_VALIDATE)) {
-        err = mResources->mustValidateDisplay(display) ? IComposerClient::EX_NOT_VALIDATED
-                                                       : executePresentDisplay(display);
-        if (!err) {
-            mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Presented);
-            return;
-        }
+    auto err = mResources->mustValidateDisplay(display) ? IComposerClient::EX_NOT_VALIDATED
+                                                        : executePresentDisplay(display);
+    if (!err) {
+        mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Presented);
+        return;
     }
 
     // Fallback to validate
diff --git a/hwc3/ComposerCommandEngine.h b/hwc3/ComposerCommandEngine.h
index ae68285..872c7e5 100644
--- a/hwc3/ComposerCommandEngine.h
+++ b/hwc3/ComposerCommandEngine.h
@@ -30,7 +30,7 @@
   public:
       ComposerCommandEngine(IComposerHal* hal, IResourceManager* resources)
             : mHal(hal), mResources(resources) {}
-      bool init();
+      int32_t init();
 
       int32_t execute(const std::vector<DisplayCommand>& commands,
                       std::vector<CommandResultPayload>* result);
diff --git a/hwc3/Util.h b/hwc3/Util.h
index 5305787..76e0f2d 100644
--- a/hwc3/Util.h
+++ b/hwc3/Util.h
@@ -28,14 +28,26 @@
                                            FullMethodName{ __PRETTY_FUNCTION__ };           \
                      constexpr static const char *__kFullName__ =  __kFullNameObj__.get();  \
                      ATRACE_NAME(__kFullName__)
+
+#define DEBUG_DISPLAY_FUNC(display)                                                     \
+    constexpr static FullMethodName __kFullNameObj__{__PRETTY_FUNCTION__};              \
+    constexpr static const char *__kFullName__ = __kFullNameObj__.get();                \
+    if (CC_UNLIKELY(ATRACE_ENABLED())) {                                                \
+        ::android::String8 _traceName_;                                                 \
+        _traceName_.appendFormat("%s(display=%" PRId64 ",..)", __kFullName__, display); \
+        ATRACE_BEGIN(_traceName_.c_str());                                              \
+    }                                                                                   \
+    ScopedTraceEnder _traceEnder_
 #else
 
 #ifdef LOG_FUNC
-#define DEBUG_FUNC() DebugFunction _dbgFnObj_(__func__)
+#define DEBUG_DISPLAY_FUNC(display) DebugFunction _dbgFnObj_(__func__, display)
 #else
-#define DEBUG_FUNC()
+#define DEBUG_DISPLAY_FUNC(display)
 #endif
 
+#define DEBUG_FUNC() DEBUG_DISPLAY_FUNC(std::nullopt)
+
 #endif
 
 #define RET_IF_ERR(expr)                  \
@@ -51,14 +63,33 @@
 
 namespace aidl::android::hardware::graphics::composer3::impl {
 
+class ScopedTraceEnder {
+public:
+    ~ScopedTraceEnder() { ATRACE_END(); }
+};
+
 class DebugFunction {
 public:
-    DebugFunction(const char* name) : mName(name) { LOG(INFO) << mName << " Enter"; }
+    DebugFunction(const char *name, std::optional<int64_t> display)
+          : mName(name), mDisplay(display) {
+        if (mDisplay) {
+            LOG(INFO) << mName << "(display=" << *mDisplay << ",..) Enter";
+        } else {
+            LOG(INFO) << mName << " Enter";
+        }
+    }
 
-    ~DebugFunction() { LOG(INFO) << mName << " Exit"; }
+    ~DebugFunction() {
+        if (mDisplay) {
+            LOG(INFO) << mName << "(display=" << *mDisplay << ",..) Exit";
+        } else {
+            LOG(INFO) << mName << " Exit";
+        }
+    }
 
 private:
     const char* mName;
+    std::optional<int64_t> mDisplay;
 };
 
 class FullMethodName {
diff --git a/hwc3/hwc3-default.xml b/hwc3/hwc3-default.xml
index 05a7c09..fd9e638 100644
--- a/hwc3/hwc3-default.xml
+++ b/hwc3/hwc3-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.graphics.composer3</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
diff --git a/hwc3/impl/HalImpl.cpp b/hwc3/impl/HalImpl.cpp
index c3011f9..93cc6ad 100644
--- a/hwc3/impl/HalImpl.cpp
+++ b/hwc3/impl/HalImpl.cpp
@@ -99,6 +99,20 @@
     hal->getEventCallback()->onSeamlessPossible(display);
 }
 
+void refreshRateChangedDebug(hwc2_callback_data_t callbackData, hwc2_display_t hwcDisplay,
+                             hwc2_vsync_period_t hwcVsyncPeriodNanos) {
+    auto hal = static_cast<HalImpl*>(callbackData);
+    int64_t display;
+    int32_t vsyncPeriodNanos;
+
+    h2a::translate(hwcDisplay, display);
+    h2a::translate(hwcVsyncPeriodNanos, vsyncPeriodNanos);
+    hal->getEventCallback()->onRefreshRateChangedDebug(RefreshRateChangedDebugData{
+            .display = display,
+            .vsyncPeriodNanos = vsyncPeriodNanos,
+    });
+}
+
 } // nampesapce hook
 
 HalImpl::HalImpl(std::unique_ptr<ExynosDevice> device) : mDevice(std::move(device)) {
@@ -130,6 +144,7 @@
     }
 
     mCaps.insert(Capability::BOOT_DISPLAY_CONFIG);
+    mCaps.insert(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG);
 }
 
 int32_t HalImpl::getHalDisplay(int64_t display, ExynosDisplay*& halDisplay) {
@@ -193,6 +208,9 @@
     // register HWC3 Callback
     mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onVsyncIdle, this,
                                   reinterpret_cast<hwc2_function_pointer_t>(hook::vsyncIdle));
+    mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug, this,
+                                  reinterpret_cast<hwc2_function_pointer_t>(
+                                          hook::refreshRateChangedDebug));
 }
 
 void HalImpl::unregisterEventCallback() {
@@ -204,6 +222,8 @@
 
     // unregister HWC3 Callback
     mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onVsyncIdle, this, nullptr);
+    mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug, this,
+                                  nullptr);
 
     mEventCallback = nullptr;
 }
@@ -457,6 +477,10 @@
     return HWC2_ERROR_NONE;
 }
 
+int32_t HalImpl::getOverlaySupport(OverlayProperties* caps) {
+    return mDevice->getOverlaySupport(caps);
+}
+
 int32_t HalImpl::getMaxVirtualDisplayCount(int32_t* count) {
     uint32_t hwcCount = mDevice->getMaxVirtualDisplayCount();
     h2a::translate(hwcCount, *count);
@@ -558,10 +582,10 @@
 
    // TODO: not expect acceptDisplayChanges if there are no changes to accept
     if (halDisplay->mRenderingState == RENDERING_STATE_VALIDATED) {
-        LOG(INFO) << halDisplay->mDisplayName.string()
+        LOG(INFO) << halDisplay->mDisplayName.c_str()
                    << ": acceptDisplayChanges was not called";
         if (halDisplay->acceptDisplayChanges() != HWC2_ERROR_NONE) {
-            LOG(ERROR) << halDisplay->mDisplayName.string()
+            LOG(ERROR) << halDisplay->mDisplayName.c_str()
             << ": acceptDisplayChanges is failed";
         }
     }
@@ -632,6 +656,14 @@
     return halDisplay->getPreferredBootDisplayConfig(config);
 }
 
+int32_t HalImpl::getHdrConversionCapabilities(std::vector<common::HdrConversionCapability>*) {
+    return HWC2_ERROR_UNSUPPORTED;
+}
+
+int32_t HalImpl::setHdrConversionStrategy(const common::HdrConversionStrategy&, common::Hdr*) {
+    return HWC2_ERROR_UNSUPPORTED;
+}
+
 int32_t HalImpl::setAutoLowLatencyMode(int64_t display, bool on) {
     ExynosDisplay* halDisplay;
     RET_IF_ERR(getHalDisplay(display, halDisplay));
@@ -1045,4 +1077,18 @@
     return halDisplay->getDisplayIdleTimerSupport(outSupport);
 }
 
+int32_t HalImpl::getDisplayMultiThreadedPresentSupport(const int64_t& display, bool& outSupport) {
+    ExynosDisplay* halDisplay;
+    RET_IF_ERR(getHalDisplay(display, halDisplay));
+
+    return halDisplay->getDisplayMultiThreadedPresentSupport(outSupport);
+}
+
+int32_t HalImpl::setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled) {
+    ExynosDisplay* halDisplay;
+    RET_IF_ERR(getHalDisplay(display, halDisplay));
+
+    return halDisplay->setRefreshRateChangedCallbackDebugEnabled(enabled);
+}
+
 } // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/impl/HalImpl.h b/hwc3/impl/HalImpl.h
index f772ca4..9cb8f1d 100644
--- a/hwc3/impl/HalImpl.h
+++ b/hwc3/impl/HalImpl.h
@@ -71,6 +71,7 @@
     int32_t getDisplayPhysicalOrientation(int64_t display, common::Transform* orientation) override;
     int32_t getDozeSupport(int64_t display, bool& outSupport) override;
     int32_t getHdrCapabilities(int64_t display, HdrCapabilities* caps) override;
+    int32_t getOverlaySupport(OverlayProperties* caps) override;
     int32_t getMaxVirtualDisplayCount(int32_t* count) override;
     int32_t getPerFrameMetadataKeys(int64_t display,
                                     std::vector<PerFrameMetadataKey>* keys) override;
@@ -92,6 +93,8 @@
     int32_t setBootDisplayConfig(int64_t display, int32_t config) override;
     int32_t clearBootDisplayConfig(int64_t display) override;
     int32_t getPreferredBootDisplayConfig(int64_t display, int32_t* config) override;
+    int32_t getHdrConversionCapabilities(std::vector<common::HdrConversionCapability>*) override;
+    int32_t setHdrConversionStrategy(const common::HdrConversionStrategy&, common::Hdr*) override;
     int32_t setAutoLowLatencyMode(int64_t display, bool on) override;
     int32_t setClientTarget(int64_t display, buffer_handle_t target,
                             const ndk::ScopedFileDescriptor& fence, common::Dataspace dataspace,
@@ -136,6 +139,8 @@
                               const ndk::ScopedFileDescriptor& releaseFence) override;
     int32_t setVsyncEnabled(int64_t display, bool enabled) override;
     int32_t getDisplayIdleTimerSupport(int64_t display, bool& outSupport) override;
+    int32_t getDisplayMultiThreadedPresentSupport(const int64_t& display,
+                                                  bool& outSupport) override;
     int32_t setIdleTimerEnabled(int64_t display, int32_t timeout) override;
     int32_t getRCDLayerSupport(int64_t display, bool& outSupport) override;
     int32_t setLayerBlockingRegion(
@@ -153,6 +158,7 @@
             const std::optional<ClockMonotonicTimestamp> expectedPresentTime) override;
 
     EventCallback* getEventCallback() { return mEventCallback; }
+    int32_t setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled) override;
 
 private:
     void initCaps();
diff --git a/hwc3/include/IComposerHal.h b/hwc3/include/IComposerHal.h
index 6fe25c5..9a9108f 100644
--- a/hwc3/include/IComposerHal.h
+++ b/hwc3/include/IComposerHal.h
@@ -25,6 +25,9 @@
 #include <aidl/android/hardware/graphics/common/ColorTransform.h>
 #include <aidl/android/hardware/graphics/common/Dataspace.h>
 #include <aidl/android/hardware/graphics/common/FRect.h>
+#include <aidl/android/hardware/graphics/common/Hdr.h>
+#include <aidl/android/hardware/graphics/common/HdrConversionCapability.h>
+#include <aidl/android/hardware/graphics/common/HdrConversionStrategy.h>
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <aidl/android/hardware/graphics/common/Point.h>
 #include <aidl/android/hardware/graphics/common/Rect.h>
@@ -55,6 +58,7 @@
 #include <aidl/android/hardware/graphics/composer3/HdrCapabilities.h>
 #include <aidl/android/hardware/graphics/composer3/LayerBrightness.h>
 #include <aidl/android/hardware/graphics/composer3/LayerCommand.h>
+#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h>
 #include <aidl/android/hardware/graphics/composer3/ParcelableBlendMode.h>
 #include <aidl/android/hardware/graphics/composer3/ParcelableComposition.h>
 #include <aidl/android/hardware/graphics/composer3/ParcelableDataspace.h>
@@ -67,6 +71,7 @@
 #include <aidl/android/hardware/graphics/composer3/PresentFence.h>
 #include <aidl/android/hardware/graphics/composer3/PresentOrValidate.h>
 #include <aidl/android/hardware/graphics/composer3/ReadbackBufferAttributes.h>
+#include <aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.h>
 #include <aidl/android/hardware/graphics/composer3/ReleaseFences.h>
 #include <aidl/android/hardware/graphics/composer3/RenderIntent.h>
 #include <aidl/android/hardware/graphics/composer3/VirtualDisplay.h>
@@ -102,6 +107,7 @@
                                                 const VsyncPeriodChangeTimeline& timeline) = 0;
         virtual void onVsyncIdle(int64_t display) = 0;
         virtual void onSeamlessPossible(int64_t display) = 0;
+        virtual void onRefreshRateChangedDebug(const RefreshRateChangedDebugData& data) = 0;
     };
     virtual void registerEventCallback(EventCallback* callback) = 0;
     virtual void unregisterEventCallback() = 0;
@@ -121,7 +127,8 @@
                                       DisplayAttribute attribute, int32_t* outValue) = 0;
     virtual int32_t getDisplayBrightnessSupport(int64_t display, bool& outSupport) = 0;
     virtual int32_t getDisplayIdleTimerSupport(int64_t display, bool& outSupport) = 0;
-
+    virtual int32_t getDisplayMultiThreadedPresentSupport(const int64_t& display,
+                                                          bool& outSupport) = 0;
     virtual int32_t getDisplayCapabilities(int64_t display,
                                            std::vector<DisplayCapability>* caps) = 0;
     virtual int32_t getDisplayConfigs(int64_t display, std::vector<int32_t>* configs) = 0;
@@ -137,6 +144,7 @@
                                                   common::Transform* orientation) = 0;
     virtual int32_t getDozeSupport(int64_t display, bool& outSupport) = 0;
     virtual int32_t getHdrCapabilities(int64_t display, HdrCapabilities* caps) = 0;
+    virtual int32_t getOverlaySupport(OverlayProperties* caps) = 0;
     virtual int32_t getMaxVirtualDisplayCount(int32_t* count) = 0;
     virtual int32_t getPerFrameMetadataKeys(int64_t display,
                                             std::vector<PerFrameMetadataKey>* keys) = 0;
@@ -158,6 +166,9 @@
     virtual int32_t setBootDisplayConfig(int64_t display, int32_t config) = 0;
     virtual int32_t clearBootDisplayConfig(int64_t display) = 0;
     virtual int32_t getPreferredBootDisplayConfig(int64_t display, int32_t* config) = 0;
+    virtual int32_t getHdrConversionCapabilities(std::vector<common::HdrConversionCapability>*) = 0;
+    virtual int32_t setHdrConversionStrategy(const common::HdrConversionStrategy&,
+                                             common::Hdr*) = 0;
     virtual int32_t setAutoLowLatencyMode(int64_t display, bool on) = 0;
     virtual int32_t setClientTarget(int64_t display, buffer_handle_t target,
                                     const ndk::ScopedFileDescriptor& fence,
@@ -220,6 +231,7 @@
     virtual int32_t setLayerBlockingRegion(
             int64_t display, int64_t layer,
             const std::vector<std::optional<common::Rect>>& blockingRegion) = 0;
+    virtual int32_t setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled) = 0;
 };
 
 } // namespace aidl::android::hardware::graphics::composer3::detail
diff --git a/include/displaycolor/displaycolor.h b/include/displaycolor/displaycolor.h
index 0856add..f23d8a8 100644
--- a/include/displaycolor/displaycolor.h
+++ b/include/displaycolor/displaycolor.h
@@ -34,6 +34,7 @@
 /**
  * hwc/displaycolor interface history
  *
+ * 7.0.0.2022-03-22 Interface refactor
  * 6.2.0.2022-05-18 Get calibrated serial number.
  * 6.1.0.2022-04-29 dim solid color layer
  * 6.0.0.2022-02-22 Get whether dimming in linear.
@@ -61,8 +62,8 @@
     }
 
 } kInterfaceVersion {
-    6,
-    2,
+    7,
+    0,
     0,
 };
 
@@ -345,6 +346,13 @@
         const ConfigType *config = nullptr;
     };
 
+    /// A collection of stages. For example, It could be pre-blending stages
+    //(per-channel) or post-blending stages.
+    template <typename ... IStageData>
+    struct IStageDataCollection : public IStageData ... {
+        virtual ~IStageDataCollection() {}
+    };
+
     /// Interface for accessing data for panel
     class IPanel {
       public:
@@ -364,7 +372,7 @@
      * @param scene Display scene data to use during the update.
      * @return OK if successful, error otherwise.
      */
-    virtual int Update(DisplayType display, const DisplayScene &scene) = 0;
+    virtual int Update(const DisplayType display, const DisplayScene &scene) = 0;
 
     /**
      * @brief Update display color data. This function is expected to be called
@@ -375,29 +383,27 @@
      * @param scene Display scene data to use during the update.
      * @return OK if successful, error otherwise.
      */
-    virtual int UpdatePresent(DisplayType display, const DisplayScene &scene) = 0;
+    virtual int UpdatePresent(const DisplayType display, const DisplayScene &scene) = 0;
 
     /**
      * @brief Check if refresh rate regamma compensation is enabled.
      *
      * @return true for yes.
      */
-    virtual bool IsRrCompensationEnabled(DisplayType display) = 0;
+    virtual bool IsRrCompensationEnabled(const DisplayType display) = 0;
 
     /**
      * @brief Get calibration information for each profiles.
      * @param display The display to get the calibration information.
      */
-    virtual const CalibrationInfo &GetCalibrationInfo(
-        DisplayType display) const = 0;
+    virtual const CalibrationInfo &GetCalibrationInfo(const DisplayType display) const = 0;
 
     /**
      * @brief Get a map of supported ColorModes, and supported RenderIntents for
      * each ColorMode.
      * @param display The display to get the color modes and render intents.
      */
-    virtual const ColorModesMap &ColorModesAndRenderIntents(
-        DisplayType display) const = 0;
+    virtual const ColorModesMap &ColorModesAndRenderIntents(const DisplayType display) const = 0;
 
     /**
      * @brief Get pixel format and dataspace of blending stage.
@@ -406,7 +412,7 @@
      * @param dataspace Dataspace of blending stage
      * @return OK if successful, error otherwise.
      */
-    virtual int GetBlendingProperty(DisplayType display,
+    virtual int GetBlendingProperty(const DisplayType display,
                                     hwc::PixelFormat &pixel_format,
                                     hwc::Dataspace &dataspace,
                                     bool &dimming_linear) const = 0;
diff --git a/libacryl/Android.mk b/libacryl/Android.mk
index abbc2f2..2984d2d 100644
--- a/libacryl/Android.mk
+++ b/libacryl/Android.mk
@@ -16,7 +16,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_CFLAGS += -DLOG_TAG=\"libacryl\"
+LOCAL_CFLAGS += -DLOG_TAG=\"hwc-libacryl\"
 #LOCAL_CFLAGS += -DLIBACRYL_DEBUG
 
 ifdef BOARD_LIBACRYL_DEFAULT_COMPOSITOR
@@ -47,6 +47,7 @@
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/local_include
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libcap
 
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 
diff --git a/libacryl/acrylic_factory.cpp b/libacryl/acrylic_factory.cpp
index 7242ecd..b59f409 100644
--- a/libacryl/acrylic_factory.cpp
+++ b/libacryl/acrylic_factory.cpp
@@ -23,181 +23,16 @@
 
 #include "acrylic_g2d.h"
 #include "acrylic_internal.h"
-
-static uint32_t all_fimg2d_gs101_formats[] = {
-    HAL_PIXEL_FORMAT_RGBA_8888,
-    HAL_PIXEL_FORMAT_BGRA_8888,
-    HAL_PIXEL_FORMAT_RGBA_1010102,
-    HAL_PIXEL_FORMAT_RGBX_8888,
-    HAL_PIXEL_FORMAT_RGB_888,
-    HAL_PIXEL_FORMAT_RGB_565,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P,
-    HAL_PIXEL_FORMAT_YCrCb_420_SP,                  // NV21 (YVU420 semi-planar)
-    HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M,         // NV21 on multi-buffer
-    HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_FULL,    // NV21 on multi-buffer
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP,           // NV12 (YUV420 semi-planar)
-    HAL_PIXEL_FORMAT_GOOGLE_NV12_SP,                // NV12 (YUV420 semi-planar)
-    MALI_GRALLOC_FORMAT_INTERNAL_YUV420_8BIT_I,     // NV12 AFBC
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN,          // NV12 with MFC alignment constraints
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M,         // NV12M with MFC alignment constraints on multi-buffer
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_PRIV,    // NV12M with MFC alignment constraints on multi-buffer
-    HAL_PIXEL_FORMAT_YCbCr_422_SP,                  // YUV422 2P (YUV422 semi-planar)
-    HAL_PIXEL_FORMAT_YCBCR_P010,
-    HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B,
-    MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_10B_SBWC,
-};
-
-static uint32_t all_fimg2d_gs201_formats[] = {
-    HAL_PIXEL_FORMAT_RGBA_8888,
-    HAL_PIXEL_FORMAT_BGRA_8888,
-    HAL_PIXEL_FORMAT_RGBA_1010102,
-    HAL_PIXEL_FORMAT_RGBX_8888,
-    HAL_PIXEL_FORMAT_RGB_888,
-    HAL_PIXEL_FORMAT_RGB_565,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P,
-    HAL_PIXEL_FORMAT_YCrCb_420_SP,                  // NV21 (YVU420 semi-planar)
-    HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M,         // NV21 on multi-buffer
-    HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_FULL,    // NV21 on multi-buffer
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP,           // NV12 (YUV420 semi-planar)
-    HAL_PIXEL_FORMAT_GOOGLE_NV12_SP,                // NV12 (YUV420 semi-planar)
-    MALI_GRALLOC_FORMAT_INTERNAL_YUV420_8BIT_I,     // NV12 AFBC
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN,          // NV12 with MFC alignment constraints
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M,         // NV12M with MFC alignment constraints on multi-buffer
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_PRIV,    // NV12M with MFC alignment constraints on multi-buffer
-    HAL_PIXEL_FORMAT_YCbCr_422_SP,                  // YUV422 2P (YUV422 semi-planar)
-    HAL_PIXEL_FORMAT_YCBCR_P010,
-    HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B,
-    MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_10B_SBWC,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L50,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L75,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC_L50,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC_L75,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L40,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L60,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L80,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC_L40,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC_L60,
-    HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC_L80,
-};
-
-// The presence of the dataspace definitions are in the order
-// of application's preference to reduce comparations.
-static int all_hwc_dataspaces[] = {
-    HAL_DATASPACE_STANDARD_BT709,
-    HAL_DATASPACE_STANDARD_BT709 | HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_STANDARD_BT709 | HAL_DATASPACE_RANGE_LIMITED,
-    HAL_DATASPACE_STANDARD_BT2020,
-    HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_RANGE_LIMITED,
-    HAL_DATASPACE_STANDARD_BT601_625,
-    HAL_DATASPACE_STANDARD_BT601_625 | HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_STANDARD_BT601_625 | HAL_DATASPACE_RANGE_LIMITED,
-    HAL_DATASPACE_STANDARD_BT601_525,
-    HAL_DATASPACE_STANDARD_BT601_525 | HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_STANDARD_BT601_525 | HAL_DATASPACE_RANGE_LIMITED,
-    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED,
-    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED | HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED | HAL_DATASPACE_RANGE_LIMITED,
-    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED,
-    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED | HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED | HAL_DATASPACE_RANGE_LIMITED,
-    HAL_DATASPACE_STANDARD_DCI_P3,
-    HAL_DATASPACE_STANDARD_DCI_P3 | HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_STANDARD_DCI_P3 | HAL_DATASPACE_RANGE_LIMITED,
-    HAL_DATASPACE_STANDARD_FILM,
-    HAL_DATASPACE_STANDARD_FILM | HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_STANDARD_FILM | HAL_DATASPACE_RANGE_LIMITED,
-    // 0 should be treated as BT709 Limited range
-    0,
-    HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_RANGE_LIMITED,
-    // Depricated legacy dataspace definitions
-    HAL_DATASPACE_SRGB,
-    HAL_DATASPACE_JFIF,
-    HAL_DATASPACE_BT601_525,
-    HAL_DATASPACE_BT601_625,
-    HAL_DATASPACE_BT709,
-};
-
-const static stHW2DCapability __capability_fimg2d_gs101 = {
-    .max_upsampling_num = {8, 8},
-    .max_downsampling_factor = {4, 4},
-    .max_upsizing_num = {8, 8},
-    .max_downsizing_factor = {4, 4},
-    .min_src_dimension = {1, 1},
-    .max_src_dimension = {8192, 8192},
-    .min_dst_dimension = {1, 1},
-    .max_dst_dimension = {8192, 8192},
-    .min_pix_align = {1, 1},
-    .rescaling_count = 0,
-    .compositing_mode = HW2DCapability::BLEND_NONE | HW2DCapability::BLEND_SRC_COPY | HW2DCapability::BLEND_SRC_OVER,
-    .transform_type = HW2DCapability::TRANSFORM_ALL,
-    .auxiliary_feature = HW2DCapability::FEATURE_PLANE_ALPHA | HW2DCapability::FEATURE_UORDER_WRITE
-                         | HW2DCapability::FEATURE_AFBC_ENCODE | HW2DCapability::FEATURE_AFBC_DECODE
-                         | HW2DCapability::FEATURE_SOLIDCOLOR,
-    .num_formats = ARRSIZE(all_fimg2d_gs101_formats),
-    .num_dataspaces = ARRSIZE(all_hwc_dataspaces),
-    .max_layers = 4,
-    .pixformats = all_fimg2d_gs101_formats,
-    .dataspaces = all_hwc_dataspaces,
-    .base_align = 1,
-};
-
-const static stHW2DCapability __capability_fimg2d_gs201 = {
-    .max_upsampling_num = {8, 8},
-    .max_downsampling_factor = {4, 4},
-    .max_upsizing_num = {8, 8},
-    .max_downsizing_factor = {4, 4},
-    .min_src_dimension = {1, 1},
-    .max_src_dimension = {8192, 8192},
-    .min_dst_dimension = {1, 1},
-    .max_dst_dimension = {8192, 8192},
-    .min_pix_align = {1, 1},
-    .rescaling_count = 0,
-    .compositing_mode = HW2DCapability::BLEND_NONE | HW2DCapability::BLEND_SRC_COPY | HW2DCapability::BLEND_SRC_OVER,
-    .transform_type = HW2DCapability::TRANSFORM_ALL,
-    .auxiliary_feature = HW2DCapability::FEATURE_PLANE_ALPHA | HW2DCapability::FEATURE_UORDER_WRITE
-                         | HW2DCapability::FEATURE_AFBC_ENCODE | HW2DCapability::FEATURE_AFBC_DECODE
-                         | HW2DCapability::FEATURE_SOLIDCOLOR,
-    .num_formats = ARRSIZE(all_fimg2d_gs201_formats),
-    .num_dataspaces = ARRSIZE(all_hwc_dataspaces),
-    .max_layers = 4,
-    .pixformats = all_fimg2d_gs201_formats,
-    .dataspaces = all_hwc_dataspaces,
-    .base_align = 1,
-};
-
-static const HW2DCapability capability_fimg2d_gs101(__capability_fimg2d_gs101);
-
-static const HW2DCapability capability_fimg2d_gs201(__capability_fimg2d_gs201);
+#include "acrylic_capability.h"
 
 Acrylic *Acrylic::createInstance(const char *spec)
 {
     Acrylic *compositor = nullptr;
 
     ALOGD_TEST("Creating a new Acrylic instance of '%s'", spec);
-
-    if (strcmp(spec, "fimg2d_gs101") == 0) {
-        compositor = new AcrylicCompositorG2D(capability_fimg2d_gs101, true);
-    } else if (strcmp(spec, "fimg2d_gs201") == 0) {
-        compositor = new AcrylicCompositorG2D(capability_fimg2d_gs201, true);
-    } else {
-        ALOGE("Unknown HW2D compositor spec., %s", spec);
-        return nullptr;
+    compositor = createAcrylicCompositorG2D(spec);
+    if (compositor) {
+        ALOGI("%s compositor added", spec);
     }
 
     ALOGE_IF(!compositor, "Failed to create HW2D compositor of '%s'", spec);
diff --git a/libacryl/acrylic_formats.cpp b/libacryl/acrylic_formats.cpp
index bb004fe..b7be04e 100644
--- a/libacryl/acrylic_formats.cpp
+++ b/libacryl/acrylic_formats.cpp
@@ -91,6 +91,7 @@
     {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_S10B,      V4L2_PIX_FMT_NV12N_10B      },
     {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_S10B,     V4L2_PIX_FMT_NV12M_S10B     },
     {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M,            V4L2_PIX_FMT_NV12M_P010     },
+    {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN,          V4L2_PIX_FMT_NV12_P010      },
     {HAL_PIXEL_FORMAT_YCBCR_P010,                     V4L2_PIX_FMT_NV12_P010      },
     {HAL_PIXEL_FORMAT_YCbCr_422_I,                    V4L2_PIX_FMT_YUYV           },
     {HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_I,             V4L2_PIX_FMT_YVYU           },
@@ -172,6 +173,7 @@
     {HAL_PIXEL_FORMAT_YCBCR_P010,                       1, 0x22, {24, 0, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010,                    2},
     {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M,              2, 0x22, {16, 8, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010,                    2},
     {HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B,               1, 0x22, {24, 0, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010,                    2},
+    {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN,            1, 0x22, {24, 0, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010,                    2},
     {MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I,       1, 0x22, {15, 0, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010,                    2},
     {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC,       2, 0x22, { 8, 4, 0, 0}, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC,     2},
     {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC,        1, 0x22, {12, 0, 0, 0}, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC,     2},
diff --git a/libacryl/acrylic_g2d.cpp b/libacryl/acrylic_g2d.cpp
index f3f4567..605e9f1 100644
--- a/libacryl/acrylic_g2d.cpp
+++ b/libacryl/acrylic_g2d.cpp
@@ -508,6 +508,7 @@
     {HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B,         G2D_FMT_NV12_P010, 1, 0},
     {MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I, G2D_FMT_NV12_P010, 1, 0},
     {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M,        G2D_FMT_NV12_P010, 2, 0},
+    {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN,      G2D_FMT_NV12_P010, 1, 0},
     {HAL_PIXEL_FORMAT_YCbCr_422_I,                G2D_FMT_YUYV,      1, 0},
     {HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_I,         G2D_FMT_YVYU,      1, 0},
     {HAL_PIXEL_FORMAT_YCbCr_422_SP,               G2D_FMT_NV16,      1, 0},
diff --git a/libacryl/acrylic_g2d.h b/libacryl/acrylic_g2d.h
index e377017..6ed5942 100644
--- a/libacryl/acrylic_g2d.h
+++ b/libacryl/acrylic_g2d.h
@@ -70,7 +70,12 @@
             return;
 
         for (unsigned int i = 0; i < mCmds->layer_count; i++) {
-            unsigned int idx = (mCmds->layer_hdr_mode[i].offset >> 8) - 2;
+            unsigned int idx;
+
+            if (mWriter->hasColorFillLayer())
+                idx = (mCmds->layer_hdr_mode[i].offset >> 8) - 3;
+            else
+                idx = (mCmds->layer_hdr_mode[i].offset >> 8) - 2;
 
             // If premultiplied alpha values are de-premultied before HDR conversion,
             // it should be multiplied again after the conversion. But some of the HDR processors
diff --git a/libacryl/acrylic_layer.cpp b/libacryl/acrylic_layer.cpp
index b90d541..5c587fc 100644
--- a/libacryl/acrylic_layer.cpp
+++ b/libacryl/acrylic_layer.cpp
@@ -140,7 +140,8 @@
 
     for (int i = 0; i < num_buffers; i++) {
         if ((offset[i] < 0) || (static_cast<size_t>(offset[i]) >= len[i])) {
-            ALOGE("Too large offset %ld for length %zu of buffer[%d]", offset[i], len[i], i);
+            ALOGE("Too large offset %jd for length %zu of buffer[%d]",
+                  static_cast<intmax_t>(offset[i]), len[i], i);
             return false;
         }
 
@@ -155,8 +156,8 @@
         m.mBufferFd[i] = fd[i];
         mBufferLength[i] = len[i];
         mBufferOffset[i] = offset[i];
-        ALOGD_TEST("Configured buffer[%d]: fd %d, len %zu, offset %u (type: %s)",
-                   i, m.mBufferFd[i], mBufferLength[i], mBufferOffset[i],
+        ALOGD_TEST("Configured buffer[%d]: fd %d, len %zu, offset %jd (type: %s)", i,
+                   m.mBufferFd[i], mBufferLength[i], static_cast<intmax_t>(mBufferOffset[i]),
                    canvasTypeName(mCanvasType));
     }
 
diff --git a/libacryl/hdrplugin_headers/hardware/exynos/g2d_hdr_plugin.h b/libacryl/hdrplugin_headers/hardware/exynos/g2d_hdr_plugin.h
index 02b863a..aefed60 100644
--- a/libacryl/hdrplugin_headers/hardware/exynos/g2d_hdr_plugin.h
+++ b/libacryl/hdrplugin_headers/hardware/exynos/g2d_hdr_plugin.h
@@ -39,6 +39,7 @@
     virtual void setTargetDisplayLuminance(unsigned int __unused min, unsigned int __unused max) { };
     virtual struct g2d_commandlist *getCommands() = 0;
     virtual void putCommands(struct g2d_commandlist __unused *commands) { };
+    virtual bool hasColorFillLayer(void) { return false; }
 };
 
 #endif/* __LIBACRYL_PLUGIN_G2D_HDR_H__ */
diff --git a/libhwc2.1/Android.mk b/libhwc2.1/Android.mk
index 71391cd..1e23ab7 100644
--- a/libhwc2.1/Android.mk
+++ b/libhwc2.1/Android.mk
@@ -67,8 +67,8 @@
 	libvendorgraphicbuffer libbinder_ndk \
 	android.hardware.power-V2-ndk pixel-power-ext-V1-ndk
 
-LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V1-ndk \
-                          com.google.hardware.pixel.display-V7-ndk \
+LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V2-ndk \
+                          com.google.hardware.pixel.display-V8-ndk \
                           libbinder_ndk \
                           libbase \
                           libpng \
@@ -97,6 +97,7 @@
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libexternaldisplay \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libvirtualdisplay \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \
+	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libcolormanager \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdisplayinterface \
@@ -134,7 +135,7 @@
 include $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/Android.mk
 
 LOCAL_CFLAGS += -DHLOG_CODE=0
-LOCAL_CFLAGS += -DLOG_TAG=\"display\"
+LOCAL_CFLAGS += -DLOG_TAG=\"hwc-display\"
 LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver)
 
@@ -158,9 +159,10 @@
 LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libbinder libexynosdisplay libacryl \
 	android.hardware.graphics.composer@2.4 \
 	android.hardware.graphics.allocator@2.0 \
-	android.hardware.graphics.mapper@2.0
+	android.hardware.graphics.mapper@2.0 \
+	android.hardware.graphics.composer3-V2-ndk
 
-LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V7-ndk \
+LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V8-ndk \
                           libbinder_ndk \
                           libbase
 
@@ -180,6 +182,7 @@
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libexternaldisplay \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libvirtualdisplay \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \
+	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libcolormanager \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \
 	$(TOP)/hardware/google/graphics/common/libhwc2.1/libhwcService \
@@ -190,7 +193,7 @@
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_C_INCLUDES)
 
 LOCAL_CFLAGS := -DHLOG_CODE=0
-LOCAL_CFLAGS += -DLOG_TAG=\"hwcservice\"
+LOCAL_CFLAGS += -DLOG_TAG=\"hwc-service\"
 LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver)
 
 LOCAL_SRC_FILES := \
@@ -220,8 +223,8 @@
 	android.hardware.graphics.mapper@2.0 \
 	libui
 
-LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V1-ndk \
-                          com.google.hardware.pixel.display-V7-ndk \
+LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V2-ndk \
+                          com.google.hardware.pixel.display-V8-ndk \
                           libbinder_ndk \
                           libbase
 
@@ -230,7 +233,7 @@
 LOCAL_HEADER_LIBRARIES += libgralloc_headers
 
 LOCAL_CFLAGS := -DHLOG_CODE=0
-LOCAL_CFLAGS += -DLOG_TAG=\"hwcomposer\"
+LOCAL_CFLAGS += -DLOG_TAG=\"hwc-2\"
 LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver)
 
 ifeq ($(BOARD_USES_HWC_SERVICES),true)
@@ -251,6 +254,7 @@
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libmaindisplay \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libexternaldisplay \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libvirtualdisplay \
+	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libcolormanager \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \
 	$(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \
diff --git a/libhwc2.1/ExynosHWC.cpp b/libhwc2.1/ExynosHWC.cpp
index fee44ed..914c54f 100644
--- a/libhwc2.1/ExynosHWC.cpp
+++ b/libhwc2.1/ExynosHWC.cpp
@@ -192,7 +192,7 @@
     if (!exynosDevice)
         *outCapabilities = 0;
     else
-        return exynosDevice->getCapabilities(outCount, outCapabilities);
+        return exynosDevice->getCapabilitiesLegacy(outCount, outCapabilities);
 }
 
 void exynos_dump(hwc2_device_t *dev, uint32_t *outSize, char *outBuffer)
@@ -520,10 +520,10 @@
 
         if (exynosDisplay->mHWCRenderingState == RENDERING_STATE_VALIDATED) {
             ALOGI("%s:: acceptDisplayChanges was not called",
-                    exynosDisplay->mDisplayName.string());
+                    exynosDisplay->mDisplayName.c_str());
             if (exynosDisplay->acceptDisplayChanges() != HWC2_ERROR_NONE) {
                 ALOGE("%s:: acceptDisplayChanges is failed",
-                        exynosDisplay->mDisplayName.string());
+                        exynosDisplay->mDisplayName.c_str());
             }
         }
         int32_t ret = exynosDisplay->presentDisplay(outRetireFence);
diff --git a/libhwc2.1/ExynosHWCDebug.cpp b/libhwc2.1/ExynosHWCDebug.cpp
index bbf676c..3473d50 100644
--- a/libhwc2.1/ExynosHWCDebug.cpp
+++ b/libhwc2.1/ExynosHWCDebug.cpp
@@ -18,33 +18,13 @@
 #include <sync/sync.h>
 #include "exynos_sync.h"
 
-uint32_t mErrLogSize = 0;
-uint32_t mFenceLogSize = 0;
-
-int32_t saveErrorLog(const String8 &errString, ExynosDisplay *display)
-{
+int32_t saveErrorLog(const String8 &errString, ExynosDisplay *display) {
+    if (display == nullptr) return -1;
     int32_t ret = NO_ERROR;
-    if (mErrLogSize >= ERR_LOG_SIZE)
-        return -1;
 
-    FILE *pFile = NULL;
-    char filePath[128];
-    sprintf(filePath, "%s/hwc_error_log.txt", ERROR_LOG_PATH0);
-    pFile = fopen(filePath, "a");
-    if (pFile == NULL) {
-        ALOGE("Fail to open file %s/hwc_error_log.txt, error: %s", ERROR_LOG_PATH0, strerror(errno));
-        sprintf(filePath, "%s/hwc_error_log.txt", ERROR_LOG_PATH1);
-        pFile = fopen(filePath, "a");
-    }
-    if (pFile == NULL) {
-        ALOGE("Fail to open file %s/hwc_error_log.txt, error: %s", ERROR_LOG_PATH1, strerror(errno));
-        return -errno;
-    }
+    auto &fileWriter = display->mErrLogFileWriter;
 
-    mErrLogSize = ftell(pFile);
-    if (mErrLogSize >= ERR_LOG_SIZE) {
-        if (pFile != NULL)
-            fclose(pFile);
+    if (!fileWriter.chooseOpenedFile()) {
         return -1;
     }
 
@@ -52,47 +32,19 @@
     struct timeval tv;
     gettimeofday(&tv, NULL);
 
-    if (display != NULL) {
-        saveString.appendFormat("%s %s %" PRIu64 ": %s\n", getLocalTimeStr(tv).string(),
-                                display->mDisplayName.string(), display->mErrorFrameCount,
-                                errString.string());
-    } else {
-        saveString.appendFormat("%s : %s\n", getLocalTimeStr(tv).string(), errString.string());
-    }
+    saveString.appendFormat("%s errFrameNumber %" PRIu64 ": %s\n", getLocalTimeStr(tv).c_str(),
+                            display->mErrorFrameCount, errString.c_str());
 
-    if (pFile != NULL) {
-        fwrite(saveString.string(), 1, saveString.size(), pFile);
-        mErrLogSize = (uint32_t)ftell(pFile);
-        ret = mErrLogSize;
-        fclose(pFile);
-    }
+    fileWriter.write(saveString);
+    fileWriter.flush();
     return ret;
 }
 
 int32_t saveFenceTrace(ExynosDisplay *display) {
     int32_t ret = NO_ERROR;
+    auto &fileWriter = display->mFenceFileWriter;
 
-    if (mFenceLogSize >= FENCE_ERR_LOG_SIZE)
-        return -1;
-
-    FILE *pFile = NULL;
-    char filePath[128];
-    sprintf(filePath, "%s/hwc_fence_state.txt", ERROR_LOG_PATH0);
-    pFile = fopen(filePath, "a");
-    if (pFile == NULL) {
-        ALOGE("Fail to open file %s/hwc_fence_state.txt, error: %s", ERROR_LOG_PATH0, strerror(errno));
-        sprintf(filePath, "%s/hwc_fence_state.txt", ERROR_LOG_PATH1);
-        pFile = fopen(filePath, "a");
-    }
-    if (pFile == NULL) {
-        ALOGE("Fail to open file %s, error: %s", ERROR_LOG_PATH1, strerror(errno));
-        return -errno;
-    }
-
-    mFenceLogSize = ftell(pFile);
-    if (mFenceLogSize >= FENCE_ERR_LOG_SIZE) {
-        if (pFile != NULL)
-            fclose(pFile);
+    if (!fileWriter.chooseOpenedFile()) {
         return -1;
     }
 
@@ -102,7 +54,7 @@
 
     struct timeval tv;
     gettimeofday(&tv, NULL);
-    saveString.appendFormat("\n====== Fences at time:%s ======\n", getLocalTimeStr(tv).string());
+    saveString.appendFormat("\n====== Fences at time:%s ======\n", getLocalTimeStr(tv).c_str());
 
     if (device != NULL) {
         for (const auto &[fd, info] : device->mFenceInfos) {
@@ -112,17 +64,12 @@
 
             for (const auto &trace : info.traces) {
                 saveString.appendFormat("> dir: %d, type: %d, ip: %d, time:%s\n", trace.direction,
-                                        trace.type, trace.ip, getLocalTimeStr(trace.time).string());
+                                        trace.type, trace.ip, getLocalTimeStr(trace.time).c_str());
             }
         }
     }
 
-    if (pFile != NULL) {
-        fwrite(saveString.string(), 1, saveString.size(), pFile);
-        mFenceLogSize = (uint32_t)ftell(pFile);
-        ret = mFenceLogSize;
-        fclose(pFile);
-    }
-
+    fileWriter.write(saveString);
+    fileWriter.flush();
     return ret;
 }
diff --git a/libhwc2.1/ExynosHWCDebug.h b/libhwc2.1/ExynosHWCDebug.h
index 01a49cf..2f2d0b3 100644
--- a/libhwc2.1/ExynosHWCDebug.h
+++ b/libhwc2.1/ExynosHWCDebug.h
@@ -17,6 +17,8 @@
 #define HWC_DEBUG_H
 
 #include <utils/String8.h>
+#include <utils/Trace.h>
+
 #include "ExynosHWC.h"
 #include "ExynosHWCHelper.h"
 
@@ -43,6 +45,8 @@
     eDebugColorManagement         =   0x00080000,
     eDebugAttrSetting             =   0x00100000,
     eDebugDisplayConfig           =   0x00400000,
+    eDebugTDM                     =   0x00800000,
+    eDebugLoadBalancing           =   0x01000000,
 };
 
 class ExynosDisplay;
@@ -91,31 +95,38 @@
 #define DISPLAY_LOGD(type, msg, ...) \
     {\
         if (hwcCheckDebugMessages(type)) \
-            ALOGD("%s:: [%s] " msg, __func__, mDisplayName.string(), ##__VA_ARGS__); \
+            ALOGD("%s:: [%s] " msg, __func__, mDisplayName.c_str(), ##__VA_ARGS__); \
     }
 #define MPP_LOGD(type, msg, ...) \
     {\
     if (hwcCheckDebugMessages(type)) \
-        ALOGD("%s:: [%s][%d] " msg, __func__, mName.string(), mLogicalIndex, ##__VA_ARGS__); \
+        ALOGD("%s:: [%s][%d] " msg, __func__, mName.c_str(), mLogicalIndex, ##__VA_ARGS__); \
     }
 #endif
-#define DISPLAY_LOGV(msg, ...) ALOGV("[%s] " msg, mDisplayName.string(), ##__VA_ARGS__)
-#define DISPLAY_LOGI(msg, ...) ALOGI("[%s] " msg, mDisplayName.string(), ##__VA_ARGS__)
-#define DISPLAY_LOGW(msg, ...) ALOGW("[%s] " msg, mDisplayName.string(), ##__VA_ARGS__)
+#define DISPLAY_LOGV(msg, ...) ALOGV("[%s] " msg, mDisplayName.c_str(), ##__VA_ARGS__)
+#define DISPLAY_LOGI(msg, ...) ALOGI("[%s] " msg, mDisplayName.c_str(), ##__VA_ARGS__)
+#define DISPLAY_LOGW(msg, ...) ALOGW("[%s] " msg, mDisplayName.c_str(), ##__VA_ARGS__)
 #define DISPLAY_LOGE(msg, ...) \
     {\
-        ALOGE("[%s] " msg, mDisplayName.string(), ##__VA_ARGS__); \
+        ALOGE("[%s] " msg, mDisplayName.c_str(), ##__VA_ARGS__); \
         String8 saveString; \
         saveString.appendFormat(msg, ##__VA_ARGS__); \
         saveErrorLog(saveString, this); \
     }
 
-#define MPP_LOGV(msg, ...) ALOGV("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__)
-#define MPP_LOGI(msg, ...) ALOGI("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__)
-#define MPP_LOGW(msg, ...) ALOGW("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__)
+#define DISPLAY_DRM_LOGI(msg, ...) \
+    ALOGI("[%s] " msg, mExynosDisplay->mDisplayName.c_str(), ##__VA_ARGS__)
+#define DISPLAY_DRM_LOGW(msg, ...) \
+    ALOGW("[%s] " msg, mExynosDisplay->mDisplayName.c_str(), ##__VA_ARGS__)
+#define DISPLAY_DRM_LOGE(msg, ...) \
+    ALOGE("[%s] " msg, mExynosDisplay->mDisplayName.c_str(), ##__VA_ARGS__)
+
+#define MPP_LOGV(msg, ...) ALOGV("[%s][%d] " msg, mName.c_str(), mLogicalIndex, ##__VA_ARGS__)
+#define MPP_LOGI(msg, ...) ALOGI("[%s][%d] " msg, mName.c_str(), mLogicalIndex, ##__VA_ARGS__)
+#define MPP_LOGW(msg, ...) ALOGW("[%s][%d] " msg, mName.c_str(), mLogicalIndex, ##__VA_ARGS__)
 #define MPP_LOGE(msg, ...) \
     {\
-        ALOGE("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__); \
+        ALOGE("[%s][%d] " msg, mName.c_str(), mLogicalIndex, ##__VA_ARGS__); \
         String8 saveString; \
         saveString.appendFormat(msg, ##__VA_ARGS__); \
         saveErrorLog(saveString, mAssignedDisplay); \
@@ -129,4 +140,38 @@
         saveErrorLog(saveString, display); \
     }
 
+class ScopedTraceEnder {
+public:
+    ~ScopedTraceEnder() { ATRACE_END(); }
+};
+
+#define ATRACE_FORMAT(fmt, ...)                     \
+    if (CC_UNLIKELY(ATRACE_ENABLED())) {            \
+        String8 traceName;                          \
+        traceName.appendFormat(fmt, ##__VA_ARGS__); \
+        ATRACE_BEGIN(traceName.c_str());            \
+    }                                               \
+    ScopedTraceEnder traceEnder
+
+#define DISPLAY_ATRACE_NAME(name) ATRACE_FORMAT("%s for %s", name, mDisplayTraceName.c_str())
+#define DISPLAY_ATRACE_CALL() DISPLAY_ATRACE_NAME(__func__)
+#define DISPLAY_ATRACE_INT(name, value)                                                   \
+    if (CC_UNLIKELY(ATRACE_ENABLED())) {                                                  \
+        ATRACE_INT(String8::format("%s for %s", name, mDisplayTraceName.c_str()).c_str(), \
+                   value);                                                                \
+    }
+#define DISPLAY_ATRACE_INT64(name, value)                                                   \
+    if (CC_UNLIKELY(ATRACE_ENABLED())) {                                                    \
+        ATRACE_INT64(String8::format("%s for %s", name, mDisplayTraceName.c_str()).c_str(), \
+                     value);                                                                \
+    }
+
+#define DISPLAY_LOGD_AND_ATRACE_NAME(debugFlag, fmt, ...)                    \
+    if (hwcCheckDebugMessages(debugFlag) || CC_UNLIKELY(ATRACE_ENABLED())) { \
+        String8 log;                                                         \
+        log.appendFormat((fmt), ##__VA_ARGS__);                              \
+        DISPLAY_LOGD(debugFlag, "%s", log.c_str());                          \
+        if (CC_UNLIKELY(ATRACE_ENABLED())) ATRACE_NAME(log.c_str());         \
+    }
+
 #endif
diff --git a/libhwc2.1/histogram_mediator.cpp b/libhwc2.1/histogram_mediator.cpp
index 991b972..f23feec 100644
--- a/libhwc2.1/histogram_mediator.cpp
+++ b/libhwc2.1/histogram_mediator.cpp
@@ -56,12 +56,12 @@
     ExynosDisplayDrmInterface *moduleDisplayInterface =
             static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get());
 
-    if (moduleDisplayInterface->setHistogramControl(
-                hidl_histogram_control_t::HISTOGRAM_CONTROL_REQUEST) != NO_ERROR) {
-        return histogram::HistogramErrorCode::ENABLE_HIST_ERROR;
-    }
     {
         std::unique_lock<std::mutex> lk(mIDLHistogram->mDataCollectingMutex);
+        if (moduleDisplayInterface->setHistogramControl(
+                hidl_histogram_control_t::HISTOGRAM_CONTROL_REQUEST) != NO_ERROR) {
+            return histogram::HistogramErrorCode::ENABLE_HIST_ERROR;
+        }
         mIDLHistogram->mHistReq_pending = true;
     }
     return histogram::HistogramErrorCode::NONE;
@@ -93,7 +93,7 @@
 }
 
 histogram::HistogramErrorCode histogram::HistogramMediator::setRoiWeightThreshold(
-        const RoiRect roi, const Weight weight, const HistogramPos pos) {
+        const RoiRect &roi, const Weight &weight, const HistogramPos &pos) {
     int threshold = calculateThreshold(roi);
     mIDLHistogram->setHistogramROI((uint16_t)roi.left, (uint16_t)roi.top,
                                    (uint16_t)(roi.right - roi.left),
@@ -118,7 +118,7 @@
     return histogram::HistogramErrorCode::NONE;
 }
 
-histogram::RoiRect histogram::HistogramMediator::calRoi(RoiRect roi) {
+histogram::RoiRect histogram::HistogramMediator::calRoi(const RoiRect &roi) {
     RoiRect roi_return = {-1, -1, -1, -1};
     ExynosDisplayDrmInterface *moduleDisplayInterface =
             static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get());
diff --git a/libhwc2.1/histogram_mediator.h b/libhwc2.1/histogram_mediator.h
index eac4c98..54d28c9 100644
--- a/libhwc2.1/histogram_mediator.h
+++ b/libhwc2.1/histogram_mediator.h
@@ -62,9 +62,9 @@
     HistogramErrorCode requestHist();
     HistogramErrorCode cancelHistRequest();
     HistogramErrorCode collectRoiLuma(std::vector<char16_t> *buf);
-    HistogramErrorCode setRoiWeightThreshold(const RoiRect roi, const Weight weight,
-                                             const HistogramPos pos);
-    RoiRect calRoi(RoiRect roi);
+    HistogramErrorCode setRoiWeightThreshold(const RoiRect &roi, const Weight &weight,
+                                             const HistogramPos &pos);
+    RoiRect calRoi(const RoiRect &roi);
     struct HistogramReceiver : public IDLHistogram {
         HistogramReceiver() : mHistData(){};
         void callbackHistogram(char16_t *bin) override;
@@ -73,10 +73,38 @@
         bool mHistReq_pending = false;
         std::mutex mDataCollectingMutex; // for data collecting operations
     };
+
+    struct HistogramConfig {
+        RoiRect mRoi;
+        Weight mWeights;
+        HistogramPos mPos;
+
+        HistogramConfig() {}
+
+        HistogramConfig(const RoiRect &roi, const Weight &weights, const HistogramPos &pos) {
+            mRoi = roi;
+            mWeights = weights;
+            mPos = pos;
+        }
+
+        bool operator!=(const HistogramConfig &rhs) {
+            return mRoi != rhs.mRoi || mWeights != rhs.mWeights || mPos != rhs.mPos;
+        }
+
+        HistogramConfig &operator=(const HistogramConfig &rhs) {
+            mRoi = rhs.mRoi;
+            mWeights = rhs.mWeights;
+            mPos = rhs.mPos;
+            return *this;
+        }
+    };
+
     uint32_t getFrameCount();
     void setSampleFrameCounter(int32_t id) { mSampledFrameCounter = id; }
     uint32_t getSampleFrameCounter() { return mSampledFrameCounter; }
     bool histRequested() { return mIDLHistogram->mHistReq_pending; }
+    std::mutex mConfigMutex;
+    HistogramConfig mConfig GUARDED_BY(mConfigMutex);
 
 private:
     int calculateThreshold(const RoiRect &roi);
diff --git a/libhwc2.1/libdevice/BrightnessController.cpp b/libhwc2.1/libdevice/BrightnessController.cpp
index b8ae2ee..b651ead 100644
--- a/libhwc2.1/libdevice/BrightnessController.cpp
+++ b/libhwc2.1/libdevice/BrightnessController.cpp
@@ -90,9 +90,9 @@
 void BrightnessController::initBrightnessSysfs() {
     String8 nodeName;
     nodeName.appendFormat(BRIGHTNESS_SYSFS_NODE, mPanelIndex);
-    mBrightnessOfs.open(nodeName.string(), std::ofstream::out);
+    mBrightnessOfs.open(nodeName.c_str(), std::ofstream::out);
     if (mBrightnessOfs.fail()) {
-        ALOGE("%s %s fail to open", __func__, nodeName.string());
+        ALOGE("%s %s fail to open", __func__, nodeName.c_str());
         mBrightnessOfs.close();
         return;
     }
@@ -100,9 +100,9 @@
     nodeName.clear();
     nodeName.appendFormat(MAX_BRIGHTNESS_SYSFS_NODE, mPanelIndex);
 
-    std::ifstream ifsMaxBrightness(nodeName.string());
+    std::ifstream ifsMaxBrightness(nodeName.c_str());
     if (ifsMaxBrightness.fail()) {
-        ALOGE("%s fail to open %s", __func__, nodeName.string());
+        ALOGE("%s fail to open %s", __func__, nodeName.c_str());
         return;
     }
 
@@ -117,9 +117,9 @@
     String8 nodeName;
     nodeName.appendFormat(kLocalCabcModeFileNode, mPanelIndex);
 
-    mCabcModeOfs.open(nodeName.string(), std::ofstream::out);
+    mCabcModeOfs.open(nodeName.c_str(), std::ofstream::out);
     if (mCabcModeOfs.fail()) {
-        ALOGE("%s %s fail to open", __func__, nodeName.string());
+        ALOGE("%s %s fail to open", __func__, nodeName.c_str());
         mCabcModeOfs.close();
         return;
     }
@@ -166,9 +166,9 @@
     String8 nodeName;
     nodeName.appendFormat(kDimBrightnessFileNode, mPanelIndex);
 
-    std::ifstream ifsDimBrightness(nodeName.string());
+    std::ifstream ifsDimBrightness(nodeName.c_str());
     if (ifsDimBrightness.fail()) {
-        ALOGW("%s fail to open %s", __func__, nodeName.string());
+        ALOGW("%s fail to open %s", __func__, nodeName.c_str());
     } else {
         ifsDimBrightness >> mDimBrightness;
         ifsDimBrightness.close();
@@ -247,21 +247,23 @@
         } else {
             level = brightness < 0 ? 0 : static_cast<uint32_t>(brightness * mMaxBrightness + 0.5f);
         }
-        // go sysfs path
+        // clear dirty before go sysfs path
+        mBrightnessFloatReq.clear_dirty();
     }
 
     // Sysfs path is faster than drm path. If there is an unchecked drm path change, the sysfs
     // path should check the sysfs content.
     if (mUncheckedGbhmRequest) {
         ATRACE_NAME("check_ghbm_mode");
-        checkSysfsStatus(kGlobalHbmModeFileNode,
+        checkSysfsStatus(GetPanelSysfileByIndex(kGlobalHbmModeFileNode),
                          {std::to_string(toUnderlying(mPendingGhbmStatus.load()))}, vsyncNs * 5);
         mUncheckedGbhmRequest = false;
     }
 
     if (mUncheckedLhbmRequest) {
         ATRACE_NAME("check_lhbm_mode");
-        checkSysfsStatus(kLocalHbmModeFileNode, {std::to_string(mPendingLhbmStatus)}, vsyncNs * 5);
+        checkSysfsStatus(GetPanelSysfileByIndex(kLocalHbmModeFileNode),
+                         {std::to_string(mPendingLhbmStatus)}, vsyncNs * 5);
         mUncheckedLhbmRequest = false;
     }
 
@@ -300,7 +302,8 @@
 
     if (mUncheckedBlRequest) {
         ATRACE_NAME("check_bl_value");
-        checkSysfsStatus(BRIGHTNESS_SYSFS_NODE, {std::to_string(mPendingBl)}, vsyncNs * 5);
+        checkSysfsStatus(GetPanelSysfileByIndex(BRIGHTNESS_SYSFS_NODE),
+                         {std::to_string(mPendingBl)}, vsyncNs * 5);
         mUncheckedBlRequest = false;
     }
 
@@ -314,6 +317,13 @@
 
     std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
     mLhbmReq.store(on);
+    // As kernel timeout timer might disable LHBM without letting HWC know, enforce mLhbmReq and
+    // mLhbm dirty to ensure the enabling request can be passed through kernel unconditionally.
+    // TODO-b/260915350: move LHBM timeout mechanism from kernel to HWC for easier control and sync.
+    if (on) {
+        mLhbmReq.set_dirty();
+        mLhbm.set_dirty();
+    }
     if (mLhbmReq.is_dirty()) {
         updateStates();
     }
@@ -698,34 +708,39 @@
 }
 
 // Return immediately if it's already in the status. Otherwise poll the status
-int BrightnessController::checkSysfsStatus(const char* file,
+int BrightnessController::checkSysfsStatus(const std::string& file,
                                            const std::vector<std::string>& expectedValue,
                                            const nsecs_t timeoutNs) {
     ATRACE_CALL();
 
-    if (expectedValue.size() == 0) return false;
+    if (expectedValue.size() == 0) {
+      return -EINVAL;
+    }
 
     char buf[16];
-    String8 nodeName;
-    nodeName.appendFormat(file, mPanelIndex);
-    UniqueFd fd = open(nodeName.string(), O_RDONLY);
+    UniqueFd fd = open(file.c_str(), O_RDONLY);
+    if (fd.get() < 0) {
+        ALOGE("%s failed to open sysfs %s: %s", __func__, file.c_str(), strerror(errno));
+        return -ENOENT;
+    }
 
     int size = read(fd.get(), buf, sizeof(buf));
     if (size <= 0) {
-        ALOGE("%s failed to read from %s", __func__, kLocalHbmModeFileNode);
-        return false;
+        ALOGE("%s failed to read from %s: %s", __func__, file.c_str(), strerror(errno));
+        return -EIO;
     }
 
     // '- 1' to remove trailing '\n'
     std::string val = std::string(buf, size - 1);
     if (std::find(expectedValue.begin(), expectedValue.end(), val) != expectedValue.end()) {
-        return true;
+        return OK;
     } else if (timeoutNs == 0) {
-        return false;
+        // not get the expected value and no intention to wait
+        return -EINVAL;
     }
 
     struct pollfd pfd;
-    int ret = EINVAL;
+    int ret = -EINVAL;
 
     auto startTime = systemTime(SYSTEM_TIME_MONOTONIC);
     pfd.fd = fd.get();
@@ -739,9 +754,9 @@
         }
         int pollRet = poll(&pfd, 1, ns2ms(remainTimeNs));
         if (pollRet == 0) {
-            ALOGW("%s poll timeout", __func__);
+            ALOGW("%s poll %s timeout", __func__, file.c_str());
             // time out
-            ret = ETIMEDOUT;
+            ret = -ETIMEDOUT;
             break;
         } else if (pollRet > 0) {
             if (!(pfd.revents & POLLPRI)) {
@@ -754,7 +769,8 @@
                 val = std::string(buf, size - 1);
                 if (std::find(expectedValue.begin(), expectedValue.end(), val) !=
                     expectedValue.end()) {
-                    ret = 0;
+                    ret = OK;
+                    break;
                 } else {
                     std::string values;
                     for (auto& s : expectedValue) {
@@ -763,27 +779,27 @@
                     if (values.size() > 0) {
                         values.resize(values.size() - 1);
                     }
-                    ALOGE("%s read %s expected %s after notified", __func__, val.c_str(),
-                          values.c_str());
-                    ret = EINVAL;
+                    ALOGW("%s read %s expected %s after notified on file %s", __func__, val.c_str(),
+                          values.c_str(), file.c_str());
                 }
             } else {
-                ret = EIO;
-                ALOGE("%s failed to read after notified %d", __func__, errno);
+                ret = -EIO;
+                ALOGE("%s failed to read after notified %d on file %s", __func__, errno,
+                      file.c_str());
+                break;
             }
-            break;
         } else {
             if (errno == EAGAIN || errno == EINTR) {
                 continue;
             }
 
-            ALOGE("%s poll failed %d", __func__, errno);
-            ret = errno;
+            ALOGE("%s poll failed %d on file %s", __func__, errno, file.c_str());
+            ret = -errno;
             break;
         }
     };
 
-    return ret == NO_ERROR;
+    return ret;
 }
 
 void BrightnessController::resetLhbmState() {
diff --git a/libhwc2.1/libdevice/BrightnessController.h b/libhwc2.1/libdevice/BrightnessController.h
index 9090689..66f4b23 100644
--- a/libhwc2.1/libdevice/BrightnessController.h
+++ b/libhwc2.1/libdevice/BrightnessController.h
@@ -114,8 +114,12 @@
         std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex);
         return mLhbm.get();
     }
-    int checkSysfsStatus(const char *file, const std::vector<std::string>& expectedValue,
+    int checkSysfsStatus(const std::string& file, const std::vector<std::string>& expectedValue,
                          const nsecs_t timeoutNs);
+    bool fileExists(const std::string& file) {
+        struct stat sb;
+        return stat(file.c_str(), &sb) == 0;
+    }
     void resetLhbmState();
 
     uint32_t getBrightnessLevel() {
@@ -143,6 +147,21 @@
 
     int updateCabcMode();
 
+    const std::string GetPanelSysfileByIndex(const char *file_pattern) {
+        String8 nodeName;
+        nodeName.appendFormat(file_pattern, mPanelIndex);
+        return nodeName.c_str();
+    }
+
+    const std::string GetPanelRefreshRateSysfile() {
+        String8 nodeName;
+        nodeName.appendFormat(kRefreshrateFileNode,
+                              mPanelIndex == 0           ? "primary"
+                                      : mPanelIndex == 1 ? "secondary"
+                                                         : "unknown");
+        return nodeName.c_str();
+    }
+
     struct BrightnessTable {
         float mBriStart;
         float mBriEnd;
@@ -217,6 +236,8 @@
                 "/sys/class/backlight/panel%d-backlight/local_hbm_mode";
     static constexpr const char* kDimBrightnessFileNode =
             "/sys/class/backlight/panel%d-backlight/dim_brightness";
+    static constexpr const char* kRefreshrateFileNode =
+            "/sys/devices/platform/exynos-drm/%s-panel/refresh_rate";
 
 private:
     // sync brightness change for mixed composition when there is more than 50% luminance change.
diff --git a/libhwc2.1/libdevice/DisplayColorLoader.h b/libhwc2.1/libdevice/DisplayColorLoader.h
new file mode 100644
index 0000000..02bbbf8
--- /dev/null
+++ b/libhwc2.1/libdevice/DisplayColorLoader.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef DISPLAY_COLOR_LOADER_H
+#define DISPLAY_COLOR_LOADER_H
+
+#include <dlfcn.h>
+#include <log/log.h>
+#include <string>
+#include <vector>
+
+template <typename GsInterfaceType, const char *entry>
+class DisplayColorLoader {
+    static_assert(entry != nullptr);
+    public:
+      DisplayColorLoader(const DisplayColorLoader &) = delete;
+      DisplayColorLoader& operator=(const DisplayColorLoader &) = delete;
+
+      DisplayColorLoader(const std::string &libName) {
+          libHandle = dlopen(libName.c_str(), RTLD_LAZY);
+
+          if (libHandle == nullptr) {
+              ALOGE("%s: failed to load library %s\n", __func__, libName.c_str());
+              getDisplayColor = nullptr;
+              return;
+          }
+
+          const displaycolor::DisplayColorIntfVer *(*getVersion)();
+          getVersion = reinterpret_cast<decltype(getVersion)>(dlsym(libHandle, "GetInterfaceVersion"));
+          if (getVersion == nullptr) {
+              ALOGE("%s: prebuilt lib is not versioned", __func__);
+              return;
+          }
+
+          auto intfVer = getVersion();
+
+          if (intfVer != nullptr &&
+              displaycolor::kInterfaceVersion.Compatible(*intfVer)) {
+              getDisplayColor = reinterpret_cast<decltype(getDisplayColor)>(dlsym(libHandle, entry));
+
+              if (getDisplayColor == nullptr) {
+                  ALOGE("%s: failed to get %s\n", __func__, entry);
+              } else if (!(displaycolor::kInterfaceVersion == *intfVer)) {
+                  ALOGW("%s: different hwc/displaycolor patch level %u.%u.%u vs .%u",
+                        __func__,
+                        intfVer->major,
+                        intfVer->minor,
+                        displaycolor::kInterfaceVersion.patch,
+                        intfVer->patch);
+              }
+          } else {
+              if (intfVer != nullptr) {
+                  ALOGE("%s: prebuilt lib version %u.%u.%u expected %u.%u.%u",
+                        __func__,
+                        intfVer->major,
+                        intfVer->minor,
+                        intfVer->patch,
+                        displaycolor::kInterfaceVersion.major,
+                        displaycolor::kInterfaceVersion.minor,
+                        displaycolor::kInterfaceVersion.patch);
+              } else {
+                  ALOGE("%s: prebult lib getVersion returns null", __func__);
+              }
+          }
+      }
+
+      GsInterfaceType *GetDisplayColor(
+              const std::vector<displaycolor::DisplayInfo> &display_info) {
+          if (getDisplayColor != nullptr) {
+              return getDisplayColor(display_info);
+          }
+
+          return nullptr;
+      }
+
+      ~DisplayColorLoader() {
+          if (libHandle != nullptr) {
+              dlclose(libHandle);
+          }
+      }
+
+    private:
+      void *libHandle;
+      GsInterfaceType *(*getDisplayColor)(const std::vector<displaycolor::DisplayInfo> &);
+};
+
+#endif //DISPLAY_COLOR_LOADER_H
diff --git a/libhwc2.1/libdevice/ExynosDevice.cpp b/libhwc2.1/libdevice/ExynosDevice.cpp
index a53bd3e..8082351 100644
--- a/libhwc2.1/libdevice/ExynosDevice.cpp
+++ b/libhwc2.1/libdevice/ExynosDevice.cpp
@@ -45,7 +45,6 @@
 
 class ExynosDevice;
 
-extern uint32_t mFenceLogSize;
 extern void PixelDisplayInit(ExynosDisplay *exynos_display, const std::string_view instance_str);
 
 static const std::map<const uint32_t, const std::string_view> pixelDisplayIntfName =
@@ -96,9 +95,18 @@
     exynosHWCControl.sysFenceLogging = false;
     exynosHWCControl.useDynamicRecomp = false;
 
-    mInterfaceType = getDeviceInterfaceType();
+    hwcDebug = 0;
 
+    mInterfaceType = getDeviceInterfaceType();
     ALOGD("HWC2 : %s : interface type(%d)", __func__, mInterfaceType);
+
+    /*
+     * This order should not be changed
+     * new ExynosResourceManager ->
+     * create displays and add them to the list ->
+     * initDeviceInterface() ->
+     * ExynosResourceManager::updateRestrictions()
+     */
     mResourceManager = new ExynosResourceManagerModule(this);
 
     for (size_t i = 0; i < AVAILABLE_DISPLAY_UNITS.size(); i++) {
@@ -107,7 +115,9 @@
         ALOGD("Create display[%zu] type: %d, index: %d", i, display_t.type, display_t.index);
         switch(display_t.type) {
             case HWC_DISPLAY_PRIMARY:
-                exynos_display = (ExynosDisplay *)(new ExynosPrimaryDisplayModule(display_t.index, this));
+                exynos_display =
+                        (ExynosDisplay *)(new ExynosPrimaryDisplayModule(display_t.index, this,
+                                                                         display_t.display_name));
                 if(display_t.index == 0) {
                     exynos_display->mPlugState = true;
                     ExynosMPP::mainDisplayWidth = exynos_display->mXres;
@@ -121,10 +131,14 @@
                 }
                 break;
             case HWC_DISPLAY_EXTERNAL:
-                exynos_display = (ExynosDisplay *)(new ExynosExternalDisplayModule(display_t.index, this));
+                exynos_display =
+                        (ExynosDisplay *)(new ExynosExternalDisplayModule(display_t.index, this,
+                                                                          display_t.display_name));
                 break;
             case HWC_DISPLAY_VIRTUAL:
-                exynos_display = (ExynosDisplay *)(new ExynosVirtualDisplayModule(display_t.index, this));
+                exynos_display =
+                        (ExynosDisplay *)(new ExynosVirtualDisplayModule(display_t.index, this,
+                                                                         display_t.display_name));
                 mNumVirtualDisplay = 0;
                 break;
             default:
@@ -132,8 +146,8 @@
                 break;
         }
         exynos_display->mDeconNodeName.appendFormat("%s", display_t.decon_node_name.c_str());
-        exynos_display->mDisplayName.appendFormat("%s", display_t.display_name.c_str());
         mDisplays.add(exynos_display);
+        mDisplayMap.insert(std::make_pair(exynos_display->mDisplayId, exynos_display));
 
 #ifndef FORCE_DISABLE_DR
         if (exynos_display->mDREnable)
@@ -145,7 +159,6 @@
 
     dynamicRecompositionThreadCreate();
 
-    hwcDebug = 0;
     for (uint32_t i = 0; i < FENCE_IP_ALL; i++)
         hwcFenceDebug[i] = 0;
 
@@ -154,24 +167,25 @@
         sprintf(fence_names[i], "_%2dh", i);
     }
 
-    String8 saveString;
-    saveString.appendFormat("ExynosDevice is initialized");
-    uint32_t errFileSize = saveErrorLog(saveString);
-    ALOGI("Initial errlog size: %d bytes\n", errFileSize);
+    for (auto it : mDisplays) {
+        std::string displayName = std::string(it->mDisplayName.c_str());
+        it->mErrLogFileWriter.setPrefixName(displayName + "_hwc_error_log");
+        it->mDebugDumpFileWriter.setPrefixName(displayName + "_hwc_debug");
+        it->mFenceFileWriter.setPrefixName(displayName + "_hwc_fence_state");
+        String8 saveString;
+        saveString.appendFormat("ExynosDisplay %s is initialized", it->mDisplayName.c_str());
+        saveErrorLog(saveString, it);
+    }
 
-    /*
-     * This order should not be changed
-     * new ExynosResourceManager ->
-     * create displays and add them to the list ->
-     * initDeviceInterface() ->
-     * ExynosResourceManager::updateRestrictions()
-     */
     initDeviceInterface(mInterfaceType);
+
+    // registerRestrictions();
     mResourceManager->updateRestrictions();
+    mResourceManager->initDisplays(mDisplays, mDisplayMap);
+    mResourceManager->initDisplaysTDMInfo();
 
     if (mInterfaceType == INTERFACE_TYPE_DRM) {
-        /* disable vblank immediately after updates */
-        setVBlankOffDelay(-1);
+        setVBlankOffDelay(1);
     }
 
     char value[PROPERTY_VALUE_MAX];
@@ -212,6 +226,7 @@
                     display->mDisplayInterface) != NO_ERROR) {
             ALOGD("Remove display[%d], Failed to initialize display interface", i);
             mDisplays.removeAt(i);
+            mDisplayMap.erase(display->mDisplayId);
             delete display;
         } else {
             i++;
@@ -261,6 +276,17 @@
     return true;
 }
 
+bool ExynosDevice::hasOtherDisplayOn(ExynosDisplay *display) {
+    for (uint32_t i = 0; i < mDisplays.size(); i++) {
+        if (mDisplays[i] == display) continue;
+        if ((mDisplays[i]->mType != HWC_DISPLAY_VIRTUAL) &&
+            mDisplays[i]->mPowerModeState.has_value() &&
+            (mDisplays[i]->mPowerModeState.value() != (hwc2_power_mode_t)HWC_POWER_MODE_OFF))
+            return true;
+    }
+    return false;
+}
+
 bool ExynosDevice::isDynamicRecompositionThreadAlive()
 {
     android_atomic_acquire_load(&mDRThreadStatus);
@@ -342,24 +368,6 @@
 
     return NULL;
 }
-/**
- * @param display
- * @return ExynosDisplay
- */
-ExynosDisplay* ExynosDevice::getDisplay(uint32_t display) {
-    if (mDisplays.isEmpty()) {
-        ALOGE("mDisplays.size(%zu), requested display(%d)",
-                mDisplays.size(), display);
-        return NULL;
-    }
-
-    for (size_t i = 0;i < mDisplays.size(); i++) {
-        if (mDisplays[i]->mDisplayId == display)
-            return (ExynosDisplay*)mDisplays[i];
-    }
-
-    return NULL;
-}
 
 /**
  * Device Functions for HWC 2.0
@@ -399,7 +407,7 @@
         size_t copySize = min(static_cast<size_t>(*outSize), result.size());
         ALOGI("HWC dump:: resultSize(%zu), outSize(%d), copySize(%zu)", result.size(), *outSize,
               copySize);
-        strlcpy(outBuffer, result.string(), copySize);
+        strlcpy(outBuffer, result.c_str(), copySize);
     }
 }
 
@@ -802,13 +810,12 @@
     return false;
 }
 
-void ExynosDevice::getCapabilities(uint32_t *outCount, int32_t* outCapabilities)
-{
+void ExynosDevice::getCapabilitiesLegacy(uint32_t *outCount, int32_t *outCapabilities) {
     uint32_t capabilityNum = 0;
 #ifdef HWC_SUPPORT_COLOR_TRANSFORM
     capabilityNum++;
 #endif
-#ifdef HWC_SKIP_VALIDATE
+#ifndef HWC_NO_SUPPORT_SKIP_VALIDATE
     capabilityNum++;
 #endif
     if (outCapabilities == NULL) {
@@ -819,18 +826,38 @@
         ALOGE("%s:: invalid outCount(%d), should be(%d)", __func__, *outCount, capabilityNum);
         return;
     }
-#if defined(HWC_SUPPORT_COLOR_TRANSFORM) || defined(HWC_SKIP_VALIDATE)
+#if defined(HWC_SUPPORT_COLOR_TRANSFORM) || !defined(HWC_NO_SUPPORT_SKIP_VALIDATE)
     uint32_t index = 0;
 #endif
 #ifdef HWC_SUPPORT_COLOR_TRANSFORM
     outCapabilities[index++] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
 #endif
-#ifdef HWC_SKIP_VALIDATE
+#ifndef HWC_NO_SUPPORT_SKIP_VALIDATE
     outCapabilities[index++] = HWC2_CAPABILITY_SKIP_VALIDATE;
 #endif
     return;
 }
 
+void ExynosDevice::getCapabilities(uint32_t *outCount, int32_t *outCapabilities) {
+    uint32_t capabilityNum = 0;
+#ifdef HWC_SUPPORT_COLOR_TRANSFORM
+    capabilityNum++;
+#endif
+    if (outCapabilities == NULL) {
+        *outCount = capabilityNum;
+        return;
+    }
+    if (capabilityNum != *outCount) {
+        ALOGE("%s:: invalid outCount(%d), should be(%d)", __func__, *outCount, capabilityNum);
+        return;
+    }
+#if defined(HWC_SUPPORT_COLOR_TRANSFORM)
+    uint32_t index = 0;
+    outCapabilities[index++] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
+#endif
+    return;
+}
+
 void ExynosDevice::clearGeometryChanged()
 {
     mGeometryChanged = 0;
@@ -895,7 +922,6 @@
 
     if (exynosHWCControl.doFenceFileDump) {
         ALOGD("Fence file dump !");
-        if (mFenceLogSize != 0) ALOGD("Fence file not empty!");
         saveFenceTrace(display);
         exynosHWCControl.doFenceFileDump = false;
     }
@@ -981,7 +1007,7 @@
     VendorGraphicBufferMeta gmeta(mBuffer);
 
     snprintf(filePath, MAX_DEV_NAME,
-            "%s/%s", WRITEBACK_CAPTURE_PATH, fileName.string());
+            "%s/%s", WRITEBACK_CAPTURE_PATH, fileName.c_str());
     FILE *fp = fopen(filePath, "w");
     if (fp) {
         uint32_t writeSize =
@@ -1193,3 +1219,19 @@
                                       hwc2_display_t hwcDisplay)>(callbackInfo.funcPointer);
     callbackFunc(callbackInfo.callbackData, displayId);
 }
+
+void ExynosDevice::onRefreshRateChangedDebug(hwc2_display_t displayId, uint32_t vsyncPeriod) {
+    Mutex::Autolock lock(mDeviceCallbackMutex);
+    const auto &refreshRateCallback =
+            mHwc3CallbackInfos.find(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug);
+
+    if (refreshRateCallback == mHwc3CallbackInfos.end()) return;
+
+    const auto &callbackInfo = refreshRateCallback->second;
+    if (callbackInfo.funcPointer == nullptr || callbackInfo.callbackData == nullptr) return;
+
+    auto callbackFunc =
+            reinterpret_cast<void (*)(hwc2_callback_data_t callbackData, hwc2_display_t hwcDisplay,
+                                      hwc2_vsync_period_t)>(callbackInfo.funcPointer);
+    callbackFunc(callbackInfo.callbackData, displayId, vsyncPeriod);
+}
diff --git a/libhwc2.1/libdevice/ExynosDevice.h b/libhwc2.1/libdevice/ExynosDevice.h
index d6821f6..35eb947 100644
--- a/libhwc2.1/libdevice/ExynosDevice.h
+++ b/libhwc2.1/libdevice/ExynosDevice.h
@@ -17,6 +17,7 @@
 #ifndef _EXYNOSDEVICE_H
 #define _EXYNOSDEVICE_H
 
+#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h>
 #include <aidl/com/google/hardware/pixel/display/BnDisplay.h>
 #include <cutils/atomic.h>
 #include <displaycolor/displaycolor.h>
@@ -35,6 +36,7 @@
 #include <map>
 #include <thread>
 
+#include "ExynosDeviceInterface.h"
 #include "ExynosHWC.h"
 #include "ExynosHWCHelper.h"
 #include "ExynosHWCModule.h"
@@ -61,6 +63,7 @@
 using LbeState = ::aidl::com::google::hardware::pixel::display::LbeState;
 using PanelCalibrationStatus = ::aidl::com::google::hardware::pixel::display::PanelCalibrationStatus;
 
+using OverlayProperties = aidl::android::hardware::graphics::composer3::OverlayProperties;
 using namespace android;
 
 struct exynos_callback_info_t {
@@ -141,10 +144,8 @@
     GEOMETRY_ERROR_CASE                       = 1ULL << 63,
 };
 
-class ExynosDevice;
 class ExynosDisplay;
 class ExynosResourceManager;
-class ExynosDeviceInterface;
 
 class ExynosDevice {
     public:
@@ -153,6 +154,7 @@
          * Display list that managed by Device.
          */
         android::Vector< ExynosDisplay* > mDisplays;
+        std::map<uint32_t, ExynosDisplay *> mDisplayMap;
 
         int mNumVirtualDisplay;
 
@@ -235,7 +237,7 @@
         /**
          * @param display
          */
-        ExynosDisplay* getDisplay(uint32_t display);
+        ExynosDisplay* getDisplay(uint32_t display) { return mDisplayMap[display]; }
 
         /**
          * Device Functions for HWC 2.0
@@ -297,6 +299,7 @@
         void setDisplayMode(uint32_t displayMode);
         bool checkDisplayConnection(uint32_t displayId);
         bool checkNonInternalConnection();
+        void getCapabilitiesLegacy(uint32_t *outCount, int32_t *outCapabilities);
         void getCapabilities(uint32_t *outCount, int32_t* outCapabilities);
         void setGeometryChanged(uint64_t changedBit) { mGeometryChanged|= changedBit;};
         void clearGeometryChanged();
@@ -338,6 +341,12 @@
                                      hwc2_function_pointer_t point);
         void onVsyncIdle(hwc2_display_t displayId);
         bool isDispOffAsyncSupported() { return mDisplayOffAsync; };
+        bool hasOtherDisplayOn(ExynosDisplay *display);
+        virtual int32_t getOverlaySupport([[maybe_unused]] OverlayProperties* caps){
+            return HWC2_ERROR_UNSUPPORTED;
+        }
+
+        void onRefreshRateChangedDebug(hwc2_display_t displayId, uint32_t vsyncPeriod);
 
     protected:
         void initDeviceInterface(uint32_t interfaceType);
diff --git a/libhwc2.1/libdevice/ExynosDisplay.cpp b/libhwc2.1/libdevice/ExynosDisplay.cpp
index 6d4dce3..8c66345 100644
--- a/libhwc2.1/libdevice/ExynosDisplay.cpp
+++ b/libhwc2.1/libdevice/ExynosDisplay.cpp
@@ -31,6 +31,7 @@
 #include <sys/ioctl.h>
 #include <utils/CallStack.h>
 
+#include <charconv>
 #include <future>
 #include <map>
 
@@ -60,7 +61,8 @@
 constexpr float nsecsPerSec = std::chrono::nanoseconds(1s).count();
 constexpr int64_t nsecsIdleHintTimeout = std::chrono::nanoseconds(100ms).count();
 
-ExynosDisplay::PowerHalHintWorker::PowerHalHintWorker(uint32_t displayId)
+ExynosDisplay::PowerHalHintWorker::PowerHalHintWorker(uint32_t displayId,
+                                                      const String8 &displayTraceName)
       : Worker("DisplayHints", HAL_PRIORITY_URGENT_DISPLAY),
         mNeedUpdateRefreshRateHint(false),
         mLastRefreshRateHint(0),
@@ -69,8 +71,10 @@
         mIdleHintDeadlineTime(0),
         mIdleHintSupportIsChecked(false),
         mIdleHintIsSupported(false),
+        mDisplayTraceName(displayTraceName),
         mPowerModeState(HWC2_POWER_MODE_OFF),
         mVsyncPeriod(16666666),
+        mConnectRetryCount(0),
         mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)),
         mPowerHalExtAidl(nullptr),
         mPowerHalAidl(nullptr),
@@ -110,7 +114,8 @@
     mPowerHalAidl = IPower::fromBinder(pwBinder);
 
     if (!mPowerHalAidl) {
-        ALOGE("failed to connect power HAL");
+        ALOGE("failed to connect power HAL (retry %u)", mConnectRetryCount);
+        mConnectRetryCount++;
         return -EINVAL;
     }
 
@@ -121,10 +126,12 @@
 
     if (!mPowerHalExtAidl) {
         mPowerHalAidl = nullptr;
-        ALOGE("failed to connect power HAL extension");
+        ALOGE("failed to connect power HAL extension (retry %u)", mConnectRetryCount);
+        mConnectRetryCount++;
         return -EINVAL;
     }
 
+    mConnectRetryCount = 0;
     AIBinder_linkToDeath(pwExtBinder.get(), mDeathRecipient.get(), reinterpret_cast<void *>(this));
     // ensure the hint session is recreated every time powerhal is recreated
     mPowerHintSession = nullptr;
@@ -190,6 +197,10 @@
 
 int32_t ExynosDisplay::PowerHalHintWorker::checkRefreshRateHintSupport(int refreshRate) {
     int32_t ret = NO_ERROR;
+
+    if (!isPowerHalExist()) {
+        return -EOPNOTSUPP;
+    }
     const auto its = mRefreshRateHintSupportMap.find(refreshRate);
     if (its == mRefreshRateHintSupportMap.end()) {
         /* check new hint */
@@ -262,6 +273,11 @@
 
 int32_t ExynosDisplay::PowerHalHintWorker::checkIdleHintSupport(void) {
     int32_t ret = NO_ERROR;
+
+    if (!isPowerHalExist()) {
+        return -EOPNOTSUPP;
+    }
+
     Lock();
     if (mIdleHintSupportIsChecked) {
         ret = mIdleHintIsSupported ? NO_ERROR : -EOPNOTSUPP;
@@ -293,6 +309,10 @@
         return *(sSharedDisplayData.hintSessionSupported);
     }
 
+    if (!isPowerHalExist()) {
+        return -EOPNOTSUPP;
+    }
+
     if (connectPowerHal() != NO_ERROR) {
         ALOGW("Error connecting to the PowerHAL");
         return -EINVAL;
@@ -327,7 +347,7 @@
 
     bool enableIdleHint =
             (deadlineTime < systemTime(SYSTEM_TIME_MONOTONIC) && CC_LIKELY(deadlineTime > 0));
-    ATRACE_INT("HWCIdleHintTimer:", enableIdleHint);
+    DISPLAY_ATRACE_INT("HWCIdleHintTimer", enableIdleHint);
 
     if (mIdleHintIsEnabled != enableIdleHint || forceUpdate) {
         ret = sendPowerHalExtHint(mIdleHintStr, enableIdleHint);
@@ -443,13 +463,13 @@
     WorkDuration duration = {.durationNanos = reportedDurationNs, .timeStampNanos = systemTime()};
 
     if (sTraceHintSessionData) {
-        ATRACE_INT64("Measured duration", actualDurationNanos);
-        ATRACE_INT64("Target error term", mTargetWorkDuration - actualDurationNanos);
+        DISPLAY_ATRACE_INT64("Measured duration", actualDurationNanos);
+        DISPLAY_ATRACE_INT64("Target error term", mTargetWorkDuration - actualDurationNanos);
 
-        ATRACE_INT64("Reported duration", reportedDurationNs);
-        ATRACE_INT64("Reported target", mLastTargetDurationReported);
-        ATRACE_INT64("Reported target error term",
-                     mLastTargetDurationReported - reportedDurationNs);
+        DISPLAY_ATRACE_INT64("Reported duration", reportedDurationNs);
+        DISPLAY_ATRACE_INT64("Reported target", mLastTargetDurationReported);
+        DISPLAY_ATRACE_INT64("Reported target error term",
+                             mLastTargetDurationReported - reportedDurationNs);
     }
     ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
           " with error: %" PRId64,
@@ -473,12 +493,12 @@
     Lock();
     mTargetWorkDuration = targetDurationNanos - kTargetSafetyMargin.count();
 
-    if (sTraceHintSessionData) ATRACE_INT64("Time target", mTargetWorkDuration);
+    if (sTraceHintSessionData) DISPLAY_ATRACE_INT64("Time target", mTargetWorkDuration);
     bool shouldSignal = false;
     if (!sNormalizeTarget) {
         shouldSignal = needUpdateTargetWorkDurationLocked();
         if (shouldSignal && mActualWorkDuration.has_value() && sTraceHintSessionData) {
-            ATRACE_INT64("Target error term", *mActualWorkDuration - mTargetWorkDuration);
+            DISPLAY_ATRACE_INT64("Target error term", *mActualWorkDuration - mTargetWorkDuration);
         }
     }
     Unlock();
@@ -906,9 +926,9 @@
         if ((mOtfMPP == NULL) && (mM2mMPP == NULL))
             result.appendFormat("\tresource is not assigned\n");
         if (mOtfMPP != NULL)
-            result.appendFormat("\tassignedMPP: %s\n", mOtfMPP->mName.string());
+            result.appendFormat("\tassignedMPP: %s\n", mOtfMPP->mName.c_str());
         if (mM2mMPP != NULL)
-            result.appendFormat("\t%s\n", mM2mMPP->mName.string());
+            result.appendFormat("\t%s\n", mM2mMPP->mName.c_str());
     }
     if (mTargetBuffer != NULL) {
         uint64_t internal_format = 0;
@@ -948,9 +968,10 @@
     }
 }
 
-ExynosDisplay::ExynosDisplay(uint32_t index, ExynosDevice *device)
-      : mDisplayId(HWC_DISPLAY_PRIMARY),
-        mType(HWC_NUM_DISPLAY_TYPES),
+ExynosDisplay::ExynosDisplay(uint32_t type, uint32_t index, ExynosDevice *device,
+                             const std::string &displayName)
+      : mDisplayId(getDisplayId(type, index)),
+        mType(type),
         mIndex(index),
         mDeconNodeName(""),
         mXres(1440),
@@ -960,13 +981,15 @@
         mVsyncPeriod(16666666),
         mBtsVsyncPeriod(16666666),
         mDevice(device),
-        mDisplayName(""),
+        mDisplayName(displayName.c_str()),
+        mDisplayTraceName(String8::format("%s(%d)", displayName.c_str(), mDisplayId)),
         mPlugState(false),
         mHasSingleBuffer(false),
         mResourceManager(NULL),
         mClientCompositionInfo(COMPOSITION_CLIENT),
         mExynosCompositionInfo(COMPOSITION_EXYNOS),
         mGeometryChanged(0x0),
+        mBufferUpdates(0),
         mRenderingState(RENDERING_STATE_NONE),
         mHWCRenderingState(RENDERING_STATE_NONE),
         mDisplayBW(0),
@@ -1001,7 +1024,11 @@
         mVsyncPeriodChangeConstraints{systemTime(SYSTEM_TIME_MONOTONIC), 0},
         mVsyncAppliedTimeLine{false, 0, systemTime(SYSTEM_TIME_MONOTONIC)},
         mConfigRequestState(hwc_request_state_t::SET_CONFIG_STATE_DONE),
-        mPowerHalHint(getDisplayId(mDisplayId, mIndex)) {
+        mPowerHalHint(mDisplayId, mDisplayTraceName),
+        mErrLogFileWriter(2, ERR_LOG_SIZE),
+        mDebugDumpFileWriter(10, 1, ".dump"),
+        mFenceFileWriter(2, FENCE_ERR_LOG_SIZE),
+        mOperationRateManager(nullptr) {
     mDisplayControl.enableCompositionCrop = true;
     mDisplayControl.enableExynosCompositionOptimization = true;
     mDisplayControl.enableClientCompositionOptimization = true;
@@ -1146,6 +1173,7 @@
     }
 
     mDisplayInterface->destroyLayer(layer);
+    layer->resetAssignedResource();
 
     delete layer;
 
@@ -1280,7 +1308,7 @@
         /* Set any flag to mGeometryChanged */
         setGeometryChanged(GEOMETRY_DEVICE_SCENARIO_CHANGED);
     }
-#ifndef HWC_SKIP_VALIDATE
+#ifdef HWC_NO_SUPPORT_SKIP_VALIDATE
     if (mDevice->checkNonInternalConnection()) {
         /* Set any flag to mGeometryChanged */
         mDevice->mGeometryChanged = 0x10;
@@ -1450,11 +1478,16 @@
 void ExynosDisplay::clearGeometryChanged()
 {
     mGeometryChanged = 0;
+    mBufferUpdates = 0;
     for (size_t i=0; i < mLayers.size(); i++) {
         mLayers[i]->clearGeometryChanged();
     }
 }
 
+bool ExynosDisplay::isFrameUpdate() {
+    return mGeometryChanged > 0 || mBufferUpdates > 0;
+}
+
 int ExynosDisplay::handleStaticLayers(ExynosCompositionInfo& compositionInfo)
 {
     if (compositionInfo.mType != COMPOSITION_CLIENT)
@@ -1510,7 +1543,7 @@
                     android::String8 result;
                     result.appendFormat("config[%zu]\n", i);
                     dumpConfig(result, mLastDpuData.configs[i]);
-                    DISPLAY_LOGE("%s", result.string());
+                    DISPLAY_LOGE("%s", result.c_str());
                 }
                 DISPLAY_LOGE("compositionInfo.mLastWinConfigData config [%d, %d, %d]",
                         compositionInfo.mLastWinConfigData.fd_idma[0],
@@ -1676,11 +1709,14 @@
     return NO_ERROR;
 }
 
-bool ExynosDisplay::skipSignalIdleForVideoLayer(void) {
-    /* ignore the frame update in case we have video layer but ui layer is not updated */
+bool ExynosDisplay::skipSignalIdle(void) {
     for (size_t i = 0; i < mLayers.size(); i++) {
-        if (!mLayers[i]->isLayerFormatYuv() &&
-            mLayers[i]->mLastLayerBuffer != mLayers[i]->mLayerBuffer) {
+        // Frame update for refresh rate overlay indicator layer can be ignored
+        if (mLayers[i]->mRequestedCompositionType == HWC2_COMPOSITION_REFRESH_RATE_INDICATOR)
+            continue;
+        // Frame update for video layer can be ignored
+        if (mLayers[i]->isLayerFormatYuv()) continue;
+        if (mLayers[i]->mLastLayerBuffer != mLayers[i]->mLayerBuffer) {
             return false;
         }
     }
@@ -2388,31 +2424,15 @@
     return 0;
 }
 
-void ExynosDisplay::printDebugInfos(String8 &reason)
-{
-    FILE *pFile = NULL;
+void ExynosDisplay::printDebugInfos(String8 &reason) {
     struct timeval tv;
     gettimeofday(&tv, NULL);
     reason.appendFormat("errFrameNumber: %" PRId64 " time:%s\n", mErrorFrameCount,
-                        getLocalTimeStr(tv).string());
-    ALOGD("%s", reason.string());
+                        getLocalTimeStr(tv).c_str());
+    ALOGD("%s", reason.c_str());
 
-    if (mErrorFrameCount < HWC_PRINT_FRAME_NUM) {
-        char filePath[128];
-        sprintf(filePath, "%s/%s_hwc_debug%d.dump", ERROR_LOG_PATH0, mDisplayName.string(), (int)mErrorFrameCount);
-        pFile = fopen(filePath, "wb");
-        if (pFile == NULL) {
-            ALOGE("Fail to open file %s, error: %s", filePath, strerror(errno));
-            sprintf(filePath, "%s/%s_hwc_debug%d.dump", ERROR_LOG_PATH1, mDisplayName.string(), (int)mErrorFrameCount);
-            pFile = fopen(filePath, "wb");
-        }
-        if (pFile == NULL) {
-            ALOGE("Fail to open file %s, error: %s", filePath, strerror(errno));
-        } else {
-            ALOGI("%s was created", filePath);
-            fwrite(reason.string(), 1, reason.size(), pFile);
-        }
-    }
+    bool fileOpened = mDebugDumpFileWriter.chooseOpenedFile();
+    mDebugDumpFileWriter.write(reason);
     mErrorFrameCount++;
 
     android::String8 result;
@@ -2423,25 +2443,21 @@
     ExynosCompositionInfo exynosCompInfo = mExynosCompositionInfo;
     clientCompInfo.dump(result);
     exynosCompInfo.dump(result);
-    ALOGD("%s", result.string());
-    if (pFile != NULL) {
-        fwrite(result.string(), 1, result.size(), pFile);
-    }
+    ALOGD("%s", result.c_str());
+    mDebugDumpFileWriter.write(result);
     result.clear();
 
     result.appendFormat("=======================  dump exynos layers (%zu)  ================================\n",
             mLayers.size());
-    ALOGD("%s", result.string());
-    if (pFile != NULL) {
-        fwrite(result.string(), 1, result.size(), pFile);
-    }
+    ALOGD("%s", result.c_str());
+    mDebugDumpFileWriter.write(result);
     result.clear();
     for (uint32_t i = 0; i < mLayers.size(); i++) {
         ExynosLayer *layer = mLayers[i];
         layer->printLayer();
-        if (pFile != NULL) {
+        if (fileOpened) {
             layer->dump(result);
-            fwrite(result.string(), 1, result.size(), pFile);
+            mDebugDumpFileWriter.write(result);
             result.clear();
         }
     }
@@ -2449,41 +2465,35 @@
     if (mIgnoreLayers.size()) {
         result.appendFormat("=======================  dump ignore layers (%zu)  ================================\n",
                             mIgnoreLayers.size());
-        ALOGD("%s", result.string());
-        if (pFile != NULL) {
-            fwrite(result.string(), 1, result.size(), pFile);
-        }
+        ALOGD("%s", result.c_str());
+        mDebugDumpFileWriter.write(result);
         result.clear();
         for (uint32_t i = 0; i < mIgnoreLayers.size(); i++) {
             ExynosLayer *layer = mIgnoreLayers[i];
             layer->printLayer();
-            if (pFile != NULL) {
+            if (fileOpened) {
                 layer->dump(result);
-                fwrite(result.string(), 1, result.size(), pFile);
+                mDebugDumpFileWriter.write(result);
                 result.clear();
             }
         }
     }
 
     result.appendFormat("=============================  dump win configs  ===================================\n");
-    ALOGD("%s", result.string());
-    if (pFile != NULL) {
-        fwrite(result.string(), 1, result.size(), pFile);
-    }
+    ALOGD("%s", result.c_str());
+    mDebugDumpFileWriter.write(result);
     result.clear();
     for (size_t i = 0; i < mDpuData.configs.size(); i++) {
         ALOGD("config[%zu]", i);
         printConfig(mDpuData.configs[i]);
-        if (pFile != NULL) {
+        if (fileOpened) {
             result.appendFormat("config[%zu]\n", i);
             dumpConfig(result, mDpuData.configs[i]);
-            fwrite(result.string(), 1, result.size(), pFile);
+            mDebugDumpFileWriter.write(result);
             result.clear();
         }
     }
-    if (pFile != NULL) {
-        fclose(pFile);
-    }
+    mDebugDumpFileWriter.flush();
 }
 
 int32_t ExynosDisplay::validateWinConfigData()
@@ -2503,7 +2513,7 @@
                     if ((config.assignedMPP != NULL) &&
                         (config.assignedMPP == compare_config.assignedMPP)) {
                         DISPLAY_LOGE("WIN_CONFIG error: duplicated assignedMPP(%s) between win%zu, win%zu",
-                                config.assignedMPP->mName.string(), i, j);
+                                config.assignedMPP->mName.c_str(), i, j);
                         compare_config.state = compare_config.WIN_STATE_DISABLED;
                         flagValidConfig = false;
                         continue;
@@ -2545,7 +2555,7 @@
                 {
                     DISPLAY_LOGE("WIN_CONFIG error: invalid src alignment : %zu, "\
                             "assignedMPP: %s, mppType:%d, format(%d), s_x: %d(%d), s_y: %d(%d), s_w : %d(%d), s_h : %d(%d)", i,
-                            config.assignedMPP->mName.string(), exynosMPP->mLogicalType, config.format, config.src.x, srcXAlign,
+                            config.assignedMPP->mName.c_str(), exynosMPP->mLogicalType, config.format, config.src.x, srcXAlign,
                             config.src.y, srcYAlign, config.src.w, srcWidthAlign, config.src.h, srcHeightAlign);
                     configInvalid = true;
                 }
@@ -3025,6 +3035,9 @@
     } else if ((mLayers[layerIndex]->mCompositionType == HWC2_COMPOSITION_SOLID_COLOR) &&
                (mLayers[layerIndex]->mValidateCompositionType == HWC2_COMPOSITION_DEVICE)) {
         type = HWC2_COMPOSITION_SOLID_COLOR;
+    } else if ((mLayers[layerIndex]->mCompositionType == HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) &&
+               (mLayers[layerIndex]->mValidateCompositionType == HWC2_COMPOSITION_DEVICE)) {
+        type = HWC2_COMPOSITION_REFRESH_RATE_INDICATOR;
     } else {
         type = mLayers[layerIndex]->mValidateCompositionType;
     }
@@ -3376,7 +3389,7 @@
 }
 
 int32_t ExynosDisplay::presentDisplay(int32_t* outRetireFence) {
-    ATRACE_CALL();
+    DISPLAY_ATRACE_CALL();
     gettimeofday(&updateTimeInfo.lastPresentTime, NULL);
 
     const bool mixedComposition = isMixedComposition();
@@ -3471,7 +3484,7 @@
          * presentDisplay() can be called before validateDisplay()
          * when HWC2_CAPABILITY_SKIP_VALIDATE is supported
          */
-#ifndef HWC_SKIP_VALIDATE
+#ifdef HWC_NO_SUPPORT_SKIP_VALIDATE
         DISPLAY_LOGE("%s:: Skip validate is not supported. Invalid rendering state : %d", __func__, mRenderingState);
         goto err;
 #endif
@@ -3602,10 +3615,14 @@
         goto err;
     }
 
-    if (mGeometryChanged != 0 || !skipSignalIdleForVideoLayer()) {
+    if (mGeometryChanged != 0 || !skipSignalIdle()) {
         mPowerHalHint.signalIdle();
     }
 
+    if (isFrameUpdate()) {
+        updateRefreshRateIndicator();
+    }
+
     handleWindowUpdate();
 
     setDisplayWinConfigData();
@@ -3649,7 +3666,7 @@
                     mLayers[i]->mExynosCompositionType,
                     mLayers[i]->mValidateCompositionType);
             if (mLayers[i]->mM2mMPP != NULL)
-                DISPLAY_LOGE("\t%s is assigned", mLayers[i]->mM2mMPP->mName.string());
+                DISPLAY_LOGE("\t%s is assigned", mLayers[i]->mM2mMPP->mName.c_str());
             if (mLayers[i]->mAcquireFence > 0)
                 fence_close(mLayers[i]->mAcquireFence, this,
                         FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_LAYER);
@@ -3832,7 +3849,7 @@
             for (size_t i = 0; i < mLastDpuData.configs.size(); i++) {
                 errString.appendFormat("config[%zu]\n", i);
                 dumpConfig(errString, mLastDpuData.configs[i]);
-                DISPLAY_LOGE("\t%s", errString.string());
+                DISPLAY_LOGE("\t%s", errString.c_str());
                 errString.clear();
             }
             errString.appendFormat("%s:: skip flag is enabled but buffer is updated\n",
@@ -3981,9 +3998,16 @@
 int32_t ExynosDisplay::setDisplayBrightness(float brightness, bool waitPresent)
 {
     if (mBrightnessController) {
-        return mBrightnessController->processDisplayBrightness(brightness, mVsyncPeriod,
-                                                               waitPresent);
+        int32_t ret;
+
+        ret = mBrightnessController->processDisplayBrightness(brightness, mVsyncPeriod,
+                                                              waitPresent);
+        if (ret == NO_ERROR && mOperationRateManager) {
+            mOperationRateManager->onBrightness(mBrightnessController->getBrightnessLevel());
+        }
+        return ret;
     }
+
     return HWC2_ERROR_UNSUPPORTED;
 }
 
@@ -4053,17 +4077,23 @@
         hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints,
         hwc_vsync_period_change_timeline_t* outTimeline)
 {
-    ATRACE_CALL();
+    DISPLAY_ATRACE_CALL();
     Mutex::Autolock lock(mDisplayMutex);
+    const nsecs_t current = systemTime(SYSTEM_TIME_MONOTONIC);
+    const nsecs_t diffMs = ns2ms(vsyncPeriodChangeConstraints->desiredTimeNanos - current);
+    DISPLAY_LOGD(eDebugDisplayConfig, "config(%d->%d), seamless(%d), diff(%" PRId64 ")",
+                 mActiveConfig, config, vsyncPeriodChangeConstraints->seamlessRequired, diffMs);
 
-    DISPLAY_LOGD(eDebugDisplayConfig,
-                 "config(%d), seamless(%d), "
-                 "desiredTime(%" PRId64 ")",
-                 config, vsyncPeriodChangeConstraints->seamlessRequired,
-                 vsyncPeriodChangeConstraints->desiredTimeNanos);
+    if (CC_UNLIKELY(ATRACE_ENABLED())) ATRACE_NAME(("diff:" + std::to_string(diffMs)).c_str());
 
     if (isBadConfig(config)) return HWC2_ERROR_BAD_CONFIG;
 
+    if (!isConfigSettingEnabled()) {
+        mPendingConfig = config;
+        DISPLAY_LOGI("%s: config setting disabled, set pending config=%d", __func__, config);
+        return HWC2_ERROR_NONE;
+    }
+
     if (mDisplayConfigs[mActiveConfig].groupId != mDisplayConfigs[config].groupId) {
         if (vsyncPeriodChangeConstraints->seamlessRequired) {
             DISPLAY_LOGD(eDebugDisplayConfig, "Case : Seamless is not allowed");
@@ -4106,6 +4136,7 @@
     mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_PENDING;
     mVsyncPeriodChangeConstraints = *vsyncPeriodChangeConstraints;
     mDesiredConfig = config;
+    DISPLAY_ATRACE_INT("Pending ActiveConfig", mDesiredConfig);
 
     calculateTimeline(config, vsyncPeriodChangeConstraints, outTimeline);
 
@@ -4249,14 +4280,6 @@
                      __func__, mConfigRequestState);
         mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_DONE;
         updateAppliedActiveConfig(mActiveConfig, systemTime(SYSTEM_TIME_MONOTONIC));
-
-        std::lock_guard<std::mutex> lock(mPeakRefreshRateMutex);
-        bool isPeakRefreshRate = isCurrentPeakRefreshRate();
-        ATRACE_INT("isPeakRefreshRate", isPeakRefreshRate);
-        if (isPeakRefreshRate && mNotifyPeakRefreshRate) {
-            mPeakRefreshRateCondition.notify_one();
-            mNotifyPeakRefreshRate = false;
-        }
     }
     return NO_ERROR;
 }
@@ -4326,6 +4349,7 @@
 
 int32_t ExynosDisplay::doDisplayConfigPostProcess(ExynosDevice *dev)
 {
+    ATRACE_CALL();
     uint64_t current = systemTime(SYSTEM_TIME_MONOTONIC);
 
     int64_t actualChangeTime = 0;
@@ -4340,11 +4364,13 @@
     if (actualChangeTime >= mVsyncPeriodChangeConstraints.desiredTimeNanos) {
         DISPLAY_LOGD(eDebugDisplayConfig, "Request setActiveConfig");
         needSetActiveConfig = true;
-        ATRACE_INT("Pending ActiveConfig", 0);
+        DISPLAY_ATRACE_INT("Pending ActiveConfig", 0);
+        DISPLAY_ATRACE_INT64("TimeToChangeConfig", 0);
     } else {
         DISPLAY_LOGD(eDebugDisplayConfig, "setActiveConfig still pending (mDesiredConfig %d)",
                      mDesiredConfig);
-        ATRACE_INT("Pending ActiveConfig", mDesiredConfig);
+        DISPLAY_ATRACE_INT("Pending ActiveConfig", mDesiredConfig);
+        DISPLAY_ATRACE_INT64("TimeToChangeConfig", ns2ms(actualChangeTime - current));
     }
 
     if (needSetActiveConfig) {
@@ -4470,8 +4496,7 @@
 
 int32_t ExynosDisplay::validateDisplay(
         uint32_t* outNumTypes, uint32_t* outNumRequests) {
-
-    ATRACE_CALL();
+    DISPLAY_ATRACE_CALL();
     gettimeofday(&updateTimeInfo.lastValidateTime, NULL);
     Mutex::Autolock lock(mDisplayMutex);
 
@@ -4612,6 +4637,7 @@
 
 int32_t ExynosDisplay::startPostProcessing()
 {
+    ATRACE_CALL();
     int ret = NO_ERROR;
     String8 errString;
 
@@ -4698,7 +4724,7 @@
     Mutex::Autolock lock(mDisplayMutex);
     result.appendFormat("[%s] display information size: %d x %d, vsyncState: %d, colorMode: %d, "
                         "colorTransformHint: %d, orientation %d\n",
-                        mDisplayName.string(), mXres, mYres, mVsyncState, mColorMode,
+                        mDisplayName.c_str(), mXres, mYres, mVsyncState, mColorMode,
                         mColorTransformHint, mMountOrientation);
     mClientCompositionInfo.dump(result);
     mExynosCompositionInfo.dump(result);
@@ -5018,9 +5044,7 @@
     return ret;
 }
 
-
-int32_t ExynosDisplay::addExynosCompositionLayer(uint32_t layerIndex)
-{
+int32_t ExynosDisplay::addExynosCompositionLayer(uint32_t layerIndex, float totalUsedCapa) {
     bool invalidFlag = false;
     int32_t changeFlag = NO_ERROR;
     int ret = 0;
@@ -5099,7 +5123,7 @@
         layer->setExynosMidImage(dst_img);
         bool isAssignable = false;
         if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0)
-            isAssignable = m2mMPP->isAssignable(this, src_img, dst_img);
+            isAssignable = m2mMPP->isAssignable(this, src_img, dst_img, totalUsedCapa);
 
         if (layer->mValidateCompositionType == HWC2_COMPOSITION_CLIENT)
         {
@@ -5123,7 +5147,7 @@
             if ((ret = m2mMPP->assignMPP(this, layer)) != NO_ERROR)
             {
                 HWC_LOGE(this, "%s:: %s MPP assignMPP() error (%d)",
-                        __func__, m2mMPP->mName.string(), ret);
+                        __func__, m2mMPP->mName.c_str(), ret);
                 return ret;
             }
             if (layer->mValidateCompositionType == HWC2_COMPOSITION_DEVICE) mWindowNumUsed--;
@@ -5164,7 +5188,7 @@
                 if ((ret = m2mMPP->assignMPP(this, mLayers[maxPriorityIndex])) != NO_ERROR)
                 {
                     ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                            __func__, m2mMPP->mName.string(), ret);
+                            __func__, m2mMPP->mName.c_str(), ret);
                     return ret;
                 }
             }
@@ -5859,13 +5883,13 @@
                 break;
         }
     }
-    ATRACE_INT("HWComposer: DPU Layer", dpu_count);
-    ATRACE_INT("HWComposer: G2D Layer", g2d_count);
-    ATRACE_INT("HWComposer: GPU Layer", gpu_count);
-    ATRACE_INT("HWComposer: RCD Layer", rcd_count);
-    ATRACE_INT("HWComposer: DPU Cached Layer", skip_count);
-    ATRACE_INT("HWComposer: SF Cached Layer", mIgnoreLayers.size());
-    ATRACE_INT("HWComposer: Total Layer", mLayers.size() + mIgnoreLayers.size());
+    DISPLAY_ATRACE_INT("HWComposer: DPU Layer", dpu_count);
+    DISPLAY_ATRACE_INT("HWComposer: G2D Layer", g2d_count);
+    DISPLAY_ATRACE_INT("HWComposer: GPU Layer", gpu_count);
+    DISPLAY_ATRACE_INT("HWComposer: RCD Layer", rcd_count);
+    DISPLAY_ATRACE_INT("HWComposer: DPU Cached Layer", skip_count);
+    DISPLAY_ATRACE_INT("HWComposer: SF Cached Layer", mIgnoreLayers.size());
+    DISPLAY_ATRACE_INT("HWComposer: Total Layer", mLayers.size() + mIgnoreLayers.size());
 }
 
 void ExynosDisplay::updateBrightnessState() {
@@ -5924,6 +5948,9 @@
 
 int32_t ExynosDisplay::flushDisplayBrightnessChange() {
     if (mBrightnessController) {
+        if (mOperationRateManager) {
+            mOperationRateManager->onBrightness(mBrightnessController->getBrightnessLevel());
+        }
         return mBrightnessController->applyPendingChangeViaSysfs(mVsyncPeriod);
     }
     return NO_ERROR;
@@ -6041,6 +6068,11 @@
     return mDisplayInterface->getDisplayIdleTimerSupport(outSupport);
 }
 
+int32_t ExynosDisplay::getDisplayMultiThreadedPresentSupport(bool &outSupport) {
+    outSupport = mDisplayControl.multiThreadedPresent;
+    return NO_ERROR;
+}
+
 bool ExynosDisplay::isMixedComposition() {
     for (size_t i = 0; i < mLayers.size(); i++) {
         if (mLayers[i]->mBrightness < 1.0) {
@@ -6073,3 +6105,227 @@
     }
     return HWC2_ERROR_BAD_CONFIG;
 }
+
+FILE *ExynosDisplay::RotatingLogFileWriter::openLogFile(const std::string &filename,
+                                                        const std::string &mode) {
+    FILE *file = nullptr;
+    auto fullpath = std::string(ERROR_LOG_PATH0) + "/" + filename;
+    file = fopen(fullpath.c_str(), mode.c_str());
+    if (file != nullptr) {
+        return file;
+    }
+    ALOGE("Fail to open file %s, error: %s", fullpath.c_str(), strerror(errno));
+    fullpath = std::string(ERROR_LOG_PATH1) + "/" + filename;
+    file = fopen(fullpath.c_str(), mode.c_str());
+    if (file == nullptr) {
+        ALOGE("Fail to open file %s, error: %s", fullpath.c_str(), strerror(errno));
+    }
+    return file;
+}
+
+std::optional<nsecs_t> ExynosDisplay::RotatingLogFileWriter::getLastModifiedTimestamp(
+        const std::string &filename) {
+    struct stat fileStat;
+    auto fullpath = std::string(ERROR_LOG_PATH0) + "/" + filename;
+    if (stat(fullpath.c_str(), &fileStat) == 0) {
+        return fileStat.st_mtim.tv_sec * nsecsPerSec + fileStat.st_mtim.tv_nsec;
+    }
+    fullpath = std::string(ERROR_LOG_PATH1) + "/" + filename;
+    if (stat(fullpath.c_str(), &fileStat) == 0) {
+        return fileStat.st_mtim.tv_sec * nsecsPerSec + fileStat.st_mtim.tv_nsec;
+    }
+    return std::nullopt;
+}
+
+bool ExynosDisplay::RotatingLogFileWriter::chooseOpenedFile() {
+    if (mLastFileIndex < 0) {
+        // HWC could be restarted, so choose to open new file or continue the last modified file
+        int chosenIndex = 0;
+        nsecs_t lastModifTimestamp = 0;
+        for (int i = 0; i < mMaxFileCount; ++i) {
+            auto timestamp = getLastModifiedTimestamp(mPrefixName + std::to_string(i) + mExtension);
+            if (!timestamp.has_value()) {
+                chosenIndex = i;
+                break;
+            }
+            if (i == 0 || lastModifTimestamp < *timestamp) {
+                chosenIndex = i;
+                lastModifTimestamp = *timestamp;
+            }
+        }
+        auto filename = mPrefixName + std::to_string(chosenIndex) + mExtension;
+        mFile = openLogFile(filename, "ab");
+        if (mFile == nullptr) {
+            ALOGE("Unable to open log file for %s", filename.c_str());
+            return false;
+        }
+        mLastFileIndex = chosenIndex;
+    }
+
+    // Choose to use the same last file or move on to the next file
+    for (int i = 0; i < 2; ++i) {
+        if (mFile == nullptr) {
+            mFile = openLogFile(mPrefixName + std::to_string(mLastFileIndex) + mExtension,
+                                (i == 0) ? "ab" : "wb");
+        }
+        if (mFile != nullptr) {
+            auto fileSize = ftell(mFile);
+            if (fileSize < mThresholdSizePerFile) return true;
+            fclose(mFile);
+            mFile = nullptr;
+        }
+        mLastFileIndex = (mLastFileIndex + 1) % mMaxFileCount;
+    }
+    return false;
+}
+
+ExynosDisplay::RefreshRateIndicatorHandler::RefreshRateIndicatorHandler(ExynosDisplay *display)
+      : mDisplay(display), mLastRefreshRate(0), mLastCallbackTime(0) {}
+
+int32_t ExynosDisplay::RefreshRateIndicatorHandler::init() {
+    auto path = String8::format(kRefreshRateStatePathFormat, mDisplay->mIndex);
+    mFd.Set(open(path.c_str(), O_RDONLY));
+    if (mFd.get() < 0) {
+        ALOGE("Failed to open sysfs(%s) for refresh rate debug event: %s", path.c_str(),
+              strerror(errno));
+        return -errno;
+    }
+
+    return NO_ERROR;
+}
+
+void ExynosDisplay::RefreshRateIndicatorHandler::updateRefreshRateLocked(int refreshRate) {
+    ATRACE_CALL();
+    ATRACE_INT("Refresh rate indicator event", refreshRate);
+    auto lastUpdate = mDisplay->getLastLayerUpdateTime();
+    // Ignore refresh rate increase that is caused by refresh rate indicator update but there's
+    // no update for the other layers
+    if (refreshRate > mLastRefreshRate && mLastRefreshRate > 0 && lastUpdate < mLastCallbackTime) {
+        mIgnoringLastUpdate = true;
+        return;
+    }
+    mIgnoringLastUpdate = false;
+    if (refreshRate == mLastRefreshRate) {
+        return;
+    }
+    mLastRefreshRate = refreshRate;
+    mLastCallbackTime = systemTime(CLOCK_MONOTONIC);
+    ATRACE_INT("Refresh rate indicator callback", mLastRefreshRate);
+    mDisplay->mDevice->onRefreshRateChangedDebug(mDisplay->mDisplayId, s2ns(1) / mLastRefreshRate);
+}
+
+void ExynosDisplay::RefreshRateIndicatorHandler::handleSysfsEvent() {
+    ATRACE_CALL();
+    std::scoped_lock lock(mMutex);
+
+    char buffer[1024];
+    lseek(mFd.get(), 0, SEEK_SET);
+    int ret = read(mFd.get(), &buffer, sizeof(buffer));
+    if (ret < 0) {
+        ALOGE("%s: Failed to read refresh rate from fd %d: %s", __func__, mFd.get(),
+              strerror(errno));
+        return;
+    }
+    std::string_view bufferView(buffer);
+    auto pos = bufferView.find('@');
+    if (pos == std::string::npos) {
+        ALOGE("%s: Failed to parse refresh rate event (invalid format)", __func__);
+        return;
+    }
+    int refreshRate = 0;
+    std::from_chars(bufferView.data() + pos + 1, bufferView.data() + bufferView.size() - 1,
+                    refreshRate);
+    updateRefreshRateLocked(refreshRate);
+}
+
+void ExynosDisplay::RefreshRateIndicatorHandler::updateRefreshRate(int refreshRate) {
+    std::scoped_lock lock(mMutex);
+    updateRefreshRateLocked(refreshRate);
+}
+
+int32_t ExynosDisplay::setRefreshRateChangedCallbackDebugEnabled(bool enabled) {
+    if ((!!mRefreshRateIndicatorHandler) == enabled) {
+        ALOGW("%s: RefreshRateChangedCallbackDebug is already %s", __func__,
+              enabled ? "enabled" : "disabled");
+        return NO_ERROR;
+    }
+    int32_t ret = NO_ERROR;
+    if (enabled) {
+        mRefreshRateIndicatorHandler = std::make_shared<RefreshRateIndicatorHandler>(this);
+        if (!mRefreshRateIndicatorHandler) {
+            ALOGE("%s: Failed to create refresh rate debug handler", __func__);
+            return -ENOMEM;
+        }
+        ret = mRefreshRateIndicatorHandler->init();
+        if (ret != NO_ERROR) {
+            ALOGE("%s: Failed to initialize refresh rate debug handler: %d", __func__, ret);
+            mRefreshRateIndicatorHandler.reset();
+            return ret;
+        }
+        ret = mDevice->mDeviceInterface->registerSysfsEventHandler(mRefreshRateIndicatorHandler);
+        if (ret != NO_ERROR) {
+            ALOGE("%s: Failed to register sysfs event handler: %d", __func__, ret);
+            mRefreshRateIndicatorHandler.reset();
+            return ret;
+        }
+        // Call the callback immediately
+        mRefreshRateIndicatorHandler->handleSysfsEvent();
+    } else {
+        ret = mDevice->mDeviceInterface->unregisterSysfsEventHandler(
+                mRefreshRateIndicatorHandler->getFd());
+        mRefreshRateIndicatorHandler.reset();
+    }
+    return ret;
+}
+
+nsecs_t ExynosDisplay::getLastLayerUpdateTime() {
+    Mutex::Autolock lock(mDRMutex);
+    nsecs_t time = 0;
+    for (size_t i = 0; i < mLayers.size(); ++i) {
+        // The update from refresh rate indicator layer should be ignored
+        if (mLayers[i]->mRequestedCompositionType == HWC2_COMPOSITION_REFRESH_RATE_INDICATOR)
+            continue;
+        time = max(time, mLayers[i]->mLastUpdateTime);
+    }
+    return time;
+}
+
+void ExynosDisplay::updateRefreshRateIndicator() {
+    // Update refresh rate indicator if the last update event is ignored to make sure that
+    // the refresh rate caused by the current frame update will be applied immediately since
+    // we may not receive the sysfs event if the refresh rate is the same as the last ignored one.
+    if (!mRefreshRateIndicatorHandler || !mRefreshRateIndicatorHandler->isIgnoringLastUpdate())
+        return;
+    mRefreshRateIndicatorHandler->handleSysfsEvent();
+}
+
+uint32_t ExynosDisplay::getPeakRefreshRate() {
+    float opRate = mOperationRateManager ? mOperationRateManager->getOperationRate() : 0;
+    return static_cast<uint32_t>(std::round(opRate ?: mPeakRefreshRate));
+}
+
+VsyncPeriodNanos ExynosDisplay::getVsyncPeriod(const int32_t config) {
+    const auto &it = mDisplayConfigs.find(config);
+    if (it == mDisplayConfigs.end()) return 0;
+    return mDisplayConfigs[config].vsyncPeriod;
+}
+
+uint32_t ExynosDisplay::getRefreshRate(const int32_t config) {
+    VsyncPeriodNanos period = getVsyncPeriod(config);
+    if (!period) return 0;
+    constexpr float nsecsPerSec = std::chrono::nanoseconds(1s).count();
+    return round(nsecsPerSec / period * 0.1f) * 10;
+}
+
+uint32_t ExynosDisplay::getConfigId(const int32_t refreshRate, const int32_t width,
+                                    const int32_t height) {
+    for (auto entry : mDisplayConfigs) {
+        auto config = entry.first;
+        auto displayCfg = entry.second;
+        if (getRefreshRate(config) == refreshRate && displayCfg.width == width &&
+            displayCfg.height == height) {
+            return config;
+        }
+    }
+    return UINT_MAX;
+}
diff --git a/libhwc2.1/libdevice/ExynosDisplay.h b/libhwc2.1/libdevice/ExynosDisplay.h
index c5e9704..5ad016e 100644
--- a/libhwc2.1/libdevice/ExynosDisplay.h
+++ b/libhwc2.1/libdevice/ExynosDisplay.h
@@ -27,6 +27,7 @@
 #include <chrono>
 #include <set>
 
+#include "DeconHeader.h"
 #include "ExynosDisplayInterface.h"
 #include "ExynosHWC.h"
 #include "ExynosHWCDebug.h"
@@ -34,6 +35,7 @@
 #include "ExynosHwc3Types.h"
 #include "ExynosMPP.h"
 #include "ExynosResourceManager.h"
+#include "drmeventlistener.h"
 #include "worker.h"
 
 #define HWC_CLEARDISPLAY_WITH_COLORMAP
@@ -285,6 +287,22 @@
         static int compare(ExynosLayer * const *lhs, ExynosLayer *const *rhs);
 };
 
+class DisplayTDMInfo {
+    public:
+        /* Could be extended */
+        typedef struct ResourceAmount {
+            uint32_t totalAmount;
+        } ResourceAmount_t;
+        std::map<tdm_attr_t, ResourceAmount_t> mAmount;
+
+        uint32_t initTDMInfo(ResourceAmount_t amount, tdm_attr_t attr) {
+            mAmount[attr] = amount;
+            return 0;
+        }
+
+        ResourceAmount_t getAvailableAmount(tdm_attr_t attr) { return mAmount[attr]; }
+};
+
 class ExynosCompositionInfo : public ExynosMPPSource {
     public:
         ExynosCompositionInfo():ExynosCompositionInfo(COMPOSITION_NONE){};
@@ -367,13 +385,15 @@
     bool forceReserveMPP = false;
     /** Skip M2MMPP processing **/
     bool skipM2mProcessing = true;
+    /** Enable multi-thread present **/
+    bool multiThreadedPresent = false;
 };
 
 class ExynosDisplay {
     public:
-        uint32_t mDisplayId;
-        uint32_t mType;
-        uint32_t mIndex;
+        const uint32_t mDisplayId;
+        const uint32_t mType;
+        const uint32_t mIndex;
         String8 mDeconNodeName;
         uint32_t mXres;
         uint32_t mYres;
@@ -386,13 +406,15 @@
         int                     mPsrMode;
 
         /* Constructor */
-        ExynosDisplay(uint32_t index, ExynosDevice *device);
+        ExynosDisplay(uint32_t type, uint32_t index, ExynosDevice* device,
+                      const std::string& displayName);
         /* Destructor */
         virtual ~ExynosDisplay();
 
         ExynosDevice *mDevice;
 
-        String8 mDisplayName;
+        const String8 mDisplayName;
+        const String8 mDisplayTraceName;
         HwcMountOrientation mMountOrientation = HwcMountOrientation::ROT_0;
         Mutex mDisplayMutex;
 
@@ -428,10 +450,17 @@
          * Geometry change info is described by bit map.
          * This flag is cleared when resource assignment for all displays
          * is done.
+         * Geometry changed to layer REFRESH_RATE_INDICATOR will be excluded.
          */
         uint64_t  mGeometryChanged;
 
         /**
+         * The number of buffer updates in the current frame.
+         * Buffer update for layer REFRESH_RATE_INDICATOR will be excluded.
+         */
+        uint32_t mBufferUpdates;
+
+        /**
          * Rendering step information that is seperated by
          * VALIDATED, ACCEPTED_CHANGE, PRESENTED.
          */
@@ -533,10 +562,8 @@
         hwc2_config_t mDesiredConfig;
 
         hwc2_config_t mActiveConfig = UINT_MAX;
-
-        bool mNotifyPeakRefreshRate = false;
-        std::mutex mPeakRefreshRateMutex;
-        std::condition_variable mPeakRefreshRateCondition;
+        hwc2_config_t mPendingConfig = UINT_MAX;
+        int64_t mLastVsyncTimestamp = 0;
 
         void initDisplay();
 
@@ -547,7 +574,7 @@
         int32_t initializeValidateInfos();
         int32_t addClientCompositionLayer(uint32_t layerIndex);
         int32_t removeClientCompositionLayer(uint32_t layerIndex);
-        int32_t addExynosCompositionLayer(uint32_t layerIndex);
+        int32_t addExynosCompositionLayer(uint32_t layerIndex, float totalUsedCapa);
 
         /**
          * Dynamic AFBC Control solution : To get the prepared information is applied to current or not.
@@ -1173,6 +1200,7 @@
         void setHWCControl(uint32_t ctrl, int32_t val);
         void setGeometryChanged(uint64_t changedBit);
         void clearGeometryChanged();
+        bool isFrameUpdate();
 
         virtual void setDDIScalerEnable(int width, int height);
         virtual int getDDIScalerMode(int width, int height);
@@ -1207,6 +1235,7 @@
         virtual uint64_t getPendingExpectedPresentTime() { return 0; }
         virtual void applyExpectedPresentTime() {}
         virtual int32_t getDisplayIdleTimerSupport(bool& outSupport);
+        virtual int32_t getDisplayMultiThreadedPresentSupport(bool& outSupport);
         virtual int32_t setDisplayIdleTimer(const int32_t __unused timeoutMs) {
             return HWC2_ERROR_UNSUPPORTED;
         }
@@ -1255,15 +1284,17 @@
         virtual void updateAppliedActiveConfig(const hwc2_config_t /*newConfig*/,
                                                const int64_t /*ts*/) {}
 
+        virtual bool isConfigSettingEnabled() { return true; }
+        virtual void enableConfigSetting(bool /*en*/) {}
+
         // is the hint session both enabled and supported
         bool usePowerHintSession();
 
-        void setMinDisplayVsyncPeriod(uint32_t period) { mMinDisplayVsyncPeriod = period; }
-
-        bool isCurrentPeakRefreshRate(void) {
-            return ((mConfigRequestState == hwc_request_state_t::SET_CONFIG_STATE_DONE) &&
-                    (mVsyncPeriod == mMinDisplayVsyncPeriod));
-        }
+        void setPeakRefreshRate(float rr) { mPeakRefreshRate = rr; }
+        uint32_t getPeakRefreshRate();
+        VsyncPeriodNanos getVsyncPeriod(const int32_t config);
+        uint32_t getRefreshRate(const int32_t config);
+        uint32_t getConfigId(const int32_t refreshRate, const int32_t width, const int32_t height);
 
         // check if there are any dimmed layers
         bool isMixedComposition();
@@ -1276,7 +1307,7 @@
     private:
         bool skipStaticLayerChanged(ExynosCompositionInfo& compositionInfo);
 
-        bool skipSignalIdleForVideoLayer();
+        bool skipSignalIdle();
 
         /// minimum possible dim rate in the case hbm peak is 1000 nits and norml
         // display brightness is 2 nits
@@ -1287,8 +1318,8 @@
         static constexpr float kHdrFullScreen = 0.5;
         uint32_t mHdrFullScrenAreaThreshold;
 
-        // vsync period of peak refresh rate
-        uint32_t mMinDisplayVsyncPeriod;
+        // peak refresh rate
+        float mPeakRefreshRate = -1.0f;
 
         // track if the last frame is a mixed composition, to detect mixed
         // composition to non-mixed composition transition.
@@ -1297,7 +1328,7 @@
         /* Display hint to notify power hal */
         class PowerHalHintWorker : public Worker {
         public:
-            PowerHalHintWorker(uint32_t displayId);
+            PowerHalHintWorker(uint32_t displayId, const String8& displayTraceName);
             virtual ~PowerHalHintWorker();
             int Init();
 
@@ -1370,12 +1401,16 @@
             // whether idle hint is supported
             bool mIdleHintIsSupported;
 
+            String8 mDisplayTraceName;
             std::string mIdleHintStr;
             std::string mRefreshRateHintPrefixStr;
 
             hwc2_power_mode_t mPowerModeState;
             uint32_t mVsyncPeriod;
 
+            uint32_t mConnectRetryCount;
+            bool isPowerHalExist() { return mConnectRetryCount < 10; }
+
             ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
 
             // for power HAL extension hints
@@ -1455,8 +1490,8 @@
         static const constexpr nsecs_t SIGNAL_TIME_PENDING = INT64_MAX;
         static const constexpr nsecs_t SIGNAL_TIME_INVALID = -1;
         std::unordered_map<uint32_t, RollingAverage<kAveragesBufferSize>> mRollingAverages;
-        // mPowerHalHint should be declared only after mDisplayId and mIndex have been declared
-        // since the result of getDisplayId(mDisplayId, mIndex) is needed as the parameter of
+        // mPowerHalHint should be declared only after mDisplayId and mDisplayTraceName have been
+        // declared since mDisplayId and mDisplayTraceName are needed as the parameter of
         // PowerHalHintWorker's constructor
         PowerHalHintWorker mPowerHalHint;
 
@@ -1496,6 +1531,106 @@
                 hwc2_config_t config,
                 hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints,
                 hwc_vsync_period_change_timeline_t* outTimeline);
+
+    public:
+        /* Override for each display's meaning of 'enabled state'
+         * Primary : Power on, this function overrided in primary display module
+         * Exteranal : Plug-in, default */
+        virtual bool isEnabled() { return mPlugState; }
+
+        // Resource TDM (Time-Division Multiplexing)
+        std::map<uint32_t, DisplayTDMInfo> mDisplayTDMInfo;
+
+        class RotatingLogFileWriter {
+        public:
+            RotatingLogFileWriter(uint32_t maxFileCount, uint32_t thresholdSizePerFile,
+                                  std::string extension = ".txt")
+                  : mMaxFileCount(maxFileCount),
+                    mThresholdSizePerFile(thresholdSizePerFile),
+                    mPrefixName(""),
+                    mExtension(extension),
+                    mLastFileIndex(-1),
+                    mFile(nullptr) {}
+
+            ~RotatingLogFileWriter() {
+                if (mFile) {
+                    fclose(mFile);
+                }
+            }
+
+            bool chooseOpenedFile();
+            void write(const String8& content) {
+                if (mFile) {
+                    fwrite(content.c_str(), 1, content.size(), mFile);
+                }
+            }
+            void flush() {
+                if (mFile) {
+                    fflush(mFile);
+                }
+            }
+            void setPrefixName(const std::string& prefixName) { mPrefixName = prefixName; }
+
+        private:
+            FILE* openLogFile(const std::string& filename, const std::string& mode);
+            std::optional<nsecs_t> getLastModifiedTimestamp(const std::string& filename);
+
+            uint32_t mMaxFileCount;
+            uint32_t mThresholdSizePerFile;
+            std::string mPrefixName;
+            std::string mExtension;
+            int32_t mLastFileIndex;
+            FILE* mFile;
+        };
+        RotatingLogFileWriter mErrLogFileWriter;
+        RotatingLogFileWriter mDebugDumpFileWriter;
+        RotatingLogFileWriter mFenceFileWriter;
+
+    protected:
+        class OperationRateManager {
+        public:
+            OperationRateManager() {}
+            virtual ~OperationRateManager() {}
+
+            virtual int32_t onLowPowerMode(bool __unused enabled) { return 0; }
+            virtual int32_t onPeakRefreshRate(uint32_t __unused rate) { return 0; }
+            virtual int32_t onConfig(hwc2_config_t __unused cfg) { return 0; }
+            virtual int32_t onBrightness(uint32_t __unused dbv) { return 0; }
+            virtual int32_t onPowerMode(int32_t __unused mode) { return 0; }
+            virtual int32_t getOperationRate() { return 0; }
+        };
+
+    public:
+        std::unique_ptr<OperationRateManager> mOperationRateManager;
+        bool isOperationRateSupported() { return mOperationRateManager != nullptr; }
+
+        class RefreshRateIndicatorHandler : public DrmSysfsEventHandler {
+        public:
+            RefreshRateIndicatorHandler(ExynosDisplay* display);
+            int32_t init();
+            virtual void handleSysfsEvent() override;
+            virtual int getFd() override { return mFd.get(); };
+            bool isIgnoringLastUpdate() { return mIgnoringLastUpdate; }
+            void updateRefreshRate(int refreshRate);
+
+        private:
+            void updateRefreshRateLocked(int refreshRate) REQUIRES(mMutex);
+
+            ExynosDisplay* mDisplay;
+            int mLastRefreshRate GUARDED_BY(mMutex);
+            nsecs_t mLastCallbackTime GUARDED_BY(mMutex);
+            std::atomic_bool mIgnoringLastUpdate = false;
+            UniqueFd mFd;
+            std::mutex mMutex;
+
+            static constexpr auto kRefreshRateStatePathFormat =
+                    "/sys/class/backlight/panel%d-backlight/state";
+        };
+
+        std::shared_ptr<RefreshRateIndicatorHandler> mRefreshRateIndicatorHandler;
+        int32_t setRefreshRateChangedCallbackDebugEnabled(bool enabled);
+        void updateRefreshRateIndicator();
+        nsecs_t getLastLayerUpdateTime();
 };
 
 #endif //_EXYNOSDISPLAY_H
diff --git a/libhwc2.1/libdevice/ExynosLayer.cpp b/libhwc2.1/libdevice/ExynosLayer.cpp
index 24c6cac..740ffa4 100644
--- a/libhwc2.1/libdevice/ExynosLayer.cpp
+++ b/libhwc2.1/libdevice/ExynosLayer.cpp
@@ -39,6 +39,7 @@
       : ExynosMPPSource(MPP_SOURCE_LAYER, this),
         mDisplay(display),
         mCompositionType(HWC2_COMPOSITION_INVALID),
+        mRequestedCompositionType(HWC2_COMPOSITION_INVALID),
         mExynosCompositionType(HWC2_COMPOSITION_INVALID),
         mValidateCompositionType(HWC2_COMPOSITION_INVALID),
         mValidateExynosCompositionType(HWC2_COMPOSITION_INVALID),
@@ -59,6 +60,7 @@
         mNextLastFpsTime(0),
         mLastLayerBuffer(NULL),
         mLayerBuffer(NULL),
+        mLastUpdateTime(0),
         mDamageNum(0),
         mBlending(HWC2_BLEND_MODE_NONE),
         mPlaneAlpha(1.0),
@@ -324,7 +326,7 @@
         uint32_t minDstHeight = exynosMPPVG->getDstMinHeight(dst_img);
         if ((uint32_t)WIDTH(mDisplayFrame) < minDstWidth) {
             ALOGI("%s DRM layer displayFrame width %d is smaller than otf minWidth %d",
-                    mDisplay->mDisplayName.string(),
+                    mDisplay->mDisplayName.c_str(),
                     WIDTH(mDisplayFrame), minDstWidth);
             mPreprocessedInfo.displayFrame.right = mDisplayFrame.left +
                 pixel_align(WIDTH(mDisplayFrame), minDstWidth);
@@ -337,7 +339,7 @@
         }
         if ((uint32_t)HEIGHT(mDisplayFrame) < minDstHeight) {
             ALOGI("%s DRM layer displayFrame height %d is smaller than vpp minHeight %d",
-                    mDisplay->mDisplayName.string(),
+                    mDisplay->mDisplayName.c_str(),
                     HEIGHT(mDisplayFrame), minDstHeight);
             mPreprocessedInfo.displayFrame.bottom = mDisplayFrame.top +
                 pixel_align(HEIGHT(mDisplayFrame), minDstHeight);
@@ -419,6 +421,11 @@
         Mutex::Autolock lock(mDisplay->mDRMutex);
         mLayerBuffer = buffer;
         checkFps(mLastLayerBuffer != mLayerBuffer);
+        if (mLayerBuffer != mLastLayerBuffer) {
+            mLastUpdateTime = systemTime(CLOCK_MONOTONIC);
+            if (mRequestedCompositionType != HWC2_COMPOSITION_REFRESH_RATE_INDICATOR)
+                mDisplay->mBufferUpdates++;
+        }
     }
     mPrevAcquireFence =
             fence_close(mPrevAcquireFence, mDisplay, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_UNDEFINED);
@@ -511,6 +518,7 @@
     }
 
     mCompositionType = type;
+    mRequestedCompositionType = type;
 
     return HWC2_ERROR_NONE;
 }
@@ -953,12 +961,12 @@
 {
     int32_t ret = NO_ERROR;
     if (mM2mMPP != NULL) {
-        HDEBUGLOGD(eDebugResourceManager, "\t\t %s mpp is reset", mM2mMPP->mName.string());
+        HDEBUGLOGD(eDebugResourceManager, "\t\t %s mpp is reset", mM2mMPP->mName.c_str());
         mM2mMPP->resetAssignedState(this);
         mM2mMPP = NULL;
     }
     if (mOtfMPP != NULL) {
-        HDEBUGLOGD(eDebugResourceManager, "\t\t %s mpp is reset", mOtfMPP->mName.string());
+        HDEBUGLOGD(eDebugResourceManager, "\t\t %s mpp is reset", mOtfMPP->mName.c_str());
         mOtfMPP->resetAssignedState();
         mOtfMPP = NULL;
     }
@@ -1028,7 +1036,7 @@
               .add("fd", std::vector<int>({fd, fd1, fd2}))
               .add("AFBC", static_cast<bool>(mCompressed));
         }
-        tb.add("format", getFormatStr(format, mCompressed ? AFBC : 0).string())
+        tb.add("format", getFormatStr(format, mCompressed ? AFBC : 0).c_str())
           .add("dataSpace", mDataSpace, true)
           .add("colorTr", mLayerColorTransform.enable)
           .add("blend", mBlending, true)
@@ -1069,13 +1077,13 @@
     if ((mDisplay != NULL) && (mDisplay->mResourceManager != NULL)) {
         result.appendFormat("MPPFlags for otfMPP\n");
         for (uint32_t i = 0; i < mDisplay->mResourceManager->getOtfMPPSize(); i++) {
-            result.appendFormat("[%s: 0x%" PRIx64 "] ", mDisplay->mResourceManager->getOtfMPP(i)->mName.string(),
+            result.appendFormat("[%s: 0x%" PRIx64 "] ", mDisplay->mResourceManager->getOtfMPP(i)->mName.c_str(),
                     mCheckMPPFlag[mDisplay->mResourceManager->getOtfMPP(i)->mLogicalType]);
         }
         result.appendFormat("\n");
         result.appendFormat("MPPFlags for m2mMPP\n");
         for (uint32_t i = 0; i < mDisplay->mResourceManager->getM2mMPPSize(); i++) {
-            result.appendFormat("[%s: 0x%" PRIx64 "] ", mDisplay->mResourceManager->getM2mMPP(i)->mName.string(),
+            result.appendFormat("[%s: 0x%" PRIx64 "] ", mDisplay->mResourceManager->getM2mMPP(i)->mName.c_str(),
                     mCheckMPPFlag[mDisplay->mResourceManager->getM2mMPP(i)->mLogicalType]);
             if ((i!=0) && (i%4==0)) result.appendFormat("\n");
         }
@@ -1085,9 +1093,9 @@
     if ((mOtfMPP == NULL) && (mM2mMPP == NULL))
         result.appendFormat("\tresource is not assigned.\n");
     if (mOtfMPP != NULL)
-        result.appendFormat("\tassignedMPP: %s\n", mOtfMPP->mName.string());
+        result.appendFormat("\tassignedMPP: %s\n", mOtfMPP->mName.c_str());
     if (mM2mMPP != NULL)
-        result.appendFormat("\tassignedM2mMPP: %s\n", mM2mMPP->mName.string());
+        result.appendFormat("\tassignedM2mMPP: %s\n", mM2mMPP->mName.c_str());
     result.appendFormat("\tdump midImg\n");
     dumpExynosImage(result, mMidImg);
 
@@ -1112,7 +1120,7 @@
         fd2 = -1;
     }
     result.appendFormat("handle: %p [fd: %d, %d, %d], acquireFence: %d, tr: 0x%2x, AFBC: %1d, dataSpace: 0x%8x, format: %s\n",
-            mLayerBuffer, fd, fd1, fd2, mAcquireFence, mTransform, mCompressed, mDataSpace, getFormatStr(format, mCompressed? AFBC : 0).string());
+            mLayerBuffer, fd, fd1, fd2, mAcquireFence, mTransform, mCompressed, mDataSpace, getFormatStr(format, mCompressed? AFBC : 0).c_str());
     result.appendFormat("\tblend: 0x%4x, planeAlpha: %3.1f, zOrder: %d, color[0x%2x, 0x%2x, 0x%2x, 0x%2x]\n",
             mBlending, mPlaneAlpha, mZOrder, mColor.r, mColor.g, mColor.b, mColor.a);
     result.appendFormat("\tfps: %.2f, priority: %d, windowIndex: %d\n", mFps, mOverlayPriority,
@@ -1128,38 +1136,40 @@
     if ((mDisplay != NULL) && (mDisplay->mResourceManager != NULL)) {
         result.appendFormat("MPPFlags for otfMPP\n");
         for (uint32_t i = 0; i < mDisplay->mResourceManager->getOtfMPPSize(); i++) {
-            result.appendFormat("[%s: 0x%" PRIx64 "] ", mDisplay->mResourceManager->getOtfMPP(i)->mName.string(),
+            result.appendFormat("[%s: 0x%" PRIx64 "] ", mDisplay->mResourceManager->getOtfMPP(i)->mName.c_str(),
                     mCheckMPPFlag[mDisplay->mResourceManager->getOtfMPP(i)->mLogicalType]);
         }
         result.appendFormat("\n");
         result.appendFormat("MPPFlags for m2mMPP\n");
         for (uint32_t i = 0; i < mDisplay->mResourceManager->getM2mMPPSize(); i++) {
-            result.appendFormat("[%s: 0x%" PRIx64 "] ", mDisplay->mResourceManager->getM2mMPP(i)->mName.string(),
+            result.appendFormat("[%s: 0x%" PRIx64 "] ", mDisplay->mResourceManager->getM2mMPP(i)->mName.c_str(),
                     mCheckMPPFlag[mDisplay->mResourceManager->getM2mMPP(i)->mLogicalType]);
             if ((i!=0) && (i%4==0)) result.appendFormat("\n");
         }
         result.appendFormat("\n");
     }
 
-    ALOGD("%s", result.string());
+    ALOGD("%s", result.c_str());
     result.clear();
 
     if ((mOtfMPP == NULL) && (mM2mMPP == NULL))
         ALOGD("\tresource is not assigned.");
     if (mOtfMPP != NULL)
-        ALOGD("\tassignedMPP: %s", mOtfMPP->mName.string());
+        ALOGD("\tassignedMPP: %s", mOtfMPP->mName.c_str());
     if (mM2mMPP != NULL)
-        ALOGD("\tassignedM2mMPP: %s", mM2mMPP->mName.string());
+        ALOGD("\tassignedM2mMPP: %s", mM2mMPP->mName.c_str());
     ALOGD("\t++ dump midImg ++");
     dumpExynosImage(result, mMidImg);
-    ALOGD("%s", result.string());
+    ALOGD("%s", result.c_str());
 
 }
 
 void ExynosLayer::setGeometryChanged(uint64_t changedBit)
 {
+    mLastUpdateTime = systemTime(CLOCK_MONOTONIC);
     mGeometryChanged |= changedBit;
-    mDisplay->setGeometryChanged(changedBit);
+    if (mRequestedCompositionType != HWC2_COMPOSITION_REFRESH_RATE_INDICATOR)
+        mDisplay->setGeometryChanged(changedBit);
 }
 
 int ExynosLayer::allocMetaParcel()
diff --git a/libhwc2.1/libdevice/ExynosLayer.h b/libhwc2.1/libdevice/ExynosLayer.h
index c180fb3..e1df54d 100644
--- a/libhwc2.1/libdevice/ExynosLayer.h
+++ b/libhwc2.1/libdevice/ExynosLayer.h
@@ -77,6 +77,7 @@
 
 enum {
     HWC2_COMPOSITION_DISPLAY_DECORATION = toUnderlying(Composition::DISPLAY_DECORATION),
+    HWC2_COMPOSITION_REFRESH_RATE_INDICATOR = toUnderlying(Composition::REFRESH_RATE_INDICATOR),
     /*add after hwc2_composition_t, margin number here*/
     HWC2_COMPOSITION_EXYNOS = 32,
 };
@@ -91,10 +92,20 @@
 
         /**
          * Layer's compositionType
+         *
+         * If acceptDisplayChanges() is called, it will be set to the validated type
+         * since SF may update their state and doesn't call back into HWC
          */
         int32_t mCompositionType;
 
         /**
+         * Composition type that is originally requested by SF only using setLayerComposisionType()
+         *
+         * It will not be changed if applyDisplayChanges() is called.
+         */
+        int32_t mRequestedCompositionType;
+
+        /**
          * Composition type that is used by HAL
          * (ex: COMPOSITION_G2D)
          */
@@ -178,6 +189,8 @@
          */
         buffer_handle_t mLayerBuffer;
 
+        nsecs_t mLastUpdateTime;
+
         /**
          * Surface Damage
          */
diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp
index febd76d..eab4cd1 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp
+++ b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp
@@ -312,3 +312,12 @@
         primaryDisplay->handleDisplayIdleEnter(idleTeVrefresh);
     }
 }
+
+int32_t ExynosDeviceDrmInterface::registerSysfsEventHandler(
+        std::shared_ptr<DrmSysfsEventHandler> handler) {
+    return mDrmDevice->event_listener()->RegisterSysfsHandler(std::move(handler));
+}
+
+int32_t ExynosDeviceDrmInterface::unregisterSysfsEventHandler(int sysfsFd) {
+    return mDrmDevice->event_listener()->UnRegisterSysfsHandler(sysfsFd);
+}
diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h
index 9aa2798..69fc4f0 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h
+++ b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h
@@ -31,6 +31,10 @@
         virtual int32_t initDisplayInterface(
                 std::unique_ptr<ExynosDisplayInterface> &dispInterface) override;
         virtual void updateRestrictions() override;
+        virtual int32_t registerSysfsEventHandler(
+                std::shared_ptr<DrmSysfsEventHandler> handler) override;
+        virtual int32_t unregisterSysfsEventHandler(int sysfsFd) override;
+
     protected:
         class ExynosDrmEventHandler : public DrmEventHandler,
                                       public DrmHistogramEventHandler,
diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.cpp
index eb54aca..4893310 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.cpp
+++ b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.cpp
@@ -27,9 +27,7 @@
 #include "ExynosResourceManager.h"
 #include "ExynosResourceRestriction.h"
 
-#ifndef USE_MODULE_ATTR
-extern feature_support_t feature_table[];
-#endif
+using namespace SOC_VERSION;
 
 void ExynosDeviceInterface::printDppRestriction(struct hwc_dpp_ch_restriction res)
 {
@@ -101,7 +99,7 @@
             queried_format.format = format;
             queried_format.reserved = 0;
             resourceManager->makeFormatRestrictions(queried_format);
-            HDEBUGLOGD(eDebugAttrSetting, "%s : %d", getMPPStr(hwType).string(), format);
+            HDEBUGLOGD(eDebugAttrSetting, "%s : %d", getMPPStr(hwType).c_str(), format);
         }
     }
 
diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h
index 747f016..dd976b0 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h
+++ b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h
@@ -17,8 +17,9 @@
 #ifndef _EXYNOSDEVICEINTERFACE_H
 #define _EXYNOSDEVICEINTERFACE_H
 
-#include "ExynosHWCHelper.h"
 #include "ExynosDisplayInterface.h"
+#include "ExynosHWCHelper.h"
+#include "drmeventlistener.h"
 
 struct hwc_dpp_size_range {
   uint32_t min;
@@ -82,12 +83,21 @@
         virtual ~ExynosDeviceInterface(){};
         virtual void init(ExynosDevice *exynosDevice) = 0;
         virtual int32_t initDisplayInterface(
-                std::unique_ptr<ExynosDisplayInterface> &dispInterface)
-        { return 0;};
+                std::unique_ptr<ExynosDisplayInterface> __unused &dispInterface) {
+            return 0;
+        };
         /* Fill mDPUInfo according to interface type */
         virtual void updateRestrictions() = 0;
         virtual bool getUseQuery() { return mUseQuery; };
 
+        virtual int32_t registerSysfsEventHandler(
+                std::shared_ptr<DrmSysfsEventHandler> __unused handler) {
+            return android::INVALID_OPERATION;
+        }
+        virtual int32_t unregisterSysfsEventHandler(int __unused sysfsFd) {
+            return android::INVALID_OPERATION;
+        }
+
         uint32_t getNumDPPChs() { return mDPUInfo.dpuInfo.dpp_chs.size(); };
         uint32_t getNumSPPChs() { return mDPUInfo.dpuInfo.spp_chs.size(); };
         uint32_t getSPPChId(uint32_t index) { return mDPUInfo.dpuInfo.spp_chs.at(index).id; };
diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
index 19a5d2f..6f11eb7 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
+++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
@@ -31,8 +31,10 @@
 #include "ExynosHWCDebug.h"
 #include "ExynosHWCHelper.h"
 #include "ExynosLayer.h"
+#include "ExynosPrimaryDisplay.h"
 
 using namespace std::chrono_literals;
+using namespace SOC_VERSION;
 
 constexpr uint32_t MAX_PLANE_NUM = 3;
 constexpr uint32_t CBCR_INDEX = 1;
@@ -118,21 +120,26 @@
     return true;
 }
 
-bool FramebufferManager::checkShrink() {
+void FramebufferManager::checkShrink() {
     Mutex::Autolock lock(mMutex);
 
     mCacheShrinkPending = mCachedLayerBuffers.size() > MAX_CACHED_LAYERS;
-    return mCacheShrinkPending;
+    mCacheM2mSecureShrinkPending =
+            mCachedM2mSecureLayerBuffers.size() > MAX_CACHED_M2M_SECURE_LAYERS;
 }
 
 void FramebufferManager::cleanup(const ExynosLayer *layer) {
     ATRACE_CALL();
 
     Mutex::Autolock lock(mMutex);
-    if (auto it = mCachedLayerBuffers.find(layer); it != mCachedLayerBuffers.end()) {
-        mCleanBuffers.splice(mCleanBuffers.end(), std::move(it->second));
-        mCachedLayerBuffers.erase(it);
-    }
+    auto clean = [&](std::map<const ExynosLayer *, FBList> &layerBuffs) {
+        if (auto it = layerBuffs.find(layer); it != layerBuffs.end()) {
+            mCleanBuffers.splice(mCleanBuffers.end(), std::move(it->second));
+            layerBuffs.erase(it);
+        }
+    };
+    clean(mCachedLayerBuffers);
+    clean(mCachedM2mSecureLayerBuffers);
 }
 
 void FramebufferManager::removeFBsThreadRoutine()
@@ -159,6 +166,7 @@
     uint32_t bpp = 0;
     uint32_t bufferNum, planeNum = 0;
     uint32_t bufWidth, bufHeight = 0;
+    bool isM2mSecureLayer = (config.protection && config.layer && config.layer->mM2mMPP);
     DrmArray<uint32_t> pitches = {0};
     DrmArray<uint32_t> offsets = {0};
     DrmArray<uint64_t> modifiers = {0};
@@ -198,7 +206,7 @@
             return -EINVAL;
         }
 
-        fbId = findCachedFbId(config.layer,
+        fbId = findCachedFbId(config.layer, isM2mSecureLayer,
                               [bufferDesc = Framebuffer::BufferDesc{config.buffer_id, drmFormat,
                                                                     config.protection}](
                                       auto &buffer) { return buffer->bufferDesc == bufferDesc; });
@@ -257,7 +265,7 @@
         handles[0] = 0xff000000;
         bpp = getBytePerPixelOfPrimaryPlane(HAL_PIXEL_FORMAT_BGRA_8888);
         pitches[0] = config.dst.w * bpp;
-        fbId = findCachedFbId(config.layer,
+        fbId = findCachedFbId(config.layer, isM2mSecureLayer,
                               [colorDesc = Framebuffer::SolidColorDesc{bufWidth, bufHeight}](
                                       auto &buffer) { return buffer->colorDesc == colorDesc; });
         if (fbId != 0) {
@@ -289,11 +297,10 @@
 
     if (config.layer || config.buffer_id) {
         Mutex::Autolock lock(mMutex);
-        auto &cachedBuffers = mCachedLayerBuffers[config.layer];
-        auto maxCachedBufferSize = MAX_CACHED_BUFFERS_PER_LAYER;
-        if (config.protection && config.layer && config.layer->mM2mMPP) {
-            maxCachedBufferSize = MAX_CACHED_SECURE_BUFFERS_PER_G2D_LAYER;
-        }
+        auto &cachedBuffers = (!isM2mSecureLayer) ? mCachedLayerBuffers[config.layer]
+                                                  : mCachedM2mSecureLayerBuffers[config.layer];
+        auto maxCachedBufferSize = (!isM2mSecureLayer) ? MAX_CACHED_BUFFERS_PER_LAYER
+                                                       : MAX_CACHED_M2M_SECURE_BUFFERS_PER_LAYER;
 
         if (cachedBuffers.size() > maxCachedBufferSize) {
             ALOGW("FBManager: cached buffers size %zu exceeds limitation(%zu) while adding fbId %d",
@@ -311,6 +318,7 @@
                                     Framebuffer::BufferDesc{config.buffer_id, drmFormat,
                                                             config.protection}));
             mHasSecureFramebuffer |= (isFramebuffer(config.layer) && config.protection);
+            mHasM2mSecureLayerBuffer |= isM2mSecureLayer;
         }
     } else {
         ALOGW("FBManager: possible leakage fbId %d was created", fbId);
@@ -319,7 +327,7 @@
     return 0;
 }
 
-void FramebufferManager::flip(bool hasSecureFrameBuffer) {
+void FramebufferManager::flip(const bool hasSecureFrameBuffer, const bool hasM2mSecureLayerBuffer) {
     bool needCleanup = false;
     {
         Mutex::Autolock lock(mMutex);
@@ -327,6 +335,10 @@
         if (!hasSecureFrameBuffer) {
             destroySecureFramebufferLocked();
         }
+
+        if (!hasM2mSecureLayerBuffer) {
+            destroyM2mSecureLayerBufferLocked();
+        }
         needCleanup = mCleanBuffers.size() > 0;
     }
 
@@ -339,6 +351,7 @@
 {
     Mutex::Autolock lock(mMutex);
     mCachedLayerBuffers.clear();
+    mCachedM2mSecureLayerBuffers.clear();
     mCleanBuffers.clear();
 }
 
@@ -356,31 +369,50 @@
     }
 }
 
-void FramebufferManager::markInuseLayerLocked(const ExynosLayer *layer) {
-    if (mCacheShrinkPending) {
+void FramebufferManager::markInuseLayerLocked(const ExynosLayer *layer,
+                                              const bool isM2mSecureLayer) {
+    if (!isM2mSecureLayer && mCacheShrinkPending) {
         mCachedLayersInuse.insert(layer);
     }
+
+    if (isM2mSecureLayer && mCacheM2mSecureShrinkPending) {
+        mCachedM2mSecureLayersInuse.insert(layer);
+    }
 }
 
 void FramebufferManager::destroyUnusedLayersLocked() {
-    if (!mCacheShrinkPending || mCachedLayersInuse.size() == mCachedLayerBuffers.size()) {
-        mCachedLayersInuse.clear();
-        return;
-    }
-
-    ALOGW("FBManager: shrink cached layers from %zu to %zu", mCachedLayerBuffers.size(),
-          mCachedLayersInuse.size());
-
-    for (auto layer = mCachedLayerBuffers.begin(); layer != mCachedLayerBuffers.end();) {
-        if (mCachedLayersInuse.find(layer->first) == mCachedLayersInuse.end()) {
-            mCleanBuffers.splice(mCleanBuffers.end(), std::move(layer->second));
-            layer = mCachedLayerBuffers.erase(layer);
-        } else {
-            ++layer;
+    auto destroyUnusedLayers =
+            [&](const bool &cacheShrinkPending, std::set<const ExynosLayer *> &cachedLayersInuse,
+                std::map<const ExynosLayer *, FBList> &cachedLayerBuffers) -> bool {
+        if (!cacheShrinkPending || cachedLayersInuse.size() == cachedLayerBuffers.size()) {
+            cachedLayersInuse.clear();
+            return false;
         }
+
+        for (auto layer = cachedLayerBuffers.begin(); layer != cachedLayerBuffers.end();) {
+            if (cachedLayersInuse.find(layer->first) == cachedLayersInuse.end()) {
+                mCleanBuffers.splice(mCleanBuffers.end(), std::move(layer->second));
+                layer = cachedLayerBuffers.erase(layer);
+            } else {
+                ++layer;
+            }
+        }
+        cachedLayersInuse.clear();
+        return true;
+    };
+
+    auto cachedLayerSize = mCachedLayerBuffers.size();
+    if (destroyUnusedLayers(mCacheShrinkPending, mCachedLayersInuse, mCachedLayerBuffers)) {
+        ALOGW("FBManager: shrink cached layers from %zu to %zu", cachedLayerSize,
+              mCachedLayerBuffers.size());
     }
 
-    mCachedLayersInuse.clear();
+    cachedLayerSize = mCachedM2mSecureLayerBuffers.size();
+    if (destroyUnusedLayers(mCacheM2mSecureShrinkPending, mCachedM2mSecureLayersInuse,
+                            mCachedM2mSecureLayerBuffers)) {
+        ALOGW("FBManager: shrink cached M2M secure layers from %zu to %zu", cachedLayerSize,
+              mCachedM2mSecureLayerBuffers.size());
+    }
 }
 
 void FramebufferManager::destroySecureFramebufferLocked() {
@@ -406,6 +438,22 @@
     }
 }
 
+void FramebufferManager::destroyM2mSecureLayerBufferLocked() {
+    if (!mHasM2mSecureLayerBuffer) {
+        return;
+    }
+
+    mHasM2mSecureLayerBuffer = false;
+
+    for (auto &layer : mCachedM2mSecureLayerBuffers) {
+        auto &bufferList = layer.second;
+        if (bufferList.size()) {
+            mCleanBuffers.splice(mCleanBuffers.end(), bufferList, bufferList.begin(),
+                                 bufferList.end());
+        }
+    }
+}
+
 void ExynosDisplayDrmInterface::destroyLayer(ExynosLayer *layer) {
     mFBManager.cleanup(layer);
 }
@@ -429,7 +477,8 @@
     return NO_ERROR;
 }
 
-ExynosDisplayDrmInterface::ExynosDisplayDrmInterface(ExynosDisplay *exynosDisplay)
+ExynosDisplayDrmInterface::ExynosDisplayDrmInterface(ExynosDisplay *exynosDisplay):
+    mMonitorDescription{0}
 {
     mType = INTERFACE_TYPE_DRM;
     init(exynosDisplay);
@@ -452,6 +501,7 @@
 void ExynosDisplayDrmInterface::init(ExynosDisplay *exynosDisplay)
 {
     mExynosDisplay = exynosDisplay;
+    mDisplayTraceName = mExynosDisplay->mDisplayTraceName;
     mDrmDevice = NULL;
     mDrmCrtc = NULL;
     mDrmConnector = NULL;
@@ -597,6 +647,27 @@
     ALOGW("%s ignore unrecoganized orientation %" PRId64, __func__, drmOrientation);
 }
 
+void ExynosDisplayDrmInterface::parseRCDId(const DrmProperty &property) {
+    if (mExynosDisplay->mType != HWC_DISPLAY_PRIMARY) {
+        ALOGW("%s invalid display type: %d", __func__, mExynosDisplay->mType);
+        return;
+    }
+
+    if (property.id() == 0) {
+        static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId = -1;
+        return;
+    }
+
+    auto [err, rcd_id] = property.value();
+    if (err < 0) {
+        ALOGW("%s failed to get drm prop value", __func__);
+        return;
+    }
+
+    if (getSpecialChannelId(rcd_id) >= 0)
+        static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId = rcd_id;
+}
+
 uint32_t ExynosDisplayDrmInterface::getDrmDisplayId(uint32_t type, uint32_t index)
 {
     return type+index;
@@ -620,12 +691,12 @@
     mReadbackInfo.init(mDrmDevice, drmDisplayId);
     if ((mDrmCrtc = mDrmDevice->GetCrtcForDisplay(drmDisplayId)) == NULL) {
         ALOGE("%s:: GetCrtcForDisplay is NULL (id: %d)",
-                mExynosDisplay->mDisplayName.string(), drmDisplayId);
+                mExynosDisplay->mDisplayName.c_str(), drmDisplayId);
         return -EINVAL;
     }
     if ((mDrmConnector = mDrmDevice->GetConnectorForDisplay(drmDisplayId)) == NULL) {
         ALOGE("%s:: GetConnectorForDisplay is NULL (id: %d)",
-                mExynosDisplay->mDisplayName.string(), drmDisplayId);
+                mExynosDisplay->mDisplayName.c_str(), drmDisplayId);
         return -EINVAL;
     }
 
@@ -666,7 +737,7 @@
 
     getLowPowerDrmModeModeInfo();
 
-    mDrmVSyncWorker.Init(mDrmDevice, drmDisplayId);
+    mDrmVSyncWorker.Init(mDrmDevice, drmDisplayId, mDisplayTraceName);
     mDrmVSyncWorker.RegisterCallback(std::shared_ptr<VsyncCallback>(this));
 
     if (!mDrmDevice->planes().empty()) {
@@ -683,6 +754,8 @@
     parseMipiSyncEnums(mDrmConnector->mipi_sync());
     updateMountOrientation();
 
+    if (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) parseRCDId(mDrmCrtc->rcd_plane_id_property());
+
     if (mExynosDisplay->mBrightnessController &&
             mExynosDisplay->mBrightnessController->initDrm(*mDrmDevice, *mDrmConnector)) {
         ALOGW("%s failed to init brightness controller", __func__);
@@ -720,13 +793,37 @@
         if (!mExynosDisplay->mPlugState || !mVsyncCallback.getVSyncEnabled()) {
             return;
         }
+
+        // Refresh rate during enabling LHBM might be different from the one SF expects.
+        // HWC just reports the SF expected Vsync to make UI smoothness consistent even if
+        // HWC runs at different refresh rate temporarily.
+        if (!mExynosDisplay->isConfigSettingEnabled()) {
+            int64_t pendingPeriodNs =
+                    mExynosDisplay->getVsyncPeriod(mExynosDisplay->mPendingConfig);
+            int64_t activePeriodNs = mExynosDisplay->getVsyncPeriod(mExynosDisplay->mActiveConfig);
+            if (pendingPeriodNs && mExynosDisplay->mLastVsyncTimestamp) {
+                if (activePeriodNs > pendingPeriodNs) {
+                    DISPLAY_DRM_LOGW("wrong vsync period: %" PRId64 "us (active), %" PRId64
+                                     "us (pending)",
+                                     activePeriodNs / 1000, pendingPeriodNs / 1000);
+                } else if (activePeriodNs != pendingPeriodNs) {
+                    int64_t deltaNs = timestamp - mExynosDisplay->mLastVsyncTimestamp;
+                    if (deltaNs < (pendingPeriodNs - ms2ns(2))) {
+                        DISPLAY_DRM_LOGI("skip mismatching Vsync callback, delta=%" PRId64 "us",
+                                         deltaNs / 1000);
+                        return;
+                    }
+                }
+            }
+        }
+        mExynosDisplay->mLastVsyncTimestamp = timestamp;
     }
 
     ExynosDevice *exynosDevice = mExynosDisplay->mDevice;
 
     if (exynosDevice->onVsync_2_4(mExynosDisplay->mDisplayId, timestamp,
                                   mExynosDisplay->mVsyncPeriod)) {
-        ATRACE_INT(vsyncPeriodTag, static_cast<int32_t>(mExynosDisplay->mVsyncPeriod));
+        DISPLAY_ATRACE_INT(vsyncPeriodTag, static_cast<int32_t>(mExynosDisplay->mVsyncPeriod));
         return;
     }
 
@@ -824,7 +921,7 @@
 
     ExynosDevice *exynosDevice = mExynosDisplay->mDevice;
     if (exynosDevice->isCallbackAvailable(HWC2_CALLBACK_VSYNC_2_4)) {
-        ATRACE_INT(vsyncPeriodTag, 0);
+        DISPLAY_ATRACE_INT(vsyncPeriodTag, 0);
     }
 
     return NO_ERROR;
@@ -899,11 +996,12 @@
         /* key: (width<<32 | height) */
         std::map<uint64_t, uint32_t> groupIds;
         uint32_t groupId = 0;
-        uint32_t min_vsync_period = UINT_MAX;
+        float peakRr = -1;
 
         for (const DrmMode &mode : mDrmConnector->modes()) {
             displayConfigs_t configs;
-            configs.vsyncPeriod = nsecsPerSec/ mode.v_refresh();
+            float rr = mode.v_refresh();
+            configs.vsyncPeriod = nsecsPerSec / rr;
             configs.width = mode.h_display();
             configs.height = mode.v_display();
             uint64_t key = ((uint64_t)configs.width<<32) | configs.height;
@@ -920,14 +1018,15 @@
             configs.Xdpi = mm_width ? (mode.h_display() * kUmPerInch) / mm_width : -1;
             // Dots per 1000 inches
             configs.Ydpi = mm_height ? (mode.v_display() * kUmPerInch) / mm_height : -1;
-            // find min vsync period
-            if (configs.vsyncPeriod <= min_vsync_period) min_vsync_period = configs.vsyncPeriod;
+            // find peak rr
+            if (rr > peakRr)
+                  peakRr = rr;
             mExynosDisplay->mDisplayConfigs.insert(std::make_pair(mode.id(), configs));
             ALOGD("config group(%d), w(%d), h(%d), vsync(%d), xdpi(%d), ydpi(%d)",
                     configs.groupId, configs.width, configs.height,
                     configs.vsyncPeriod, configs.Xdpi, configs.Ydpi);
         }
-        mExynosDisplay->setMinDisplayVsyncPeriod(min_vsync_period);
+        mExynosDisplay->setPeakRefreshRate(peakRr);
     }
 
     uint32_t num_modes = static_cast<uint32_t>(mDrmConnector->modes().size());
@@ -954,7 +1053,7 @@
     for (uint32_t i = 0; i < num_modes; i++) {
         auto mode = mDrmConnector->modes().at(i);
         ALOGD("%s display config[%d] %s:: id(%d), clock(%d), flags(%d), type(%d)",
-                mExynosDisplay->mDisplayName.string(), i, mode.name().c_str(), mode.id(), mode.clock(), mode.flags(), mode.type());
+                mExynosDisplay->mDisplayName.c_str(), i, mode.name().c_str(), mode.id(), mode.clock(), mode.flags(), mode.type());
         ALOGD("\th_display(%d), h_sync_start(%d), h_sync_end(%d), h_total(%d), h_skew(%d)",
                 mode.h_display(), mode.h_sync_start(), mode.h_sync_end(), mode.h_total(), mode.h_skew());
         ALOGD("\tv_display(%d), v_sync_start(%d), v_sync_end(%d), v_total(%d), v_scan(%d), v_refresh(%f)",
@@ -1081,8 +1180,9 @@
 int32_t ExynosDisplayDrmInterface::setActiveConfigWithConstraints(
         hwc2_config_t config, bool test)
 {
-    ALOGD("%s:: %s config(%d) test(%d)", __func__, mExynosDisplay->mDisplayName.string(), config,
+    ALOGD("%s:: %s config(%d) test(%d)", __func__, mExynosDisplay->mDisplayName.c_str(), config,
           test);
+
     auto mode = std::find_if(mDrmConnector->modes().begin(), mDrmConnector->modes().end(),
             [config](DrmMode const &m) { return m.id() == config;});
     if (mode == mDrmConnector->modes().end()) {
@@ -1119,6 +1219,10 @@
     if (!test) {
         if (modeBlob) { /* only replace desired mode if it has changed */
             mDesiredModeState.setMode(*mode, modeBlob, drmReq);
+            if (mExynosDisplay->mOperationRateManager) {
+                mExynosDisplay->mOperationRateManager->onConfig(config);
+            }
+            DISPLAY_DRM_LOGI("%s: config(%d)", __func__, config);
         } else {
             ALOGD("%s:: same desired mode %d", __func__, config);
         }
@@ -1204,11 +1308,15 @@
         return HWC2_ERROR_BAD_CONFIG;
     }
 
+    if (mExynosDisplay->mOperationRateManager) {
+        mExynosDisplay->mOperationRateManager->onConfig(config);
+    }
+
     mExynosDisplay->updateAppliedActiveConfig(config, systemTime(SYSTEM_TIME_MONOTONIC));
     if (!setActiveDrmMode(*mode)) {
-        ALOGI("%s:: %s config(%d)", __func__, mExynosDisplay->mDisplayName.string(), config);
+        DISPLAY_DRM_LOGI("%s: config(%d)", __func__, config);
     } else {
-        ALOGE("%s:: %s config(%d) failed", __func__, mExynosDisplay->mDisplayName.string(), config);
+        DISPLAY_DRM_LOGE("%s: config(%d) failed", __func__, config);
     }
 
     return 0;
@@ -1332,7 +1440,7 @@
     if ((ret == 0) && (hdr_formats & (1 << typeBit))) {
         mExynosDisplay->mHdrTypes.push_back(HAL_HDR_DOLBY_VISION);
         HDEBUGLOGD(eDebugHWC, "%s: supported hdr types : %d",
-                mExynosDisplay->mDisplayName.string(), HAL_HDR_DOLBY_VISION);
+                mExynosDisplay->mDisplayName.c_str(), HAL_HDR_DOLBY_VISION);
     }
     std::tie(typeBit, ret) = prop_hdr_formats.GetEnumValueWithName("HDR10");
     if ((ret == 0) && (hdr_formats & (1 << typeBit))) {
@@ -1341,23 +1449,23 @@
             mExynosDisplay->mHdrTypes.push_back(HAL_HDR_HDR10_PLUS);
         }
         HDEBUGLOGD(eDebugHWC, "%s: supported hdr types : %d",
-                mExynosDisplay->mDisplayName.string(), HAL_HDR_HDR10);
+                mExynosDisplay->mDisplayName.c_str(), HAL_HDR_HDR10);
     }
     std::tie(typeBit, ret) = prop_hdr_formats.GetEnumValueWithName("HLG");
     if ((ret == 0) && (hdr_formats & (1 << typeBit))) {
         mExynosDisplay->mHdrTypes.push_back(HAL_HDR_HLG);
         HDEBUGLOGD(eDebugHWC, "%s: supported hdr types : %d",
-                mExynosDisplay->mDisplayName.string(), HAL_HDR_HLG);
+                mExynosDisplay->mDisplayName.c_str(), HAL_HDR_HLG);
     }
 
     ALOGI("%s: get hdrCapabilities info max_luminance(%" PRId64 "), "
             "max_avg_luminance(%" PRId64 "), min_luminance(%" PRId64 "), "
             "hdr_formats(0x%" PRIx64 ")",
-            mExynosDisplay->mDisplayName.string(),
+            mExynosDisplay->mDisplayName.c_str(),
             max_luminance, max_avg_luminance, min_luminance, hdr_formats);
 
     ALOGI("%s: mHdrTypes size(%zu), maxLuminance(%f), maxAverageLuminance(%f), minLuminance(%f)",
-            mExynosDisplay->mDisplayName.string(), mExynosDisplay->mHdrTypes.size(), mExynosDisplay->mMaxLuminance,
+            mExynosDisplay->mDisplayName.c_str(), mExynosDisplay->mHdrTypes.size(), mExynosDisplay->mMaxLuminance,
             mExynosDisplay->mMaxAverageLuminance, mExynosDisplay->mMinLuminance);
 
     return 0;
@@ -1365,11 +1473,11 @@
 
 int ExynosDisplayDrmInterface::getDeconChannel(ExynosMPP *otfMPP)
 {
-    int32_t channelNum = sizeof(IDMA_CHANNEL_MAP)/sizeof(dpp_channel_map_t);
+    int32_t channelNum = sizeof(idma_channel_map)/sizeof(dpp_channel_map_t);
     for (int i = 0; i < channelNum; i++) {
-        if((IDMA_CHANNEL_MAP[i].type == otfMPP->mPhysicalType) &&
-           (IDMA_CHANNEL_MAP[i].index == otfMPP->mPhysicalIndex))
-            return IDMA_CHANNEL_MAP[i].channel;
+        if((idma_channel_map[i].type == otfMPP->mPhysicalType) &&
+           (idma_channel_map[i].index == otfMPP->mPhysicalIndex))
+            return idma_channel_map[i].channel;
     }
     return -EINVAL;
 }
@@ -1381,6 +1489,7 @@
         const std::unique_ptr<DrmPlane> &plane,
         uint32_t &fbId)
 {
+    ATRACE_CALL();
     int ret = NO_ERROR;
 
     if (fbId == 0) {
@@ -1579,7 +1688,7 @@
 
         HDEBUGLOGD(eDebugWindowUpdate,
                 "%s: partial region updated [%d, %d, %d, %d] -> [%d, %d, %d, %d] blob(%d)",
-                mExynosDisplay->mDisplayName.string(),
+                mExynosDisplay->mDisplayName.c_str(),
                 mPartialRegionState.partial_rect.x1,
                 mPartialRegionState.partial_rect.y1,
                 mPartialRegionState.partial_rect.x2,
@@ -1661,12 +1770,16 @@
     std::unordered_map<uint32_t, uint32_t> planeEnableInfo;
     android::String8 result;
     bool hasSecureFrameBuffer = false;
+    bool hasM2mSecureLayerBuffer = false;
 
-    mFrameCounter++;
+    if (mExynosDisplay->isFrameUpdate()) {
+        mFrameCounter++;
+    }
     funcReturnCallback retCallback([&]() {
         if ((ret == NO_ERROR) && !drmReq.getError()) {
-            mFBManager.flip(hasSecureFrameBuffer);
+            mFBManager.flip(hasSecureFrameBuffer, hasM2mSecureLayerBuffer);
         } else if (ret == -ENOMEM) {
+            ALOGW("OOM, release all cached buffers by FBManager");
             mFBManager.releaseAll();
         }
     });
@@ -1763,6 +1876,7 @@
                 return ret;
             }
             hasSecureFrameBuffer |= (isFramebuffer(config.layer) && config.protection);
+            hasM2mSecureLayerBuffer |= (config.protection && config.layer && config.layer->mM2mMPP);
             /* Set this plane is enabled */
             planeEnableInfo[plane->id()] = 1;
         }
@@ -1770,15 +1884,18 @@
 
     for (size_t i = 0; i < mExynosDisplay->mDpuData.rcdConfigs.size(); ++i) {
         exynos_win_config_data &config = mExynosDisplay->mDpuData.rcdConfigs[i];
-        if (config.state == config.WIN_STATE_RCD) {
-            const int channelId = mExynosDisplay->mDevice->getSpecialPlaneId(
-                    mExynosDisplay->mIndex); // TODO: b/227584297
-            auto &plane = mDrmDevice->planes().at(channelId);
-            uint32_t fbId = 0;
-            if ((ret = setupCommitFromDisplayConfig(drmReq, config, i, plane, fbId)) < 0) {
-                HWC_LOGE(mExynosDisplay, "setupCommitFromDisplayConfig failed, config[%zu]", i);
+        if ((config.state == config.WIN_STATE_RCD) &&
+            (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY)) {
+            const int32_t rcdId = static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId;
+            const int32_t channelId = getSpecialChannelId(rcdId);
+            if (channelId >= 0) {
+                auto &plane = mDrmDevice->planes().at(channelId);
+                uint32_t fbId = 0;
+                if ((ret = setupCommitFromDisplayConfig(drmReq, config, i, plane, fbId)) < 0) {
+                    HWC_LOGE(mExynosDisplay, "setupCommitFromDisplayConfig failed, config[%zu]", i);
+                }
+                planeEnableInfo[plane->id()] = 1;
             }
-            planeEnableInfo[plane->id()] = 1;
         }
     }
 
@@ -1792,6 +1909,15 @@
                 (exynosMPP->mReservedDisplay != (int32_t)mExynosDisplay->mDisplayId))
                 continue;
 
+            if ((exynosMPP == NULL) && (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) &&
+                (plane->id() != static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId))
+                continue;
+
+            /* If this plane is not supported by the CRTC binded with ExynosDisplay,
+             * it should be disabled by this ExynosDisplay */
+            if (!plane->GetCrtcSupported(*mDrmCrtc))
+                continue;
+
             if ((ret = drmReq.atomicAddProperty(plane->id(),
                     plane->crtc_property(), 0)) < 0)
                 return ret;
@@ -1924,6 +2050,21 @@
     return NO_ERROR;
 }
 
+int32_t ExynosDisplayDrmInterface::triggerClearDisplayPlanes()
+{
+    ATRACE_CALL();
+    DrmModeAtomicReq drmReq(this);
+
+    clearDisplayPlanes(drmReq);
+    int ret = NO_ERROR;
+    if ((ret = drmReq.commit(0, true))) {
+        HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset ret=(%d)\n",
+                __func__, ret);
+        return ret;
+    }
+    return ret;
+}
+
 int32_t ExynosDisplayDrmInterface::clearDisplayPlanes(DrmModeAtomicReq &drmReq)
 {
     int ret = NO_ERROR;
@@ -1937,6 +2078,11 @@
             (exynosMPP->mReservedDisplay != (int32_t)mExynosDisplay->mDisplayId))
             continue;
 
+        /* If this plane is not supported by the CRTC binded with ExynosDisplay,
+         * it should not be disabled by this ExynosDisplay */
+        if (!plane->GetCrtcSupported(*mDrmCrtc))
+            continue;
+
         if ((ret = drmReq.atomicAddProperty(plane->id(),
                                             plane->crtc_property(), 0)) < 0) {
             break;
@@ -1954,7 +2100,8 @@
 int32_t ExynosDisplayDrmInterface::clearDisplay(bool needModeClear)
 {
     ExynosDevice *exynosDevice = mExynosDisplay->mDevice;
-    const bool isAsyncOff = needModeClear && exynosDevice->isDispOffAsyncSupported();
+    const bool isAsyncOff = needModeClear && exynosDevice->isDispOffAsyncSupported() &&
+            !exynosDevice->hasOtherDisplayOn(mExynosDisplay);
     int ret = NO_ERROR;
     DrmModeAtomicReq drmReq(this);
 
@@ -2050,7 +2197,7 @@
         result.appendFormat("atomic commit error\n");
         if (hwcCheckDebugMessages(eDebugDisplayInterfaceConfig) == false)
             dumpAtomicCommitInfo(result);
-        HWC_LOGE(mDrmDisplayInterface->mExynosDisplay, "%s", result.string());
+        HWC_LOGE(mDrmDisplayInterface->mExynosDisplay, "%s", result.c_str());
     }
 
     if(mPset)
@@ -2093,7 +2240,7 @@
         return result;
 
     if (debugPrint)
-        ALOGD("%s atomic config ++++++++++++", mDrmDisplayInterface->mExynosDisplay->mDisplayName.string());
+        ALOGD("%s atomic config ++++++++++++", mDrmDisplayInterface->mExynosDisplay->mDisplayName.c_str());
 
     for (int i = 0; i < drmModeAtomicGetCursor(mPset); i++) {
         const DrmProperty *property = NULL;
@@ -2155,10 +2302,10 @@
 
         if (debugPrint)
             ALOGD("property[%d] %s object_id: %d, property_id: %d, name: %s,  value: %" PRId64 ")\n",
-                    i, objectName.string(), mPset->items[i].object_id, mPset->items[i].property_id, property->name().c_str(), mPset->items[i].value);
+                    i, objectName.c_str(), mPset->items[i].object_id, mPset->items[i].property_id, property->name().c_str(), mPset->items[i].value);
         else
             result.appendFormat("property[%d] %s object_id: %d, property_id: %d, name: %s,  value: %" PRId64 ")\n",
-                i,  objectName.string(), mPset->items[i].object_id, mPset->items[i].property_id, property->name().c_str(), mPset->items[i].value);
+                i,  objectName.c_str(), mPset->items[i].object_id, mPset->items[i].property_id, property->name().c_str(), mPset->items[i].value);
     }
     return result;
 }
@@ -2378,6 +2525,11 @@
     edid_buf[59] = height & 0xff;
     edid_buf[61] = (height >> 4) & 0xf0;
 
+    if (mMonitorDescription[0] != 0) {
+        /* Descriptor block 3 starts at address 90, data offset is 5 bytes */
+        memcpy(&edid_buf[95], mMonitorDescription.data(), mMonitorDescription.size());
+    }
+
     unsigned int sum = std::accumulate(edid_buf.begin(), edid_buf.end() - 1, 0);
     edid_buf[127] = (0x100 - (sum & 0xFF)) & 0xFF;
     if (outData) {
@@ -2397,14 +2549,14 @@
 {
     if ((mDrmDevice == nullptr) || (mDrmConnector == nullptr)) {
         ALOGE("%s: display(%s) mDrmDevice(%p), mDrmConnector(%p)",
-                __func__, mExynosDisplay->mDisplayName.string(),
+                __func__, mExynosDisplay->mDisplayName.c_str(),
                 mDrmDevice, mDrmConnector);
         return HWC2_ERROR_UNSUPPORTED;
     }
 
     if (mDrmConnector->edid_property().id() == 0) {
         ALOGD("%s: edid_property is not supported",
-                mExynosDisplay->mDisplayName.string());
+                mExynosDisplay->mDisplayName.c_str());
         return HWC2_ERROR_UNSUPPORTED;
     }
 
@@ -2421,14 +2573,14 @@
     }
     if (blobId == 0) {
         ALOGD("%s: edid_property is supported but blob is not valid",
-                mExynosDisplay->mDisplayName.string());
+                mExynosDisplay->mDisplayName.c_str());
         return getDisplayFakeEdid(*outPort, *outDataSize, outData);
     }
 
     blob = drmModeGetPropertyBlob(mDrmDevice->fd(), blobId);
     if (blob == nullptr) {
         ALOGD("%s: Failed to get blob",
-                mExynosDisplay->mDisplayName.string());
+                mExynosDisplay->mDisplayName.c_str());
         return HWC2_ERROR_UNSUPPORTED;
     }
 
@@ -2443,3 +2595,16 @@
 
     return HWC2_ERROR_NONE;
 }
+
+int32_t ExynosDisplayDrmInterface::getSpecialChannelId(uint32_t planeId) {
+    ExynosDevice *exynosDevice = mExynosDisplay->mDevice;
+    for (int i = 0; i < exynosDevice->getSpecialPlaneNum(); i++) {
+        const int32_t channelId = exynosDevice->getSpecialPlaneId(i);
+        auto &plane = mDrmDevice->planes().at(channelId);
+        if (plane->id() == planeId) return channelId;
+    }
+
+    ALOGE("%s: Failed to get RCD planeId.", __func__);
+
+    return -EINVAL;
+}
diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h
index 561e5b3..3997b0f 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h
+++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h
@@ -37,6 +37,9 @@
 /* Max plane number of buffer object */
 #define HWC_DRM_BO_MAX_PLANES 4
 
+/* Monitor Descriptor data is 13 bytes in VESA EDID Standard */
+#define MONITOR_DESCRIPTOR_DATA_LENGTH 13
+
 #ifndef HWC_FORCE_PANIC_PATH
 #define HWC_FORCE_PANIC_PATH "/d/dpu/panic"
 #endif
@@ -60,7 +63,7 @@
         // layer. Those fbIds will be cleaned up once the layer was destroyed.
         int32_t getBuffer(const exynos_win_config_data &config, uint32_t &fbId);
 
-        bool checkShrink();
+        void checkShrink();
 
         void cleanup(const ExynosLayer *layer);
 
@@ -68,7 +71,7 @@
         // layers after the previous fdIds were update successfully on the
         // screen.
         // This should be called after the frame update.
-        void flip(bool hasSecureFrameBuffer);
+        void flip(const bool hasSecureFrameBuffer, const bool hasM2mSecureLayerBuffer);
 
         // release all currently tracked buffers, this can be called for example when display is turned
         // off
@@ -109,7 +112,8 @@
         using FBList = std::list<std::unique_ptr<Framebuffer>>;
 
         template <class UnaryPredicate>
-        uint32_t findCachedFbId(const ExynosLayer *layer, UnaryPredicate predicate);
+        uint32_t findCachedFbId(const ExynosLayer *layer, const bool isM2mSecureLayer,
+                                UnaryPredicate predicate);
         int addFB2WithModifiers(uint32_t state, uint32_t width, uint32_t height, uint32_t drmFormat,
                                 const DrmArray<uint32_t> &handles,
                                 const DrmArray<uint32_t> &pitches,
@@ -123,15 +127,19 @@
         void freeBufHandle(uint32_t handle);
         void removeFBsThreadRoutine();
 
-        void markInuseLayerLocked(const ExynosLayer *layer) REQUIRES(mMutex);
+        void markInuseLayerLocked(const ExynosLayer *layer, const bool isM2mSecureLayer)
+                REQUIRES(mMutex);
         void destroyUnusedLayersLocked() REQUIRES(mMutex);
         void destroySecureFramebufferLocked() REQUIRES(mMutex);
+        void destroyM2mSecureLayerBufferLocked() REQUIRES(mMutex);
 
         int mDrmFd = -1;
 
-        // mCachedLayerBuffers map keep the relationship between Layer and
-        // FBList. The map entry will be deleted once the layer is destroyed.
+        // mCachedLayerBuffers map keep the relationship between Layer and FBList.
+        // mCachedM2mSecureLayerBuffers map keep the relationship between M2M secure
+        // Layer and FBList. The map entry will be deleted once the layer is destroyed.
         std::map<const ExynosLayer *, FBList> mCachedLayerBuffers;
+        std::map<const ExynosLayer *, FBList> mCachedM2mSecureLayerBuffers;
 
         // mCleanBuffers list keeps fbIds of destroyed layers. Those fbIds will
         // be destroyed in mRmFBThread thread.
@@ -140,11 +148,15 @@
         // mCacheShrinkPending is set when we want to clean up unused layers
         // in mCachedLayerBuffers. When the flag is set, mCachedLayersInuse will
         // keep in-use layers in this frame update. Those unused layers will be
-        // freed at the end of the update.
+        // freed at the end of the update. mCacheM2mSecureShrinkPending is same to
+        // mCacheShrinkPending but for mCachedM2mSecureLayerBuffers.
         // TODO: have a better way to maintain inuse layers
         bool mCacheShrinkPending = false;
+        bool mCacheM2mSecureShrinkPending = false;
         bool mHasSecureFramebuffer = false;
+        bool mHasM2mSecureLayerBuffer = false;
         std::set<const ExynosLayer *> mCachedLayersInuse;
+        std::set<const ExynosLayer *> mCachedM2mSecureLayersInuse;
 
         std::thread mRmFBThread;
         bool mRmFBThreadRunning = false;
@@ -152,8 +164,9 @@
         Mutex mMutex;
 
         static constexpr size_t MAX_CACHED_LAYERS = 16;
+        static constexpr size_t MAX_CACHED_M2M_SECURE_LAYERS = 1;
         static constexpr size_t MAX_CACHED_BUFFERS_PER_LAYER = 32;
-        static constexpr size_t MAX_CACHED_SECURE_BUFFERS_PER_G2D_LAYER = 3;
+        static constexpr size_t MAX_CACHED_M2M_SECURE_BUFFERS_PER_LAYER = 3;
 };
 
 inline bool isFramebuffer(const ExynosLayer *layer) {
@@ -161,10 +174,12 @@
 }
 
 template <class UnaryPredicate>
-uint32_t FramebufferManager::findCachedFbId(const ExynosLayer *layer, UnaryPredicate predicate) {
+uint32_t FramebufferManager::findCachedFbId(const ExynosLayer *layer, const bool isM2mSecureLayer,
+                                            UnaryPredicate predicate) {
     Mutex::Autolock lock(mMutex);
-    markInuseLayerLocked(layer);
-    const auto &cachedBuffers = mCachedLayerBuffers[layer];
+    markInuseLayerLocked(layer, isM2mSecureLayer);
+    const auto &cachedBuffers =
+            (!isM2mSecureLayer) ? mCachedLayerBuffers[layer] : mCachedM2mSecureLayerBuffers[layer];
     const auto it = std::find_if(cachedBuffers.begin(), cachedBuffers.end(), predicate);
     return (it != cachedBuffers.end()) ? (*it)->fbId : 0;
 }
@@ -324,10 +339,12 @@
         virtual int32_t setHistogramData(void *bin) { return NO_ERROR; }
         int32_t getActiveModeHDisplay() { return mActiveModeState.mode.h_display(); }
         int32_t getActiveModeVDisplay() { return mActiveModeState.mode.v_display(); }
+        uint32_t getActiveModeId() { return mActiveModeState.mode.id(); }
         int32_t panelHsize() { return mPanelResolutionHsize; }
         int32_t panelVsize() { return mPanelResolutionVsize; }
         int32_t getPanelResolution();
         uint32_t getCrtcId() { return mDrmCrtc->id(); }
+        int32_t triggerClearDisplayPlanes();
 
     protected:
         enum class HalMipiSyncType : uint32_t {
@@ -406,6 +423,7 @@
         void parseColorModeEnums(const DrmProperty &property);
         void parseMipiSyncEnums(const DrmProperty &property);
         void updateMountOrientation();
+        void parseRCDId(const DrmProperty &property);
 
         int32_t setupWritebackCommit(DrmModeAtomicReq &drmReq);
         int32_t clearWritebackCommit(DrmModeAtomicReq &drmReq);
@@ -415,6 +433,7 @@
         int32_t getLowPowerDrmModeModeInfo();
         int32_t setActiveDrmMode(DrmMode const &mode);
         void setMaxWindowNum(uint32_t num) { mMaxWindowNum = num; };
+        int32_t getSpecialChannelId(uint32_t planeId);
 
     protected:
         struct PartialRegionState {
@@ -490,10 +509,12 @@
 
         DrmReadbackInfo mReadbackInfo;
         FramebufferManager mFBManager;
+        std::array<uint8_t, MONITOR_DESCRIPTOR_DATA_LENGTH> mMonitorDescription;
 
     private:
         int32_t getDisplayFakeEdid(uint8_t &outPort, uint32_t &outDataSize, uint8_t *outData);
 
+        String8 mDisplayTraceName;
         DrmMode mDozeDrmMode;
         uint32_t mMaxWindowNum = 0;
         int32_t mFrameCounter = 0;
diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h b/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h
index d133774..b87c2e2 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h
+++ b/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h
@@ -53,6 +53,7 @@
         virtual int32_t updateHdrCapabilities();
         virtual int32_t deliverWinConfigData() {return NO_ERROR;};
         virtual int32_t clearDisplay(bool __unused needModeClear = false) {return NO_ERROR;};
+        virtual int32_t triggerClearDisplayPlanes() { return NO_ERROR; }
         virtual int32_t disableSelfRefresh(uint32_t __unused disable) {return NO_ERROR;};
         virtual int32_t setForcePanic() {return NO_ERROR;};
         virtual int getDisplayFd() {return -1;};
@@ -79,6 +80,7 @@
         virtual int32_t getDefaultModeId(int32_t* __unused modeId) {
             return HWC2_ERROR_UNSUPPORTED;
         }
+        virtual uint32_t getActiveModeId() { return UINT_MAX; }
 
         virtual int32_t waitVBlank() { return 0; };
     public:
diff --git a/libhwc2.1/libdrmresource/drm/drmcrtc.cpp b/libhwc2.1/libdrmresource/drm/drmcrtc.cpp
index 21fd040..55cee3c 100644
--- a/libhwc2.1/libdrmresource/drm/drmcrtc.cpp
+++ b/libhwc2.1/libdrmresource/drm/drmcrtc.cpp
@@ -97,6 +97,8 @@
       ALOGI("Failed to get &histogram_threshold property");
   if (drm_->GetCrtcProperty(*this, "histogram_pos", &histogram_position_property_))
       ALOGI("Failed to get &histogram_position property");
+  if (drm_->GetCrtcProperty(*this, "rcd_plane_id", &rcd_plane_id_property_))
+      ALOGI("Failed to get &rcd_plane_id property");
 
   properties_.push_back(&active_property_);
   properties_.push_back(&mode_property_);
@@ -126,6 +128,8 @@
   properties_.push_back(&histogram_threshold_property_);
   properties_.push_back(&histogram_position_property_);
 
+  properties_.push_back(&rcd_plane_id_property_);
+
   return 0;
 }
 
@@ -262,4 +266,8 @@
     return histogram_position_property_;
 }
 
+const DrmProperty &DrmCrtc::rcd_plane_id_property() const {
+    return rcd_plane_id_property_;
+}
+
 }  // namespace android
diff --git a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp
index 3132bc5..bd12d30 100644
--- a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp
+++ b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp
@@ -17,19 +17,21 @@
 #define LOG_TAG "hwc-drm-event-listener"
 
 #include "drmeventlistener.h"
-#include "drmdevice.h"
-#include <drm/samsung_drm.h>
 
 #include <assert.h>
+#include <drm/samsung_drm.h>
 #include <errno.h>
-#include <linux/netlink.h>
-#include <sys/socket.h>
-
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
+#include <inttypes.h>
+#include <linux/netlink.h>
 #include <log/log.h>
+#include <sys/socket.h>
+#include <utils/String8.h>
 #include <xf86drm.h>
 
+#include "drmdevice.h"
+
 namespace android {
 
 DrmEventListener::DrmEventListener(DrmDevice *drm)
@@ -143,6 +145,43 @@
     panel_idle_handler_ = NULL;
 }
 
+int DrmEventListener::RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler) {
+  if (!handler)
+    return -EINVAL;
+  if (handler->getFd() < 0)
+    return -EINVAL;
+  std::scoped_lock lock(mutex_);
+  if (sysfs_handlers_.find(handler->getFd()) != sysfs_handlers_.end()) {
+    ALOGE("%s: DrmSysfsEventHandler for fd:%d has been added to epoll", __func__, handler->getFd());
+    return -EINVAL;
+  }
+
+  struct epoll_event ev;
+  ev.events = EPOLLPRI;
+  ev.data.fd = handler->getFd();
+  if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, handler->getFd(), &ev) < 0) {
+    ALOGE("%s: Failed to add fd into epoll: %s", __func__, strerror(errno));
+    return -errno;
+  }
+  sysfs_handlers_.emplace(handler->getFd(), std::move(handler));
+  return 0;
+}
+
+int DrmEventListener::UnRegisterSysfsHandler(int sysfs_fd) {
+  std::scoped_lock lock(mutex_);
+  auto it = sysfs_handlers_.find(sysfs_fd);
+  if (it == sysfs_handlers_.end()) {
+    ALOGE("%s: DrmSysfsEventHandler for fd:%d not found", __func__, sysfs_fd);
+    return -EINVAL;
+  }
+  if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, sysfs_fd, nullptr) < 0) {
+    ALOGE("%s: Failed to remove fd from epoll: %s", __func__, strerror(errno));
+    return -errno;
+  }
+  sysfs_handlers_.erase(it);
+  return 0;
+}
+
 bool DrmEventListener::IsDrmInTUI() {
   char buffer[1024];
   int ret;
@@ -267,6 +306,23 @@
   tui_handler_->handleTUIEvent();
 }
 
+void DrmEventListener::SysfsEventHandler(int fd) {
+  std::shared_ptr<DrmSysfsEventHandler> handler;
+  {
+    std::scoped_lock lock(mutex_);
+    // Copy the shared_ptr to avoid the handler object gets destroyed
+    // while it's handling the event without holding mutex_
+    auto it = sysfs_handlers_.find(fd);
+    if (it != sysfs_handlers_.end())
+            handler = it->second;
+  }
+  if (handler) {
+    handler->handleSysfsEvent();
+  } else {
+    ALOGW("Unhandled sysfs event from fd:%d", fd);
+  }
+}
+
 void DrmEventListener::Routine() {
   struct epoll_event events[maxFds];
   int nfds, n;
@@ -280,11 +336,13 @@
       if (events[n].data.fd == uevent_fd_.get()) {
         UEventHandler();
       } else if (events[n].data.fd == drm_->fd()) {
-          DRMEventHandler();
+        DRMEventHandler();
       }
     } else if (events[n].events & EPOLLPRI) {
       if (tuievent_fd_.get() >= 0 && events[n].data.fd == tuievent_fd_.get()) {
         TUIEventHandler();
+      } else {
+        SysfsEventHandler(events[n].data.fd);
       }
     }
   }
diff --git a/libhwc2.1/libdrmresource/drm/vsyncworker.cpp b/libhwc2.1/libdrmresource/drm/vsyncworker.cpp
index d2b4a02..a795fb3 100644
--- a/libhwc2.1/libdrmresource/drm/vsyncworker.cpp
+++ b/libhwc2.1/libdrmresource/drm/vsyncworker.cpp
@@ -36,7 +36,6 @@
 using namespace std::chrono_literals;
 
 constexpr auto nsecsPerSec = std::chrono::nanoseconds(1s).count();
-constexpr auto hwVsyncPeriodTag = "HWVsyncPeriod";
 
 namespace android {
 
@@ -52,9 +51,12 @@
     Exit();
 }
 
-int VSyncWorker::Init(DrmDevice *drm, int display) {
+int VSyncWorker::Init(DrmDevice *drm, int display, const String8 &display_trace_name) {
     drm_ = drm;
     display_ = display;
+    display_trace_name_ = display_trace_name;
+    hw_vsync_period_tag_.appendFormat("HWVsyncPeriod for %s", display_trace_name.c_str());
+    hw_vsync_enabled_tag_.appendFormat("HWCVsync for %s", display_trace_name.c_str());
 
     return InitWorker();
 }
@@ -71,8 +73,8 @@
     last_timestamp_ = -1;
     Unlock();
 
-    ATRACE_INT("HWCVsync", static_cast<int32_t>(enabled));
-    ATRACE_INT64(hwVsyncPeriodTag, 0);
+    ATRACE_INT(hw_vsync_enabled_tag_.c_str(), static_cast<int32_t>(enabled));
+    ATRACE_INT64(hw_vsync_period_tag_.c_str(), 0);
     Signal();
 }
 
@@ -211,8 +213,8 @@
 
     if (last_timestamp_ >= 0) {
         int64_t period = timestamp - last_timestamp_;
-        ATRACE_INT64(hwVsyncPeriodTag, period);
-        ALOGV("HW vsync period %" PRId64 "ns", period);
+        ATRACE_INT64(hw_vsync_period_tag_.c_str(), period);
+        ALOGV("HW vsync period %" PRId64 "ns for %s", period, display_trace_name_.c_str());
     }
 
     last_timestamp_ = timestamp;
diff --git a/libhwc2.1/libdrmresource/include/drmcrtc.h b/libhwc2.1/libdrmresource/include/drmcrtc.h
index 9149f51..6bb73fd 100644
--- a/libhwc2.1/libdrmresource/include/drmcrtc.h
+++ b/libhwc2.1/libdrmresource/include/drmcrtc.h
@@ -72,6 +72,8 @@
   const DrmProperty &histogram_threshold_property() const;
   const DrmProperty &histogram_position_property() const;
 
+  const DrmProperty &rcd_plane_id_property() const;
+
   const std::vector<DrmProperty *> &properties() const {
       return properties_;
   }
@@ -113,6 +115,8 @@
   DrmProperty histogram_threshold_property_;
   DrmProperty histogram_position_property_;
 
+  DrmProperty rcd_plane_id_property_;
+
   std::vector<DrmProperty *> properties_;
 };
 }  // namespace android
diff --git a/libhwc2.1/libdrmresource/include/drmeventlistener.h b/libhwc2.1/libdrmresource/include/drmeventlistener.h
index 474b116..e85ca0a 100644
--- a/libhwc2.1/libdrmresource/include/drmeventlistener.h
+++ b/libhwc2.1/libdrmresource/include/drmeventlistener.h
@@ -17,11 +17,13 @@
 #ifndef ANDROID_DRM_EVENT_LISTENER_H_
 #define ANDROID_DRM_EVENT_LISTENER_H_
 
+#include <sys/epoll.h>
+
+#include <map>
+
 #include "autofd.h"
 #include "worker.h"
 
-#include <sys/epoll.h>
-
 namespace android {
 
 class DrmDevice;
@@ -62,9 +64,19 @@
   virtual void handleIdleEnterEvent(char const *event) = 0;
 };
 
+class DrmSysfsEventHandler {
+ public:
+  DrmSysfsEventHandler() {}
+  virtual ~DrmSysfsEventHandler() {}
+
+  virtual void handleSysfsEvent() = 0;
+  virtual int getFd() = 0;
+};
+
 class DrmEventListener : public Worker {
- static constexpr const char kTUIStatusPath[] = "/sys/devices/platform/exynos-drm/tui_status";
- static const uint32_t maxFds = 3;
+  static constexpr const char kTUIStatusPath[] = "/sys/devices/platform/exynos-drm/tui_status";
+  static const uint32_t maxFds = 4;
+
  public:
   DrmEventListener(DrmDevice *drm);
   virtual ~DrmEventListener();
@@ -79,11 +91,13 @@
   void UnRegisterTUIHandler(DrmTUIEventHandler *handler);
   void RegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler);
   void UnRegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler);
+  int RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler);
+  int UnRegisterSysfsHandler(int sysfs_fd);
 
   bool IsDrmInTUI();
 
-  static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec,
-                          unsigned int tv_usec, void *user_data);
+  static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec,
+                          void *user_data);
 
  protected:
   virtual void Routine();
@@ -92,6 +106,7 @@
   void UEventHandler();
   void DRMEventHandler();
   void TUIEventHandler();
+  void SysfsEventHandler(int fd);
 
   UniqueFd epoll_fd_;
   UniqueFd uevent_fd_;
@@ -102,7 +117,10 @@
   std::unique_ptr<DrmHistogramEventHandler> histogram_handler_;
   std::unique_ptr<DrmTUIEventHandler> tui_handler_;
   std::unique_ptr<DrmPanelIdleEventHandler> panel_idle_handler_;
+  std::mutex mutex_;
+  std::map<int, std::shared_ptr<DrmSysfsEventHandler>> sysfs_handlers_;
 };
+
 }  // namespace android
 
 #endif
diff --git a/libhwc2.1/libdrmresource/include/vsyncworker.h b/libhwc2.1/libdrmresource/include/vsyncworker.h
index bd69712..ce12eea 100644
--- a/libhwc2.1/libdrmresource/include/vsyncworker.h
+++ b/libhwc2.1/libdrmresource/include/vsyncworker.h
@@ -17,14 +17,15 @@
 #ifndef ANDROID_EVENT_WORKER_H_
 #define ANDROID_EVENT_WORKER_H_
 
-#include "drmdevice.h"
-#include "worker.h"
-
-#include <stdint.h>
-#include <map>
-
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
+#include <stdint.h>
+#include <utils/String8.h>
+
+#include <map>
+
+#include "drmdevice.h"
+#include "worker.h"
 
 namespace android {
 
@@ -39,7 +40,7 @@
      VSyncWorker();
      ~VSyncWorker() override;
 
-     int Init(DrmDevice *drm, int display);
+     int Init(DrmDevice *drm, int display, const String8 &display_trace_name);
      void RegisterCallback(std::shared_ptr<VsyncCallback> callback);
 
      void VSyncControl(bool enabled);
@@ -61,6 +62,9 @@
      int display_;
      std::atomic_bool enabled_;
      int64_t last_timestamp_;
+     String8 hw_vsync_period_tag_;
+     String8 hw_vsync_enabled_tag_;
+     String8 display_trace_name_;
 };
 }  // namespace android
 
diff --git a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp
index 36fde04..ed99759 100644
--- a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp
+++ b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp
@@ -30,15 +30,11 @@
 
 using namespace SOC_VERSION;
 
-ExynosExternalDisplay::ExynosExternalDisplay(uint32_t index, ExynosDevice *device)
-    :   ExynosDisplay(index, device)
-{
+ExynosExternalDisplay::ExynosExternalDisplay(uint32_t index, ExynosDevice* device,
+                                             const std::string& displayName)
+      : ExynosDisplay(HWC_DISPLAY_EXTERNAL, index, device, displayName) {
     DISPLAY_LOGD(eDebugExternalDisplay, "");
 
-    mType = HWC_DISPLAY_EXTERNAL;
-    mIndex = index;
-    mDisplayId = getDisplayId(mType, mIndex);
-
     mDisplayControl.cursorSupport = true;
 
     mEnabled = false;
diff --git a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.h b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.h
index 199ef4d..f0caabc 100644
--- a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.h
+++ b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.h
@@ -28,7 +28,7 @@
         hwc2_config_t mActiveConfigIndex;
 
         /* Methods */
-        ExynosExternalDisplay(uint32_t index, ExynosDevice *device);
+        ExynosExternalDisplay(uint32_t index, ExynosDevice* device, const std::string& displayName);
         ~ExynosExternalDisplay();
 
         virtual void init();
diff --git a/libhwc2.1/libhwcService/ExynosHWCService.cpp b/libhwc2.1/libhwcService/ExynosHWCService.cpp
index ba8f996..fd8278b 100644
--- a/libhwc2.1/libhwcService/ExynosHWCService.cpp
+++ b/libhwc2.1/libhwcService/ExynosHWCService.cpp
@@ -492,4 +492,28 @@
     return NO_ERROR;
 }
 
+int32_t ExynosHWCService::setDisplayMultiThreadedPresent(const int32_t& displayId,
+                                                         const bool& enable) {
+    auto display = mHWCCtx->device->getDisplay(displayId);
+
+    if (display == nullptr) return -EINVAL;
+
+    display->mDisplayControl.multiThreadedPresent = enable;
+    ALOGD("ExynosHWCService::%s() display(%u) enable=%d", __func__, displayId, enable);
+    return NO_ERROR;
+}
+
+int32_t ExynosHWCService::triggerRefreshRateIndicatorUpdate(uint32_t displayId,
+                                                            uint32_t refreshRate) {
+    auto display = mHWCCtx->device->getDisplay(displayId);
+
+    if (display == nullptr) return -EINVAL;
+
+    ALOGD("ExynosHWCService::%s() displayID(%u) refreshRate(%u)", __func__, displayId, refreshRate);
+    if (display->mRefreshRateIndicatorHandler) {
+        display->mRefreshRateIndicatorHandler->updateRefreshRate(refreshRate);
+    }
+    return NO_ERROR;
+}
+
 } //namespace android
diff --git a/libhwc2.1/libhwcService/ExynosHWCService.h b/libhwc2.1/libhwcService/ExynosHWCService.h
index 3400fcc..abb525f 100644
--- a/libhwc2.1/libhwcService/ExynosHWCService.h
+++ b/libhwc2.1/libhwcService/ExynosHWCService.h
@@ -79,6 +79,11 @@
     int32_t setDisplayRCDLayerEnabled(uint32_t displayIndex, bool enable) override;
     int32_t triggerDisplayIdleEnter(uint32_t displayIndex, uint32_t idleTeRefreshRate) override;
 
+    virtual int32_t setDisplayMultiThreadedPresent(const int32_t& display_id,
+                                                   const bool& enable) override;
+    virtual int32_t triggerRefreshRateIndicatorUpdate(uint32_t displayId,
+                                                      uint32_t refreshRate) override;
+
 private:
     friend class Singleton<ExynosHWCService>;
     ExynosHWCService();
diff --git a/libhwc2.1/libhwcService/IExynosHWC.cpp b/libhwc2.1/libhwcService/IExynosHWC.cpp
index e0867fa..f092696 100644
--- a/libhwc2.1/libhwcService/IExynosHWC.cpp
+++ b/libhwc2.1/libhwcService/IExynosHWC.cpp
@@ -64,6 +64,8 @@
     SET_DISPLAY_RCDLAYER_ENABLED = 1007,
     TRIGGER_DISPLAY_IDLE_ENTER = 1008,
     SET_DISPLAY_DBM = 1009,
+    SET_DISPLAY_MULTI_THREADED_PRESENT = 1010,
+    TRIGGER_REFRESH_RATE_INDICATOR_UPDATE = 1011,
 };
 
 class BpExynosHWCService : public BpInterface<IExynosHWCService> {
@@ -445,7 +447,7 @@
         data.writeUint32(displayIndex);
         data.writeUint32(idleTeRefreshRate);
 
-        auto result = remote()->transact(SET_DISPLAY_RCDLAYER_ENABLED, data, &reply);
+        auto result = remote()->transact(TRIGGER_DISPLAY_IDLE_ENTER, data, &reply);
         ALOGE_IF(result != NO_ERROR, "TRIGGER_DISPLAY_IDLE_ENTER transact error(%d)", result);
         return result;
     }
@@ -459,6 +461,30 @@
         if (result) ALOGE("SET_DISPLAY_DBM transact error(%d)", result);
         return result;
     }
+
+    virtual int32_t setDisplayMultiThreadedPresent(const int32_t& displayId,
+                                                   const bool& enable) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor());
+        data.writeInt32(displayId);
+        data.writeBool(enable);
+        int result = remote()->transact(SET_DISPLAY_MULTI_THREADED_PRESENT, data, &reply);
+        if (result) ALOGE("SET_DISPLAY_MULTI_THREADED_PRESENT transact error(%d)", result);
+        return result;
+    }
+
+    virtual int32_t triggerRefreshRateIndicatorUpdate(uint32_t displayId,
+                                                      uint32_t refreshRate) override {
+        Parcel data, reply;
+        data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor());
+        data.writeUint32(displayId);
+        data.writeUint32(refreshRate);
+
+        auto result = remote()->transact(TRIGGER_REFRESH_RATE_INDICATOR_UPDATE, data, &reply);
+        ALOGE_IF(result != NO_ERROR, "TRIGGER_REFRESH_RATE_INDICATOR_UPDATE transact error(%d)",
+                 result);
+        return result;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(ExynosHWCService, "android.hal.ExynosHWCService");
@@ -713,6 +739,22 @@
             return NO_ERROR;
         } break;
 
+        case SET_DISPLAY_MULTI_THREADED_PRESENT: {
+            CHECK_INTERFACE(IExynosHWCService, data, reply);
+            int32_t displayId = data.readInt32();
+            bool enable = data.readBool();
+            int32_t error = setDisplayMultiThreadedPresent(displayId, enable);
+            reply->writeInt32(error);
+            return NO_ERROR;
+        } break;
+
+        case TRIGGER_REFRESH_RATE_INDICATOR_UPDATE: {
+            CHECK_INTERFACE(IExynosHWCService, data, reply);
+            uint32_t displayId = data.readUint32();
+            uint32_t refreshRate = data.readUint32();
+            return triggerRefreshRateIndicatorUpdate(displayId, refreshRate);
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libhwc2.1/libhwcService/IExynosHWC.h b/libhwc2.1/libhwcService/IExynosHWC.h
index 23cb113..bf51c85 100644
--- a/libhwc2.1/libhwcService/IExynosHWC.h
+++ b/libhwc2.1/libhwcService/IExynosHWC.h
@@ -74,6 +74,9 @@
     virtual int32_t setDisplayRCDLayerEnabled(uint32_t displayIndex, bool enable) = 0;
     virtual int32_t triggerDisplayIdleEnter(uint32_t displayIndex, uint32_t idleTeRefreshRate) = 0;
     virtual int32_t setDisplayDbm(int32_t display_id, uint32_t on) = 0;
+    virtual int32_t setDisplayMultiThreadedPresent(const int32_t& displayId,
+                                                   const bool& enable) = 0;
+    virtual int32_t triggerRefreshRateIndicatorUpdate(uint32_t displayId, uint32_t refreshRate) = 0;
 };
 
 /* Native Interface */
diff --git a/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp b/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp
index 1c10909..1e963b9 100644
--- a/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp
+++ b/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp
@@ -36,6 +36,7 @@
 using vendor::graphics::BufferUsage;
 using vendor::graphics::VendorGraphicBufferUsage;
 using vendor::graphics::VendorGraphicBufferMeta;
+using namespace SOC_VERSION;
 
 #define AFBC_MAGIC  0xafbc
 
@@ -271,6 +272,30 @@
     return false;
 }
 
+bool isFormat10Bit(int format) {
+    for (unsigned int i = 0; i < FORMAT_MAX_CNT; i++) {
+        if (exynos_format_desc[i].halFormat == format) {
+            if ((exynos_format_desc[i].type & BIT_MASK) == BIT10)
+                return true;
+            else
+                return false;
+        }
+    }
+    return false;
+}
+
+bool isFormat8Bit(int format) {
+    for (unsigned int i = 0; i < FORMAT_MAX_CNT; i++) {
+        if (exynos_format_desc[i].halFormat == format) {
+            if ((exynos_format_desc[i].type & BIT_MASK) == BIT8)
+                return true;
+            else
+                return false;
+        }
+    }
+    return false;
+}
+
 bool isFormatYCrCb(int format)
 {
     return format == HAL_PIXEL_FORMAT_EXYNOS_YV12_M;
@@ -464,7 +489,7 @@
     String8 result;
     dumpExynosImage(result, img);
 
-    ALOGD("%s", result.string());
+    ALOGD("%s", result.c_str());
 }
 
 void dumpExynosImage(String8& result, exynos_image &img)
@@ -472,7 +497,7 @@
     result.appendFormat("\tbufferHandle: %p, fullWidth: %d, fullHeight: %d, x: %d, y: %d, w: %d, "
                         "h: %d, format: %s\n",
                         img.bufferHandle, img.fullWidth, img.fullHeight, img.x, img.y, img.w, img.h,
-                        getFormatStr(img.format, img.compressed ? AFBC : 0).string());
+                        getFormatStr(img.format, img.compressed ? AFBC : 0).c_str());
     result.appendFormat("\tusageFlags: 0x%" PRIx64 ", layerFlags: 0x%8x, acquireFenceFd: %d, releaseFenceFd: %d\n",
             img.usageFlags, img.layerFlags, img.acquireFenceFd, img.releaseFenceFd);
     result.appendFormat("\tdataSpace(%d), blending(%d), transform(0x%2x), afbc(%d)\n",
@@ -647,11 +672,13 @@
         HDEBUGLOGD(eDebugMPP, "size(Y) : %d", P010_Y_SIZE(width, height));
         return P010_Y_SIZE(width, height);
     case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN:
-        return YUV420N_Y_SIZE(width, height);
+        return NV12N_Y_SIZE(width, height);
+    case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN:
+        return 2 * __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16);
     case HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B:
-        return 2 * __ALIGN_UP(width, 64) * __ALIGN_UP(height, 8);
+        return 2 * __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16);
     case HAL_PIXEL_FORMAT_GOOGLE_NV12_SP:
-        return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 8);
+        return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16);
     case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC:
     case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L50:
     case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L75:
@@ -672,6 +699,8 @@
     case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_10B_SBWC:
         return SBWC_10B_Y_SIZE(width, height) +
             SBWC_10B_Y_HEADER_SIZE(width, height);
+    case MALI_GRALLOC_FORMAT_INTERNAL_NV21:
+        return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 2);
     }
 
     return NV12M_Y_SIZE(width, height) + ((width % 128) == 0 ? 0 : 256);
@@ -696,10 +725,12 @@
     case HAL_PIXEL_FORMAT_YCBCR_P010:
         HDEBUGLOGD(eDebugMPP, "size(CbCr) : %d", P010_CBCR_SIZE(width, height));
         return P010_CBCR_SIZE(width, height);
+    case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN:
+        return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16);
     case HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B:
-        return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 8);
+        return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16);
     case HAL_PIXEL_FORMAT_GOOGLE_NV12_SP:
-        return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 8) / 2;
+        return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16) / 2;
     case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC:
     case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L50:
     case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L75:
@@ -891,7 +922,7 @@
 
     for (const auto& trace : info.traces) {
         FT_LOGD("> dir: %d, type: %d, ip: %d, time:%s", trace.direction, trace.type, trace.ip,
-                getLocalTimeStr(trace.time).string());
+                getLocalTimeStr(trace.time).c_str());
     }
 }
 
@@ -925,7 +956,7 @@
             }
         }
 
-        FT_LOGW("%s", errString.string());
+        FT_LOGW("%s", errString.c_str());
     };
 
     reportLeakFds(+1);
@@ -993,10 +1024,10 @@
 
 String8 getMPPStr(int typeId) {
     if (typeId < MPP_DPP_NUM){
-        int cnt = sizeof(AVAILABLE_OTF_MPP_UNITS)/sizeof(exynos_mpp_t);
+        int cnt = sizeof(available_otf_mpp_units)/sizeof(exynos_mpp_t);
         for (int i = 0; i < cnt; i++){
-            if (AVAILABLE_OTF_MPP_UNITS[i].physicalType == typeId)
-                return String8(AVAILABLE_OTF_MPP_UNITS[i].name);
+            if (available_otf_mpp_units[i].physicalType == typeId)
+                return String8(available_otf_mpp_units[i].name);
         }
     } else {
         int cnt = sizeof(AVAILABLE_M2M_MPP_UNITS)/sizeof(exynos_mpp_t);
diff --git a/libhwc2.1/libhwchelper/ExynosHWCHelper.h b/libhwc2.1/libhwchelper/ExynosHWCHelper.h
index 3262634..87b6163 100644
--- a/libhwc2.1/libhwchelper/ExynosHWCHelper.h
+++ b/libhwc2.1/libhwchelper/ExynosHWCHelper.h
@@ -82,22 +82,35 @@
 };
 
 typedef enum format_type {
-    TYPE_UNDEF      = 0,
+    TYPE_UNDEF       = 0,
 
     /* format */
-    FORMAT_SHIFT    = 0,
-    FORMAT_MASK     = 0x00000fff,
-    RGB             = 0x00000001,
-    YUV420          = 0x00000002,
-    YUV422          = 0x00000004,
-    P010            = 0x00000008,
+    FORMAT_SHIFT     = 0,
+    FORMAT_MASK      = 0x00000fff,
+
+    FORMAT_RGB_MASK  = 0x0000000f,
+    RGB              = 0x00000001,
+
+    FORMAT_YUV_MASK  = 0x000000f0,
+    YUV420           = 0x00000010,
+    YUV422           = 0x00000020,
+    P010             = 0x00000030,
+
+    FORMAT_SBWC_MASK = 0x00000f00,
+    SBWC_LOSSLESS    = 0x00000100,
+    SBWC_LOSSY_40    = 0x00000200,
+    SBWC_LOSSY_50    = 0x00000300,
+    SBWC_LOSSY_60    = 0x00000400,
+    SBWC_LOSSY_75    = 0x00000500,
+    SBWC_LOSSY_80    = 0x00000600,
 
     /* bit */
-    BIT_SHIFT       = 12,
-    BIT_MASK        = 0x000ff000,
-    BIT8            = 0x00001000,
-    BIT10           = 0x00002000,
-    BIT8_2          = 0x00004000,
+    BIT_SHIFT        = 16,
+    BIT_MASK         = 0x000f0000,
+    BIT8             = 0x00010000,
+    BIT10            = 0x00020000,
+    BIT8_2           = 0x00030000,
+    BIT16            = 0x00040000,
 
     /* compression */
     /*
@@ -105,12 +118,12 @@
      * descriptions of format (ex: drmFormat, bufferNum, bpp...)
      * in format_description
      */
-    COMP_SHIFT      = 20,
-    COMP_MASK       = 0x0ff00000,
-    COMP_ANY        = 0x08000000, /* the highest bit */
-    AFBC            = 0x00100000,
-    SBWC            = 0x00200000,
-    SBWC_LOSSY      = 0x00400000,
+    COMP_SHIFT       = 20,
+    COMP_MASK        = 0x0ff00000,
+    COMP_ANY         = 0x08000000, /* the highest bit */
+    AFBC             = 0x00100000,
+    SBWC             = 0x00200000,
+    SBWC_LOSSY       = 0x00400000,
 
 } format_type_t;
 
@@ -190,6 +203,8 @@
         2, 2, 24, YUV420|BIT10|P010, false, String8("EXYNOS_YCbCr_P010_M"), 0},
     {HAL_PIXEL_FORMAT_YCBCR_P010, DECON_PIXEL_FORMAT_NV12_P010, DRM_FORMAT_P010,
         2, 1, 24, YUV420|BIT10|P010, false, String8("EXYNOS_YCbCr_P010"), 0},
+    {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN, DECON_PIXEL_FORMAT_NV12_P010, DRM_FORMAT_P010,
+        2, 1, 24, YUV420|BIT10|P010, false, String8("EXYNOS_YCbCr_P010_SPN"), 0},
 
     {HAL_PIXEL_FORMAT_GOOGLE_NV12_SP, DECON_PIXEL_FORMAT_MAX, DRM_FORMAT_NV12,
         2, 1, 12, YUV420|BIT8, false, String8("GOOGLE_YCbCr_420_SP"), 0},
@@ -199,6 +214,8 @@
         1, 1, 12, YUV420|BIT8|AFBC, false, String8("MALI_GRALLOC_FORMAT_INTERNAL_YUV420_8BIT_I"), 0},
     {MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I, DECON_PIXEL_FORMAT_MAX, DRM_FORMAT_YUV420_10BIT,
         1, 1, 15, YUV420|BIT10|AFBC, false, String8("MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I"), 0},
+    {MALI_GRALLOC_FORMAT_INTERNAL_NV21, DECON_PIXEL_FORMAT_NV21, DRM_FORMAT_NV21,
+        2, 1, 12, YUV420|BIT8, false, String8("MALI_GRALLOC_FORMAT_INTERNAL_NV21"), 0},
 
     /* YUV 422 */
     {HAL_PIXEL_FORMAT_EXYNOS_CbYCrY_422_I, DECON_PIXEL_FORMAT_MAX, DRM_FORMAT_UNDEFINED,
@@ -426,6 +443,8 @@
 bool isFormatLossy(int format);
 bool isFormatSBWC(int format);
 bool isFormatP010(int format);
+bool isFormat10Bit(int format);
+bool isFormat8Bit(int format);
 bool formatHasAlphaChannel(int format);
 unsigned int isNarrowRgb(int format, android_dataspace data_space);
 bool isAFBCCompressed(const buffer_handle_t handle);
diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
index 0b3099d..eb4f0bb 100644
--- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
+++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
@@ -43,7 +43,15 @@
         {{DisplayType::DISPLAY_PRIMARY, "/sys/devices/platform/exynos-drm/primary-panel/"},
          {DisplayType::DISPLAY_SECONDARY, "/sys/devices/platform/exynos-drm/secondary-panel/"}};
 
-static constexpr const char *PROPERTY_BOOT_MODE = "persist.vendor.display.primary.boot_config";
+static String8 getPropertyBootModeStr(const int32_t dispId) {
+    String8 str;
+    if (dispId == 0) {
+        str.appendFormat("persist.vendor.display.primary.boot_config");
+    } else {
+        str.appendFormat("persist.vendor.display.%d.primary.boot_config", dispId);
+    }
+    return str;
+}
 
 static std::string loadPanelGammaCalibration(const std::string &file) {
     std::ifstream ifs(file);
@@ -73,8 +81,9 @@
     return gamma;
 }
 
-ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device)
-      : ExynosDisplay(index, device),
+ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device,
+                                           const std::string &displayName)
+      : ExynosDisplay(HWC_DISPLAY_PRIMARY, index, device, displayName),
         mMinIdleRefreshRate(0),
         mRefreshRateDelayNanos(0),
         mLastRefreshRateAppliedNanos(0),
@@ -85,9 +94,6 @@
     mNumMaxPriorityAllowed = 5;
 
     /* Initialization */
-    mType = HWC_DISPLAY_PRIMARY;
-    mIndex = index;
-    mDisplayId = getDisplayId(mType, mIndex);
     mFramesToReachLhbmPeakBrightness =
             property_get_int32("vendor.primarydisplay.lhbm.frames_to_reach_peak_brightness", 3);
 
@@ -119,7 +125,7 @@
     mResolutionInfo.nPanelType[2] = PANEL_LEGACY;
 
     char value[PROPERTY_VALUE_MAX];
-    const char *earlyWakeupNodeBase = EARLY_WAKUP_NODE_0_BASE;
+    const char *earlyWakeupNodeBase = early_wakeup_node_0_base;
     if (getDisplayTypeFromIndex(mIndex) == DisplayType::DISPLAY_SECONDARY &&
         property_get("vendor.display.secondary_early_wakeup_node", value, "") > 0) {
         earlyWakeupNodeBase = value;
@@ -130,6 +136,8 @@
     mBrightnessController = std::make_unique<BrightnessController>(
             mIndex, [this]() { mDevice->onRefresh(mDisplayId); },
             [this]() { updatePresentColorConversionInfo(); });
+
+    mDisplayControl.multiThreadedPresent = true;
 }
 
 ExynosPrimaryDisplay::~ExynosPrimaryDisplay()
@@ -170,8 +178,9 @@
 }
 
 int32_t ExynosPrimaryDisplay::doDisplayConfigInternal(hwc2_config_t config) {
-    if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON)) {
-        mPendActiveConfig = config;
+    if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) ||
+        !isConfigSettingEnabled()) {
+        mPendingConfig = config;
         mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_DONE;
         DISPLAY_LOGI("%s:: Pending desired Config: %d", __func__, config);
         return NO_ERROR;
@@ -180,8 +189,8 @@
 }
 
 int32_t ExynosPrimaryDisplay::getActiveConfigInternal(hwc2_config_t *outConfig) {
-    if (outConfig && mPendActiveConfig != UINT_MAX) {
-        *outConfig = mPendActiveConfig;
+    if (outConfig && mPendingConfig != UINT_MAX) {
+        *outConfig = mPendingConfig;
         return HWC2_ERROR_NONE;
     }
     return ExynosDisplay::getActiveConfigInternal(outConfig);
@@ -195,19 +204,21 @@
         ALOGI("%s:: Same display config is set", __func__);
         return HWC2_ERROR_NONE;
     }
-    if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON)) {
-        mPendActiveConfig = config;
+    if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) ||
+        !isConfigSettingEnabled()) {
+        mPendingConfig = config;
         return HWC2_ERROR_NONE;
     }
     return ExynosDisplay::setActiveConfigInternal(config, force);
 }
 
 int32_t ExynosPrimaryDisplay::applyPendingConfig() {
-    hwc2_config_t config;
+    if (!isConfigSettingEnabled()) return HWC2_ERROR_NONE;
 
-    if (mPendActiveConfig != UINT_MAX) {
-        config = mPendActiveConfig;
-        mPendActiveConfig = UINT_MAX;
+    hwc2_config_t config;
+    if (mPendingConfig != UINT_MAX) {
+        config = mPendingConfig;
+        mPendingConfig = UINT_MAX;
     } else {
         getActiveConfigInternal(&config);
     }
@@ -237,13 +248,13 @@
 
     ALOGD("%s: mode=%s (%d) vsyncPeriod=%d", __func__, modeStr, config,
             mode.vsyncPeriod);
-    ret = property_set(PROPERTY_BOOT_MODE, modeStr);
+    ret = property_set(getPropertyBootModeStr(mDisplayId).c_str(), modeStr);
 
     return !ret ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_CONFIG;
 }
 
 int32_t ExynosPrimaryDisplay::clearBootDisplayConfig() {
-    auto ret = property_set(PROPERTY_BOOT_MODE, nullptr);
+    auto ret = property_set(getPropertyBootModeStr(mDisplayId).c_str(), nullptr);
 
     ALOGD("%s: clearing boot mode", __func__);
     return !ret ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_CONFIG;
@@ -251,7 +262,7 @@
 
 int32_t ExynosPrimaryDisplay::getPreferredDisplayConfigInternal(int32_t *outConfig) {
     char modeStr[PROPERTY_VALUE_MAX];
-    auto ret = property_get(PROPERTY_BOOT_MODE, modeStr, "");
+    auto ret = property_get(getPropertyBootModeStr(mDisplayId).c_str(), modeStr, "");
 
     if (ret <= 0) {
         return mDisplayInterface->getDefaultModeId(outConfig);
@@ -274,6 +285,10 @@
     updateAppliedActiveConfig(0, 0);
     int ret = NO_ERROR;
     if (mDisplayId != 0 || !mFirstPowerOn) {
+        if (mDevice->hasOtherDisplayOn(this)) {
+            // TODO: This is useful for cmd mode, and b/282094671 tries to handles video mode
+            mDisplayInterface->triggerClearDisplayPlanes();
+        }
         ret = applyPendingConfig();
     }
 
@@ -370,6 +385,9 @@
     } else if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME)) {
         mode = HWC2_POWER_MODE_ON;
         mPauseDisplay = false;
+    } else if (mPauseDisplay) {
+        ALOGI("Skip power mode transition due to pause display.");
+        return HWC2_ERROR_NONE;
     }
 
     if (mPowerModeState.has_value() && (mode == static_cast<int32_t>(mPowerModeState.value()))) {
@@ -385,6 +403,7 @@
     else
         mDREnable = mDRDefault;
 
+    if (mOperationRateManager) mOperationRateManager->onPowerMode(mode);
     switch (mode) {
         case HWC2_POWER_MODE_DOZE_SUSPEND:
         case HWC2_POWER_MODE_DOZE:
@@ -521,130 +540,225 @@
     return mBrightnessController->isLhbmSupported();
 }
 
+bool ExynosPrimaryDisplay::isConfigSettingEnabled() {
+    int64_t msSinceDisabled =
+            (systemTime(SYSTEM_TIME_MONOTONIC) - mConfigSettingDisabledTimestamp) / 1000000;
+    return !mConfigSettingDisabled || msSinceDisabled > kConfigDisablingMaxDurationMs;
+}
+
+void ExynosPrimaryDisplay::enableConfigSetting(bool en) {
+    DISPLAY_ATRACE_INT("ConfigSettingDisabled", !en);
+
+    if (!en) {
+        mConfigSettingDisabled = true;
+        mConfigSettingDisabledTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+        return;
+    }
+
+    mConfigSettingDisabled = false;
+}
+
+int32_t ExynosPrimaryDisplay::setLhbmDisplayConfigLocked(uint32_t peakRate) {
+    auto hwConfig = mDisplayInterface->getActiveModeId();
+    auto config = getConfigId(peakRate, mDisplayConfigs[hwConfig].width,
+                              mDisplayConfigs[hwConfig].height);
+    if (config == UINT_MAX) {
+        DISPLAY_LOGE("%s: failed to get config for rate=%d", __func__, peakRate);
+        return -EINVAL;
+    }
+
+    if (mPendingConfig == UINT_MAX && mActiveConfig != config) mPendingConfig = mActiveConfig;
+    if (config != hwConfig) {
+        if (ExynosDisplay::setActiveConfigInternal(config, true) == HWC2_ERROR_NONE) {
+            DISPLAY_LOGI("%s: succeeded to set config=%d rate=%d", __func__, config, peakRate);
+        } else {
+            DISPLAY_LOGW("%s: failed to set config=%d rate=%d", __func__, config, peakRate);
+        }
+    } else {
+        DISPLAY_LOGI("%s: keep config=%d rate=%d", __func__, config, peakRate);
+    }
+    enableConfigSetting(false);
+    return OK;
+}
+
+void ExynosPrimaryDisplay::restoreLhbmDisplayConfigLocked() {
+    enableConfigSetting(true);
+    hwc2_config_t pendingConfig = mPendingConfig;
+    auto hwConfig = mDisplayInterface->getActiveModeId();
+    if (pendingConfig != UINT_MAX && pendingConfig != hwConfig) {
+        if (applyPendingConfig() == HWC2_ERROR_NONE) {
+            DISPLAY_LOGI("%s: succeeded to set config=%d rate=%d", __func__, pendingConfig,
+                         getRefreshRate(pendingConfig));
+        } else {
+            DISPLAY_LOGE("%s: failed to set config=%d rate=%d", __func__, pendingConfig,
+                         getRefreshRate(pendingConfig));
+        }
+    } else {
+        mPendingConfig = UINT_MAX;
+        DISPLAY_LOGI("%s: keep config=%d rate=%d", __func__, hwConfig, getRefreshRate(hwConfig));
+    }
+}
+
 // This function should be called by other threads (e.g. sensor HAL).
 // HWCService can call this function but it should be for test purpose only.
 int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
+    int ret = OK;
     // NOTE: mLhbmOn could be set to false at any time by setPowerOff in another
     // thread. Make sure no side effect if that happens. Or add lock if we have
     // to when new code is added.
-    ATRACE_CALL();
+    DISPLAY_ATRACE_CALL();
+    DISPLAY_LOGI("%s: enabled=%d", __func__, enabled);
     {
-        ATRACE_NAME("wait for power mode on");
+        ATRACE_NAME("wait_for_power_on");
         std::unique_lock<std::mutex> lock(mPowerModeMutex);
         if (mPowerModeState != HWC2_POWER_MODE_ON) {
             mNotifyPowerOn = true;
             if (!mPowerOnCondition.wait_for(lock, std::chrono::milliseconds(2000), [this]() {
                     return (mPowerModeState == HWC2_POWER_MODE_ON);
                 })) {
-                ALOGW("%s(%d) wait for power mode on timeout !", __func__, enabled);
+                DISPLAY_LOGW("%s: wait for power mode on timeout !", __func__);
                 return TIMED_OUT;
             }
         }
     }
 
-    if (enabled) {
-        ATRACE_NAME("wait for peak refresh rate");
-        std::unique_lock<std::mutex> lock(mPeakRefreshRateMutex);
-        mNotifyPeakRefreshRate = true;
-        if (!mPeakRefreshRateCondition.wait_for(lock,
-                                                std::chrono::milliseconds(
-                                                        kLhbmWaitForPeakRefreshRateMs),
-                                                [this]() { return isCurrentPeakRefreshRate(); })) {
-            ALOGW("setLhbmState(on) wait for peak refresh rate timeout !");
-            return TIMED_OUT;
-        }
-    }
-
-    if (enabled) {
-        setLHBMRefreshRateThrottle(kLhbmRefreshRateThrottleMs);
-    }
-
-    bool wasDisabled =
-            mBrightnessController
-                    ->checkSysfsStatus(BrightnessController::kLocalHbmModeFileNode,
-                                       {std::to_string(static_cast<int>(
-                                               BrightnessController::LhbmMode::DISABLED))},
-                                       0);
+    auto lhbmSysfs = mBrightnessController->GetPanelSysfileByIndex(
+            BrightnessController::kLocalHbmModeFileNode);
+    ret = mBrightnessController->checkSysfsStatus(lhbmSysfs,
+                                         {std::to_string(static_cast<int>(
+                                                 BrightnessController::LhbmMode::DISABLED))},
+                                         0);
+    bool wasDisabled = ret == OK;
     if (!enabled && wasDisabled) {
-        ALOGW("lhbm is at DISABLED state, skip disabling");
+        DISPLAY_LOGW("%s: lhbm is at DISABLED state, skip disabling", __func__);
         return NO_ERROR;
     } else if (enabled && !wasDisabled) {
         requestLhbm(true);
-        ALOGI("lhbm is at ENABLING or ENABLED state, re-enable to reset timeout timer");
+        DISPLAY_LOGI("%s: lhbm is at ENABLING or ENABLED state, re-enable to reset timeout timer",
+                     __func__);
         return NO_ERROR;
     }
 
-    int64_t lhbmEnablingNanos;
-    std::vector<std::string> checkingValue = {
-            std::to_string(static_cast<int>(BrightnessController::LhbmMode::DISABLED))};
-    if (enabled) {
-        checkingValue = {std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLING)),
-                         std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLED))};
-        lhbmEnablingNanos = systemTime(SYSTEM_TIME_MONOTONIC);
-    }
-    requestLhbm(enabled);
-    constexpr uint32_t kSysfsCheckTimeoutMs = 500;
-    ALOGI("setLhbmState =%d", enabled);
-    bool succeed =
-            mBrightnessController->checkSysfsStatus(BrightnessController::kLocalHbmModeFileNode,
-                                                    checkingValue, ms2ns(kSysfsCheckTimeoutMs));
-    if (!succeed) {
-        ALOGE("failed to update lhbm mode");
-        if (enabled) {
-            setLHBMRefreshRateThrottle(0);
+    std::vector<std::string> checkingValue;
+    if (!enabled) {
+        ATRACE_NAME("disable_lhbm");
+        {
+            Mutex::Autolock lock(mDisplayMutex);
+            restoreLhbmDisplayConfigLocked();
         }
-        return -ENODEV;
+        requestLhbm(false);
+        {
+            ATRACE_NAME("wait_for_lhbm_off_cmd");
+            checkingValue = {
+                    std::to_string(static_cast<int>(BrightnessController::LhbmMode::DISABLED))};
+            ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue,
+                                                          ms2ns(kSysfsCheckTimeoutMs));
+            if (ret != OK) {
+                DISPLAY_LOGW("%s: failed to send lhbm-off cmd", __func__);
+            }
+        }
+        setLHBMRefreshRateThrottle(0);
+        mLhbmOn = false;
+        return NO_ERROR;
     }
 
-    if (enabled) {
-        int64_t lhbmEnablingDoneNanos = systemTime(SYSTEM_TIME_MONOTONIC);
-        bool enablingStateSupported = !mFramesToReachLhbmPeakBrightness;
+    ATRACE_NAME("enable_lhbm");
+    int64_t lhbmWaitForRrNanos, lhbmEnablingNanos, lhbmEnablingDoneNanos;
+    bool enablingStateSupported = !mFramesToReachLhbmPeakBrightness;
+    uint32_t peakRate = 0;
+    auto rrSysfs = mBrightnessController->GetPanelRefreshRateSysfile();
+    lhbmWaitForRrNanos = systemTime(SYSTEM_TIME_MONOTONIC);
+    {
+        Mutex::Autolock lock(mDisplayMutex);
+        peakRate = getPeakRefreshRate();
+        if (peakRate < 60) {
+            DISPLAY_LOGE("%s: invalid peak rate=%d", __func__, peakRate);
+            return -EINVAL;
+        }
+        ret = setLhbmDisplayConfigLocked(peakRate);
+        if (ret != OK) return ret;
+    }
+
+    if (mBrightnessController->fileExists(rrSysfs)) {
+        ATRACE_NAME("wait_for_peak_rate_cmd");
+        ret = mBrightnessController->checkSysfsStatus(rrSysfs, {std::to_string(peakRate)},
+                                                      ms2ns(kLhbmWaitForPeakRefreshRateMs));
+        if (ret != OK) {
+            DISPLAY_LOGW("%s: failed to poll peak refresh rate=%d, ret=%d", __func__, peakRate,
+                         ret);
+        }
+    } else {
+        ATRACE_NAME("wait_for_peak_rate_blindly");
+        DISPLAY_LOGW("%s: missing refresh rate path: %s", __func__, rrSysfs.c_str());
+        // blindly wait for (3 full frames + 1 frame uncertainty) to ensure DM finishes
+        // switching refresh rate
+        for (int32_t i = 0; i < 4; i++) {
+            if (mDisplayInterface->waitVBlank()) {
+                DISPLAY_LOGE("%s: failed to blindly wait for peak refresh rate=%d, i=%d", __func__,
+                             peakRate, i);
+                ret = -ENODEV;
+                goto enable_err;
+            }
+        }
+    }
+
+    setLHBMRefreshRateThrottle(kLhbmRefreshRateThrottleMs);
+    checkingValue = {std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLING)),
+                     std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLED))};
+    lhbmEnablingNanos = systemTime(SYSTEM_TIME_MONOTONIC);
+    requestLhbm(true);
+    {
+        ATRACE_NAME("wait_for_lhbm_on_cmd");
+        ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue,
+                                                      ms2ns(kSysfsCheckTimeoutMs));
+        if (ret != OK) {
+            DISPLAY_LOGE("%s: failed to enable lhbm", __func__);
+            setLHBMRefreshRateThrottle(0);
+            goto enable_err;
+        }
+    }
+
+    lhbmEnablingDoneNanos = systemTime(SYSTEM_TIME_MONOTONIC);
+    {
+        ATRACE_NAME("wait_for_peak_brightness");
         if (enablingStateSupported) {
-            ATRACE_NAME("lhbm_wait_peak_brightness");
-            if (!mBrightnessController
-                         ->checkSysfsStatus(BrightnessController::kLocalHbmModeFileNode,
+            ret = mBrightnessController->checkSysfsStatus(lhbmSysfs,
                                             {std::to_string(static_cast<int>(
                                                     BrightnessController::LhbmMode::ENABLED))},
-                                            ms2ns(kSysfsCheckTimeoutMs))) {
-                ALOGE("failed to wait for lhbm becoming effective");
-                return -EIO;
+                                            ms2ns(kSysfsCheckTimeoutMs));
+            if (ret != OK) {
+                DISPLAY_LOGE("%s: failed to wait for lhbm becoming effective", __func__);
+                goto enable_err;
             }
         } else {
             // lhbm takes effect at next vblank
-            ATRACE_NAME("lhbm_wait_apply");
-            if (mDisplayInterface->waitVBlank()) {
-                ALOGE("%s failed to wait vblank for taking effect", __func__);
-                return -ENODEV;
-            }
-            ATRACE_NAME("lhbm_wait_peak_brightness");
-            for (int32_t i = mFramesToReachLhbmPeakBrightness; i > 0; i--) {
-                if (mDisplayInterface->waitVBlank()) {
-                    ALOGE("%s failed to wait vblank for peak brightness, %d", __func__, i);
-                    return -ENODEV;
+            for (int32_t i = mFramesToReachLhbmPeakBrightness + 1; i > 0; i--) {
+                ret = mDisplayInterface->waitVBlank();
+                if (ret) {
+                    DISPLAY_LOGE("%s: failed to wait vblank for peak brightness, %d", __func__, i);
+                    goto enable_err;
                 }
             }
         }
-        ALOGI("lhbm delay mode: %s, latency(ms): total: %d cmd: %d\n",
-              enablingStateSupported ? "poll" : "fixed",
-              static_cast<int>((systemTime(SYSTEM_TIME_MONOTONIC) - lhbmEnablingNanos) / 1000000),
-              static_cast<int>((lhbmEnablingDoneNanos - lhbmEnablingNanos) / 1000000));
-    } else {
-        setLHBMRefreshRateThrottle(0);
-        // lhbm takes effect at next vblank
-        ATRACE_NAME("lhbm_wait_apply");
-        if (mDisplayInterface->waitVBlank()) {
-            ALOGE("%s failed to wait vblank for taking effect", __func__);
-            return -ENODEV;
-        }
     }
+    DISPLAY_LOGI("%s: latency: %04d = %03d|rr@%03d + %03d|en + %03d|boost@%s", __func__,
+                 getTimestampDeltaMs(0, lhbmWaitForRrNanos),
+                 getTimestampDeltaMs(lhbmEnablingNanos, lhbmWaitForRrNanos), peakRate,
+                 getTimestampDeltaMs(lhbmEnablingDoneNanos, lhbmEnablingNanos),
+                 getTimestampDeltaMs(0, lhbmEnablingDoneNanos),
+                 enablingStateSupported ? "polling" : "fixed");
 
-    mLhbmOn = enabled;
+    mLhbmOn = true;
     if (!mPowerModeState.has_value() || (*mPowerModeState == HWC2_POWER_MODE_OFF && mLhbmOn)) {
         mLhbmOn = false;
-        ALOGE("%s power off during request lhbm on", __func__);
+        DISPLAY_LOGE("%s: power off during request lhbm on", __func__);
         return -EINVAL;
     }
     return NO_ERROR;
+enable_err:
+    Mutex::Autolock lock(mDisplayMutex);
+    restoreLhbmDisplayConfigLocked();
+    return ret;
 }
 
 bool ExynosPrimaryDisplay::getLhbmState() {
@@ -657,6 +771,7 @@
     if (delayMs) {
         // make new throttle take effect
         mLastRefreshRateAppliedNanos = systemTime(SYSTEM_TIME_MONOTONIC);
+        DISPLAY_ATRACE_INT64("LastRefreshRateAppliedMs", ns2ms(mLastRefreshRateAppliedNanos));
     }
 
     setRefreshRateThrottleNanos(std::chrono::duration_cast<std::chrono::nanoseconds>(
@@ -864,6 +979,7 @@
 
 int ExynosPrimaryDisplay::setRefreshRateThrottleNanos(const int64_t delayNanos,
                                                       const VrrThrottleRequester requester) {
+    ATRACE_CALL();
     ALOGI("%s() requester(%u) set delay to %" PRId64 "ns", __func__, toUnderlying(requester),
           delayNanos);
     if (delayNanos < 0) {
@@ -881,12 +997,12 @@
         }
     }
 
+    DISPLAY_ATRACE_INT64("RefreshRateDelay", ns2ms(maxDelayNanos));
     if (mRefreshRateDelayNanos == maxDelayNanos) {
         return NO_ERROR;
     }
 
     mRefreshRateDelayNanos = maxDelayNanos;
-
     return setDisplayIdleDelayNanos(mRefreshRateDelayNanos, DispIdleTimerRequester::VRR_THROTTLE);
 }
 
@@ -902,12 +1018,16 @@
     for (uint32_t i = 0; i < toUnderlying(VrrThrottleRequester::MAX); i++) {
         result.appendFormat("\t[%u] vote to %" PRId64 " ns\n", i, mVrrThrottleNanos[i]);
     }
+    if (mOperationRateManager) {
+        result.appendFormat("Operation rate: %d\n", mOperationRateManager->getOperationRate());
+    }
     result.appendFormat("\n");
 }
 
 void ExynosPrimaryDisplay::calculateTimeline(
         hwc2_config_t config, hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
         hwc_vsync_period_change_timeline_t *outTimeline) {
+    ATRACE_CALL();
     int64_t desiredUpdateTime = vsyncPeriodChangeConstraints->desiredTimeNanos;
     const int64_t origDesiredUpdateTime = desiredUpdateTime;
     const int64_t threshold = mRefreshRateDelayNanos;
@@ -935,31 +1055,30 @@
     getConfigAppliedTime(mVsyncPeriodChangeConstraints.desiredTimeNanos, actualChangeTime,
                          outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos);
 
-    if (isDelayed) {
-        DISPLAY_LOGD(eDebugDisplayConfig,
-                     "requested config : %d(%d)->%d(%d) is delayed! "
-                     "delta %" PRId64 ", delay %" PRId64 ", threshold %" PRId64 ", "
-                     "desired %" PRId64 "->%" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64
-                     ", refreshTimeNanos:%" PRId64,
-                     mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config,
-                     mDisplayConfigs[config].vsyncPeriod, lastUpdateDelta,
-                     threshold - lastUpdateDelta, threshold, origDesiredUpdateTime,
-                     mVsyncPeriodChangeConstraints.desiredTimeNanos,
-                     outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos);
-    } else {
-        DISPLAY_LOGD(eDebugDisplayConfig,
-                     "requested config : %d(%d)->%d(%d), "
-                     "lastUpdateDelta %" PRId64 ", threshold %" PRId64 ", "
-                     "desired %" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64 "",
-                     mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config,
-                     mDisplayConfigs[config].vsyncPeriod, lastUpdateDelta, threshold,
-                     mVsyncPeriodChangeConstraints.desiredTimeNanos,
-                     outTimeline->newVsyncAppliedTimeNanos);
-    }
+    const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    DISPLAY_LOGD_AND_ATRACE_NAME(eDebugDisplayConfig,
+                                 "requested config : %d(%d)->%d(%d), isDelay:%d,"
+                                 " delta %" PRId64 ", delay %" PRId64 ", threshold %" PRId64 ", "
+                                 "now:%" PRId64 ", desired %" PRId64 "->%" PRId64
+                                 ", newVsyncAppliedTimeNanos : %" PRId64
+                                 ", refreshTimeNanos:%" PRId64
+                                 ", mLastRefreshRateAppliedNanos:%" PRId64,
+                                 mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config,
+                                 mDisplayConfigs[config].vsyncPeriod, isDelayed,
+                                 ns2ms(lastUpdateDelta), ns2ms(threshold - lastUpdateDelta),
+                                 ns2ms(threshold), ns2ms(now), ns2ms(origDesiredUpdateTime),
+                                 ns2ms(mVsyncPeriodChangeConstraints.desiredTimeNanos),
+                                 ns2ms(outTimeline->newVsyncAppliedTimeNanos),
+                                 ns2ms(outTimeline->refreshTimeNanos),
+                                 ns2ms(mLastRefreshRateAppliedNanos));
+
+    const int64_t diffMs = ns2ms(outTimeline->refreshTimeNanos - now);
+    DISPLAY_ATRACE_INT64("TimeToChangeConfig", diffMs);
 }
 
 void ExynosPrimaryDisplay::updateAppliedActiveConfig(const hwc2_config_t newConfig,
                                                      const int64_t ts) {
+    ATRACE_CALL();
     if (mAppliedActiveConfig == 0 ||
         getDisplayVsyncPeriodFromConfig(mAppliedActiveConfig) !=
                 getDisplayVsyncPeriodFromConfig(newConfig)) {
@@ -968,6 +1087,7 @@
                      " -> %" PRIu64 ")",
                      __func__, mAppliedActiveConfig, newConfig, mLastRefreshRateAppliedNanos, ts);
         mLastRefreshRateAppliedNanos = ts;
+        DISPLAY_ATRACE_INT64("LastRefreshRateAppliedMs", ns2ms(mLastRefreshRateAppliedNanos));
     }
 
     mAppliedActiveConfig = newConfig;
@@ -978,6 +1098,7 @@
     ATRACE_CALL();
     uint32_t refreshRate = static_cast<uint32_t>(round(nsecsPerSec / vsyncPeriod * 0.1f) * 10);
 
+    Mutex::Autolock lock(mDRMutex);
     if (vsyncPeriod < btsVsyncPeriod) {
         for (size_t i = 0; i < mLayers.size(); i++) {
             if (mLayers[i]->mOtfMPP && mLayers[i]->mM2mMPP == nullptr &&
diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
index e66bb2a..323eb5a 100644
--- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
+++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
@@ -25,7 +25,7 @@
 class ExynosPrimaryDisplay : public ExynosDisplay {
     public:
         /* Methods */
-        ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device);
+        ExynosPrimaryDisplay(uint32_t index, ExynosDevice* device, const std::string& displayName);
         ~ExynosPrimaryDisplay();
         virtual void setDDIScalerEnable(int width, int height);
         virtual int getDDIScalerMode(int width, int height);
@@ -64,6 +64,8 @@
         virtual int32_t setBootDisplayConfig(int32_t config) override;
         virtual int32_t clearBootDisplayConfig() override;
         virtual int32_t getPreferredDisplayConfigInternal(int32_t* outConfig) override;
+        virtual bool isConfigSettingEnabled() override;
+        virtual void enableConfigSetting(bool en) override;
 
     protected:
         /* setPowerMode(int32_t mode)
@@ -88,6 +90,8 @@
         ResolutionInfo mResolutionInfo;
         std::string getPanelSysfsPath(const displaycolor::DisplayType& type);
 
+        uint32_t mRcdId = -1;
+
     private:
         static constexpr const char* kDisplayCalFilePath = "/mnt/vendor/persist/display/";
         static constexpr const char* kPanelGammaCalFilePrefix = "gamma_calib_data";
@@ -96,7 +100,6 @@
         bool checkLhbmMode(bool status, nsecs_t timoutNs);
         void setLHBMRefreshRateThrottle(const uint32_t delayMs);
 
-        hwc2_config_t mPendActiveConfig = UINT_MAX;
         bool mFirstPowerOn = true;
         bool mNotifyPowerOn = false;
         std::mutex mPowerModeMutex;
@@ -113,14 +116,25 @@
         int32_t setDisplayIdleDelayNanos(int32_t delayNanos,
                                          const DispIdleTimerRequester requester);
         void initDisplayHandleIdleExit();
+        int32_t setLhbmDisplayConfigLocked(uint32_t peakRate);
+        void restoreLhbmDisplayConfigLocked();
 
         // LHBM
         FILE* mLhbmFd;
         std::atomic<bool> mLhbmOn;
         int32_t mFramesToReachLhbmPeakBrightness;
+        bool mConfigSettingDisabled = false;
+        int64_t mConfigSettingDisabledTimestamp = 0;
         // timeout value of waiting for peak refresh rate
-        static constexpr uint32_t kLhbmWaitForPeakRefreshRateMs = 200;
-        static constexpr uint32_t kLhbmRefreshRateThrottleMs = 1000;
+        static constexpr uint32_t kLhbmWaitForPeakRefreshRateMs = 100U;
+        static constexpr uint32_t kLhbmRefreshRateThrottleMs = 1000U;
+        static constexpr uint32_t kConfigDisablingMaxDurationMs = 1000U;
+        static constexpr uint32_t kSysfsCheckTimeoutMs = 500U;
+
+        int32_t getTimestampDeltaMs(int64_t endNs, int64_t beginNs) {
+            if (endNs == 0) endNs = systemTime(SYSTEM_TIME_MONOTONIC);
+            return (endNs - beginNs) / 1000000;
+        }
 
         FILE* mEarlyWakeupDispFd;
         static constexpr const char* kWakeupDispFilePath =
diff --git a/libhwc2.1/libresource/ExynosMPP.cpp b/libhwc2.1/libresource/ExynosMPP.cpp
index 740cec7..fae248a 100644
--- a/libhwc2.1/libresource/ExynosMPP.cpp
+++ b/libhwc2.1/libresource/ExynosMPP.cpp
@@ -43,13 +43,11 @@
 
 using namespace android;
 using namespace vendor::graphics;
+using namespace SOC_VERSION;
 
 int ExynosMPP::mainDisplayWidth = 0;
 int ExynosMPP::mainDisplayHeight = 0;
 extern struct exynos_hwc_control exynosHWCControl;
-#ifndef USE_MODULE_ATTR
-extern feature_support_t feature_table[];
-#endif
 
 void dumpExynosMPPImgInfo(uint32_t type, exynos_mpp_img_info &imgInfo)
 {
@@ -100,6 +98,8 @@
     memset(&mMidImg, 0, sizeof(mMidImg));
     mMidImg.acquireFenceFd = -1;
     mMidImg.releaseFenceFd = -1;
+
+    mHWResourceAmount.clear();
 }
 
 ExynosMPPSource::ExynosMPPSource(uint32_t sourceType, void *source)
@@ -130,6 +130,40 @@
     mMidImg = mid_img;
 }
 
+uint32_t ExynosMPPSource::needHWResource(tdm_attr_t attr) {
+    uint32_t ret = 0;
+
+    switch (attr) {
+        case TDM_ATTR_SBWC:
+            ret = (isFormatSBWC(mSrcImg.format)) ? 1 : 0;
+            break;
+        case TDM_ATTR_AFBC:
+            ret = (mSrcImg.compressed == 1) ? 1 : 0;
+            break;
+        case TDM_ATTR_ITP: // CSC
+            ret = (isFormatYUV(mSrcImg.format)) ? 1 : 0;
+            break;
+        case TDM_ATTR_ROT_90:
+            ret = ((mSrcImg.transform & HAL_TRANSFORM_ROT_90) == 0) ? 0 : 1;
+            break;
+        case TDM_ATTR_SCALE:
+            {
+                bool isPerpendicular = !!(mSrcImg.transform & HAL_TRANSFORM_ROT_90);
+                if (isPerpendicular) {
+                    ret = ((mSrcImg.w != mDstImg.h) || (mSrcImg.h != mDstImg.w)) ? 1 : 0;
+                } else {
+                    ret = ((mSrcImg.w != mDstImg.w) || (mSrcImg.h != mDstImg.h)) ? 1 : 0;
+                }
+            }
+            break;
+        default:
+            ret = 0;
+            break;
+    }
+
+    return ret;
+}
+
 ExynosMPP::ExynosMPP(ExynosResourceManager* resourceManager,
         uint32_t physicalType, uint32_t logicalType, const char *name,
         uint32_t physicalIndex, uint32_t logicalIndex, uint32_t preAssignInfo)
@@ -162,6 +196,9 @@
     mDstAllocatedSize(DST_SIZE_UNKNOWN),
     mUseM2MSrcFence(false),
     mAttr(0),
+    mAssignOrder(0),
+    mAXIPortId(0),
+    mHWBlockId(0),
     mNeedSolidColorLayer(false)
 {
     if (mPhysicalType < MPP_DPP_NUM) {
@@ -314,7 +351,7 @@
     return checkCSCRestriction(src, dst);
 }
 
-bool ExynosMPP::isSupportedHDR10Plus(struct exynos_image &src, struct exynos_image &dst)
+bool ExynosMPP::isSupportedHDR(struct exynos_image &src, struct exynos_image &dst)
 {
 
     uint32_t srcStandard = (src.dataSpace & HAL_DATASPACE_STANDARD_MASK);
@@ -322,7 +359,7 @@
     uint32_t srcTransfer = (src.dataSpace & HAL_DATASPACE_TRANSFER_MASK);
     uint32_t dstTransfer = (dst.dataSpace & HAL_DATASPACE_TRANSFER_MASK);
 
-    if (hasHdr10Plus(src)) {
+    if (hasHdr10Plus(src) || hasHdrInfo(src) ) {
         if (mAttr & MPP_ATTR_HDR10PLUS)
             return true;
         else if ((srcStandard == dstStandard) && (srcTransfer == dstTransfer))
@@ -807,7 +844,7 @@
     if (mExynosMPP == NULL)
         return false;
 
-    ALOGI("%s threadLoop is started", mExynosMPP->mName.string());
+    ALOGI("%s threadLoop is started", mExynosMPP->mName.c_str());
     while(mRunning) {
         Mutex::Autolock lock(mMutex);
         while((mFreedBuffers.size() == 0) &&
@@ -824,7 +861,7 @@
             if ((mStateFences.size() != 0) &&
                     (mExynosMPP->mHWState != MPP_HW_STATE_RUNNING)) {
                 ALOGW("%s, mHWState(%d) but mStateFences size(%zu)",
-                        mExynosMPP->mName.string(), mExynosMPP->mHWState,
+                        mExynosMPP->mName.c_str(), mExynosMPP->mHWState,
                         mStateFences.size());
                 checkStateFences();
             }
@@ -852,14 +889,14 @@
         dumpExynosMPPImgInfo(eDebugMPP|eDebugFence|eDebugBuf, freeBuffer);
         if (fence_valid(freeBuffer.acrylicAcquireFenceFd)) {
             if (sync_wait(freeBuffer.acrylicAcquireFenceFd, 1000) < 0)
-                HWC_LOGE(NULL, "%s:: acquire fence sync_wait error", mExynosMPP->mName.string());
+                HWC_LOGE(NULL, "%s:: acquire fence sync_wait error", mExynosMPP->mName.c_str());
             freeBuffer.acrylicAcquireFenceFd =
                 fence_close(freeBuffer.acrylicAcquireFenceFd, mExynosMPP->mAssignedDisplay,
                         FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_ALL);
         }
         if (fence_valid(freeBuffer.acrylicReleaseFenceFd)) {
             if (sync_wait(freeBuffer.acrylicReleaseFenceFd, 1000) < 0)
-                HWC_LOGE(NULL, "%s:: release fence sync_wait error", mExynosMPP->mName.string());
+                HWC_LOGE(NULL, "%s:: release fence sync_wait error", mExynosMPP->mName.c_str());
             freeBuffer.acrylicReleaseFenceFd =
                 fence_close(freeBuffer.acrylicReleaseFenceFd, mExynosMPP->mAssignedDisplay,
                         FENCE_TYPE_SRC_RELEASE, FENCE_IP_ALL);
@@ -885,7 +922,7 @@
         if (fence_valid(fence)) {
             if (sync_wait(fence, 5000) < 0) {
                 HWC_LOGE(NULL, "%s::[%s][%d] sync_wait(%d) error(%s)", __func__,
-                        mExynosMPP->mName.string(), mExynosMPP->mLogicalIndex, fence, strerror(errno));
+                        mExynosMPP->mName.c_str(), mExynosMPP->mLogicalIndex, fence, strerror(errno));
                 ret = false;
             }
             fence = fence_close(fence, mExynosMPP->mAssignedDisplay,
@@ -964,9 +1001,10 @@
     mDstImgs[index].format = format;
 
     MPP_LOGD(eDebugMPP|eDebugBuf, "free outbuf[%d] %p", index, freeDstBuf.bufferHandle);
-    if (freeDstBuf.bufferHandle != NULL)
+
+    if (freeDstBuf.bufferHandle != NULL) {
         freeOutBuf(freeDstBuf);
-    else {
+    } else {
         if (mAssignedDisplay != NULL) {
             freeDstBuf.acrylicAcquireFenceFd = fence_close(freeDstBuf.acrylicAcquireFenceFd,
                     mAssignedDisplay, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_G2D);
@@ -1081,16 +1119,23 @@
 
     VendorGraphicBufferMeta gmeta(dst_handle);
 
+    uint32_t prevAssignedBufferNum =
+            getBufferNumOfFormat(gmeta.format, getCompressionType(dst_handle));
+    uint32_t assignedBufferNum = getBufferNumOfFormat(dst.format, getCompressionType(dst_handle));
+
     MPP_LOGD(eDebugMPP | eDebugBuf, "\tdst_handle(%p) afbc (%u) sbwc (%u) lossy (%u)", dst_handle,
              isAFBCCompressed(dst_handle), isFormatSBWC(gmeta.format), isFormatLossy(gmeta.format));
     MPP_LOGD(eDebugMPP | eDebugBuf,
-             "\tAssignedDisplay[%d, %d] format[0x%8x, 0x%8x], bufferType[%d, %d], usageFlags: "
-             "0x%" PRIx64 ", need afbc %u sbwc %u lossy %u",
+             "\tAssignedDisplay[%d, %d] format[0x%8x, 0x%8x], bufferType[%d, %d], bufferNum[%d, "
+             "%d] "
+             "usageFlags: 0x%" PRIx64 ", need afbc %u sbwc %u lossy %u",
              mPrevAssignedDisplayType, assignedDisplay, gmeta.format, dst.format,
-             mDstImgs[index].bufferType, getBufferType(dst.usageFlags), dst.usageFlags,
-             dst.compressed, isFormatSBWC(dst.format), isFormatLossy(dst.format));
+             mDstImgs[index].bufferType, getBufferType(dst.usageFlags), prevAssignedBufferNum,
+             assignedBufferNum, dst.usageFlags, dst.compressed, isFormatSBWC(dst.format),
+             isFormatLossy(dst.format));
 
     bool realloc = (mPrevAssignedDisplayType != assignedDisplay) ||
+            (prevAssignedBufferNum < assignedBufferNum) ||
             (formatToBpp(gmeta.format) < formatToBpp(dst.format)) ||
             ((gmeta.stride * gmeta.vstride) < (int)(dst.fullWidth * dst.fullHeight)) ||
             (mDstImgs[index].bufferType != getBufferType(dst.usageFlags)) ||
@@ -1355,9 +1400,10 @@
     if (dstImgInfo->bufferType == MPP_BUFFER_SECURE_DRM)
         attribute |= AcrylicCanvas::ATTR_PROTECTED;
 
-    if (mAssignedDisplay != NULL)
+    if (mAssignedDisplay != NULL) {
         mAcrylicHandle->setCanvasDimension(pixel_align(mAssignedDisplay->mXres, G2D_JUSTIFIED_DST_ALIGN),
                 pixel_align(mAssignedDisplay->mYres, G2D_JUSTIFIED_DST_ALIGN));
+    }
 
     /* setup dst */
     if (needCompressDstBuf()) {
@@ -1879,13 +1925,15 @@
         return NO_ERROR;
     }
 
-    if (state == MPP_HW_STATE_RUNNING)
+    if (state == MPP_HW_STATE_RUNNING) {
         mHWState = MPP_HW_STATE_RUNNING;
-    else if (state == MPP_HW_STATE_IDLE) {
-        if (mLastStateFenceFd >= 0)
+    } else if (state == MPP_HW_STATE_IDLE) {
+        if (mLastStateFenceFd >= 0) {
             mResourceManageThread->addStateFence(mLastStateFenceFd);
-        else
+        } else {
             mHWState = MPP_HW_STATE_IDLE;
+        }
+
         mLastStateFenceFd = -1;
 
         if ((mPhysicalType == MPP_G2D) && (mHWBusyFlag == false)) {
@@ -2056,7 +2104,7 @@
         return -eMPPUnsupportedFormat;
     else if (!isDataspaceSupportedByMPP(src, dst))
         return -eMPPUnsupportedCSC;
-    else if (!isSupportedHDR10Plus(src, dst))
+    else if (!isSupportedHDR(src, dst))
         return -eMPPUnsupportedDynamicMeta;
     else if (!isSupportedBlend(src))
         return -eMPPUnsupportedBlending;
@@ -2320,41 +2368,50 @@
             isAssignable, mAssignedSources.size(), getSrcMaxBlendingNum(src, dst));
     return isAssignable;
 }
-bool ExynosMPP::isAssignable(ExynosDisplay *display,
-        struct exynos_image &src, struct exynos_image &dst)
+
+bool ExynosMPP::isAssignable(ExynosDisplay *display, struct exynos_image &src,
+                             struct exynos_image &dst, float totalUsedCapacity)
 {
     bool isAssignable = isAssignableState(display, src, dst);
-    return (isAssignable && hasEnoughCapa(display, src, dst));
+    return (isAssignable && hasEnoughCapa(display, src, dst, totalUsedCapacity));
 }
 
-bool ExynosMPP::hasEnoughCapa(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst)
+bool ExynosMPP::hasEnoughCapa(ExynosDisplay *display, struct exynos_image &src,
+                              struct exynos_image &dst, float totalUsedCapacity)
 {
     if (mCapacity == -1)
         return true;
 
-    float totalUsedCapacity = ExynosResourceManager::getResourceUsedCapa(*this);
-    MPP_LOGD(eDebugCapacity|eDebugMPP, "totalUsedCapacity(%f), mUsedCapacity(%f)",
-            totalUsedCapacity, mUsedCapacity);
+    MPP_LOGD(eDebugCapacity | eDebugMPP, "totalUsedCapacity(%f), mUsedCapacity(%f)",
+             totalUsedCapacity, mUsedCapacity);
 
     /* mUsedCapacity should be re-calculated including src, dst passed as parameters*/
     totalUsedCapacity -= mUsedCapacity;
 
     float requiredCapacity = getRequiredCapacity(display, src, dst);
 
-    MPP_LOGD(eDebugCapacity|eDebugMPP, "mCapacity(%f), usedCapacity(%f), RequiredCapacity(%f)",
-            mCapacity, totalUsedCapacity, requiredCapacity);
+    MPP_LOGD(eDebugCapacity | eDebugMPP, "mCapacity(%f), usedCapacity(%f), RequiredCapacity(%f)",
+             mCapacity, totalUsedCapacity, requiredCapacity);
 
     if (mCapacity >= (totalUsedCapacity + requiredCapacity))
         return true;
-    else if ((hasHdrInfo(src)) &&
-             (totalUsedCapacity == 0) && (requiredCapacity < (mCapacity * 1.2))) {
-        /* HDR video will be excepted from G2D capa calculation */
-        /* if DRM has assigned before, totalUsedCapacity will be non-zero */
+    else if (isCapacityExceptionCondition(totalUsedCapacity, requiredCapacity, src))
         return true;
-    } else
+    else
         return false;
 }
 
+bool ExynosMPP::isCapacityExceptionCondition(float totalUsedCapacity, float requiredCapacity,
+                                             struct exynos_image &src)
+{
+    if ((hasHdrInfo(src) && (totalUsedCapacity == 0) &&
+         (requiredCapacity < (mCapacity * MPP_HDR_MARGIN)))) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
 void ExynosMPP::getPPCIndex(const struct exynos_image &src,
         const struct exynos_image &dst,
         uint32_t &formatIndex, uint32_t &rotIndex, uint32_t &scaleIndex,
@@ -2855,7 +2912,7 @@
         assignedDisplayType = mAssignedDisplay->mType;
 
     result.appendFormat("%s: types mppType(%d), (p:%d, l:0x%2x), indexs(p:%d, l:%d), preAssignDisplay(0x%2x)\n",
-            mName.string(), mMPPType, mPhysicalType, mLogicalType, mPhysicalIndex, mLogicalIndex, mPreAssignDisplayInfo);
+            mName.c_str(), mMPPType, mPhysicalType, mLogicalType, mPhysicalIndex, mLogicalIndex, mPreAssignDisplayInfo);
     result.appendFormat("\tEnable: %d, HWState: %d, AssignedState: %d, assignedDisplay(%d)\n",
             mEnable, mHWState, mAssignedState, assignedDisplayType);
     result.appendFormat("\tPrevAssignedState: %d, PrevAssignedDisplayType: %d, ReservedDisplay: %d\n",
diff --git a/libhwc2.1/libresource/ExynosMPP.h b/libhwc2.1/libresource/ExynosMPP.h
index dd9bfd7..715c9dc 100644
--- a/libhwc2.1/libresource/ExynosMPP.h
+++ b/libhwc2.1/libresource/ExynosMPP.h
@@ -113,6 +113,11 @@
 #ifndef MPP_G2D_CAPACITY
 #define MPP_G2D_CAPACITY    8
 #endif
+// G2D or MSC additional margin capacity when HDR layer is passed.
+#ifndef MPP_HDR_MARGIN
+#define MPP_HDR_MARGIN 1.2
+#endif
+
 #ifndef MPP_MSC_CAPACITY
 #define MPP_MSC_CAPACITY    8
 #endif
@@ -167,6 +172,7 @@
     eMPPUnsupportedDRM            =     1ULL << 31,
     eMPPUnsupportedDynamicMeta    =     1ULL << 32,
     eMPPSatisfiedRestriction      =     1ULL << 33,
+    eMPPExeedHWResource           =     1ULL << 34,
 };
 
 enum {
@@ -220,11 +226,13 @@
 #ifndef DEFAULT_MPP_DST_FORMAT
 #define DEFAULT_MPP_DST_FORMAT HAL_PIXEL_FORMAT_RGBA_8888
 #endif
+
+/* TODO: Switch back to single-fd format, tracked in b/261356480 */
 #ifndef DEFAULT_MPP_DST_YUV_FORMAT
-#define DEFAULT_MPP_DST_YUV_FORMAT HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN
+#define DEFAULT_MPP_DST_YUV_FORMAT HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M
 #endif
 #ifndef DEFAULT_MPP_DST_UNCOMP_YUV_FORMAT
-#define DEFAULT_MPP_DST_UNCOMP_YUV_FORMAT HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN
+#define DEFAULT_MPP_DST_UNCOMP_YUV_FORMAT HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M
 #endif
 
 typedef struct exynos_mpp_img_info {
@@ -454,7 +462,22 @@
 
         ExynosMPP *mOtfMPP;
         ExynosMPP *mM2mMPP;
+
+        /**
+         * SRAM/HW resource info
+         */
+        std::unordered_map<tdm_attr_t, int32_t> mHWResourceAmount;
+        uint32_t getHWResourceAmount(tdm_attr_t attr) { return mHWResourceAmount[attr]; }
+
+        uint32_t setHWResourceAmount(tdm_attr_t attr, uint32_t amount) {
+            mHWResourceAmount[attr] = amount;
+            return 0;
+        }
+
+        /* return 1 if it's needed */
+        uint32_t needHWResource(tdm_attr_t attr);
 };
+
 bool exynosMPPSourceComp(const ExynosMPPSource* l, const ExynosMPPSource* r);
 void dump(const restriction_size_t &restrictionSize, String8 &result);
 
@@ -547,6 +570,10 @@
     /* MPP's attribute bit (supported feature bit) */
     uint64_t    mAttr;
 
+    uint32_t mAssignOrder;
+    uint32_t mAXIPortId;
+    uint32_t mHWBlockId;
+
     bool mNeedSolidColorLayer;
 
     ExynosMPP(ExynosResourceManager* resourceManager,
@@ -570,7 +597,7 @@
     virtual int64_t isSupported(ExynosDisplay &display, struct exynos_image &src, struct exynos_image &dst);
 
     bool isDataspaceSupportedByMPP(struct exynos_image &src, struct exynos_image &dst);
-    bool isSupportedHDR10Plus(struct exynos_image &src, struct exynos_image &dst);
+    bool isSupportedHDR(struct exynos_image &src, struct exynos_image &dst);
     bool isSupportedBlend(struct exynos_image &src);
     virtual bool isSupportedTransform(struct exynos_image &src);
     bool isSupportedCapability(ExynosDisplay &display, struct exynos_image &src);
@@ -639,11 +666,12 @@
     int32_t reserveMPP(int32_t displayType = -1);
 
     bool isAssignableState(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst);
-    bool isAssignable(ExynosDisplay *display,
-            struct exynos_image &src, struct exynos_image &dst);
+    bool isAssignable(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst,
+                      float totalUsedCapacity);
     int32_t assignMPP(ExynosDisplay *display, ExynosMPPSource* mppSource);
 
-    bool hasEnoughCapa(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst);
+    bool hasEnoughCapa(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst,
+                       float totalUsedCapa);
     float getRequiredCapacity(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst);
     int32_t updateUsedCapacity();
     void resetUsedCapacity();
@@ -671,6 +699,13 @@
     void setPPC(float ppc) { mPPC = ppc; };
     void setClockKhz(uint32_t clock) { mClockKhz = clock; };
 
+    virtual void initTDMInfo(uint32_t hwBlockIndex, uint32_t axiPortIndex) {
+        mHWBlockId = hwBlockIndex;
+        mAXIPortId = axiPortIndex;
+    }
+    virtual uint32_t getHWBlockId() { return mHWBlockId; }
+    virtual uint32_t getAXIPortId() { return mAXIPortId; }
+
 protected:
     uint32_t getBufferType(uint64_t usage);
     uint32_t getBufferType(const buffer_handle_t handle);
@@ -711,6 +746,12 @@
      */
     virtual bool checkCSCRestriction(struct exynos_image &src, struct exynos_image &dst);
 
+    /*
+     * Check additional conditions those have a capacity exception.
+     */
+    virtual bool isCapacityExceptionCondition(float totalUsedCapacity, float requiredCapacity,
+                                              struct exynos_image &src);
+
     uint32_t mClockKhz = 0;
     float mPPC = 0;
 };
diff --git a/libhwc2.1/libresource/ExynosMPPType.h b/libhwc2.1/libresource/ExynosMPPType.h
index a4b3026..83477c9 100644
--- a/libhwc2.1/libresource/ExynosMPPType.h
+++ b/libhwc2.1/libresource/ExynosMPPType.h
@@ -18,8 +18,14 @@
 #define _EXYNOSMPPTYPE_H
 
 #include <system/graphics.h>
+#include <utils/String8.h>
+
+#include <unordered_map>
+
 #include "DeconHeader.h"
 
+using namespace android;
+
 /*
  * physical types
  * Resources are sorted by physical type.
@@ -28,16 +34,15 @@
 typedef enum {
     MPP_DPP_G = 0,
     MPP_DPP_GF,
+    MPP_DPP_GFS,
     MPP_DPP_VG,
     MPP_DPP_VGS,
     MPP_DPP_VGF,
     MPP_DPP_VGFS,
     MPP_DPP_VGRFS,
-    /* DPP count */
-    /* If you add DPP, You should increase this value */
-    MPP_DPP_NUM = 7,
+    MPP_DPP_NUM,
 
-    MPP_MSC = 7,
+    MPP_MSC,
     MPP_G2D,
     MPP_P_TYPE_MAX
 } mpp_phycal_type_t;
@@ -46,6 +51,7 @@
 typedef enum {
     MPP_LOGICAL_DPP_G = 0x01,
     MPP_LOGICAL_DPP_GF = 0x02,
+    MPP_LOGICAL_DPP_GFS = 0x03,
     MPP_LOGICAL_DPP_VG = 0x04,
     MPP_LOGICAL_DPP_VGS = 0x08,
     MPP_LOGICAL_DPP_VGF = 0x10,
@@ -60,7 +66,7 @@
      * Increase MPP_LOGICAL_TYPE_NUM
      * if type is added
      */
-    MPP_LOGICAL_TYPE_NUM = 12
+    MPP_LOGICAL_TYPE_NUM = 13
 } mpp_logical_type_t;
 
 enum {
@@ -81,6 +87,28 @@
     MPP_ATTR_HDR10PLUS              = 0x10000000,
 };
 
+// Resource TDM (Time-Division Muliplexing)
+typedef enum {
+    TDM_ATTR_SRAM_AMOUNT,
+    TDM_ATTR_AFBC,
+    TDM_ATTR_SBWC,
+    TDM_ATTR_ITP, // CSC //
+    TDM_ATTR_ROT_90,
+    TDM_ATTR_SCALE,
+    TDM_ATTR_WCG,
+    TDM_ATTR_MAX,
+} tdm_attr_t;
+
+const std::unordered_map<tdm_attr_t, String8> HWAttrs = {
+    {TDM_ATTR_SRAM_AMOUNT, String8("SRAM")},
+    {TDM_ATTR_AFBC,        String8("AFBC")},
+    {TDM_ATTR_SBWC,        String8("SBWC")},
+    {TDM_ATTR_ITP,         String8("CSC")}, // CSC //
+    {TDM_ATTR_ROT_90,      String8("ROT")},
+    {TDM_ATTR_SCALE,       String8("SCALE")},
+    {TDM_ATTR_WCG,         String8("WCG")},
+};
+
 typedef struct feature_support_t {
     mpp_phycal_type_t hwType; /* MPP_DPP_VG, MPP_DPP_VGFS, ... */
     uint64_t attr;
@@ -110,4 +138,19 @@
     decon_idma_type channel;
 } dpp_channel_map_t;
 
+/*
+ * pre_assign_info: all display_descriptors that want to reserve
+ */
+struct exynos_mpp_t {
+    int physicalType;
+    int logicalType;
+    char name[16];
+    uint32_t physical_index;
+    uint32_t logical_index;
+    uint32_t pre_assign_info;
+    // For TDM
+    uint32_t hw_block_index;
+    uint32_t axi_port_index;
+};
+
 #endif
diff --git a/libhwc2.1/libresource/ExynosResourceManager.cpp b/libhwc2.1/libresource/ExynosResourceManager.cpp
index ba30526..5e78eff 100644
--- a/libhwc2.1/libresource/ExynosResourceManager.cpp
+++ b/libhwc2.1/libresource/ExynosResourceManager.cpp
@@ -38,51 +38,6 @@
 using namespace std::chrono_literals;
 constexpr float msecsPerSec = std::chrono::milliseconds(1s).count();
 
-#ifndef USE_MODULE_ATTR
-/* Basic supported features */
-feature_support_t feature_table[] =
-{
-    {MPP_DPP_G,
-        MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM
-    },
-
-    {MPP_DPP_GF,
-        MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM
-    },
-
-    {MPP_DPP_VG,
-        MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM
-    },
-
-    {MPP_DPP_VGS,
-        MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE | MPP_ATTR_DIM
-    },
-
-    {MPP_DPP_VGF,
-        MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM
-    },
-
-    {MPP_DPP_VGFS,
-        MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE | MPP_ATTR_DIM
-    },
-
-    {MPP_DPP_VGRFS,
-        MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE |
-        MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90 |
-        MPP_ATTR_DIM | MPP_ATTR_HDR10
-    },
-
-    {MPP_MSC,
-        MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90
-    },
-
-    {MPP_G2D,
-        MPP_ATTR_AFBC | MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90 |
-        MPP_ATTR_HDR10 | MPP_ATTR_USE_CAPA
-    }
-};
-#endif
-
 using namespace android;
 using namespace vendor::graphics;
 using namespace SOC_VERSION;
@@ -155,9 +110,9 @@
     memset(mFormatRestrictions, 0, sizeof(mFormatRestrictions));
     memset(mSizeRestrictions, 0, sizeof(mSizeRestrictions));
 
-    size_t num_mpp_units = sizeof(AVAILABLE_OTF_MPP_UNITS)/sizeof(exynos_mpp_t);
+    size_t num_mpp_units = sizeof(available_otf_mpp_units)/sizeof(exynos_mpp_t);
     for (size_t i = 0; i < num_mpp_units; i++) {
-        exynos_mpp_t exynos_mpp = AVAILABLE_OTF_MPP_UNITS[i];
+        exynos_mpp_t exynos_mpp = available_otf_mpp_units[i];
         ALOGI("otfMPP type(%d, %d), physical_index(%d), logical_index(%d)",
                 exynos_mpp.physicalType, exynos_mpp.logicalType,
                 exynos_mpp.physical_index, exynos_mpp.logical_index);
@@ -165,6 +120,7 @@
                 exynos_mpp.logicalType, exynos_mpp.name, exynos_mpp.physical_index,
                 exynos_mpp.logical_index, exynos_mpp.pre_assign_info);
         exynosMPP->mMPPType = MPP_TYPE_OTF;
+        exynosMPP->initTDMInfo(exynos_mpp.hw_block_index, exynos_mpp.axi_port_index);
         mOtfMPPs.add(exynosMPP);
     }
 
@@ -188,14 +144,14 @@
             HDEBUGLOGD(eDebugResourceManager, "otfMPP[%d]", i);
             String8 dumpMPP;
             mOtfMPPs[i]->dump(dumpMPP);
-            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
+            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.c_str());
         }
         for (uint32_t i = 0; i < mM2mMPPs.size(); i++)
         {
             HDEBUGLOGD(eDebugResourceManager, "m2mMPP[%d]", i);
             String8 dumpMPP;
             mM2mMPPs[i]->dump(dumpMPP);
-            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
+            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.c_str());
         }
     }
 
@@ -439,6 +395,11 @@
         return ret;
     }
 
+    HDEBUGLOGD(eDebugTDM, "%s layer's calculation start", __func__);
+    for (uint32_t i = 0; i < display->mLayers.size(); i++) {
+        calculateHWResourceAmount(display, display->mLayers[i]);
+    }
+
     if (mDevice->isFirstValidate()) {
         HDEBUGLOGD(eDebugResourceManager, "This is first validate");
         if (exynosHWCControl.displayMode < DISPLAY_MODE_NUM)
@@ -475,15 +436,15 @@
         HDEBUGLOGD(eDebugResourceManager, "AssignResource result");
         String8 result;
         display->mClientCompositionInfo.dump(result);
-        HDEBUGLOGD(eDebugResourceManager, "%s", result.string());
+        HDEBUGLOGD(eDebugResourceManager, "%s", result.c_str());
         result.clear();
         display->mExynosCompositionInfo.dump(result);
-        HDEBUGLOGD(eDebugResourceManager, "%s", result.string());
+        HDEBUGLOGD(eDebugResourceManager, "%s", result.c_str());
         for (uint32_t i = 0; i < display->mLayers.size(); i++) {
             result.clear();
             HDEBUGLOGD(eDebugResourceManager, "%d layer(%p) dump", i, display->mLayers[i]);
             display->mLayers[i]->printLayer();
-            HDEBUGLOGD(eDebugResourceManager, "%s", result.string());
+            HDEBUGLOGD(eDebugResourceManager, "%s", result.c_str());
         }
     }
 
@@ -500,7 +461,7 @@
             if ((ret = display->mExynosCompositionInfo.mM2mMPP->assignMPP(display, &display->mClientCompositionInfo)) != NO_ERROR)
             {
                 ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                        __func__, display->mExynosCompositionInfo.mM2mMPP->mName.string(), ret);
+                        __func__, display->mExynosCompositionInfo.mM2mMPP->mName.c_str(), ret);
                 return ret;
             }
             int prevHasCompositionLayer = display->mExynosCompositionInfo.mHasCompositionLayer;
@@ -535,7 +496,7 @@
                 layer->mValidateCompositionType = HWC2_COMPOSITION_DEVICE;
                 ret = EXYNOS_ERROR_CHANGED;
                 HDEBUGLOGD(eDebugResourceManager, "\t%s is reserved without display because of panding work",
-                        m2mMPP->mName.string());
+                        m2mMPP->mName.c_str());
                 m2mMPP->reserveMPP();
                 layer->mCheckMPPFlag[m2mMPP->mLogicalType] = eMPPHWBusy;
             }
@@ -550,7 +511,7 @@
             HWC_LOGE(display, "There is exynos composition layers but resource is null (%p)",
                     m2mMPP);
         } else if ((check_ret = m2mMPP->prioritize(2)) != NO_ERROR) {
-            HDEBUGLOGD(eDebugResourceManager, "%s setting priority error(%d)", m2mMPP->mName.string(), check_ret);
+            HDEBUGLOGD(eDebugResourceManager, "%s setting priority error(%d)", m2mMPP->mName.c_str(), check_ret);
             if (check_ret < 0) {
                 HWC_LOGE(display, "Fail to set exynoscomposition priority(%d)", ret);
             } else {
@@ -569,11 +530,11 @@
                 ret = EXYNOS_ERROR_CHANGED;
                 m2mMPP->resetUsedCapacity();
                 HDEBUGLOGD(eDebugResourceManager, "\t%s is reserved without display because of pending work",
-                        m2mMPP->mName.string());
+                        m2mMPP->mName.c_str());
                 m2mMPP->reserveMPP();
             }
         } else {
-            HDEBUGLOGD(eDebugResourceManager, "%s setting priority is ok", m2mMPP->mName.string());
+            HDEBUGLOGD(eDebugResourceManager, "%s setting priority is ok", m2mMPP->mName.c_str());
         }
     }
 
@@ -605,7 +566,7 @@
     }
 
     do {
-        HDEBUGLOGD(eDebugResourceManager, "%s:: retry_count(%d)", __func__, retry_count);
+        HDEBUGLOGD(eDebugResourceAssigning, "%s:: retry_count(%d)", __func__, retry_count);
         if ((ret = resetAssignedResources(display)) != NO_ERROR)
             return ret;
         if ((ret = assignCompositionTarget(display, COMPOSITION_CLIENT)) != NO_ERROR) {
@@ -694,12 +655,13 @@
             {
                 String8 dumpMPP;
                 mM2mMPPs[i]->dump(dumpMPP);
-                HDEBUGLOGD(eDebugCapacity, "%s", dumpMPP.string());
+                HDEBUGLOGD(eDebugCapacity, "%s", dumpMPP.c_str());
             }
         }
     }
     return ret;
 }
+
 int32_t ExynosResourceManager::updateExynosComposition(ExynosDisplay *display)
 {
     int ret = NO_ERROR;
@@ -712,8 +674,9 @@
             uint32_t firstIndex = display->mExynosCompositionInfo.mFirstIndex;
             uint32_t remainNum = m2mMPP->mMaxSrcLayerNum - (lastIndex - firstIndex + 1);
 
-            HDEBUGLOGD(eDebugResourceManager, "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d++++",
-                    firstIndex, lastIndex, remainNum);
+            HDEBUGLOGD(eDebugResourceAssigning,
+                       "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d++++",
+                       firstIndex, lastIndex, remainNum);
 
             ExynosLayer *layer = NULL;
             exynos_image src_img;
@@ -725,29 +688,32 @@
                     layer->setSrcExynosImage(&src_img);
                     layer->setDstExynosImage(&dst_img);
                     layer->setExynosImage(src_img, dst_img);
-                    bool isAssignable = false;
+                    bool isAssignableState = false;
                     if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0)
-                        isAssignable = m2mMPP->isAssignable(display, src_img, dst_img);
+                        isAssignableState = isAssignable(m2mMPP, display, src_img, dst_img, layer);
 
                     bool canChange = (layer->mValidateCompositionType != HWC2_COMPOSITION_CLIENT) &&
-                                     ((display->mDisplayControl.cursorSupport == false) ||
-                                      (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) &&
-                                     (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignable;
+                            ((display->mDisplayControl.cursorSupport == false) ||
+                             (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) &&
+                            (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignableState;
 
-                    HDEBUGLOGD(eDebugResourceManager, "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, remainNum(%d)",
-                            i, layer->mValidateCompositionType,
-                            layer->mSupportedMPPFlag, isAssignable, canChange, remainNum);
+                    HDEBUGLOGD(eDebugResourceAssigning,
+                               "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, "
+                               "remainNum(%d)",
+                               i, layer->mValidateCompositionType, layer->mSupportedMPPFlag,
+                               isAssignableState, canChange, remainNum);
                     if (canChange) {
                         layer->resetAssignedResource();
                         layer->mOverlayInfo |= eUpdateExynosComposition;
                         if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
                         {
                             ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                                    __func__, m2mMPP->mName.string(), ret);
+                                    __func__, m2mMPP->mName.c_str(), ret);
                             return ret;
                         }
                         layer->setExynosMidImage(dst_img);
-                        display->addExynosCompositionLayer(i);
+                        float totalUsedCapacity = getResourceUsedCapa(*m2mMPP);
+                        display->addExynosCompositionLayer(i, totalUsedCapacity);
                         layer->mValidateCompositionType = HWC2_COMPOSITION_EXYNOS;
                         remainNum--;
                     }
@@ -762,29 +728,32 @@
                     layer->setSrcExynosImage(&src_img);
                     layer->setDstExynosImage(&dst_img);
                     layer->setExynosImage(src_img, dst_img);
-                    bool isAssignable = false;
+                    bool isAssignableState = false;
                     if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0)
-                        isAssignable = m2mMPP->isAssignable(display, src_img, dst_img);
+                        isAssignableState = isAssignable(m2mMPP, display, src_img, dst_img, layer);
 
                     bool canChange = (layer->mValidateCompositionType != HWC2_COMPOSITION_CLIENT) &&
-                                     ((display->mDisplayControl.cursorSupport == false) ||
-                                      (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) &&
-                                     (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignable;
+                            ((display->mDisplayControl.cursorSupport == false) ||
+                             (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) &&
+                            (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignableState;
 
-                    HDEBUGLOGD(eDebugResourceManager, "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, remainNum(%d)",
-                            i, layer->mValidateCompositionType,
-                            layer->mSupportedMPPFlag, isAssignable, canChange, remainNum);
+                    HDEBUGLOGD(eDebugResourceAssigning,
+                               "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, "
+                               "remainNum(%d)",
+                               i, layer->mValidateCompositionType, layer->mSupportedMPPFlag,
+                               isAssignableState, canChange, remainNum);
                     if (canChange) {
                         layer->resetAssignedResource();
                         layer->mOverlayInfo |= eUpdateExynosComposition;
                         if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
                         {
                             ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                                    __func__, m2mMPP->mName.string(), ret);
+                                    __func__, m2mMPP->mName.c_str(), ret);
                             return ret;
                         }
                         layer->setExynosMidImage(dst_img);
-                        display->addExynosCompositionLayer(i);
+                        float totalUsedCapacity = getResourceUsedCapa(*m2mMPP);
+                        display->addExynosCompositionLayer(i, totalUsedCapacity);
                         layer->mValidateCompositionType = HWC2_COMPOSITION_EXYNOS;
                         remainNum--;
                     }
@@ -792,8 +761,10 @@
                         break;
                 }
             }
-            HDEBUGLOGD(eDebugResourceManager, "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d-----",
-                    display->mExynosCompositionInfo.mFirstIndex, display->mExynosCompositionInfo.mLastIndex, remainNum);
+            HDEBUGLOGD(eDebugResourceAssigning,
+                       "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d-----",
+                       display->mExynosCompositionInfo.mFirstIndex,
+                       display->mExynosCompositionInfo.mLastIndex, remainNum);
         }
 
         /*
@@ -816,13 +787,13 @@
                 if ((ret = otfMPP->resetAssignedState()) != NO_ERROR)
                 {
                     ALOGE("%s:: %s MPP resetAssignedState() error (%d)",
-                            __func__, otfMPP->mName.string(), ret);
+                            __func__, otfMPP->mName.c_str(), ret);
                 }
                 // assign otfMPP again
                 if ((ret = otfMPP->assignMPP(display, layer)) != NO_ERROR)
                 {
                     ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                            __func__, otfMPP->mName.string(), ret);
+                            __func__, otfMPP->mName.c_str(), ret);
                 }
             }
         }
@@ -842,27 +813,27 @@
         if ((ret = otfMPP->assignMPP(display, layer)) != NO_ERROR)
         {
             ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                    __func__, otfMPP->mName.string(), ret);
+                    __func__, otfMPP->mName.c_str(), ret);
             return ret;
         }
-        HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
-                layer_index, otfMPP->mName.string());
+        HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", layer_index,
+                   otfMPP->mName.c_str());
     }
     if (m2mMPP != NULL) {
         if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
         {
             ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                    __func__, m2mMPP->mName.string(), ret);
+                    __func__, m2mMPP->mName.c_str(), ret);
             return ret;
         }
         layer->setExynosMidImage(m2m_out_img);
-        HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
-                layer_index, m2mMPP->mName.string());
+        HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", layer_index,
+                   m2mMPP->mName.c_str());
     }
     layer->mValidateCompositionType = HWC2_COMPOSITION_DEVICE;
     display->mWindowNumUsed++;
-    HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: mWindowNumUsed(%d)",
-            layer_index, display->mWindowNumUsed);
+    HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: mWindowNumUsed(%d)", layer_index,
+               display->mWindowNumUsed);
 
     return ret;
 }
@@ -1034,27 +1005,35 @@
     }
 
     int64_t isSupported = 0;
-    bool isAssignable = false;
+    bool isAssignableState = false;
+
+    otfMppReordering(display, mOtfMPPs, src_img, dst_img);
+
     for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
+        compositionInfo->setExynosImage(src_img, dst_img);
+        compositionInfo->setExynosMidImage(dst_img);
+        HDEBUGLOGD(eDebugTDM, "%s M2M target calculation start", __func__);
+        calculateHWResourceAmount(display, compositionInfo);
+
         isSupported = mOtfMPPs[i]->isSupported(*display, src_img, dst_img);
         if (isSupported == NO_ERROR)
-            isAssignable = mOtfMPPs[i]->isAssignable(display, src_img, dst_img);
+            isAssignableState =
+                    isAssignable(mOtfMPPs[i], display, src_img, dst_img, compositionInfo);
 
-        HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)",
-                mOtfMPPs[i]->mName.string(), -isSupported, isAssignable);
-        if ((isSupported == NO_ERROR) && (isAssignable)) {
+        HDEBUGLOGD(eDebugResourceAssigning,
+                   "\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)",
+                   mOtfMPPs[i]->mName.c_str(), -isSupported, isAssignableState);
+        if ((isSupported == NO_ERROR) && (isAssignableState)) {
             if ((ret = mOtfMPPs[i]->assignMPP(display, compositionInfo)) != NO_ERROR)
             {
                 HWC_LOGE(display, "%s:: %s MPP assignMPP() error (%d)",
-                        __func__, mOtfMPPs[i]->mName.string(), ret);
+                        __func__, mOtfMPPs[i]->mName.c_str(), ret);
                 return ret;
             }
-            compositionInfo->setExynosImage(src_img, dst_img);
-            compositionInfo->setExynosMidImage(dst_img);
             compositionInfo->mOtfMPP = mOtfMPPs[i];
             display->mWindowNumUsed++;
 
-            HDEBUGLOGD(eDebugResourceManager, "%s:: %s is assigned", __func__, mOtfMPPs[i]->mName.string());
+            HDEBUGLOGD(eDebugResourceManager, "%s:: %s is assigned", __func__, mOtfMPPs[i]->mName.c_str());
             return NO_ERROR;
         }
     }
@@ -1218,40 +1197,33 @@
     uint32_t otfMppRatio = 1;
     uint32_t m2mMppRatio = 1;
     if (scaleUp) {
-        std::find_if(mOtfMPPs.begin(), mOtfMPPs.end(),
-                     [&dst_scale_img, &dst_img, &otfMpp, &otfMppRatio](auto m) {
-                         auto ratio = m->getMaxUpscale(dst_scale_img, dst_img);
-                         if (ratio > 1) {
-                             otfMpp = m;
-                             otfMppRatio = ratio;
-                             return true;
-                         }
-                         return false;
-                     });
+        for (ExynosMPP *m : mOtfMPPs) {
+            auto ratio = m->getMaxUpscale(dst_scale_img, dst_img);
+            if (ratio > 1) {
+                otfMpp = m;
+                otfMppRatio = ratio;
+                break;
+            }
+        }
         const auto reqRatio = max(float(dst_img.w) / float(srcWidth * otfMppRatio),
                                   float(dst_img.h) / float(srcHeight * otfMppRatio));
-        std::find_if(mM2mMPPs.begin(), mM2mMPPs.end(),
-                     [&src_img, &dst_scale_img, reqRatio, &m2mMpp, &m2mMppRatio](auto m) {
-                         float ratio = float(m->getMaxUpscale(src_img, dst_scale_img));
-                         if (ratio > reqRatio) {
-                             m2mMpp = m;
-                             m2mMppRatio = ratio;
-                             return true;
-                         }
-                         return false;
-                     });
+        for (ExynosMPP *m : mM2mMPPs) {
+            float ratio = float(m->getMaxUpscale(src_img, dst_scale_img));
+            if (ratio > reqRatio) {
+                m2mMpp = m;
+                m2mMppRatio = ratio;
+                break;
+            }
+        }
     } else {
-        std::find_if(mM2mMPPs.begin(), mM2mMPPs.end(),
-                     [&src_img, &dst_scale_img, display, &m2mMpp, &m2mMppRatio](auto m) {
-                         auto ratio = m->getMaxDownscale(*display, src_img, dst_scale_img);
-                         if (ratio > 1) {
-                             m2mMpp = m;
-                             m2mMppRatio = ratio;
-                             return true;
-                         }
-                         return false;
-                     });
-
+        for (ExynosMPP *m : mM2mMPPs) {
+            auto ratio = m->getMaxDownscale(*display, src_img, dst_scale_img);
+            if (ratio > 1) {
+                m2mMpp = m;
+                m2mMppRatio = ratio;
+                break;
+            }
+        }
         const float otfSrcWidth = float(srcWidth / m2mMppRatio);
         const float scaleRatio_H = otfSrcWidth / float(dst_img.w);
         const float otfSrcHeight = float(srcHeight / m2mMppRatio);
@@ -1259,19 +1231,16 @@
         const float displayRatio_V = float(dst_img.h) / float(display->mYres);
         const float resolution = otfSrcWidth * otfSrcHeight * display->getBtsRefreshRate() / 1000;
 
-        std::find_if(mOtfMPPs.begin(), mOtfMPPs.end(),
-                     [&dst_scale_img, &dst_img, resolution, scaleRatio_H, scaleRatio_V,
-                      displayRatio_V, &otfMpp, &otfMppRatio](auto m) {
-                         auto ratio = m->getDownscaleRestriction(dst_scale_img, dst_img);
+        for (ExynosMPP *m : mOtfMPPs) {
+            auto ratio = m->getDownscaleRestriction(dst_scale_img, dst_img);
 
-                         if (ratio >= scaleRatio_H && ratio >= scaleRatio_V &&
-                             m->checkDownscaleCap(resolution, displayRatio_V)) {
-                             otfMpp = m;
-                             otfMppRatio = ratio;
-                             return true;
-                         }
-                         return false;
-                     });
+            if (ratio >= scaleRatio_H && ratio >= scaleRatio_V &&
+                m->checkDownscaleCap(resolution, displayRatio_V)) {
+                otfMpp = m;
+                otfMppRatio = ratio;
+                break;
+            }
+        }
     }
 
     if (!otfMpp && !m2mMpp) {
@@ -1305,7 +1274,7 @@
             dst_scale_img.h = uint32_t(ceilf(float(srcHeight) / float(m2mMppRatio)));
         }
     }
-    HDEBUGLOGD(eDebugResourceManager,
+    HDEBUGLOGD(eDebugResourceAssigning,
                "\tsrc[%d, %d, %d,%d], dst[%d, %d, %d,%d], mid[%d, %d, %d, %d]", src_img.x,
                src_img.y, src_img.w, src_img.h, dst_img.x, dst_img.y, dst_img.w, dst_img.h,
                dst_scale_img.x, dst_scale_img.y, dst_scale_img.w, dst_scale_img.h);
@@ -1486,26 +1455,32 @@
     HDEBUGLOGD(eDebugResourceManager, "\t[%d] layer: validateFlag(0x%8x), supportedMPPFlag(0x%8x)",
             layer_index, validateFlag, layer->mSupportedMPPFlag);
 
-    if (hwcCheckDebugMessages(eDebugResourceManager)) {
+    if (hwcCheckDebugMessages(eDebugResourceAssigning)) {
         layer->printLayer();
     }
 
     if ((validateFlag == NO_ERROR) || (validateFlag == eInsufficientWindow) ||
         (validateFlag == eDimLayer)) {
-        bool isAssignable = false;
+        bool isAssignableFlag = false;
         uint64_t isSupported = 0;
         /* 1. Find available otfMPP */
         if (validateFlag != eInsufficientWindow) {
+            otfMppReordering(display, mOtfMPPs, src_img, dst_img);
+
             for (uint32_t j = 0; j < mOtfMPPs.size(); j++) {
                 if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) != 0)
-                    isAssignable = mOtfMPPs[j]->isAssignable(display, src_img, dst_img);
+                    isAssignableFlag = isAssignable(mOtfMPPs[j], display, src_img, dst_img, layer);
 
-                HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: flag (%d) supportedBit(%d), isAssignable(%d)",
-                        mOtfMPPs[j]->mName.string(),layer->mSupportedMPPFlag,
-                        (layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType), isAssignable);
-                if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) && (isAssignable)) {
+                HDEBUGLOGD(eDebugResourceAssigning,
+                           "\t\t check %s: flag (%d) supportedBit(%d), isAssignable(%d)",
+                           mOtfMPPs[j]->mName.c_str(), layer->mSupportedMPPFlag,
+                           (layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType),
+                           isAssignableFlag);
+
+                if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) && (isAssignableFlag)) {
                     isSupported = mOtfMPPs[j]->isSupported(*display, src_img, dst_img);
-                    HDEBUGLOGD(eDebugResourceManager, "\t\t\t isSuported(%" PRIx64 ")", -isSupported);
+                    HDEBUGLOGD(eDebugResourceAssigning, "\t\t\t isSupported(%" PRIx64 ")",
+                               -isSupported);
                     if (isSupported == NO_ERROR) {
                         *otfMPP = mOtfMPPs[j];
                         return HWC2_COMPOSITION_DEVICE;
@@ -1516,7 +1491,6 @@
 
         /* 2. Find available m2mMPP */
         for (uint32_t j = 0; j < mM2mMPPs.size(); j++) {
-
             if ((display->mUseDpu == true) &&
                 (mM2mMPPs[j]->mLogicalType == MPP_LOGICAL_G2D_COMBO))
                 continue;
@@ -1530,16 +1504,19 @@
             if ((validateFlag == eInsufficientWindow) &&
                 (mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_RGB) &&
                 (mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_COMBO)) {
-                HDEBUGLOGD(eDebugResourceManager, "\t\tInsufficient window but exynosComposition is not assigned");
+                HDEBUGLOGD(eDebugResourceAssigning,
+                           "\t\tInsufficient window but exynosComposition is not assigned");
                 continue;
             }
 
             bool isAssignableState = mM2mMPPs[j]->isAssignableState(display, src_img, dst_img);
 
-            HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: supportedBit(%d), isAssignableState(%d)",
-                    mM2mMPPs[j]->mName.string(),
-                    (layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType), isAssignableState);
+            HDEBUGLOGD(eDebugResourceAssigning,
+                       "\t\t check %s: supportedBit(%d), isAssignableState(%d)",
+                       mM2mMPPs[j]->mName.c_str(),
+                       (layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType), isAssignableState);
 
+            float totalUsedCapa = ExynosResourceManager::getResourceUsedCapa(*mM2mMPPs[j]);
             if (isAssignableState) {
                 if ((mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_RGB) &&
                     (mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_COMBO)) {
@@ -1553,9 +1530,10 @@
                         HWC_LOGE(display, "Fail getCandidateM2mMPPOutImages (%d)", ret);
                         return ret;
                     }
-                    HDEBUGLOGD(eDebugResourceManager, "candidate M2mMPPOutImage num: %zu", image_lists.size());
+                    HDEBUGLOGD(eDebugResourceAssigning, "candidate M2mMPPOutImage num: %zu",
+                               image_lists.size());
                     for (auto &otf_src_img : image_lists) {
-                        dumpExynosImage(eDebugResourceManager, otf_src_img);
+                        dumpExynosImage(eDebugResourceAssigning, otf_src_img);
                         exynos_image m2m_src_img = src_img;
                         /* transform is already handled by m2mMPP */
                         if (CC_UNLIKELY(otf_src_img.transform != 0 || otf_dst_img.transform != 0)) {
@@ -1573,24 +1551,43 @@
                         if (otf_src_img.needColorTransform)
                             m2m_src_img.needColorTransform = false;
 
-                        if (((isSupported = mM2mMPPs[j]->isSupported(*display, m2m_src_img, otf_src_img)) != NO_ERROR) ||
-                            ((isAssignable = mM2mMPPs[j]->hasEnoughCapa(display, m2m_src_img, otf_src_img)) == false))
-                        {
-                            HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: supportedBit(0x%" PRIx64 "), hasEnoughCapa(%d)",
-                                    mM2mMPPs[j]->mName.string(), -isSupported, isAssignable);
+                        if (((isSupported = mM2mMPPs[j]->isSupported(*display, m2m_src_img,
+                                                                     otf_src_img)) != NO_ERROR) ||
+                            ((isAssignableFlag =
+                                      mM2mMPPs[j]->hasEnoughCapa(display, m2m_src_img, otf_src_img,
+                                                                 totalUsedCapa)) == false)) {
+                            HDEBUGLOGD(eDebugResourceAssigning,
+                                       "\t\t\t check %s: supportedBit(0x%" PRIx64
+                                       "), hasEnoughCapa(%d)",
+                                       mM2mMPPs[j]->mName.c_str(), -isSupported, isAssignableFlag);
                             continue;
                         }
 
+                        otfMppReordering(display, mOtfMPPs, otf_src_img, otf_dst_img);
+
                         /* 3. Find available OtfMPP for output of m2mMPP */
                         for (uint32_t k = 0; k < mOtfMPPs.size(); k++) {
                             isSupported = mOtfMPPs[k]->isSupported(*display, otf_src_img, otf_dst_img);
-                            isAssignable = false;
-                            if (isSupported == NO_ERROR)
-                                isAssignable = mOtfMPPs[k]->isAssignable(display, otf_src_img, otf_dst_img);
+                            isAssignableFlag = false;
+                            if (isSupported == NO_ERROR) {
+                                /* to prevent HW resource execeeded */
+                                ExynosCompositionInfo dpuSrcInfo;
+                                dpuSrcInfo.mSrcImg = otf_src_img;
+                                dpuSrcInfo.mDstImg = otf_dst_img;
+                                HDEBUGLOGD(eDebugTDM,
+                                           "%s Composition target calculation start (candidates)",
+                                           __func__);
+                                calculateHWResourceAmount(display, &dpuSrcInfo);
 
-                            HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)",
-                                    mOtfMPPs[k]->mName.string(), -isSupported, isAssignable);
-                            if ((isSupported == NO_ERROR) && isAssignable) {
+                                isAssignableFlag = isAssignable(mOtfMPPs[k], display, otf_src_img,
+                                                                otf_dst_img, &dpuSrcInfo);
+                            }
+
+                            HDEBUGLOGD(eDebugResourceAssigning,
+                                       "\t\t\t check %s: supportedBit(0x%" PRIx64
+                                       "), isAssignable(%d)",
+                                       mOtfMPPs[k]->mName.c_str(), -isSupported, isAssignableFlag);
+                            if ((isSupported == NO_ERROR) && isAssignableFlag) {
                                 *m2mMPP = mM2mMPPs[j];
                                 *otfMPP = mOtfMPPs[k];
                                 m2m_out_img = otf_src_img;
@@ -1600,12 +1597,16 @@
                     }
                 } else {
                     if ((layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType) &&
-                        ((isAssignable = mM2mMPPs[j]->hasEnoughCapa(display, src_img, dst_img) == true))) {
+                        ((isAssignableFlag = mM2mMPPs[j]->hasEnoughCapa(display, src_img, dst_img,
+                                                                        totalUsedCapa) == true))) {
                         *m2mMPP = mM2mMPPs[j];
                         return HWC2_COMPOSITION_EXYNOS;
                     } else {
-                        HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: layer's mSupportedMPPFlag(0x%8x), hasEnoughCapa(%d)",
-                                mM2mMPPs[j]->mName.string(), layer->mSupportedMPPFlag, isAssignable);
+                        HDEBUGLOGD(eDebugResourceManager,
+                                   "\t\t\t check %s: layer's mSupportedMPPFlag(0x%8x), "
+                                   "hasEnoughCapa(%d)",
+                                   mM2mMPPs[j]->mName.c_str(), layer->mSupportedMPPFlag,
+                                   isAssignableFlag);
                     }
                 }
             }
@@ -1621,8 +1622,8 @@
 
 int32_t ExynosResourceManager::assignLayers(ExynosDisplay * display, uint32_t priority)
 {
-    HDEBUGLOGD(eDebugResourceManager, "%s:: display(%d), priority(%d) +++++",
-            __func__, display->mType, priority);
+    HDEBUGLOGD(eDebugResourceAssigning, "%s:: display(%d), priority(%d) +++++", __func__,
+               display->mType, priority);
 
     int32_t ret = NO_ERROR;
     bool needReAssign = false;
@@ -1660,44 +1661,47 @@
                 if ((ret = otfMPP->assignMPP(display, layer)) != NO_ERROR)
                 {
                     ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                            __func__, otfMPP->mName.string(), ret);
+                            __func__, otfMPP->mName.c_str(), ret);
                     return ret;
                 }
-                HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
-                        i, otfMPP->mName.string());
+                HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", i,
+                           otfMPP->mName.c_str());
             }
             if (m2mMPP != NULL) {
                 if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
                 {
                     ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                            __func__, m2mMPP->mName.string(), ret);
+                            __func__, m2mMPP->mName.c_str(), ret);
                     return ret;
                 }
                 layer->setExynosMidImage(m2m_out_img);
-                HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
-                        i, m2mMPP->mName.string());
+                HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", i,
+                           m2mMPP->mName.c_str());
             }
             layer->mValidateCompositionType = compositionType;
             display->mWindowNumUsed++;
-            HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: mWindowNumUsed(%d)",
-                    i, display->mWindowNumUsed);
+            HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: mWindowNumUsed(%d)", i,
+                       display->mWindowNumUsed);
         } else if (compositionType == HWC2_COMPOSITION_EXYNOS) {
+            float totalUsedCapacity = 0;
             if (m2mMPP != NULL) {
                 if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
                 {
                     ALOGE("%s:: %s MPP assignMPP() error (%d)",
-                            __func__, m2mMPP->mName.string(), ret);
+                            __func__, m2mMPP->mName.c_str(), ret);
                     return ret;
                 }
-                HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
-                        i, m2mMPP->mName.string());
+                totalUsedCapacity = getResourceUsedCapa(*m2mMPP);
+                HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", i,
+                           m2mMPP->mName.c_str());
             }
             layer->mValidateCompositionType = compositionType;
 
-            HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: exynosComposition", i);
+            HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: exynosComposition", i);
             /* G2D composition */
-            if (((ret = display->addExynosCompositionLayer(i)) == EXYNOS_ERROR_CHANGED) ||
-                 (ret < 0))
+            if (((ret = display->addExynosCompositionLayer(i, totalUsedCapacity)) ==
+                 EXYNOS_ERROR_CHANGED) ||
+                (ret < 0))
                 return ret;
             else {
                 /*
@@ -1768,7 +1772,8 @@
 
     for (uint32_t i = 0; i < display->mLayers.size(); i++) {
         ExynosLayer *layer = display->mLayers[i];
-        HDEBUGLOGD(eDebugResourceManager, "\t[%d] layer type: %d", i, layer->mValidateCompositionType);
+        HDEBUGLOGD(eDebugResourceAssigning, "\t[%d] layer type: %d", i,
+                   layer->mValidateCompositionType);
 
         if (layer->mValidateCompositionType == HWC2_COMPOSITION_DEVICE) {
             layer->mWindowIndex = windowIndex;
@@ -1786,7 +1791,7 @@
                 (compositionInfo->mLastIndex < 0)) {
                 HWC_LOGE(display, "%s:: Invalid %s CompositionInfo mHasCompositionLayer(%d), "
                         "mFirstIndex(%d), mLastIndex(%d) ",
-                        __func__, compositionInfo->getTypeStr().string(),
+                        __func__, compositionInfo->getTypeStr().c_str(),
                         compositionInfo->mHasCompositionLayer,
                         compositionInfo->mFirstIndex,
                         compositionInfo->mLastIndex);
@@ -1796,7 +1801,7 @@
                 continue;
             compositionInfo->mWindowIndex = windowIndex;
             HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] %s Composition windowIndex: %d",
-                    i, compositionInfo->getTypeStr().string(), windowIndex);
+                    i, compositionInfo->getTypeStr().c_str(), windowIndex);
         } else if (layer->mValidateCompositionType == HWC2_COMPOSITION_DISPLAY_DECORATION) {
             layer->mWindowIndex = -1;
             continue;
@@ -1818,10 +1823,10 @@
 int32_t ExynosResourceManager::updateSupportedMPPFlag(ExynosDisplay * display)
 {
     int64_t ret = 0;
-    HDEBUGLOGD(eDebugResourceManager, "%s++++++++++", __func__);
+    HDEBUGLOGD(eDebugResourceAssigning, "%s++++++++++", __func__);
     for (uint32_t i = 0; i < display->mLayers.size(); i++) {
         ExynosLayer *layer = display->mLayers[i];
-        HDEBUGLOGD(eDebugResourceManager, "[%d] layer ", i);
+        HDEBUGLOGD(eDebugResourceAssigning, "[%d] layer ", i);
 
         if (layer->mGeometryChanged == 0)
             continue;
@@ -1834,10 +1839,10 @@
         layer->setDstExynosImage(&dst_img_yuv);
         dst_img.format = DEFAULT_MPP_DST_FORMAT;
         dst_img_yuv.format = DEFAULT_MPP_DST_YUV_FORMAT;
-        HDEBUGLOGD(eDebugResourceManager, "\tsrc_img");
-        dumpExynosImage(eDebugResourceManager, src_img);
-        HDEBUGLOGD(eDebugResourceManager, "\tdst_img");
-        dumpExynosImage(eDebugResourceManager, dst_img);
+        HDEBUGLOGD(eDebugResourceAssigning, "\tsrc_img");
+        dumpExynosImage(eDebugResourceAssigning, src_img);
+        HDEBUGLOGD(eDebugResourceAssigning, "\tdst_img");
+        dumpExynosImage(eDebugResourceAssigning, dst_img);
 
         /* Initialize flags */
         layer->mSupportedMPPFlag = 0;
@@ -1847,16 +1852,18 @@
         for (uint32_t j = 0; j < mOtfMPPs.size(); j++) {
             if ((ret = mOtfMPPs[j]->isSupported(*display, src_img, dst_img)) == NO_ERROR) {
                 layer->mSupportedMPPFlag |= mOtfMPPs[j]->mLogicalType;
-                HDEBUGLOGD(eDebugResourceManager, "\t%s: supported", mOtfMPPs[j]->mName.string());
+                HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported", mOtfMPPs[j]->mName.c_str());
             } else {
                 if (((-ret) == eMPPUnsupportedFormat) &&
                     ((ret = mOtfMPPs[j]->isSupported(*display, src_img, dst_img_yuv)) == NO_ERROR)) {
                     layer->mSupportedMPPFlag |= mOtfMPPs[j]->mLogicalType;
-                    HDEBUGLOGD(eDebugResourceManager, "\t%s: supported with yuv dst", mOtfMPPs[j]->mName.string());
+                    HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported with yuv dst",
+                               mOtfMPPs[j]->mName.c_str());
                 }
             }
             if (ret < 0) {
-                HDEBUGLOGD(eDebugResourceManager, "\t%s: unsupported flag(0x%" PRIx64 ")", mOtfMPPs[j]->mName.string(), -ret);
+                HDEBUGLOGD(eDebugResourceAssigning, "\t%s: unsupported flag(0x%" PRIx64 ")",
+                           mOtfMPPs[j]->mName.c_str(), -ret);
                 uint64_t checkFlag = 0x0;
                 if (layer->mCheckMPPFlag.find(mOtfMPPs[j]->mLogicalType) !=
                         layer->mCheckMPPFlag.end()) {
@@ -1871,16 +1878,18 @@
         for (uint32_t j = 0; j < mM2mMPPs.size(); j++) {
             if ((ret = mM2mMPPs[j]->isSupported(*display, src_img, dst_img)) == NO_ERROR) {
                 layer->mSupportedMPPFlag |= mM2mMPPs[j]->mLogicalType;
-                HDEBUGLOGD(eDebugResourceManager, "\t%s: supported", mM2mMPPs[j]->mName.string());
+                HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported", mM2mMPPs[j]->mName.c_str());
             } else {
                 if (((-ret) == eMPPUnsupportedFormat) &&
                     ((ret = mM2mMPPs[j]->isSupported(*display, src_img, dst_img_yuv)) == NO_ERROR)) {
                     layer->mSupportedMPPFlag |= mM2mMPPs[j]->mLogicalType;
-                    HDEBUGLOGD(eDebugResourceManager, "\t%s: supported with yuv dst", mM2mMPPs[j]->mName.string());
+                    HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported with yuv dst",
+                               mM2mMPPs[j]->mName.c_str());
                 }
             }
             if (ret < 0) {
-                HDEBUGLOGD(eDebugResourceManager, "\t%s: unsupported flag(0x%" PRIx64 ")", mM2mMPPs[j]->mName.string(), -ret);
+                HDEBUGLOGD(eDebugResourceAssigning, "\t%s: unsupported flag(0x%" PRIx64 ")",
+                           mM2mMPPs[j]->mName.c_str(), -ret);
                 uint64_t checkFlag = 0x0;
                 if (layer->mCheckMPPFlag.find(mM2mMPPs[j]->mLogicalType) !=
                         layer->mCheckMPPFlag.end()) {
@@ -1890,9 +1899,10 @@
                 layer->mCheckMPPFlag[mM2mMPPs[j]->mLogicalType] = checkFlag;
             }
         }
-        HDEBUGLOGD(eDebugResourceManager, "[%d] layer mSupportedMPPFlag(0x%8x)", i, layer->mSupportedMPPFlag);
+        HDEBUGLOGD(eDebugResourceAssigning, "[%d] layer mSupportedMPPFlag(0x%8x)", i,
+                   layer->mSupportedMPPFlag);
     }
-    HDEBUGLOGD(eDebugResourceManager, "%s-------------", __func__);
+    HDEBUGLOGD(eDebugResourceAssigning, "%s-------------", __func__);
 
     return NO_ERROR;
 }
@@ -1906,7 +1916,7 @@
         if (hwcCheckDebugMessages(eDebugResourceManager)) {
             String8 dumpMPP;
             mOtfMPPs[i]->dump(dumpMPP);
-            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
+            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.c_str());
         }
     }
     for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
@@ -1914,7 +1924,7 @@
         if (hwcCheckDebugMessages(eDebugResourceManager)) {
             String8 dumpMPP;
             mM2mMPPs[i]->dump(dumpMPP);
-            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
+            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.c_str());
         }
     }
 
@@ -1934,7 +1944,9 @@
         }
 
         if (mOtfMPPs[i]->mPreAssignDisplayList[displayMode] != 0) {
-            HDEBUGLOGD(eDebugResourceManager, "\t%s check, dispMode(%d), 0x%8x", mOtfMPPs[i]->mName.string(), displayMode, mOtfMPPs[i]->mPreAssignDisplayList[displayMode]);
+            HDEBUGLOGD(eDebugResourceAssigning, "\t%s check, dispMode(%d), 0x%8x",
+                       mOtfMPPs[i]->mName.c_str(), displayMode,
+                       mOtfMPPs[i]->mPreAssignDisplayList[displayMode]);
 
             ExynosDisplay *display = NULL;
             for (size_t j = 0; j < mDevice->mDisplays.size(); j++) {
@@ -1942,15 +1954,19 @@
                 if (display == nullptr)
                     continue;
                 int checkBit = mOtfMPPs[i]->mPreAssignDisplayList[displayMode] & display->getDisplayPreAssignBit();
-                HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), checkBit(%d)", j, checkBit);
+                HDEBUGLOGD(eDebugResourceAssigning, "\t\tdisplay index(%zu), checkBit(%d)", j,
+                           checkBit);
                 if (checkBit) {
-                    HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), displayId(%d), display(%p)", j, display->mDisplayId, display);
+                    HDEBUGLOGD(eDebugResourceAssigning,
+                               "\t\tdisplay index(%zu), displayId(%d), display(%p)", j,
+                               display->mDisplayId, display);
                     if (display->mDisplayControl.forceReserveMPP ||
                         (display->mPlugState &&
                          ((display->mType != HWC_DISPLAY_PRIMARY) ||
                           (display->mPowerModeState.has_value() &&
                            (display->mPowerModeState.value() != HWC2_POWER_MODE_OFF))))) {
-                        HDEBUGLOGD(eDebugResourceManager, "\t\treserve to display %d", display->mDisplayId);
+                        HDEBUGLOGD(eDebugResourceAssigning, "\t\treserve to display %d",
+                                   display->mDisplayId);
                         mOtfMPPs[i]->reserveMPP(display->mDisplayId);
                         break;
                     }
@@ -1970,21 +1986,26 @@
             mM2mMPPs[i]->reserveMPP();
             continue;
         }
-        HDEBUGLOGD(eDebugResourceManager, "\t%s check, 0x%8x", mM2mMPPs[i]->mName.string(), mM2mMPPs[i]->mPreAssignDisplayList[displayMode]);
+        HDEBUGLOGD(eDebugResourceAssigning, "\t%s check, 0x%8x", mM2mMPPs[i]->mName.c_str(),
+                   mM2mMPPs[i]->mPreAssignDisplayList[displayMode]);
         if (mM2mMPPs[i]->mPreAssignDisplayList[displayMode] != 0) {
             ExynosDisplay *display = NULL;
             for (size_t j = 0; j < mDevice->mDisplays.size(); j++) {
                 display = mDevice->mDisplays[j];
                 int checkBit = mM2mMPPs[i]->mPreAssignDisplayList[displayMode] & display->getDisplayPreAssignBit();
-                HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), checkBit(%d)", j, checkBit);
+                HDEBUGLOGD(eDebugResourceAssigning, "\t\tdisplay index(%zu), checkBit(%d)", j,
+                           checkBit);
                 if (checkBit) {
-                    HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), displayId(%d), display(%p)", j, display->mDisplayId, display);
+                    HDEBUGLOGD(eDebugResourceAssigning,
+                               "\t\tdisplay index(%zu), displayId(%d), display(%p)", j,
+                               display->mDisplayId, display);
                     if ((display != NULL) && (display->mPlugState == true)) {
-                        HDEBUGLOGD(eDebugResourceManager, "\t\treserve to display %d", display->mDisplayId);
+                        HDEBUGLOGD(eDebugResourceAssigning, "\t\treserve to display %d",
+                                   display->mDisplayId);
                         mM2mMPPs[i]->reserveMPP(display->mDisplayId);
                         break;
                     } else {
-                        HDEBUGLOGD(eDebugResourceManager, "\t\treserve without display");
+                        HDEBUGLOGD(eDebugResourceAssigning, "\t\treserve without display");
                         mM2mMPPs[i]->reserveMPP();
                     }
                 }
@@ -1995,14 +2016,14 @@
         if (hwcCheckDebugMessages(eDebugResourceManager)) {
             String8 dumpMPP;
             mOtfMPPs[i]->dump(dumpMPP);
-            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
+            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.c_str());
         }
     }
     for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
         if (hwcCheckDebugMessages(eDebugResourceManager)) {
             String8 dumpMPP;
             mM2mMPPs[i]->dump(dumpMPP);
-            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
+            HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.c_str());
         }
     }
     HDEBUGLOGD(eDebugResourceManager, "%s-----------",  __func__);
@@ -2121,7 +2142,7 @@
 {
     int fps = ceil(msecsPerSec / mpp.mCapacity);
     HDEBUGLOGD(eDebugResourceAssigning, "%s setFrameRate %d",
-            mpp.mName.string(), fps);
+            mpp.mName.c_str(), fps);
     frame->setFrameRate(fps);
 }
 
@@ -2243,9 +2264,8 @@
     if (mpp.mCapacity < 0)
         return usedCapa;
 
-    HDEBUGLOGD(eDebugResourceManager, "%s:: [%s][%d] mpp[%d, %d]",
-            __func__, mpp.mName.string(), mpp.mLogicalIndex,
-            mpp.mPhysicalType, mpp.mPhysicalIndex);
+    HDEBUGLOGD(eDebugResourceAssigning, "%s:: [%s][%d] mpp[%d, %d]", __func__, mpp.mName.c_str(),
+               mpp.mLogicalIndex, mpp.mPhysicalType, mpp.mPhysicalIndex);
 
     if (mpp.mMPPType == MPP_TYPE_OTF) {
         for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
@@ -2263,8 +2283,8 @@
         }
     }
 
-    HDEBUGLOGD(eDebugResourceManager, "\t[%s][%d] mpp usedCapa: %f",
-            mpp.mName.string(), mpp.mLogicalIndex, usedCapa);
+    HDEBUGLOGD(eDebugResourceAssigning, "\t[%s][%d] mpp usedCapa: %f", mpp.mName.c_str(),
+               mpp.mLogicalIndex, usedCapa);
     return usedCapa;
 }
 
@@ -2335,7 +2355,9 @@
         return ret;
     }
 
-	return ret;
+    setDisplaysTDMInfo();
+
+    return ret;
 }
 
 int32_t ExynosResourceManager::finishAssignResourceWork()
@@ -2387,7 +2409,7 @@
     mSizeRestrictions[format][mSizeRestrictionCnt[format]++].sizeRestriction = size;
 
     HDEBUGLOGD(eDebugDefault, "MPP : %s, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
-            getMPPStr(mppId).string(),
+            getMPPStr(mppId).c_str(),
             size.maxDownScale,
             size.maxUpScale,
             size.maxFullWidth,
@@ -2411,9 +2433,9 @@
     mFormatRestrictions[mFormatRestrictionCnt] = table;
 
     HDEBUGLOGD(eDebugDefault, "MPP : %s, %d, %s, %d",
-               getMPPStr(mFormatRestrictions[mFormatRestrictionCnt].hwType).string(),
+               getMPPStr(mFormatRestrictions[mFormatRestrictionCnt].hwType).c_str(),
                mFormatRestrictions[mFormatRestrictionCnt].nodeType,
-               getFormatStr(mFormatRestrictions[mFormatRestrictionCnt].format, COMP_ANY).string(),
+               getFormatStr(mFormatRestrictions[mFormatRestrictionCnt].format, COMP_ANY).c_str(),
                mFormatRestrictions[mFormatRestrictionCnt].reserved);
     mFormatRestrictionCnt++;
 }
@@ -2495,8 +2517,8 @@
 mpp_phycal_type_t ExynosResourceManager::getPhysicalType(int ch) const {
 
     for (int i=0; i < MAX_DECON_DMA_TYPE; i++){
-        if(IDMA_CHANNEL_MAP[i].channel == ch)
-            return IDMA_CHANNEL_MAP[i].type;
+        if(idma_channel_map[i].channel == ch)
+            return idma_channel_map[i].type;
     }
 
     return MPP_P_TYPE_MAX;
@@ -2507,8 +2529,8 @@
     ExynosMPP *otfMPP = NULL;
 
     for (int i=0; i < MAX_DECON_DMA_TYPE; i++){
-        if(IDMA_CHANNEL_MAP[i].channel == ch) {
-            otfMPP = getExynosMPP(IDMA_CHANNEL_MAP[i].type, IDMA_CHANNEL_MAP[i].index);
+        if(idma_channel_map[i].channel == ch) {
+            otfMPP = getExynosMPP(idma_channel_map[i].type, idma_channel_map[i].index);
             break;
         }
     }
@@ -2636,3 +2658,84 @@
             mM2mMPPs[i]->mCapacity = capa;
     }
 }
+
+bool ExynosResourceManager::isAssignable(ExynosMPP *candidateMPP, ExynosDisplay *display,
+                                         struct exynos_image &src, struct exynos_image &dst,
+                                         ExynosMPPSource *mppSrc)
+{
+    bool ret = true;
+
+    float totalUsedCapacity = getResourceUsedCapa(*candidateMPP);
+    ret = candidateMPP->isAssignable(display, src, dst, totalUsedCapacity);
+
+    if ((ret) && (mppSrc != nullptr)) {
+        if ((candidateMPP->mMPPType == MPP_TYPE_OTF) &&
+            (!isHWResourceAvailable(display, candidateMPP, mppSrc))) {
+            if (mppSrc->mSourceType == MPP_SOURCE_LAYER) {
+                ExynosLayer *layer = (ExynosLayer *)mppSrc;
+                layer->mCheckMPPFlag[candidateMPP->mLogicalType] = eMPPExeedHWResource;
+            }
+            ret = false;
+        }
+    }
+
+    return ret;
+}
+
+void ExynosResourceManager::updateSupportWCG()
+{
+    for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
+        if (mOtfMPPs[i] == NULL) continue;
+        if (mOtfMPPs[i]->mAttr & (MPP_ATTR_WCG | MPP_ATTR_HDR10)) mDeviceSupportWCG = true;
+    }
+    for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
+        if (mM2mMPPs[i] == NULL) continue;
+        if (mM2mMPPs[i]->mAttr & (MPP_ATTR_WCG | MPP_ATTR_HDR10)) mDeviceSupportWCG = true;
+    }
+}
+
+bool ExynosResourceManager::needHdrProcessing(ExynosDisplay *display, exynos_image &srcImg,
+                                              exynos_image &dstImg)
+{
+    if (!deviceSupportWCG()) return false;
+
+    return true;
+}
+
+uint32_t ExynosResourceManager::needHWResource(ExynosDisplay *display, exynos_image &srcImg,
+                                               exynos_image &dstImg, tdm_attr_t attr)
+{
+    uint32_t ret = 0;
+
+    switch (attr) {
+        case TDM_ATTR_SBWC:
+            ret = (isFormatSBWC(srcImg.format)) ? 1 : 0;
+            break;
+        case TDM_ATTR_AFBC:
+            ret = (srcImg.compressed) ? 1 : 0;
+            break;
+        case TDM_ATTR_ITP:
+            ret = (isFormatYUV(srcImg.format)) ? 1 : 0;
+            break;
+        case TDM_ATTR_WCG:
+            ret = (needHdrProcessing(display, srcImg, dstImg)) ? 1 : 0;
+            HDEBUGLOGD(eDebugTDM, "needHdrProcessing : %d", ret);
+            break;
+        case TDM_ATTR_ROT_90:
+            ret = ((srcImg.transform & HAL_TRANSFORM_ROT_90) == 0) ? 0 : 1;
+            break;
+        case TDM_ATTR_SCALE: {
+            bool isPerpendicular = !!(srcImg.transform & HAL_TRANSFORM_ROT_90);
+            if (isPerpendicular) {
+                ret = ((srcImg.w != dstImg.h) || (srcImg.h != dstImg.w)) ? 1 : 0;
+            } else {
+                ret = ((srcImg.w != dstImg.w) || (srcImg.h != dstImg.h)) ? 1 : 0;
+            }
+        } break;
+        default:
+            ret = 0;
+            break;
+    }
+
+    return ret;
+}
diff --git a/libhwc2.1/libresource/ExynosResourceManager.h b/libhwc2.1/libresource/ExynosResourceManager.h
index badb6c7..e996554 100644
--- a/libhwc2.1/libresource/ExynosResourceManager.h
+++ b/libhwc2.1/libresource/ExynosResourceManager.h
@@ -38,18 +38,17 @@
 
 #define MAX_OVERLAY_LAYER_NUM       20
 
-#ifndef USE_MODULE_SW_FEATURE
 const std::map<mpp_phycal_type_t, uint64_t> sw_feature_table =
 {
     {MPP_DPP_G, MPP_ATTR_DIM},
     {MPP_DPP_GF, MPP_ATTR_DIM},
+    {MPP_DPP_GFS, MPP_ATTR_DIM},
     {MPP_DPP_VG, MPP_ATTR_DIM},
     {MPP_DPP_VGS, MPP_ATTR_DIM},
     {MPP_DPP_VGF, MPP_ATTR_DIM},
     {MPP_DPP_VGFS, MPP_ATTR_DIM},
     {MPP_DPP_VGRFS, MPP_ATTR_DIM},
 };
-#endif
 
 #ifndef USE_MODULE_DPU_ATTR_MAP
 const dpu_attr_map_t dpu_attr_map_table [] =
@@ -139,6 +138,12 @@
         virtual int32_t assignCompositionTarget(ExynosDisplay *display, uint32_t targetType);
         int32_t validateLayer(uint32_t index, ExynosDisplay *display, ExynosLayer *layer);
         int32_t assignLayers(ExynosDisplay *display, uint32_t priority);
+        virtual int32_t otfMppReordering(ExynosDisplay *__unused display,
+                                         ExynosMPPVector __unused &otfMPPs,
+                                         struct exynos_image __unused &src,
+                                         struct exynos_image __unused &dst) {
+            return 0;
+        }
         virtual int32_t assignLayer(ExynosDisplay *display, ExynosLayer *layer, uint32_t layer_index,
                 exynos_image &m2m_out_img, ExynosMPP **m2mMPP, ExynosMPP **otfMPP, uint32_t &overlayInfo);
         virtual int32_t assignWindow(ExynosDisplay *display);
@@ -178,6 +183,8 @@
 
         void dump(String8 &result) const;
         void setM2MCapa(uint32_t physicalType, uint32_t capa);
+        bool isAssignable(ExynosMPP *candidateMPP, ExynosDisplay *display, struct exynos_image &src,
+                          struct exynos_image &dst, ExynosMPPSource *mppSrc);
 
     private:
         int32_t changeLayerFromClientToDevice(ExynosDisplay *display, ExynosLayer *layer,
@@ -201,6 +208,41 @@
         static ExynosMPPVector mM2mMPPs;
         uint32_t mResourceReserved; /* Set MPP logical type for bit operation */
         float mMinimumSdrDimRatio;
+
+        android::Vector<ExynosDisplay *> mDisplays;
+        std::map<uint32_t, ExynosDisplay *> mDisplayMap;
+
+    protected:
+        bool mDeviceSupportWCG = false;
+
+    public:
+        void initDisplays(android::Vector<ExynosDisplay *> displays,
+                          std::map<uint32_t, ExynosDisplay *> displayMap) {
+            mDisplays = displays;
+            mDisplayMap = displayMap;
+        }
+        ExynosDisplay *getDisplay(uint32_t displayId) { return mDisplayMap[displayId]; }
+
+        virtual void updateSupportWCG();
+        virtual bool deviceSupportWCG() { return mDeviceSupportWCG; }
+
+        /* return 1 if it's needed */
+        bool needHdrProcessing(ExynosDisplay *display, exynos_image &srcImg, exynos_image &dstImg);
+        uint32_t needHWResource(ExynosDisplay *display, exynos_image &srcImg, exynos_image &dstImg,
+                                tdm_attr_t attr);
+
+        /* TDM (Time-Division Multiplexing) based Resource Management */
+        virtual bool isHWResourceAvailable(ExynosDisplay __unused *display,
+                                           ExynosMPP __unused *currentMPP,
+                                           ExynosMPPSource __unused *mppSrc) {
+            return true;
+        }
+        virtual uint32_t setDisplaysTDMInfo() { return 0; }
+        virtual uint32_t initDisplaysTDMInfo() { return 0; }
+        virtual uint32_t calculateHWResourceAmount(ExynosDisplay __unused *display,
+                                                   ExynosMPPSource __unused *mppSrc) {
+            return 0;
+        }
 };
 
 #endif //_EXYNOSRESOURCEMANAGER_H
diff --git a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.cpp b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.cpp
index d6ce85f..1f16ec8 100644
--- a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.cpp
+++ b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.cpp
@@ -15,7 +15,7 @@
  */
 
 #undef LOG_TAG
-#define LOG_TAG "virtualdisplay"
+#define LOG_TAG "hwc-virt-display"
 #include "ExynosVirtualDisplay.h"
 #include "../libdevice/ExynosDevice.h"
 #include "../libdevice/ExynosLayer.h"
@@ -28,13 +28,10 @@
 
 extern struct exynos_hwc_control exynosHWCControl;
 
-ExynosVirtualDisplay::ExynosVirtualDisplay(uint32_t index, ExynosDevice *device)
-    : ExynosDisplay(index, device)
-{
+ExynosVirtualDisplay::ExynosVirtualDisplay(uint32_t index, ExynosDevice* device,
+                                           const std::string& displayName)
+      : ExynosDisplay(HWC_DISPLAY_VIRTUAL, index, device, displayName) {
     /* Initialization */
-    mType = HWC_DISPLAY_VIRTUAL;
-    mIndex = index;
-    mDisplayId = getDisplayId(mType, mIndex);
 
     mDisplayControl.earlyStartMPP = false;
 
diff --git a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h
index 9e5daa8..786ff50 100644
--- a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h
+++ b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h
@@ -44,7 +44,7 @@
         COMPOSITION_MIXED   = COMPOSITION_GLES | COMPOSITION_HWC
     };
 
-    ExynosVirtualDisplay(uint32_t index, ExynosDevice *device);
+    ExynosVirtualDisplay(uint32_t index, ExynosDevice* device, const std::string& displayName);
     ~ExynosVirtualDisplay();
 
     void createVirtualDisplay(uint32_t width, uint32_t height, int32_t* format);
diff --git a/libhwc2.1/pixel-display-default.xml b/libhwc2.1/pixel-display-default.xml
index 86c1b03..7f2e4ba 100644
--- a/libhwc2.1/pixel-display-default.xml
+++ b/libhwc2.1/pixel-display-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>com.google.hardware.pixel.display</name>
-        <version>7</version>
+        <version>8</version>
         <fqname>IDisplay/default</fqname>
     </hal>
 </manifest>
diff --git a/libhwc2.1/pixel-display-secondary.xml b/libhwc2.1/pixel-display-secondary.xml
index 515bc21..ff313be 100644
--- a/libhwc2.1/pixel-display-secondary.xml
+++ b/libhwc2.1/pixel-display-secondary.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>com.google.hardware.pixel.display</name>
-        <version>7</version>
+        <version>8</version>
         <fqname>IDisplay/secondary</fqname>
     </hal>
 </manifest>
diff --git a/libhwc2.1/pixel-display.cpp b/libhwc2.1/pixel-display.cpp
index 32bc806..366945a 100644
--- a/libhwc2.1/pixel-display.cpp
+++ b/libhwc2.1/pixel-display.cpp
@@ -137,6 +137,30 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ndk::ScopedAStatus Display::setPeakRefreshRate(int rate) {
+    if (mDisplay && mDisplay->mOperationRateManager) {
+        mDisplay->mOperationRateManager->onPeakRefreshRate(rate);
+        return ndk::ScopedAStatus::ok();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Display::setLowPowerMode(bool enabled) {
+    if (mDisplay && mDisplay->mOperationRateManager) {
+        mDisplay->mOperationRateManager->onLowPowerMode(enabled);
+        return ndk::ScopedAStatus::ok();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Display::isOperationRateSupported(bool *_aidl_return) {
+    if (mDisplay) {
+        *_aidl_return = mDisplay->isOperationRateSupported();
+        return ndk::ScopedAStatus::ok();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 ndk::ScopedAStatus Display::setCompensationImageHandle(const NativeHandle &native_handle,
                                                        const std::string &imageName,
                                                        int *_aidl_return) {
@@ -175,19 +199,38 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
-bool Display::runMediator(const RoiRect roi, const Weight weight, const HistogramPos pos,
+bool Display::runMediator(const RoiRect &roi, const Weight &weight, const HistogramPos &pos,
                             std::vector<char16_t> *histogrambuffer) {
-    if (mMediator.setRoiWeightThreshold(roi, weight, pos) != HistogramErrorCode::NONE) {
-        ALOGE("histogram error, SET_ROI_WEIGHT_THRESHOLD ERROR\n");
-        return false;
+    bool isConfigChanged;
+    histogram::HistogramMediator::HistogramConfig pendingConfig(roi, weight, pos);
+
+    {
+        std::unique_lock<std::mutex> lk(mMediator.mConfigMutex);
+        isConfigChanged = mMediator.mConfig != pendingConfig;
+
+        if (isConfigChanged &&
+            mMediator.setRoiWeightThreshold(roi, weight, pos) != HistogramErrorCode::NONE) {
+            ALOGE("histogram error, SET_ROI_WEIGHT_THRESHOLD ERROR\n");
+            return false;
+        }
+
+        mMediator.mConfig = pendingConfig;
     }
+
     if (!mMediator.histRequested() &&
         mMediator.requestHist() == HistogramErrorCode::ENABLE_HIST_ERROR) {
         ALOGE("histogram error, ENABLE_HIST ERROR\n");
     }
-    if (mMediator.getFrameCount() != mMediator.getSampleFrameCounter()) {
-        mDisplay->mDevice->onRefresh(mDisplay->mDisplayId); // DRM not busy & sampled frame changed
+
+    /*
+     * DPU driver maintains always-on histogram engine state with up to date histogram data.
+     * Therefore we don't have explicitly to trigger onRefresh in case histogram configuration
+     * does not change.
+     */
+    if (isConfigChanged) {
+        mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
     }
+
     if (mMediator.collectRoiLuma(histogrambuffer) != HistogramErrorCode::NONE) {
         ALOGE("histogram error, COLLECT_ROI_LUMA ERROR\n");
         return false;
diff --git a/libhwc2.1/pixel-display.h b/libhwc2.1/pixel-display.h
index b1696d5..df437af 100644
--- a/libhwc2.1/pixel-display.h
+++ b/libhwc2.1/pixel-display.h
@@ -61,9 +61,12 @@
     ndk::ScopedAStatus getPanelCalibrationStatus(PanelCalibrationStatus *_aidl_return) override;
     ndk::ScopedAStatus isDbmSupported(bool *_aidl_return) override;
     ndk::ScopedAStatus setDbmState(bool enabled) override;
+    ndk::ScopedAStatus setPeakRefreshRate(int rate) override;
+    ndk::ScopedAStatus setLowPowerMode(bool enabled) override;
+    ndk::ScopedAStatus isOperationRateSupported(bool *_aidl_return) override;
 
 private:
-    bool runMediator(const RoiRect roi, const Weight weight, const HistogramPos pos,
+    bool runMediator(const RoiRect &roi, const Weight &weight, const HistogramPos &pos,
                        std::vector<char16_t> *histogrambuffer);
     ExynosDisplay *mDisplay = nullptr;
     histogram::HistogramMediator mMediator;
diff --git a/libhwjpeg/Android.bp b/libhwjpeg/Android.bp
index 3ac4d6e..86dc84d 100644
--- a/libhwjpeg/Android.bp
+++ b/libhwjpeg/Android.bp
@@ -10,6 +10,7 @@
         "AppMarkerWriter.cpp",
         "ExynosJpegEncoder.cpp",
         "ExynosJpegEncoderForCamera.cpp",
+        "FileLock.cpp",
         "hwjpeg-base.cpp",
         "hwjpeg-v4l2.cpp",
         "libhwjpeg-exynos.cpp",
@@ -24,6 +25,9 @@
         "libhardware_headers",
         "libsystem_headers",
     ],
+    export_header_lib_headers: [
+        "google_hal_headers",
+    ],
     shared_libs: [
         "liblog",
         "libutils",
diff --git a/libhwjpeg/AppMarkerWriter.cpp b/libhwjpeg/AppMarkerWriter.cpp
index 4a5edbb..f9eb12b 100644
--- a/libhwjpeg/AppMarkerWriter.cpp
+++ b/libhwjpeg/AppMarkerWriter.cpp
@@ -15,22 +15,22 @@
  * limitations under the License.
  */
 
-#include "hwjpeg-internal.h"
 #include "AppMarkerWriter.h"
-#include "IFDWriter.h"
 
-static const char ExifAsciiPrefix[] = { 'A', 'S', 'C', 'I', 'I', 0x0, 0x0, 0x0 };
-static const char ExifIdentifierCode[6] = { 'E', 'x', 'i', 'f', 0x00, 0x00 };
-static char TiffHeader[8] = { 'I', 'I', 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 };
-static const unsigned char ComponentsConfiguration[4] = { 1, 2, 3, 0 }; // YCbCr
-static const unsigned char SceneType[4] = { 1, 0, 0, 0 }; // A directly photographed image
+#include "IFDWriter.h"
+#include "hwjpeg-internal.h"
+
+static const char ExifAsciiPrefix[] = {'A', 'S', 'C', 'I', 'I', 0x0, 0x0, 0x0};
+static const char ExifIdentifierCode[6] = {'E', 'x', 'i', 'f', 0x00, 0x00};
+static char TiffHeader[8] = {'I', 'I', 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00};
+static const unsigned char ComponentsConfiguration[4] = {1, 2, 3, 0}; // YCbCr
+static const unsigned char SceneType[4] = {1, 0, 0, 0}; // A directly photographed image
 
 #ifndef __LITTLE_ENDIAN__
 CEndianessChecker __LITTLE_ENDIAN__;
 #endif
 
-CEndianessChecker::CEndianessChecker()
-{
+CEndianessChecker::CEndianessChecker() {
     int num = 1;
     __little = (*reinterpret_cast<char *>(&num) == 1);
     if (__little) {
@@ -42,15 +42,12 @@
     }
 }
 
-
 CAppMarkerWriter::CAppMarkerWriter()
-        : m_pAppBase(NULL), m_pApp1End(NULL), m_pExif(NULL), m_pExtra(NULL)
-{
+      : m_pAppBase(NULL), m_pApp1End(NULL), m_pExif(NULL), m_pExtra(NULL) {
     Init();
 }
 
-CAppMarkerWriter::CAppMarkerWriter(char *base, exif_attribute_t *exif, debug_attribute_t *debug)
-{
+CAppMarkerWriter::CAppMarkerWriter(char *base, exif_attribute_t *exif, debug_attribute_t *debug) {
     extra_appinfo_t extraInfo;
     app_info_t appInfo[15];
 
@@ -64,8 +61,7 @@
     PrepareAppWriter(base, exif, &extraInfo);
 }
 
-void CAppMarkerWriter::Init()
-{
+void CAppMarkerWriter::Init() {
     m_pApp1End = NULL;
 
     m_szApp1 = 0;
@@ -85,8 +81,8 @@
     m_pThumbSizePlaceholder = NULL;
 }
 
-void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extra_appinfo_t *extra)
-{
+void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif,
+                                        extra_appinfo_t *extra) {
     m_pAppBase = base;
     m_pExif = exif;
 
@@ -96,8 +92,7 @@
 
     if (exif) {
         // APP1
-        applen += JPEG_SEGMENT_LENFIELD_SIZE +
-                  ARRSIZE(ExifIdentifierCode) + ARRSIZE(TiffHeader);
+        applen += JPEG_SEGMENT_LENFIELD_SIZE + ARRSIZE(ExifIdentifierCode) + ARRSIZE(TiffHeader);
 
         // 0th IFD: Make, Model, Orientation, Software,
         //          DateTime, YCbCrPositioning, X/Y Resolutions, Exif and GPS
@@ -112,24 +107,21 @@
         if (m_szMake > 0) {
             m_n0thIFDFields++;
             applen += IFD_FIELD_SIZE;
-            if (m_szMake > 3)
-                    applen += m_szMake + 1;
+            if (m_szMake > 3) applen += m_szMake + 1;
         }
 
         m_szSoftware = strlen(m_pExif->software);
         if (m_szSoftware > 0) {
             m_n0thIFDFields++;
             applen += IFD_FIELD_SIZE;
-            if (m_szSoftware > 3)
-                    applen += m_szSoftware + 1;
+            if (m_szSoftware > 3) applen += m_szSoftware + 1;
         }
 
         m_szModel = strlen(m_pExif->model);
         if (m_szModel > 0) {
             m_n0thIFDFields++;
             applen += IFD_FIELD_SIZE;
-            if (m_szModel > 3)
-                applen += m_szModel + 1;
+            if (m_szModel > 3) applen += m_szModel + 1;
         }
 
         if (m_pExif->enableGps) {
@@ -144,11 +136,11 @@
          * - Flash, FlashPixVersion, ColorSpace, PixelXDimension, PixelYDimension,
          * - ExposureMode, WhiteBalance, FocalLengthIn35mmFilm, SceneCaptureType,
          * - ComponentsConfiguration
-	 * - SceneType, CustomRendered, Contrast, Saturation, Sharpness
+         * - SceneType, CustomRendered, Contrast, Saturation, Sharpness
          * (S)Rational Fields: 9
          * - ExposureTime, FNumber, ShutterSpeedValue, ApertureValue,
          * - BrightnessValue, ExposureBiasValue, MaxApertureValue, FocalLength
-	 * - DigitalZoomRatio
+         * - DigitalZoomRatio
          * ASCII Fields: 6
          * - DateTimeOriginal, DateTimeDigitized, SubsecTime, SubsecTimeOriginal,
          * - SubsecTimeDigitized, ImageUniqueID
@@ -174,28 +166,24 @@
         if (m_szUniqueID > 0) {
             m_nExifIFDFields++;
             applen += IFD_FIELD_SIZE;
-            if (m_szUniqueID > 3)
-                applen += m_szUniqueID + 1;
+            if (m_szUniqueID > 3) applen += m_szUniqueID + 1;
         }
 
         if (m_pExif->maker_note_size > 0) {
             m_nExifIFDFields++;
             applen += IFD_FIELD_SIZE;
-            if (m_pExif->maker_note_size > 4)
-                applen += m_pExif->maker_note_size;
+            if (m_pExif->maker_note_size > 4) applen += m_pExif->maker_note_size;
         }
 
         if (m_pExif->user_comment_size > 0) {
             m_nExifIFDFields++;
             applen += IFD_FIELD_SIZE;
-            if (m_pExif->user_comment_size > 4)
-                applen += m_pExif->user_comment_size;
+            if (m_pExif->user_comment_size > 4) applen += m_pExif->user_comment_size;
         }
 
         // Interoperability SubIFD
         m_nExifIFDFields++; // Interoperability is sub IFD of Exif sub IFD
-        applen += IFD_FIELD_SIZE +
-                  IFD_FIELDCOUNT_SIZE + IFD_VALOFF_SIZE + IFD_FIELD_SIZE * 2;
+        applen += IFD_FIELD_SIZE + IFD_FIELDCOUNT_SIZE + IFD_VALOFF_SIZE + IFD_FIELD_SIZE * 2;
 
         if (m_pExif->enableGps) {
             size_t len;
@@ -233,8 +221,8 @@
              * - JPEGInterchangeFormat, JPEGInterchangeFormatLength
              */
             if ((m_pExif->widthThumb < 16) || (m_pExif->heightThumb < 16)) {
-                ALOGE("Insufficient thumbnail information %dx%d",
-                      m_pExif->widthThumb, m_pExif->heightThumb);
+                ALOGE("Insufficient thumbnail information %dx%d", m_pExif->widthThumb,
+                      m_pExif->heightThumb);
                 return;
             }
 
@@ -251,13 +239,17 @@
 
     if (extra) {
         for (int idx = 0; idx < extra->num_of_appmarker; idx++) {
-            if ((extra->appInfo[idx].appid < EXTRA_APPMARKER_MIN) || (extra->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) {
+            if ((extra->appInfo[idx].appid < EXTRA_APPMARKER_MIN) ||
+                (extra->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) {
                 ALOGE("Invalid extra APP segment ID %d", extra->appInfo[idx].appid);
                 return;
             }
 
-            if ((extra->appInfo[idx].dataSize == 0) || (extra->appInfo[idx].dataSize > (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) {
-                ALOGE("Invalid APP%d segment size, %u bytes", extra->appInfo[idx].appid, extra->appInfo[idx].dataSize);
+            if ((extra->appInfo[idx].dataSize == 0) ||
+                (extra->appInfo[idx].dataSize >
+                 (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) {
+                ALOGE("Invalid APP%d segment size, %u bytes", extra->appInfo[idx].appid,
+                      extra->appInfo[idx].dataSize);
                 return;
             }
 
@@ -268,7 +260,7 @@
     m_pExtra = extra;
 
     //     |<- m_szApp1 ->|<- m_szMaxThumbSize ->|<-m_szAppX->|
-    //     |<----- size of total APP1 and APP4 segments ----->|<-APP11->|<-- main image
+    //     |<----- size of total APP1 and APPX segments ----->|<-APP11->|<-- main image
     // m_pAppBase   m_pThumbBase                 |            |    return
     //     |              |                      |            |        ||
     //     v              v                      |            |        v|
@@ -283,20 +275,16 @@
 }
 
 #define APPMARKLEN (JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE)
-char *CAppMarkerWriter::WriteAPP11(char *current, size_t dummy, size_t align)
-{
+char *CAppMarkerWriter::WriteAPP11(char *current, size_t dummy, size_t align) {
     ALOG_ASSERT((align & ~align) == 0);
 
-    if ((dummy == 0) && (align == 1))
-        return current;
+    if ((dummy == 0) && (align == 1)) return current;
 
-    if (!m_pExif && !m_pExtra)
-        return current;
+    if (!m_pExif && !m_pExtra) return current;
 
     uint16_t len = PTR_TO_ULONG(current + APPMARKLEN) & (align - 1);
 
-    if (len)
-        len = align - len;
+    if (len) len = align - len;
 
     len += dummy + JPEG_SEGMENT_LENFIELD_SIZE;
 
@@ -307,10 +295,8 @@
     return current + len;
 }
 
-char *CAppMarkerWriter::WriteAPPX(char *current, bool just_reserve)
-{
-    if (!m_pExtra)
-        return current;
+char *CAppMarkerWriter::WriteAPPX(char *current, bool just_reserve) {
+    if (!m_pExtra) return current;
 
     for (int idx = 0; idx < m_pExtra->num_of_appmarker; idx++) {
         int appid = m_pExtra->appInfo[idx].appid;
@@ -330,10 +316,8 @@
     return current;
 }
 
-char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, bool updating)
-{
-    if (!m_pExif)
-        return current;
+char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, bool updating) {
+    if (!m_pExif) return current;
 
     // APP1 Marker
     *current++ = 0xFF;
@@ -344,18 +328,15 @@
         current += JPEG_SEGMENT_LENFIELD_SIZE;
     } else {
         uint16_t len = m_szApp1;
-        if (reserve_thumbnail_space)
-            len += m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED;
+        if (reserve_thumbnail_space) len += m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED;
         current = WriteDataInBig(current, len);
     }
 
     // Exif Identifier
-    for (size_t i = 0; i < ARRSIZE(ExifIdentifierCode); i++)
-        *current++ = ExifIdentifierCode[i];
+    for (size_t i = 0; i < ARRSIZE(ExifIdentifierCode); i++) *current++ = ExifIdentifierCode[i];
 
     char *tiffheader = current;
-    for (size_t i = 0; i < ARRSIZE(TiffHeader); i++)
-        *current++ = TiffHeader[i];
+    for (size_t i = 0; i < ARRSIZE(TiffHeader); i++) *current++ = TiffHeader[i];
 
     CIFDWriter writer(tiffheader, current, m_n0thIFDFields);
 
@@ -364,12 +345,9 @@
     writer.WriteRational(EXIF_TAG_X_RESOLUTION, 1, &m_pExif->x_resolution);
     writer.WriteRational(EXIF_TAG_Y_RESOLUTION, 1, &m_pExif->y_resolution);
     writer.WriteShort(EXIF_TAG_RESOLUTION_UNIT, 1, &m_pExif->resolution_unit);
-    if (m_szMake > 0)
-        writer.WriteASCII(EXIF_TAG_MAKE, m_szMake + 1, m_pExif->maker);
-    if (m_szModel > 0)
-        writer.WriteASCII(EXIF_TAG_MODEL, m_szModel + 1, m_pExif->model);
-    if (m_szSoftware > 0)
-        writer.WriteASCII(EXIF_TAG_SOFTWARE, m_szSoftware + 1, m_pExif->software);
+    if (m_szMake > 0) writer.WriteASCII(EXIF_TAG_MAKE, m_szMake + 1, m_pExif->maker);
+    if (m_szModel > 0) writer.WriteASCII(EXIF_TAG_MODEL, m_szModel + 1, m_pExif->model);
+    if (m_szSoftware > 0) writer.WriteASCII(EXIF_TAG_SOFTWARE, m_szSoftware + 1, m_pExif->software);
     writer.WriteCString(EXIF_TAG_DATE_TIME, EXIF_DATETIME_LENGTH, m_pExif->date_time);
 
     char *pSubIFDBase = writer.BeginSubIFD(EXIF_TAG_EXIF_IFD_POINTER);
@@ -379,9 +357,11 @@
         exifwriter.WriteRational(EXIF_TAG_FNUMBER, 1, &m_pExif->fnumber);
         exifwriter.WriteShort(EXIF_TAG_EXPOSURE_PROGRAM, 1, &m_pExif->exposure_program);
         exifwriter.WriteShort(EXIF_TAG_ISO_SPEED_RATING, 1, &m_pExif->iso_speed_rating);
-        exifwriter.WriteUndef(EXIF_TAG_EXIF_VERSION, 4, reinterpret_cast<unsigned char *>(m_pExif->exif_version));
+        exifwriter.WriteUndef(EXIF_TAG_EXIF_VERSION, 4,
+                              reinterpret_cast<unsigned char *>(m_pExif->exif_version));
         exifwriter.WriteCString(EXIF_TAG_DATE_TIME_ORG, EXIF_DATETIME_LENGTH, m_pExif->date_time);
-        exifwriter.WriteCString(EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_DATETIME_LENGTH, m_pExif->date_time);
+        exifwriter.WriteCString(EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_DATETIME_LENGTH,
+                                m_pExif->date_time);
         exifwriter.WriteSRational(EXIF_TAG_SHUTTER_SPEED, 1, &m_pExif->shutter_speed);
         exifwriter.WriteRational(EXIF_TAG_APERTURE, 1, &m_pExif->aperture);
         exifwriter.WriteSRational(EXIF_TAG_BRIGHTNESS, 1, &m_pExif->brightness);
@@ -389,16 +369,21 @@
         exifwriter.WriteRational(EXIF_TAG_MAX_APERTURE, 1, &m_pExif->max_aperture);
         exifwriter.WriteShort(EXIF_TAG_METERING_MODE, 1, &m_pExif->metering_mode);
         exifwriter.WriteShort(EXIF_TAG_FLASH, 1, &m_pExif->flash);
-        exifwriter.WriteUndef(EXIF_TAG_FLASHPIX_VERSION, 4, reinterpret_cast<const unsigned char *>("0100"));
+        exifwriter.WriteUndef(EXIF_TAG_FLASHPIX_VERSION, 4,
+                              reinterpret_cast<const unsigned char *>("0100"));
         exifwriter.WriteUndef(EXIF_TAG_COMPONENTS_CONFIGURATION, 4, ComponentsConfiguration);
         exifwriter.WriteRational(EXIF_TAG_FOCAL_LENGTH, 1, &m_pExif->focal_length);
         exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME, EXIF_SUBSECTIME_LENGTH, m_pExif->sec_time);
-        exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_ORIG, EXIF_SUBSECTIME_LENGTH, m_pExif->sec_time);
-        exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_DIG, EXIF_SUBSECTIME_LENGTH, m_pExif->sec_time);
+        exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_ORIG, EXIF_SUBSECTIME_LENGTH,
+                                m_pExif->sec_time);
+        exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_DIG, EXIF_SUBSECTIME_LENGTH,
+                                m_pExif->sec_time);
         if (m_pExif->maker_note_size > 0)
-            exifwriter.WriteUndef(EXIF_TAG_MAKER_NOTE, m_pExif->maker_note_size, m_pExif->maker_note);
+            exifwriter.WriteUndef(EXIF_TAG_MAKER_NOTE, m_pExif->maker_note_size,
+                                  m_pExif->maker_note);
         if (m_pExif->user_comment_size > 0)
-            exifwriter.WriteUndef(EXIF_TAG_USER_COMMENT, m_pExif->user_comment_size, m_pExif->user_comment);
+            exifwriter.WriteUndef(EXIF_TAG_USER_COMMENT, m_pExif->user_comment_size,
+                                  m_pExif->user_comment);
         exifwriter.WriteShort(EXIF_TAG_COLOR_SPACE, 1, &m_pExif->color_space);
         exifwriter.WriteLong(EXIF_TAG_PIXEL_X_DIMENSION, 1, &m_pExif->width);
         exifwriter.WriteLong(EXIF_TAG_PIXEL_Y_DIMENSION, 1, &m_pExif->height);
@@ -407,7 +392,8 @@
         exifwriter.WriteShort(EXIF_TAG_EXPOSURE_MODE, 1, &m_pExif->exposure_mode);
         exifwriter.WriteShort(EXIF_TAG_WHITE_BALANCE, 1, &m_pExif->white_balance);
         exifwriter.WriteRational(EXIF_TAG_DIGITAL_ZOOM_RATIO, 1, &m_pExif->digital_zoom_ratio);
-        exifwriter.WriteShort(EXIF_TAG_FOCA_LENGTH_IN_35MM_FILM, 1, &m_pExif->focal_length_in_35mm_length);
+        exifwriter.WriteShort(EXIF_TAG_FOCA_LENGTH_IN_35MM_FILM, 1,
+                              &m_pExif->focal_length_in_35mm_length);
         exifwriter.WriteShort(EXIF_TAG_SCENCE_CAPTURE_TYPE, 1, &m_pExif->scene_capture_type);
         exifwriter.WriteShort(EXIF_TAG_CONTRAST, 1, &m_pExif->contrast);
         exifwriter.WriteShort(EXIF_TAG_SATURATION, 1, &m_pExif->saturation);
@@ -451,9 +437,9 @@
                 size_t idx;
                 len = min(len, static_cast<size_t>(99UL));
                 unsigned char buf[sizeof(ExifAsciiPrefix) + len + 1];
-                for (idx = 0; idx < sizeof(ExifAsciiPrefix); idx++)
-                    buf[idx] = ExifAsciiPrefix[idx];
-                strncpy(reinterpret_cast<char *>(buf) + idx, m_pExif->gps_processing_method, len + 1);
+                for (idx = 0; idx < sizeof(ExifAsciiPrefix); idx++) buf[idx] = ExifAsciiPrefix[idx];
+                strncpy(reinterpret_cast<char *>(buf) + idx, m_pExif->gps_processing_method,
+                        len + 1);
                 len += idx;
                 buf[len] = '\0';
                 gpswriter.WriteUndef(EXIF_TAG_GPS_PROCESSING_METHOD, len + 1, buf);
@@ -466,8 +452,7 @@
     }
 
     // thumbnail and the next IFD pointer is never updated.
-    if (updating)
-        return NULL;
+    if (updating) return NULL;
 
     if (m_pExif->enableThumb) {
         writer.Finish(false);
@@ -496,16 +481,14 @@
     return writer.GetNextIFDBase();
 }
 
-void CAppMarkerWriter::Finalize(size_t thumbsize)
-{
+void CAppMarkerWriter::Finalize(size_t thumbsize) {
     if (m_pThumbSizePlaceholder) {
         uint32_t len = static_cast<uint32_t>(thumbsize);
         WriteData(m_pThumbSizePlaceholder, len);
         m_pThumbSizePlaceholder = NULL;
     }
 }
-void CAppMarkerWriter::UpdateApp1Size(size_t amount)
-{
+void CAppMarkerWriter::UpdateApp1Size(size_t amount) {
     if (m_pAppBase) {
         uint16_t len = m_szApp1 + amount;
         WriteDataInBig(m_pAppBase + JPEG_MARKER_SIZE, len);
@@ -514,24 +497,25 @@
 
 static const char *dbgerrmsg = "Updating debug data failed";
 
-static inline size_t GetSegLen(char *p)
-{
+static inline size_t GetSegLen(char *p) {
     size_t len = (*reinterpret_cast<unsigned char *>(p) & 0xFF) << 8;
     return len | (*reinterpret_cast<unsigned char *>(p + 1) & 0xFF);
 }
 
-static inline size_t GetExtraAPPSize(extra_appinfo_t *info)
-{
+static inline size_t GetExtraAPPSize(extra_appinfo_t *info) {
     size_t len = 0;
 
     for (int idx = 0; idx < info->num_of_appmarker; idx++) {
-        if ((info->appInfo[idx].appid < EXTRA_APPMARKER_MIN) || (info->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) {
+        if ((info->appInfo[idx].appid < EXTRA_APPMARKER_MIN) ||
+            (info->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) {
             ALOGE("%s: Invalid extra APP segment ID %d", dbgerrmsg, info->appInfo[idx].appid);
             return 0;
         }
 
-        if ((info->appInfo[idx].dataSize == 0) || (info->appInfo[idx].dataSize > (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) {
-            ALOGE("%s: Invalid APP%d segment size, %u bytes.", dbgerrmsg, info->appInfo[idx].appid, info->appInfo[idx].dataSize);
+        if ((info->appInfo[idx].dataSize == 0) ||
+            (info->appInfo[idx].dataSize > (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) {
+            ALOGE("%s: Invalid APP%d segment size, %u bytes.", dbgerrmsg, info->appInfo[idx].appid,
+                  info->appInfo[idx].dataSize);
             return 0;
         }
 
@@ -594,34 +578,33 @@
         }
 
         appid = marker & 0xF;
-        if (((marker & 0xF0) == 0xE0) && ((appid >= EXTRA_APPMARKER_MIN) && (appid <= EXTRA_APPMARKER_LIMIT))) {
+        if (((marker & 0xF0) == 0xE0) &&
+            ((appid >= EXTRA_APPMARKER_MIN) && (appid <= EXTRA_APPMARKER_LIMIT))) {
             if (appid != extra->appInfo[idx].appid) {
-                ALOGE("%s: stored appid(%d) is different with updated appid(%d)",
-                        dbgerrmsg, appid, extra->appInfo[idx].appid);
+                ALOGE("%s: stored appid(%d) is different with updated appid(%d)", dbgerrmsg, appid,
+                      extra->appInfo[idx].appid);
                 return false;
             }
 
             seglen = GetSegLen(jpeg);
             if (seglen < (extra->appInfo[idx].dataSize + JPEG_SEGMENT_LENFIELD_SIZE)) {
-                ALOGE("%s: too small APP%d length %zu to store %u bytes",
-                        dbgerrmsg, appid, seglen, extra->appInfo[idx].dataSize);
+                ALOGE("%s: too small APP%d length %zu to store %u bytes", dbgerrmsg, appid, seglen,
+                      extra->appInfo[idx].dataSize);
                 return false;
             }
 
-            memcpy(jpeg + JPEG_SEGMENT_LENFIELD_SIZE,
-                    extra->appInfo[idx].appData, extra->appInfo[idx].dataSize);
+            memcpy(jpeg + JPEG_SEGMENT_LENFIELD_SIZE, extra->appInfo[idx].appData,
+                   extra->appInfo[idx].dataSize);
             ALOGD("Successfully updated %u bytes to APP%d", extra->appInfo[idx].dataSize, appid);
 
-            validlen -= extra->appInfo[idx].dataSize + JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE;
+            validlen -=
+                    extra->appInfo[idx].dataSize + JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE;
             idx++;
         } else {
             // just skip all other segments
             seglen = GetSegLen(jpeg);
-            if (seglen == 0)
-                seglen++; // fixup for invalid segment lengths
-            if (jpeglen < seglen)
-                seglen = jpeglen;
-
+            if (seglen == 0) seglen++; // fixup for invalid segment lengths
+            if (jpeglen < seglen) seglen = jpeglen;
         }
 
         jpeg += seglen;
@@ -633,8 +616,7 @@
 
 static const char *exiferrmsg = "Updating exif failed";
 
-bool UpdateExif(char *jpeg, size_t jpeglen, exif_attribute_t *exif)
-{
+bool UpdateExif(char *jpeg, size_t jpeglen, exif_attribute_t *exif) {
     if (!exif) {
         ALOGI("No Exif to update");
         return true;
@@ -668,8 +650,7 @@
     return true;
 }
 
-void ExtractDebugAttributeInfo(debug_attribute_t *debug, extra_appinfo_t *extra)
-{
+void ExtractDebugAttributeInfo(debug_attribute_t *debug, extra_appinfo_t *extra) {
     if (!debug) {
         extra->num_of_appmarker = 0;
         return;
diff --git a/libhwjpeg/AppMarkerWriter.h b/libhwjpeg/AppMarkerWriter.h
index 5232e31..a25d9c0 100644
--- a/libhwjpeg/AppMarkerWriter.h
+++ b/libhwjpeg/AppMarkerWriter.h
@@ -18,6 +18,8 @@
 #define __HARDWARE_SAMSUNG_SLSI_EXYNOS_APPMARKER_WRITER_H__
 
 #include <ExynosExif.h>
+
+#include "hwjpeg-internal.h"
 #include "include/hardware/exynos/ExynosExif.h"
 
 #define JPEG_MAX_SEGMENT_SIZE ((1 << 16) - 1)
@@ -33,10 +35,9 @@
 #define IFD_COUNT_SIZE 4
 #define IFD_VALOFF_SIZE 4
 
-#define IFD_FIELD_SIZE \
-            (IFD_TAG_SIZE + IFD_TYPE_SIZE + IFD_COUNT_SIZE + IFD_VALOFF_SIZE)
+#define IFD_FIELD_SIZE (IFD_TAG_SIZE + IFD_TYPE_SIZE + IFD_COUNT_SIZE + IFD_VALOFF_SIZE)
 
-#define EXTRA_APPMARKER_MIN 4
+#define EXTRA_APPMARKER_MIN 2
 #define EXTRA_APPMARKER_LIMIT 10
 
 #define MAX_GPS_PROCESSINGMETHOD_SIZE 108
@@ -49,8 +50,8 @@
     char *m_pAppBase;
     char *m_pApp1End;
     size_t m_szMaxThumbSize; // Maximum available thumbnail stream size minus JPEG_MARKER_SIZE
-    uint16_t m_szApp1; // The size of APP1 segment without marker
-    uint16_t m_szApp11; // The size of APP11 segment without marker
+    uint16_t m_szApp1;       // The size of APP1 segment without marker
+    uint16_t m_szApp11;      // The size of APP11 segment without marker
     uint16_t m_n0thIFDFields;
     uint16_t m_n1stIFDFields;
     uint16_t m_nExifIFDFields;
@@ -76,6 +77,7 @@
     char *WriteAPP1(char *base, bool reserve_thumbnail_space, bool updating = false);
     char *WriteAPPX(char *base, bool just_reserve);
     char *WriteAPP11(char *current, size_t dummy, size_t align);
+
 public:
     // dummy: number of dummy bytes written by the compressor of the main image
     // this dummy size should be added to the APP1 length. Howerver, this dummy area
@@ -84,7 +86,7 @@
     CAppMarkerWriter();
     CAppMarkerWriter(char *base, exif_attribute_t *exif, debug_attribute_t *debug);
 
-    ~CAppMarkerWriter() { }
+    ~CAppMarkerWriter() {}
 
     void PrepareAppWriter(char *base, exif_attribute_t *exif, extra_appinfo_t *info);
 
@@ -100,15 +102,14 @@
     // CalculateAPPSize() is valid after Write() is successful.
     size_t CalculateAPPSize(size_t thumblen = JPEG_MAX_SEGMENT_SIZE) {
         size_t appsize = 0;
-        if (m_szApp1 > 0)
-            appsize += m_szApp1 + JPEG_MARKER_SIZE;
+        if (m_szApp1 > 0) appsize += m_szApp1 + JPEG_MARKER_SIZE;
         if (m_pExtra) {
             for (int idx = 0; idx < m_pExtra->num_of_appmarker; idx++)
-                appsize += m_pExtra->appInfo[idx].dataSize +
-                           + JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE;
+                appsize += m_pExtra->appInfo[idx].dataSize + +JPEG_MARKER_SIZE +
+                        JPEG_SEGMENT_LENFIELD_SIZE;
         }
         if (IsThumbSpaceReserved())
-            appsize += m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED ;
+            appsize += m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED;
         else
             appsize += min(m_szMaxThumbSize, thumblen);
 
@@ -117,7 +118,8 @@
 
     char *GetApp1End() { return m_pApp1End; }
 
-    void Write(bool reserve_thumbnail_space, size_t dummy, size_t align, bool reserve_debug = false) {
+    void Write(bool reserve_thumbnail_space, size_t dummy, size_t align,
+               bool reserve_debug = false) {
         m_pApp1End = WriteAPP1(m_pAppBase, reserve_thumbnail_space);
         char *appXend = WriteAPPX(m_pApp1End, reserve_debug);
         char *app11end = WriteAPP11(appXend, dummy, align);
@@ -129,7 +131,7 @@
 
     bool IsThumbSpaceReserved() {
         return PTR_DIFF(m_pAppBase, m_pApp1End) ==
-			(m_szApp1 + m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED + JPEG_MARKER_SIZE);
+                (m_szApp1 + m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED + JPEG_MARKER_SIZE);
     }
 
     void Finalize(size_t thumbsize);
diff --git a/libhwjpeg/ExynosJpegEncoder.cpp b/libhwjpeg/ExynosJpegEncoder.cpp
index 39e7a2e..d833ca7 100644
--- a/libhwjpeg/ExynosJpegEncoder.cpp
+++ b/libhwjpeg/ExynosJpegEncoder.cpp
@@ -15,24 +15,27 @@
  * limitations under the License.
  */
 
-#include <linux/videodev2.h>
-
 #include <ExynosJpegApi.h>
+#include <linux/videodev2.h>
 
 #include "hwjpeg-internal.h"
 
-int ExynosJpegEncoder::setJpegConfig(void* pConfig)
-{
+int ExynosJpegEncoder::lock() {
+    return m_hwjpeg.lock();
+}
+
+int ExynosJpegEncoder::unlock() {
+    return m_hwjpeg.unlock();
+}
+
+int ExynosJpegEncoder::setJpegConfig(void *pConfig) {
     ExynosJpegEncoder *that = reinterpret_cast<ExynosJpegEncoder *>(pConfig);
 
-    if (!setColorFormat(that->m_v4l2Format))
-        return -1;
+    if (!setColorFormat(that->m_v4l2Format)) return -1;
 
-    if (!setJpegFormat(that->m_jpegFormat))
-        return -1;
+    if (!setJpegFormat(that->m_jpegFormat)) return -1;
 
-    if (!setSize(that->m_nWidth, that->m_nHeight))
-        return -1;
+    if (!setSize(that->m_nWidth, that->m_nHeight)) return -1;
 
     m_iInBufType = that->m_iInBufType;
     m_iOutBufType = that->m_iOutBufType;
@@ -40,127 +43,101 @@
     return 0;
 }
 
-int ExynosJpegEncoder::getInBuf(int *piBuf, int *piInputSize, int iSize)
-{
+int ExynosJpegEncoder::getInBuf(int *piBuf, int *piInputSize, int iSize) {
     if (iSize < 1) {
         ALOGE("Invalid array size %d for getInBuf()", iSize);
         return -1;
     }
 
     size_t len_buffers[iSize];
-    if (!m_hwjpeg.GetImageBuffers(piBuf, len_buffers, static_cast<unsigned int>(iSize)))
-        return -1;
+    if (!m_hwjpeg.GetImageBuffers(piBuf, len_buffers, static_cast<unsigned int>(iSize))) return -1;
 
-    for (int i = 0; i < iSize; i++)
-        piInputSize[i] = static_cast<int>(len_buffers[i]);
+    for (int i = 0; i < iSize; i++) piInputSize[i] = static_cast<int>(len_buffers[i]);
 
     return 0;
 }
 
-int ExynosJpegEncoder::getOutBuf(int *piBuf, int *piOutputSize)
-{
+int ExynosJpegEncoder::getOutBuf(int *piBuf, int *piOutputSize) {
     size_t len;
-    if (!m_hwjpeg.GetJpegBuffer(piBuf, &len))
-        return -1;
+    if (!m_hwjpeg.GetJpegBuffer(piBuf, &len)) return -1;
 
     *piOutputSize = static_cast<int>(len);
     return 0;
 }
 
-int ExynosJpegEncoder::setInBuf(int *piBuf, int *iSize)
-{
+int ExynosJpegEncoder::setInBuf(int *piBuf, int *iSize) {
     size_t buflen[3];
     unsigned int bufnum = 3;
 
-    if (!EnsureFormatIsApplied())
-        return -1;
+    if (!EnsureFormatIsApplied()) return -1;
 
-    if (!m_hwjpeg.GetImageBufferSizes(buflen, &bufnum))
-        return -1;
+    if (!m_hwjpeg.GetImageBufferSizes(buflen, &bufnum)) return -1;
 
-    for (unsigned int i = 0; i < bufnum; i++)
-        buflen[i] = static_cast<size_t>(iSize[i]);
+    for (unsigned int i = 0; i < bufnum; i++) buflen[i] = static_cast<size_t>(iSize[i]);
 
-    if (!m_hwjpeg.SetImageBuffer(piBuf, buflen, bufnum))
-        return -1;
+    if (!m_hwjpeg.SetImageBuffer(piBuf, buflen, bufnum)) return -1;
 
     m_iInBufType = JPEG_BUF_TYPE_DMA_BUF;
 
     return 0;
 }
 
-int ExynosJpegEncoder::setOutBuf(int iBuf, int iSize, int offset)
-{
-    if (!m_hwjpeg.SetJpegBuffer(iBuf, static_cast<size_t>(iSize), offset))
-        return -1;
+int ExynosJpegEncoder::setOutBuf(int iBuf, int iSize, int offset) {
+    if (!m_hwjpeg.SetJpegBuffer(iBuf, static_cast<size_t>(iSize), offset)) return -1;
 
     m_iOutBufType = JPEG_BUF_TYPE_DMA_BUF;
 
     return 0;
 }
 
-int ExynosJpegEncoder::getInBuf(char **pcBuf, int *piInputSize, int iSize)
-{
+int ExynosJpegEncoder::getInBuf(char **pcBuf, int *piInputSize, int iSize) {
     if (iSize < 1) {
         ALOGE("Invalid array size %d for getInBuf()", iSize);
         return -1;
     }
 
     size_t len_buffers[iSize];
-    if (!m_hwjpeg.GetImageBuffers(pcBuf, len_buffers, static_cast<unsigned int>(iSize)))
-        return -1;
+    if (!m_hwjpeg.GetImageBuffers(pcBuf, len_buffers, static_cast<unsigned int>(iSize))) return -1;
 
-    for (int i = 0; i < iSize; i++)
-        piInputSize[i] = static_cast<int>(len_buffers[i]);
+    for (int i = 0; i < iSize; i++) piInputSize[i] = static_cast<int>(len_buffers[i]);
 
     return 0;
 }
 
-int ExynosJpegEncoder::getOutBuf(char **pcBuf, int *piOutputSize)
-{
+int ExynosJpegEncoder::getOutBuf(char **pcBuf, int *piOutputSize) {
     size_t len;
-    if (!m_hwjpeg.GetJpegBuffer(pcBuf, &len))
-        return -1;
+    if (!m_hwjpeg.GetJpegBuffer(pcBuf, &len)) return -1;
 
     *piOutputSize = static_cast<int>(len);
     return 0;
 }
 
-int ExynosJpegEncoder::setInBuf(char **pcBuf, int *iSize)
-{
+int ExynosJpegEncoder::setInBuf(char **pcBuf, int *iSize) {
     size_t buflen[3];
     unsigned int bufnum = 3;
 
-    if (!EnsureFormatIsApplied())
-        return -1;
+    if (!EnsureFormatIsApplied()) return -1;
 
-    if (!m_hwjpeg.GetImageBufferSizes(buflen, &bufnum))
-        return -1;
+    if (!m_hwjpeg.GetImageBufferSizes(buflen, &bufnum)) return -1;
 
-    for (unsigned int i = 0; i < bufnum; i++)
-        buflen[i] = static_cast<size_t>(iSize[i]);
+    for (unsigned int i = 0; i < bufnum; i++) buflen[i] = static_cast<size_t>(iSize[i]);
 
-    if (!m_hwjpeg.SetImageBuffer(pcBuf, buflen, bufnum))
-        return -1;
+    if (!m_hwjpeg.SetImageBuffer(pcBuf, buflen, bufnum)) return -1;
 
     m_iInBufType = JPEG_BUF_TYPE_USER_PTR;
     return 0;
 }
 
-int ExynosJpegEncoder::setOutBuf(char *pcBuf, int iSize)
-{
-    if (!m_hwjpeg.SetJpegBuffer(pcBuf, static_cast<size_t>(iSize)))
-        return -1;
+int ExynosJpegEncoder::setOutBuf(char *pcBuf, int iSize) {
+    if (!m_hwjpeg.SetJpegBuffer(pcBuf, static_cast<size_t>(iSize))) return -1;
 
     m_iOutBufType = JPEG_BUF_TYPE_USER_PTR;
 
     return 0;
 }
 
-int ExynosJpegEncoder::setJpegFormat(int iV4l2JpegFormat)
-{
-    if (m_jpegFormat == iV4l2JpegFormat)
-        return 0;
+int ExynosJpegEncoder::setJpegFormat(int iV4l2JpegFormat) {
+    if (m_jpegFormat == iV4l2JpegFormat) return 0;
 
     unsigned int hfactor, vfactor;
     switch (iV4l2JpegFormat) {
@@ -193,31 +170,27 @@
             return -1;
     }
 
-    if (!m_hwjpeg.SetChromaSampFactor(hfactor, vfactor))
-        return -1;
+    if (!m_hwjpeg.SetChromaSampFactor(hfactor, vfactor)) return -1;
 
     m_jpegFormat = iV4l2JpegFormat;
 
     return 0;
 }
 
-int ExynosJpegEncoder::setColorBufSize(int *piBufSize, int iSize)
-{
+int ExynosJpegEncoder::setColorBufSize(int *piBufSize, int iSize) {
     size_t len[3];
     unsigned int num = static_cast<unsigned int>(iSize);
 
-    if (!m_hwjpeg.GetImageBufferSizes(len, &num))
-        return -1;
+    if (!m_hwjpeg.GetImageBufferSizes(len, &num)) return -1;
 
-    for (unsigned int i = 0; i < num; i++)
-        piBufSize[i] = static_cast<int>(len[i]);
+    for (unsigned int i = 0; i < num; i++) piBufSize[i] = static_cast<int>(len[i]);
 
     return 0;
 }
 
 bool ExynosJpegEncoder::__EnsureFormatIsApplied() {
     if (TestStateEither(STATE_SIZE_CHANGED | STATE_PIXFMT_CHANGED) &&
-            !m_hwjpeg.SetImageFormat(m_v4l2Format, m_nWidth, m_nHeight))
+        !m_hwjpeg.SetImageFormat(m_v4l2Format, m_nWidth, m_nHeight))
         return false;
 
     ClearState(STATE_SIZE_CHANGED | STATE_PIXFMT_CHANGED);
@@ -227,3 +200,7 @@
 int ExynosJpegEncoder::setQuality(const unsigned char q_table[]) {
     return m_hwjpeg.SetQuality(q_table) ? 0 : -1;
 }
+
+int ExynosJpegEncoder::setPadding(unsigned char *padding, unsigned int num_planes) {
+    return m_hwjpeg.SetPadding(padding, num_planes) ? 0 : -1;
+}
diff --git a/libhwjpeg/ExynosJpegEncoderForCamera.cpp b/libhwjpeg/ExynosJpegEncoderForCamera.cpp
index 741e05e..5e003aa 100644
--- a/libhwjpeg/ExynosJpegEncoderForCamera.cpp
+++ b/libhwjpeg/ExynosJpegEncoderForCamera.cpp
@@ -15,29 +15,24 @@
  * limitations under the License.
  */
 
+#include <ExynosJpegEncoderForCamera.h>
+#include <hardware/exynos/ion.h>
+#include <linux/videodev2.h>
 #include <sys/mman.h>
 #include <sys/types.h>
-
-#include <linux/videodev2.h>
-
-#include <hardware/exynos/ion.h>
 #include <system/graphics.h>
 
-#include <ExynosJpegEncoderForCamera.h>
-
-#include "hwjpeg-internal.h"
 #include "AppMarkerWriter.h"
 #include "ThumbnailScaler.h"
-#include "IFDWriter.h"
+#include "hwjpeg-internal.h"
 
 // Data length written by H/W without the scan data.
-#define NECESSARY_JPEG_LENGTH   (0x24B + 2 * JPEG_MARKER_SIZE)
+#define NECESSARY_JPEG_LENGTH (0x24B + 2 * JPEG_MARKER_SIZE)
 
-static size_t GetImageLength(unsigned int width, unsigned int height, int v4l2Format)
-{
+static size_t GetImageLength(unsigned int width, unsigned int height, int v4l2Format) {
     size_t size = width * height;
 
-    switch(v4l2Format) {
+    switch (v4l2Format) {
         case V4L2_PIX_FMT_YUYV:
         case V4L2_PIX_FMT_YVYU:
         case V4L2_PIX_FMT_UYVY:
@@ -57,22 +52,29 @@
     return 0;
 }
 
-static int GetThumbnailFormat(int v4l2Format)
-{
-        if (v4l2Format == V4L2_PIX_FMT_NV12M)
-            return V4L2_PIX_FMT_NV12;
-        else if (v4l2Format == V4L2_PIX_FMT_NV21M)
-            return V4L2_PIX_FMT_NV21;
-        else
-            return v4l2Format;
+static int GetThumbnailFormat(int v4l2Format) {
+    if (v4l2Format == V4L2_PIX_FMT_NV12M)
+        return V4L2_PIX_FMT_NV12;
+    else if (v4l2Format == V4L2_PIX_FMT_NV21M)
+        return V4L2_PIX_FMT_NV21;
+    else
+        return v4l2Format;
 }
 
 ExynosJpegEncoderForCamera::ExynosJpegEncoderForCamera(bool bBTBComp)
-        : m_phwjpeg4thumb(NULL), m_fdIONClient(-1), m_fdIONThumbImgBuffer(-1), m_pIONThumbImgBuffer(NULL),
-          m_szIONThumbImgBuffer(0), m_pIONThumbJpegBuffer(NULL), m_fdIONThumbJpegBuffer(-1), m_szIONThumbJpegBuffer(0),
-          m_nThumbWidth(0), m_nThumbHeight(0), m_nThumbQuality(0),
-          m_pStreamBase(NULL), m_fThumbBufferType(0)
-{
+      : m_phwjpeg4thumb(NULL),
+        m_fdIONClient(-1),
+        m_fdIONThumbImgBuffer(-1),
+        m_pIONThumbImgBuffer(NULL),
+        m_szIONThumbImgBuffer(0),
+        m_pIONThumbJpegBuffer(NULL),
+        m_fdIONThumbJpegBuffer(-1),
+        m_szIONThumbJpegBuffer(0),
+        m_nThumbWidth(0),
+        m_nThumbHeight(0),
+        m_nThumbQuality(0),
+        m_pStreamBase(NULL),
+        m_fThumbBufferType(0) {
     m_pAppWriter = new CAppMarkerWriter();
     if (!m_pAppWriter) {
         ALOGE("Failed to allocated an instance of CAppMarkerWriter");
@@ -94,52 +96,41 @@
         ALOGERR("Failed to create ION client for thumbnail conversion");
     }
 
-    if (!bBTBComp)
-        SetState(STATE_NO_BTBCOMP);
+    if (!bBTBComp) SetState(STATE_NO_BTBCOMP);
 
     // STATE_THUMBSIZE_CHANGED is to know if thumbnail image size need to be
     // configured to HWJPEG. If HWJPEG does not support for back-to-back
     // compression, it should not be configured.
-    if (IsBTBCompressionSupported())
-        SetState(STATE_THUMBSIZE_CHANGED);
+    if (IsBTBCompressionSupported()) SetState(STATE_THUMBSIZE_CHANGED);
 
     m_extraInfo.appInfo = m_appInfo;
 
     mThumbnailScaler.reset(ThumbnailScaler::createInstance());
-    if (!mThumbnailScaler->available())
-        ALOGW("Thumbnail scaler is not available.");
+    if (!mThumbnailScaler->available()) ALOGW("Thumbnail scaler is not available.");
 
     ALOGD("ExynosJpegEncoderForCamera Created: %p, ION %d", this, m_fdIONClient);
 }
 
-ExynosJpegEncoderForCamera::~ExynosJpegEncoderForCamera()
-{
+ExynosJpegEncoderForCamera::~ExynosJpegEncoderForCamera() {
     delete m_pAppWriter;
     delete m_phwjpeg4thumb;
 
-    if (m_pIONThumbImgBuffer != NULL)
-        munmap(m_pIONThumbImgBuffer, m_szIONThumbImgBuffer);
+    if (m_pIONThumbImgBuffer != NULL) munmap(m_pIONThumbImgBuffer, m_szIONThumbImgBuffer);
 
-    if (m_fdIONThumbImgBuffer >= 0)
-        close(m_fdIONThumbImgBuffer);
+    if (m_fdIONThumbImgBuffer >= 0) close(m_fdIONThumbImgBuffer);
 
-    if (m_pIONThumbJpegBuffer)
-        munmap(m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer);
+    if (m_pIONThumbJpegBuffer) munmap(m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer);
 
-    if (m_fdIONThumbJpegBuffer >= 0)
-        close(m_fdIONThumbJpegBuffer);
+    if (m_fdIONThumbJpegBuffer >= 0) close(m_fdIONThumbJpegBuffer);
 
-    if (m_fdIONClient >= 0)
-        exynos_ion_close(m_fdIONClient);
+    if (m_fdIONClient >= 0) exynos_ion_close(m_fdIONClient);
 
-    ALOGD("ExynosJpegEncoderForCamera Destroyed: %p, ION %d, ThumIMG %d",
-            this, m_fdIONClient, m_fdIONThumbImgBuffer);
+    ALOGD("ExynosJpegEncoderForCamera Destroyed: %p, ION %d, ThumIMG %d", this, m_fdIONClient,
+          m_fdIONThumbImgBuffer);
 }
 
-int ExynosJpegEncoderForCamera::setThumbnailSize(int w, int h)
-{
-    if ((m_nThumbWidth == w) && (m_nThumbHeight == h))
-        return 0;
+int ExynosJpegEncoderForCamera::setThumbnailSize(int w, int h) {
+    if ((m_nThumbWidth == w) && (m_nThumbHeight == h)) return 0;
 
     // w == 0 and h == 0 resets thumbnail configuration
     if (((w | h) != 0) && ((w < 16) || (h < 16))) {
@@ -150,16 +141,13 @@
     m_nThumbWidth = w;
     m_nThumbHeight = h;
 
-    if (IsBTBCompressionSupported())
-        SetState(STATE_THUMBSIZE_CHANGED);
+    if (IsBTBCompressionSupported()) SetState(STATE_THUMBSIZE_CHANGED);
 
     return 0;
 }
 
-int ExynosJpegEncoderForCamera::setThumbnailQuality(int quality)
-{
-    if (m_nThumbQuality == quality)
-        return 0;
+int ExynosJpegEncoderForCamera::setThumbnailQuality(int quality) {
+    if (m_nThumbQuality == quality) return 0;
 
     if ((quality > 100) || (quality < 1)) {
         ALOGE("Invalid quality factor %d for thumbnail image", quality);
@@ -171,6 +159,11 @@
     return GetCompressor().SetQuality(0, m_nThumbQuality) ? 0 : -1;
 }
 
+int ExynosJpegEncoderForCamera::setThumbnailPadding(unsigned char *padding,
+                                                    unsigned int num_planes) {
+    return GetCompressor().SetPadding2(padding, num_planes) ? 0 : -1;
+}
+
 bool ExynosJpegEncoderForCamera::EnsureFormatIsApplied() {
     if (TestStateEither(STATE_PIXFMT_CHANGED | STATE_SIZE_CHANGED | STATE_THUMBSIZE_CHANGED)) {
         int thumb_width = m_nThumbWidth;
@@ -184,8 +177,8 @@
         }
 
         getSize(&width, &height);
-        if (!GetCompressor().SetImageFormat(
-                    getColorFormat(), width, height, thumb_width, thumb_height))
+        if (!GetCompressor().SetImageFormat(getColorFormat(), width, height, thumb_width,
+                                            thumb_height))
             return false;
 
         ClearState(STATE_PIXFMT_CHANGED | STATE_SIZE_CHANGED | STATE_THUMBSIZE_CHANGED);
@@ -194,8 +187,7 @@
     return true;
 }
 
-size_t ExynosJpegEncoderForCamera::RemoveTrailingDummies(char *base, size_t len)
-{
+size_t ExynosJpegEncoderForCamera::RemoveTrailingDummies(char *base, size_t len) {
     ALOG_ASSERT(len > 4);
     ALOG_ASSERT((base[0] == 0xFF) && (base[1] == 0xD8)); // SOI marker
 
@@ -215,18 +207,15 @@
     return 0;
 }
 
-void *ExynosJpegEncoderForCamera::tCompressThumbnail(void *p)
-{
+void *ExynosJpegEncoderForCamera::tCompressThumbnail(void *p) {
     ExynosJpegEncoderForCamera *encoder = reinterpret_cast<ExynosJpegEncoderForCamera *>(p);
 
     size_t thumblen = encoder->CompressThumbnail();
     return reinterpret_cast<void *>(thumblen);
 }
 
-bool ExynosJpegEncoderForCamera::ProcessExif(char *base, size_t limit,
-                                             exif_attribute_t *exifInfo,
-                                             extra_appinfo_t *extra)
-{
+bool ExynosJpegEncoderForCamera::ProcessExif(char *base, size_t limit, exif_attribute_t *exifInfo,
+                                             extra_appinfo_t *extra) {
     // PREREQUISITES: The main and the thumbnail image size should be configured before.
 
     // Sanity chck
@@ -237,16 +226,16 @@
 
     if (exifInfo) {
         if ((exifInfo->width != width) || (exifInfo->height != height)) {
-            ALOGE("Inconsistant image dimension: Exif %dx%d, Thumb %dx%d",
-                    exifInfo->width, exifInfo->height, width, height);
+            ALOGE("Inconsistent image dimension: Exif %dx%d, Thumb %dx%d", exifInfo->width,
+                  exifInfo->height, width, height);
             return false;
         }
 
         if (exifInfo->enableThumb) {
             if ((exifInfo->widthThumb != static_cast<uint32_t>(m_nThumbWidth)) ||
-                    (exifInfo->heightThumb != static_cast<uint32_t>(m_nThumbHeight))) {
-                ALOGE("Inconsistant thumbnail information: Exif %dx%d, Thumb %dx%d",
-                        exifInfo->widthThumb, exifInfo->heightThumb, m_nThumbWidth, m_nThumbHeight);
+                (exifInfo->heightThumb != static_cast<uint32_t>(m_nThumbHeight))) {
+                ALOGE("Inconsistent thumbnail information: Exif %dx%d, Thumb %dx%d",
+                      exifInfo->widthThumb, exifInfo->heightThumb, m_nThumbWidth, m_nThumbHeight);
                 return false;
             }
         }
@@ -255,8 +244,7 @@
     // Giving appwriter the address beyond SOS marker
     // because it is handled by this class
     size_t align = 16;
-    if (!!(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_NO_STREAMBASE_ALIGN))
-        align = 1;
+    if (!!(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_NO_STREAMBASE_ALIGN)) align = 1;
 
     m_pAppWriter->PrepareAppWriter(base + JPEG_MARKER_SIZE, exifInfo, extra);
 
@@ -280,24 +268,21 @@
     if (!exifInfo || !exifInfo->enableThumb || (limit < (JPEG_MAX_SEGMENT_SIZE * 10)))
         reserve_thumbspace = false;
 
-    m_pAppWriter->Write(reserve_thumbspace, JPEG_MARKER_SIZE, align,
-                        TestState(STATE_HWFC_ENABLED));
+    m_pAppWriter->Write(reserve_thumbspace, JPEG_MARKER_SIZE, align, TestState(STATE_HWFC_ENABLED));
 
     ALOGD("Image compression starts from offset %zu (APPx size %zu, HWFC? %d, NBTB? %d)",
-            PTR_DIFF(base, m_pAppWriter->GetMainStreamBase()), m_pAppWriter->CalculateAPPSize(),
-            TestState(STATE_HWFC_ENABLED),TestState(STATE_NO_BTBCOMP));
+          PTR_DIFF(base, m_pAppWriter->GetMainStreamBase()), m_pAppWriter->CalculateAPPSize(),
+          TestState(STATE_HWFC_ENABLED), TestState(STATE_NO_BTBCOMP));
 
     return true;
 }
 
-bool ExynosJpegEncoderForCamera::PrepareCompression(bool thumbnail)
-{
-    if (!thumbnail)
-        return true;
+bool ExynosJpegEncoderForCamera::PrepareCompression(bool thumbnail) {
+    if (!thumbnail) return true;
 
     if (IsThumbGenerationNeeded()) {
-        if (pthread_create(&m_threadWorker, NULL,
-                tCompressThumbnail, reinterpret_cast<void *>(this)) != 0) {
+        if (pthread_create(&m_threadWorker, NULL, tCompressThumbnail,
+                           reinterpret_cast<void *>(this)) != 0) {
             ALOGERR("Failed to create thumbnail generation thread");
             return false;
         }
@@ -312,14 +297,14 @@
     if (!TestState(STATE_NO_BTBCOMP) && IsBTBCompressionSupported()) {
         if (checkOutBufType() == JPEG_BUF_TYPE_USER_PTR) {
             if (!GetCompressor().SetJpegBuffer2(m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer)) {
-                ALOGE("Failed to configure thumbnail buffer @ %p(size %zu)",
-                    m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer);
+                ALOGE("Failed to configure thumbnail buffer @ %p(size %zu)", m_pIONThumbJpegBuffer,
+                      m_szIONThumbJpegBuffer);
                 return false;
             }
         } else {
             if (!GetCompressor().SetJpegBuffer2(m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer)) {
-                ALOGE("Failed to configure thumbnail buffer @ %d(size %zu)",
-                    m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer);
+                ALOGE("Failed to configure thumbnail buffer @ %d(size %zu)", m_fdIONThumbJpegBuffer,
+                      m_szIONThumbJpegBuffer);
                 return false;
             }
         }
@@ -328,16 +313,13 @@
     return true;
 }
 
-int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo,
-                                       char** pcJpegBuffer, debug_attribute_t *debugInfo)
-{
+int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, char **pcJpegBuffer,
+                                       debug_attribute_t *debugInfo) {
     return encode(size, exifInfo, -1, pcJpegBuffer, debugInfo);
 }
 
-int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo,
-                                       int fdJpegBuffer, char** pcJpegBuffer,
-                                       debug_attribute_t *debugInfo)
-{
+int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer,
+                                       char **pcJpegBuffer, debug_attribute_t *debugInfo) {
     if ((!debugInfo) || (debugInfo->num_of_appmarker == 0)) {
         extra_appinfo_t *extra = NULL;
         return encode(size, exifInfo, fdJpegBuffer, pcJpegBuffer, extra);
@@ -351,10 +333,8 @@
     return encode(size, exifInfo, fdJpegBuffer, pcJpegBuffer, &m_extraInfo);
 }
 
-int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo,
-                                       int fdJpegBuffer, char** pcJpegBuffer,
-                                       extra_appinfo_t *appInfo)
-{
+int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer,
+                                       char **pcJpegBuffer, extra_appinfo_t *appInfo) {
     if (!(*pcJpegBuffer)) {
         ALOGE("Target stream buffer is not specified");
         return -1;
@@ -371,27 +351,26 @@
     char *jpeg_base = m_pStreamBase;
 
     ALOGI_IF(!exifInfo, "Exif is not specified. Skipping writing APP1 marker");
-    ALOGI_IF(!appInfo,
-            "Debugging information is not specified. Skipping writing APP4 marker");
+    ALOGI_IF(!appInfo, "Debugging information is not specified. Skipping writing APP4 marker");
     ALOGD("Given stream buffer size: %d bytes", *size);
 
     CStopWatch stopwatch(true);
 
-    if (!ProcessExif(jpeg_base, m_nStreamSize, exifInfo, appInfo))
-        return -1;
+    if (!ProcessExif(jpeg_base, m_nStreamSize, exifInfo, appInfo)) return -1;
 
     int offset = PTR_DIFF(m_pStreamBase, m_pAppWriter->GetMainStreamBase());
     int buffsize = static_cast<int>(m_nStreamSize - offset);
-    if ((fdJpegBuffer < 0) || !(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_DMABUF_OFFSET)) { // JPEG_BUF_TYPE_USER_PTR
+    if ((fdJpegBuffer < 0) ||
+        !(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_DMABUF_OFFSET)) { // JPEG_BUF_TYPE_USER_PTR
         if (setOutBuf(m_pAppWriter->GetMainStreamBase(), buffsize) < 0) {
-            ALOGE("Failed to configure stream buffer : fd %d, addr %p, streamSize %d",
-                    fdJpegBuffer, m_pAppWriter->GetMainStreamBase(), buffsize);
+            ALOGE("Failed to configure stream buffer : fd %d, addr %p, streamSize %d", fdJpegBuffer,
+                  m_pAppWriter->GetMainStreamBase(), buffsize);
             return -1;
         }
     } else { // JPEG_BUF_TYPE_DMA_BUF
         if (setOutBuf(fdJpegBuffer, buffsize, offset) < 0) {
-            ALOGE("Failed to configure stream buffer : fd %d, addr %p, streamSize %d",
-                    fdJpegBuffer, m_pAppWriter->GetMainStreamBase(), buffsize);
+            ALOGE("Failed to configure stream buffer : fd %d, addr %p, streamSize %d", fdJpegBuffer,
+                  m_pAppWriter->GetMainStreamBase(), buffsize);
             return -1;
         }
     }
@@ -412,10 +391,10 @@
     // CASE1 = thumbenc && IsThumbGenerationNeeded() && block_mode
     // CASE2 = thumbenc && IsThumbGenerationNeeded() && !block_mode
     // CASE3 = thumbenc && !IsThumbGenerationNeeded() && !IsBTBCompressionSupported() && !block_mode
-    // CASE4 = thumbenc && !IsThumbGenerationNeeded() && !STATE_NO_BTBCOMP && IsBTBCompressionSupported() && !block_mode
-    // CASE5 = thumbenc && !IsThumbGenerationNeeded() && !STATE_NO_BTBCOMP && IsBTBCompressionSupported() && block_mode
-    // CASE6 = !thumbenc
-    // CASE7 = thumbenc && !IsThumbGenerationNeeded() && STATE_NO_BTBCOMP && block_mode
+    // CASE4 = thumbenc && !IsThumbGenerationNeeded() && !STATE_NO_BTBCOMP &&
+    // IsBTBCompressionSupported() && !block_mode CASE5 = thumbenc && !IsThumbGenerationNeeded() &&
+    // !STATE_NO_BTBCOMP && IsBTBCompressionSupported() && block_mode CASE6 = !thumbenc CASE7 =
+    // thumbenc && !IsThumbGenerationNeeded() && STATE_NO_BTBCOMP && block_mode
 
     if (!thumbenc) {
         // Confirm that no thumbnail information is transferred to HWJPEG
@@ -423,7 +402,7 @@
     } else if (!IsThumbGenerationNeeded() && IsBTBCompressionSupported() &&
                (m_fThumbBufferType != checkInBufType())) {
         ALOGE("Buffer types of thumbnail(%d) and main(%d) images should be the same",
-                m_fThumbBufferType, checkInBufType());
+              m_fThumbBufferType, checkInBufType());
         return -1;
     } else if (!IsThumbGenerationNeeded() && (m_fThumbBufferType == 0)) {
         // Thumbnail buffer configuration failed but the client forces to compress with thumbnail
@@ -453,17 +432,14 @@
     }
 
     *size = static_cast<int>(FinishCompression(mainlen, thumblen));
-    if (*size < 0)
-        return -1;
+    if (*size < 0) return -1;
 
-    ALOGD("....compression delay(usec.): HW %u, Total %lu)",
-          GetHWDelay(), stopwatch.GetElapsed());
+    ALOGD("....compression delay(usec.): HW %u, Total %lu)", GetHWDelay(), stopwatch.GetElapsed());
 
     return 0;
 }
 
-ssize_t ExynosJpegEncoderForCamera::FinishCompression(size_t mainlen, size_t thumblen)
-{
+ssize_t ExynosJpegEncoderForCamera::FinishCompression(size_t mainlen, size_t thumblen) {
     bool btb = false;
     size_t max_streamsize = m_nStreamSize;
     char *mainbase = m_pAppWriter->GetMainStreamBase();
@@ -491,33 +467,37 @@
 
             thumblen = reinterpret_cast<size_t>(len);
         } else if (TestState(STATE_NO_BTBCOMP) || !IsBTBCompressionSupported()) {
-            thumblen = CompressThumbnailOnly(m_pAppWriter->GetMaxThumbnailSize(), m_nThumbQuality, getColorFormat(), checkInBufType());
+            thumblen = CompressThumbnailOnly(m_pAppWriter->GetMaxThumbnailSize(), m_nThumbQuality,
+                                             getColorFormat(), checkInBufType());
         } else {
             btb = true;
         }
 
-        size_t max_thumb = min(m_pAppWriter->GetMaxThumbnailSize(), max_streamsize - m_pAppWriter->CalculateAPPSize(0) - mainlen);
+        size_t max_thumb = min(m_pAppWriter->GetMaxThumbnailSize(),
+                               max_streamsize - m_pAppWriter->CalculateAPPSize(0) - mainlen);
 
         if (thumblen > max_thumb) {
             ALOGI("Too large thumbnail (%dx%d) stream size %zu (max: %zu, quality factor %d)",
                   m_nThumbWidth, m_nThumbHeight, thumblen, max_thumb, m_nThumbQuality);
             ALOGI("Retrying thumbnail compression with quality factor 50");
             thumblen = CompressThumbnailOnly(max_thumb, 50, getColorFormat(), checkInBufType());
-            if (thumblen == 0)
-                return -1;
+            if (thumblen == 0) return -1;
         }
 
         if (!m_pAppWriter->IsThumbSpaceReserved()) {
             if (PTR_TO_ULONG(m_pStreamBase + max_streamsize) <
-                        PTR_TO_ULONG(mainbase + mainlen + thumblen - JPEG_MARKER_SIZE)) {
+                PTR_TO_ULONG(mainbase + mainlen + thumblen - JPEG_MARKER_SIZE)) {
                 ALOGE("Too small JPEG buffer length %zu (APP %zu, Main %zu, Thumb %zu)",
                       max_streamsize, m_pAppWriter->CalculateAPPSize(thumblen), mainlen, thumblen);
                 return -1;
             }
 
-            // the SOI of the stream of the main image is stored after the APP4 or APP11 segment if they exist.
+            // the SOI of the stream of the main image is stored after the APP4 or APP11 segment if
+            // they exist.
             memmove(m_pAppWriter->GetApp1End() + thumblen, m_pAppWriter->GetApp1End(),
-                    mainlen + PTR_DIFF(m_pAppWriter->GetApp1End(), m_pAppWriter->GetMainStreamBase()));
+                    mainlen +
+                            PTR_DIFF(m_pAppWriter->GetApp1End(),
+                                     m_pAppWriter->GetMainStreamBase()));
             m_pAppWriter->UpdateApp1Size(thumblen);
 
             // m_nAppLength has the value of appwriter.GetExactAPPSize()
@@ -532,7 +512,8 @@
         if (m_pAppWriter->IsThumbSpaceReserved()) {
             // clear the possible stale data in the dummy area after the thumbnail stream
             memset(m_pAppWriter->GetThumbStreamBase() + thumblen, 0,
-                   m_pAppWriter->GetMaxThumbnailSize() - thumblen + m_pAppWriter->GetAPP1ResrevedSize());
+                   m_pAppWriter->GetMaxThumbnailSize() - thumblen +
+                           m_pAppWriter->GetAPP1ResrevedSize());
         }
     } else {
         thumblen = 0;
@@ -546,8 +527,8 @@
      * Note that 2 byte(size of SOI marker) is included in APP1 segment size.
      * Thus the size of SOI marker in front of the stream is not added.
      */
-    ALOGD("Completed image compression (%zd(thumb %zu) bytes, HWFC? %d, BTB? %d)",
-            mainlen, thumblen, TestState(STATE_HWFC_ENABLED), btb);
+    ALOGD("Completed image compression (%zd(thumb %zu) bytes, HWFC? %d, BTB? %d)", mainlen,
+          thumblen, TestState(STATE_HWFC_ENABLED), btb);
 
     m_pStreamBase[0] = 0xFF;
     m_pStreamBase[1] = 0xD8;
@@ -556,21 +537,17 @@
 }
 
 /* The logic in WaitForHWFC() is the same with encode() */
-ssize_t ExynosJpegEncoderForCamera::WaitForCompression()
-{
-    if (!TestState(STATE_HWFC_ENABLED))
-        return m_nStreamSize;
+ssize_t ExynosJpegEncoderForCamera::WaitForCompression() {
+    if (!TestState(STATE_HWFC_ENABLED)) return m_nStreamSize;
 
     size_t thumblen = 0;
     ssize_t streamlen = GetCompressor().WaitForCompression(&thumblen);
-    if (streamlen < 0)
-        return streamlen;
+    if (streamlen < 0) return streamlen;
 
     return FinishCompression(streamlen, thumblen);
 }
 
-bool ExynosJpegEncoderForCamera::GenerateThumbnailImage()
-{
+bool ExynosJpegEncoderForCamera::GenerateThumbnailImage() {
     int main_width, main_height;
     if (getSize(&main_width, &main_height) < 0) {
         ALOGE("Failed to get main image size");
@@ -579,11 +556,10 @@
 
     int v4l2Format = getColorFormat();
 
-    if (!AllocThumbBuffer(v4l2Format))
-        return false;
+    if (!AllocThumbBuffer(v4l2Format)) return false;
 
-    ALOGD("Generating thumbnail image: %dx%d -> %dx%d",
-          main_width, main_height, m_nThumbWidth, m_nThumbHeight);
+    ALOGD("Generating thumbnail image: %dx%d -> %dx%d", main_width, main_height, m_nThumbWidth,
+          m_nThumbHeight);
 
     if (!mThumbnailScaler) {
         ALOGE("Thumbnail scaler is not prepared");
@@ -595,8 +571,8 @@
         return false;
     }
 
-
-    if (!mThumbnailScaler->SetDstImage(m_nThumbWidth, m_nThumbHeight, GetThumbnailFormat(v4l2Format))) {
+    if (!mThumbnailScaler->SetDstImage(m_nThumbWidth, m_nThumbHeight,
+                                       GetThumbnailFormat(v4l2Format))) {
         ALOGE("Failed to configure the target image to the thumbnail scaler");
         return false;
     }
@@ -612,7 +588,8 @@
             return false;
         }
 
-        okay = mThumbnailScaler->RunStream(bufs, len_srcbufs, m_fdIONThumbImgBuffer, m_szIONThumbImgBuffer);
+        okay = mThumbnailScaler->RunStream(bufs, len_srcbufs, m_fdIONThumbImgBuffer,
+                                           m_szIONThumbImgBuffer);
     } else { // mainbuftype == JPEG_BUF_TYPE_DMA_BUF
         int bufs[ThumbnailScaler::SCALER_MAX_PLANES];
         int len_srcbufs[ThumbnailScaler::SCALER_MAX_PLANES];
@@ -621,7 +598,8 @@
             ALOGE("Failed to retrieve the main image buffers");
             return false;
         }
-        okay = mThumbnailScaler->RunStream(bufs, len_srcbufs, m_fdIONThumbImgBuffer, m_szIONThumbImgBuffer);
+        okay = mThumbnailScaler->RunStream(bufs, len_srcbufs, m_fdIONThumbImgBuffer,
+                                           m_szIONThumbImgBuffer);
     }
 
     if (!okay) {
@@ -632,14 +610,12 @@
     return true;
 }
 
-size_t ExynosJpegEncoderForCamera::CompressThumbnail()
-{
+size_t ExynosJpegEncoderForCamera::CompressThumbnail() {
     unsigned int v4l2Format = getColorFormat();
     int buftype = checkInBufType();
 
     if (IsThumbGenerationNeeded()) {
-        if (!GenerateThumbnailImage())
-            return 0;
+        if (!GenerateThumbnailImage()) return 0;
 
         // libcsc output configured by this class is always NV21.
         v4l2Format = GetThumbnailFormat(getColorFormat());
@@ -650,11 +626,11 @@
         m_szThumbnailImageLen[0] = m_szIONThumbImgBuffer;
     }
 
-    return CompressThumbnailOnly(m_pAppWriter->GetMaxThumbnailSize(), m_nThumbQuality, v4l2Format, buftype);
+    return CompressThumbnailOnly(m_pAppWriter->GetMaxThumbnailSize(), m_nThumbQuality, v4l2Format,
+                                 buftype);
 }
 
-bool ExynosJpegEncoderForCamera::AllocThumbBuffer(int v4l2Format)
-{
+bool ExynosJpegEncoderForCamera::AllocThumbBuffer(int v4l2Format) {
     if (m_fdIONClient < 0) {
         ALOGE("ION client is not created");
         return false;
@@ -667,11 +643,9 @@
     }
 
     if (m_fdIONThumbImgBuffer >= 0) {
-        if (m_szIONThumbImgBuffer >= thumbbufsize)
-            return true;
+        if (m_szIONThumbImgBuffer >= thumbbufsize) return true;
 
-        if (m_pIONThumbImgBuffer != NULL)
-            munmap(m_pIONThumbImgBuffer, m_szIONThumbImgBuffer);
+        if (m_pIONThumbImgBuffer != NULL) munmap(m_pIONThumbImgBuffer, m_szIONThumbImgBuffer);
 
         close(m_fdIONThumbImgBuffer);
 
@@ -680,9 +654,11 @@
         m_szIONThumbImgBuffer = 0;
     }
 
-    m_fdIONThumbImgBuffer = exynos_ion_alloc(m_fdIONClient, thumbbufsize, EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
+    m_fdIONThumbImgBuffer =
+            exynos_ion_alloc(m_fdIONClient, thumbbufsize, EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
     if (m_fdIONThumbImgBuffer < 0) {
-        ALOGERR("Failed to allocate %zu bytes for NV12 %ux%u", thumbbufsize, m_nThumbHeight, m_nThumbWidth);
+        ALOGERR("Failed to allocate %zu bytes for NV12 %ux%u", thumbbufsize, m_nThumbHeight,
+                m_nThumbWidth);
         m_fdIONThumbImgBuffer = -1;
         return false;
     }
@@ -692,8 +668,7 @@
     return AllocThumbJpegBuffer();
 }
 
-bool ExynosJpegEncoderForCamera::AllocThumbJpegBuffer()
-{
+bool ExynosJpegEncoderForCamera::AllocThumbJpegBuffer() {
     if (m_fdIONClient < 0) {
         ALOGE("ION client is not created");
         return false;
@@ -702,8 +677,7 @@
     size_t thumbbufsize = m_nThumbHeight * m_nThumbWidth * 3;
 
     if (m_pIONThumbJpegBuffer) {
-        if (m_szIONThumbJpegBuffer >= thumbbufsize)
-            return true;
+        if (m_szIONThumbJpegBuffer >= thumbbufsize) return true;
 
         munmap(m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer);
         close(m_fdIONThumbJpegBuffer);
@@ -713,16 +687,18 @@
         m_fdIONThumbJpegBuffer = -1;
     }
 
-    m_fdIONThumbJpegBuffer = exynos_ion_alloc(m_fdIONClient, thumbbufsize, EXYNOS_ION_HEAP_SYSTEM_MASK,
-                              ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC);
+    m_fdIONThumbJpegBuffer =
+            exynos_ion_alloc(m_fdIONClient, thumbbufsize, EXYNOS_ION_HEAP_SYSTEM_MASK,
+                             ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC);
     if (m_fdIONThumbJpegBuffer < 0) {
-        ALOGERR("Failed to allocate %zu bytes for thumbnail stream buffer of %ux%u",
-                thumbbufsize, m_nThumbHeight, m_nThumbWidth);
+        ALOGERR("Failed to allocate %zu bytes for thumbnail stream buffer of %ux%u", thumbbufsize,
+                m_nThumbHeight, m_nThumbWidth);
         return false;
     }
 
-    m_pIONThumbJpegBuffer = reinterpret_cast<char *>(
-                        mmap(NULL, thumbbufsize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fdIONThumbJpegBuffer, 0));
+    m_pIONThumbJpegBuffer =
+            reinterpret_cast<char *>(mmap(NULL, thumbbufsize, PROT_READ | PROT_WRITE, MAP_SHARED,
+                                          m_fdIONThumbJpegBuffer, 0));
     if (m_pIONThumbJpegBuffer == MAP_FAILED) {
         ALOGERR("Failed to map thumbnail stream buffer (%zu bytes)", thumbbufsize);
 
@@ -735,11 +711,10 @@
 }
 
 size_t ExynosJpegEncoderForCamera::CompressThumbnailOnly(size_t limit, int quality,
-                                                         unsigned int v4l2Format, int src_buftype)
-{
+                                                         unsigned int v4l2Format, int src_buftype) {
     if (!m_phwjpeg4thumb->SetImageFormat(v4l2Format, m_nThumbWidth, m_nThumbHeight)) {
-        ALOGE("Failed to configure thumbnail source image format to %#010x, %ux%u",
-              v4l2Format, m_nThumbWidth, m_nThumbHeight);
+        ALOGE("Failed to configure thumbnail source image format to %#010x, %ux%u", v4l2Format,
+              m_nThumbWidth, m_nThumbHeight);
         return 0;
     }
 
@@ -754,18 +729,18 @@
             [[fallthrough]];
         case V4L2_PIX_FMT_NV21M:
             num_buffers++;
-	    break;
+            break;
     }
 
     if (src_buftype == JPEG_BUF_TYPE_USER_PTR) {
-        if (!m_phwjpeg4thumb->SetImageBuffer(m_pThumbnailImageBuffer,
-                                    m_szThumbnailImageLen, num_buffers)) {
+        if (!m_phwjpeg4thumb->SetImageBuffer(m_pThumbnailImageBuffer, m_szThumbnailImageLen,
+                                             num_buffers)) {
             ALOGE("Failed to configure thumbnail buffers(userptr) for thumbnail");
             return 0;
         }
     } else { // JPEG_BUF_TYPE_DMA_BUF
-        if (!m_phwjpeg4thumb->SetImageBuffer(m_fdThumbnailImageBuffer,
-                                    m_szThumbnailImageLen, num_buffers)) {
+        if (!m_phwjpeg4thumb->SetImageBuffer(m_fdThumbnailImageBuffer, m_szThumbnailImageLen,
+                                             num_buffers)) {
             ALOGE("Failed to configure thumbnail buffers(dmabuf) for thumbnail");
             return 0;
         }
@@ -773,7 +748,7 @@
 
     if (!m_phwjpeg4thumb->SetJpegBuffer(m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer)) {
         ALOGE("Failed to configure thumbnail stream buffer (fd %d, size %zu)",
-                m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer);
+              m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer);
         return 0;
     }
 
@@ -811,12 +786,10 @@
     return 0;
 }
 
-int ExynosJpegEncoderForCamera::setInBuf2(int *piBuf, int *iSize)
-{
+int ExynosJpegEncoderForCamera::setInBuf2(int *piBuf, int *iSize) {
     NoThumbGenerationNeeded();
 
-    if (!EnsureFormatIsApplied())
-        return -1;
+    if (!EnsureFormatIsApplied()) return -1;
 
     CHWJpegCompressor &hwjpeg = GetCompressor();
     unsigned int num_buffers = 3;
@@ -831,7 +804,7 @@
     }
 
     if (IsBTBCompressionSupported() &&
-            !hwjpeg.SetImageBuffer2(m_fdThumbnailImageBuffer, m_szThumbnailImageLen, num_buffers)) {
+        !hwjpeg.SetImageBuffer2(m_fdThumbnailImageBuffer, m_szThumbnailImageLen, num_buffers)) {
         ALOGE("Failed to configure thumbnail buffers");
         return -1;
     }
@@ -841,12 +814,10 @@
     return 0;
 }
 
-int ExynosJpegEncoderForCamera::setInBuf2(char **pcBuf, int *iSize)
-{
+int ExynosJpegEncoderForCamera::setInBuf2(char **pcBuf, int *iSize) {
     NoThumbGenerationNeeded();
 
-    if (!EnsureFormatIsApplied())
-        return -1;
+    if (!EnsureFormatIsApplied()) return -1;
 
     CHWJpegCompressor &hwjpeg = GetCompressor();
     unsigned int num_buffers = 3;
@@ -861,7 +832,7 @@
     }
 
     if (IsBTBCompressionSupported() &&
-            !hwjpeg.SetImageBuffer2(m_pThumbnailImageBuffer, m_szThumbnailImageLen, num_buffers)) {
+        !hwjpeg.SetImageBuffer2(m_pThumbnailImageBuffer, m_szThumbnailImageLen, num_buffers)) {
         ALOGE("Failed to configure thumbnail buffers");
         return -1;
     }
@@ -871,8 +842,7 @@
     return 0;
 }
 
-size_t ExynosJpegEncoderForCamera::GetThumbnailImage(char *buffer, size_t buflen)
-{
+size_t ExynosJpegEncoderForCamera::GetThumbnailImage(char *buffer, size_t buflen) {
     if (m_fdIONThumbImgBuffer < 0) {
         ALOGE("No internal thumbnail buffer is allocated");
         return 0;
@@ -888,8 +858,8 @@
                 "m_szIONThumbImgBuffer(%zu) is smaller than the thumbnail (%zu)",
                 m_szIONThumbImgBuffer, thumbbufsize);
     if (m_pIONThumbImgBuffer == NULL) {
-        m_pIONThumbImgBuffer = reinterpret_cast<char *>(mmap(
-                    NULL, m_szIONThumbImgBuffer, PROT_READ, MAP_SHARED, m_fdIONThumbImgBuffer, 0));
+        m_pIONThumbImgBuffer = reinterpret_cast<char *>(
+                mmap(NULL, m_szIONThumbImgBuffer, PROT_READ, MAP_SHARED, m_fdIONThumbImgBuffer, 0));
         if (m_pIONThumbImgBuffer == MAP_FAILED) {
             m_pIONThumbImgBuffer = NULL;
             ALOGERR("Failed to map thumbnail image buffer (%zu bytes)", m_szIONThumbImgBuffer);
@@ -904,8 +874,7 @@
     return m_szIONThumbImgBuffer;
 }
 
-int ExynosJpegEncoderForCamera::destroy()
-{
+int ExynosJpegEncoderForCamera::destroy() {
     GetCompressor().Release();
     return 0;
 }
diff --git a/libhwjpeg/FileLock.cpp b/libhwjpeg/FileLock.cpp
new file mode 100644
index 0000000..6e8ecbd
--- /dev/null
+++ b/libhwjpeg/FileLock.cpp
@@ -0,0 +1,13 @@
+#include "FileLock.h"
+
+#include <bits/lockf.h>
+
+FileLock::FileLock(int fd) : fd_(fd) {}
+
+int FileLock::lock() {
+    return lockf(fd_, F_LOCK, 0);
+}
+
+int FileLock::unlock() {
+    return lockf(fd_, F_ULOCK, 0);
+}
diff --git a/libhwjpeg/IFDWriter.h b/libhwjpeg/IFDWriter.h
index 33f7ff8..61e6d17 100644
--- a/libhwjpeg/IFDWriter.h
+++ b/libhwjpeg/IFDWriter.h
@@ -21,6 +21,7 @@
 
 class CEndianessChecker {
     bool __little;
+
 public:
     CEndianessChecker();
     operator bool() { return __little; }
@@ -30,8 +31,7 @@
 #endif
 
 template <typename T>
-char *WriteDataInBig(char *p, T val)
-{
+char *WriteDataInBig(char *p, T val) {
     if (sizeof(val) == 1) {
         *p++ = val;
     } else if (__LITTLE_ENDIAN__) {
@@ -50,7 +50,7 @@
     } else {
         switch (sizeof(val)) {
             case 2:
-                *p++  = static_cast<char>(val & 0xFF);
+                *p++ = static_cast<char>(val & 0xFF);
                 *p++ = static_cast<char>((val >> 8) & 0xFF);
                 break;
             case 4:
@@ -66,11 +66,9 @@
 }
 
 template <typename T>
-char *WriteData(char *p, T val)
-{
+char *WriteData(char *p, T val) {
     const char *pt = reinterpret_cast<char *>(&val);
-    for (size_t i = 0; i < sizeof(val); i++)
-        *p++ = *pt++;
+    for (size_t i = 0; i < sizeof(val); i++) *p++ = *pt++;
     return p;
 }
 
@@ -107,13 +105,14 @@
 
         m_nTags--;
     }
+
 public:
     CIFDWriter(char *offset_base, char *ifdbase, uint16_t tagcount) {
         m_nTags = tagcount;
         m_pBase = offset_base;
         m_pIFDBase = ifdbase;
-        m_pValue = m_pIFDBase + IFD_FIELDCOUNT_SIZE +
-                   IFD_FIELD_SIZE * tagcount + IFD_NEXTIFDOFFSET_SIZE;
+        m_pValue = m_pIFDBase + IFD_FIELDCOUNT_SIZE + IFD_FIELD_SIZE * tagcount +
+                IFD_NEXTIFDOFFSET_SIZE;
 
         // COUNT field of IFD
         const char *pval = reinterpret_cast<char *>(&m_nTags);
@@ -136,8 +135,7 @@
                 *m_pValue++ = static_cast<char>(value[i]);
             }
         } else {
-            for (uint32_t i = 0; i < count; i++)
-                *m_pIFDBase++ = static_cast<char>(value[i]);
+            for (uint32_t i = 0; i < count; i++) *m_pIFDBase++ = static_cast<char>(value[i]);
             m_pIFDBase += IFD_VALOFF_SIZE - count;
         }
     }
@@ -192,8 +190,7 @@
             m_pValue[count - 1] = '\0';
             m_pValue += count;
         } else {
-            for (uint32_t i = 0; i < count; i++)
-                *m_pIFDBase++ = value[i];
+            for (uint32_t i = 0; i < count; i++) *m_pIFDBase++ = value[i];
             *(m_pIFDBase - 1) = '\0';
             m_pIFDBase += IFD_VALOFF_SIZE - count;
         }
@@ -212,11 +209,9 @@
         } else {
             uint32_t i;
 
-            for (i = 0; (i < (count - 1)) && (string[i] != '\0'); i++)
-                *m_pIFDBase++ = string[i];
+            for (i = 0; (i < (count - 1)) && (string[i] != '\0'); i++) *m_pIFDBase++ = string[i];
 
-            while (i++ < count)
-                *m_pIFDBase++ = '\0';
+            while (i++ < count) *m_pIFDBase++ = '\0';
 
             m_pIFDBase += IFD_VALOFF_SIZE - count;
         }
@@ -250,8 +245,7 @@
         m_pIFDBase = WriteOffset(m_pIFDBase, m_pValue);
 
         const char *pt = reinterpret_cast<const char *>(value);
-        for (uint32_t i = 0; i < sizeof(srational_t) * count; i++)
-            *m_pValue++ = *pt++;
+        for (uint32_t i = 0; i < sizeof(srational_t) * count; i++) *m_pValue++ = *pt++;
     }
 
     void WriteUndef(uint16_t tag, uint32_t count, const unsigned char *value) {
@@ -263,8 +257,7 @@
             memcpy(m_pValue, value, count);
             m_pValue += count;
         } else {
-            for (uint32_t i = 0; i < count; i++)
-                *m_pIFDBase++ = static_cast<char>(value[i]);
+            for (uint32_t i = 0; i < count; i++) *m_pIFDBase++ = static_cast<char>(value[i]);
             m_pIFDBase += IFD_VALOFF_SIZE - count;
         }
     }
diff --git a/libhwjpeg/LibScalerForJpeg.cpp b/libhwjpeg/LibScalerForJpeg.cpp
index 1165495..1886d49 100644
--- a/libhwjpeg/LibScalerForJpeg.cpp
+++ b/libhwjpeg/LibScalerForJpeg.cpp
@@ -15,67 +15,57 @@
  * limitations under the License.
  */
 
-#include "hwjpeg-internal.h"
 #include "LibScalerForJpeg.h"
 
+#include "hwjpeg-internal.h"
+
 #define SCALER_DEV_NODE "/dev/video50"
 
-static const char *getBufTypeString(unsigned int buftype)
-{
-    if (buftype == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-        return "destination";
-    if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-        return "source";
+static const char *getBufTypeString(unsigned int buftype) {
+    if (buftype == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return "destination";
+    if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return "source";
     return "unknown";
 }
 
-bool LibScalerForJpeg::RunStream(int srcBuf[SCALER_MAX_PLANES], int __unused srcLen[SCALER_MAX_PLANES], int dstBuf, size_t __unused dstLen)
-{
-    if (!mSrcImage.begin(V4L2_MEMORY_DMABUF) || !mDstImage.begin(V4L2_MEMORY_DMABUF))
-        return false;
+bool LibScalerForJpeg::RunStream(int srcBuf[SCALER_MAX_PLANES],
+                                 int __unused srcLen[SCALER_MAX_PLANES], int dstBuf,
+                                 size_t __unused dstLen) {
+    if (!mSrcImage.begin(V4L2_MEMORY_DMABUF) || !mDstImage.begin(V4L2_MEMORY_DMABUF)) return false;
 
     return queue(srcBuf, dstBuf);
 }
 
-bool LibScalerForJpeg::RunStream(char *srcBuf[SCALER_MAX_PLANES], int __unused srcLen[SCALER_MAX_PLANES], int dstBuf, size_t __unused dstLen)
-{
-    if (!mSrcImage.begin(V4L2_MEMORY_USERPTR) || !mDstImage.begin(V4L2_MEMORY_DMABUF))
-        return false;
+bool LibScalerForJpeg::RunStream(char *srcBuf[SCALER_MAX_PLANES],
+                                 int __unused srcLen[SCALER_MAX_PLANES], int dstBuf,
+                                 size_t __unused dstLen) {
+    if (!mSrcImage.begin(V4L2_MEMORY_USERPTR) || !mDstImage.begin(V4L2_MEMORY_DMABUF)) return false;
 
     return queue(srcBuf, dstBuf);
 }
 
-bool LibScalerForJpeg::Image::set(unsigned int width, unsigned int height, unsigned int format)
-{
-    if (same(width, height, format))
-        return true;
+bool LibScalerForJpeg::Image::set(unsigned int width, unsigned int height, unsigned int format) {
+    if (same(width, height, format)) return true;
 
     if (memoryType != 0) {
-        if (!mDevice.requestBuffers(bufferType, memoryType, 0))
-            return false;
+        if (!mDevice.requestBuffers(bufferType, memoryType, 0)) return false;
     }
 
-    if (!mDevice.setFormat(bufferType, format, width, height, planeLen))
-        return false;
+    if (!mDevice.setFormat(bufferType, format, width, height, planeLen)) return false;
 
     memoryType = 0; // new reqbufs is required.
 
     return true;
 }
 
-bool LibScalerForJpeg::Image::begin(unsigned int memtype)
-{
+bool LibScalerForJpeg::Image::begin(unsigned int memtype) {
     if (memoryType != memtype) {
         if (memoryType != 0) {
-            if (!mDevice.requestBuffers(bufferType, memoryType, 0))
-                return false;
+            if (!mDevice.requestBuffers(bufferType, memoryType, 0)) return false;
         }
 
-        if (!mDevice.requestBuffers(bufferType, memtype, 1))
-            return false;
+        if (!mDevice.requestBuffers(bufferType, memtype, 1)) return false;
 
-        if (!mDevice.streamOn(bufferType))
-            return false;
+        if (!mDevice.streamOn(bufferType)) return false;
 
         memoryType = memtype;
     }
@@ -83,41 +73,34 @@
     return true;
 }
 
-bool LibScalerForJpeg::Image::cancelBuffer()
-{
-    if (!mDevice.streamOff(bufferType))
-        return false;
+bool LibScalerForJpeg::Image::cancelBuffer() {
+    if (!mDevice.streamOff(bufferType)) return false;
 
-    if (!mDevice.streamOn(bufferType))
-        return false;
+    if (!mDevice.streamOn(bufferType)) return false;
 
     return true;
 }
 
-LibScalerForJpeg::Device::Device()
-{
+LibScalerForJpeg::Device::Device() {
     mFd = ::open(SCALER_DEV_NODE, O_RDWR);
-    if (mFd < 0)
-        ALOGERR("failed to open %s", SCALER_DEV_NODE);
+    if (mFd < 0) ALOGERR("failed to open %s", SCALER_DEV_NODE);
 }
 
-LibScalerForJpeg::Device::~Device()
-{
-    if (mFd >= 0)
-        ::close(mFd);
+LibScalerForJpeg::Device::~Device() {
+    if (mFd >= 0) ::close(mFd);
 }
 
-bool LibScalerForJpeg::Device::requestBuffers(unsigned int buftype, unsigned int memtype, unsigned int count)
-{
-    // count==0 means this port should be reconfigured and it is successful under streaming is finished.
-    if (!count)
-        streamOff(buftype);
+bool LibScalerForJpeg::Device::requestBuffers(unsigned int buftype, unsigned int memtype,
+                                              unsigned int count) {
+    // count==0 means this port should be reconfigured and it is successful under streaming is
+    // finished.
+    if (!count) streamOff(buftype);
 
     v4l2_requestbuffers reqbufs{};
 
-    reqbufs.type    = buftype;
-    reqbufs.memory  = memtype;
-    reqbufs.count   = count;
+    reqbufs.type = buftype;
+    reqbufs.memory = memtype;
+    reqbufs.count = count;
 
     if (ioctl(mFd, VIDIOC_REQBUFS, &reqbufs) < 0) {
         ALOGERR("failed REQBUFS(%s, mem=%d, count=%d)", getBufTypeString(buftype), memtype, count);
@@ -127,29 +110,30 @@
     return true;
 }
 
-bool LibScalerForJpeg::Device::setFormat(unsigned int buftype, unsigned int format, unsigned int width, unsigned int height, unsigned int planelen[SCALER_MAX_PLANES])
-{
+bool LibScalerForJpeg::Device::setFormat(unsigned int buftype, unsigned int format,
+                                         unsigned int width, unsigned int height,
+                                         unsigned int planelen[SCALER_MAX_PLANES]) {
     v4l2_format fmt{};
 
     fmt.type = buftype;
     fmt.fmt.pix_mp.pixelformat = format;
-    fmt.fmt.pix_mp.width  = width;
+    fmt.fmt.pix_mp.width = width;
     fmt.fmt.pix_mp.height = height;
 
     if (ioctl(mFd, VIDIOC_S_FMT, &fmt) < 0) {
-        ALOGERR("failed S_FMT(%s, fmt=h'%x, %ux%u)", getBufTypeString(buftype), format, width, height);
+        ALOGERR("failed S_FMT(%s, fmt=h'%x, %ux%u)", getBufTypeString(buftype), format, width,
+                height);
         return false;
     }
 
-    for (uint32_t i = 0; i < fmt.fmt.pix_mp.num_planes ; i++) {
+    for (uint32_t i = 0; i < fmt.fmt.pix_mp.num_planes; i++) {
         planelen[i] = fmt.fmt.pix_mp.plane_fmt[i].sizeimage;
     }
 
     return true;
 }
 
-bool LibScalerForJpeg::Device::streamOn(unsigned int buftype)
-{
+bool LibScalerForJpeg::Device::streamOn(unsigned int buftype) {
     if (ioctl(mFd, VIDIOC_STREAMON, &buftype) < 0) {
         ALOGERR("failed STREAMON for %s", getBufTypeString(buftype));
         return false;
@@ -158,8 +142,7 @@
     return true;
 }
 
-bool LibScalerForJpeg::Device::streamOff(unsigned int buftype)
-{
+bool LibScalerForJpeg::Device::streamOff(unsigned int buftype) {
     if (ioctl(mFd, VIDIOC_STREAMOFF, &buftype) < 0) {
         ALOGERR("failed STREAMOFF for %s", getBufTypeString(buftype));
         return false;
@@ -168,8 +151,8 @@
     return true;
 }
 
-bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, std::function<void(v4l2_buffer &)> bufferFiller)
-{
+bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype,
+                                           std::function<void(v4l2_buffer &)> bufferFiller) {
     v4l2_buffer buffer{};
     v4l2_plane plane[SCALER_MAX_PLANES];
 
@@ -183,47 +166,50 @@
     return ioctl(mFd, VIDIOC_QBUF, &buffer) >= 0;
 }
 
-bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, int buf[SCALER_MAX_PLANES], unsigned int len[SCALER_MAX_PLANES])
-{
-    if (!queueBuffer(buftype, [buf, len] (v4l2_buffer &buffer) {
-                buffer.memory = V4L2_MEMORY_DMABUF;
-                buffer.length = SCALER_MAX_PLANES;
-                for (unsigned int i = 0; i < SCALER_MAX_PLANES; i++) {
-                    buffer.m.planes[i].m.fd = buf[i];
-                    buffer.m.planes[i].length = len[i];
-                } })) {
-        ALOGERR("failed QBUF(%s, fd[]=%d %d, len[0]=%d %d)", getBufTypeString(buftype), buf[0], buf[1], len[0], len[1]);
+bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, int buf[SCALER_MAX_PLANES],
+                                           unsigned int len[SCALER_MAX_PLANES]) {
+    if (!queueBuffer(buftype, [buf, len](v4l2_buffer &buffer) {
+            buffer.memory = V4L2_MEMORY_DMABUF;
+            buffer.length = SCALER_MAX_PLANES;
+            for (unsigned int i = 0; i < SCALER_MAX_PLANES; i++) {
+                buffer.m.planes[i].m.fd = buf[i];
+                buffer.m.planes[i].length = len[i];
+            }
+        })) {
+        ALOGERR("failed QBUF(%s, fd[]=%d %d, len[0]=%d %d)", getBufTypeString(buftype), buf[0],
+                buf[1], len[0], len[1]);
         return false;
     }
 
     return true;
 }
 
-bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, char *buf[SCALER_MAX_PLANES], unsigned int len[SCALER_MAX_PLANES])
-{
-    if (!queueBuffer(buftype, [buf, len] (v4l2_buffer &buffer) {
-                buffer.memory = V4L2_MEMORY_USERPTR;
-                buffer.length = SCALER_MAX_PLANES;
-                for (unsigned int i = 0; i < SCALER_MAX_PLANES; i++) {
-                    buffer.m.planes[i].m.userptr = reinterpret_cast<unsigned long>(buf[i]);
-                    buffer.m.planes[i].length = len[i];
-                } })) {
-        ALOGERR("failed QBUF(%s, ptr[]=%p %p, len[0]=%d %d)", getBufTypeString(buftype), buf[0], buf[1], len[0], len[1]);
+bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, char *buf[SCALER_MAX_PLANES],
+                                           unsigned int len[SCALER_MAX_PLANES]) {
+    if (!queueBuffer(buftype, [buf, len](v4l2_buffer &buffer) {
+            buffer.memory = V4L2_MEMORY_USERPTR;
+            buffer.length = SCALER_MAX_PLANES;
+            for (unsigned int i = 0; i < SCALER_MAX_PLANES; i++) {
+                buffer.m.planes[i].m.userptr = reinterpret_cast<unsigned long>(buf[i]);
+                buffer.m.planes[i].length = len[i];
+            }
+        })) {
+        ALOGERR("failed QBUF(%s, ptr[]=%p %p, len[0]=%d %d)", getBufTypeString(buftype), buf[0],
+                buf[1], len[0], len[1]);
         return false;
     }
 
     return true;
 }
 
-bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, int buf, unsigned int len[SCALER_MAX_PLANES])
-{
-    if (!queueBuffer(buftype, [buf, len] (v4l2_buffer &buffer)
-                {
-                    buffer.memory = V4L2_MEMORY_DMABUF;
-                    buffer.length = 1;
-                    buffer.m.planes[0].m.fd = buf;
-                    buffer.m.planes[0].length = len[0];
-                })) {
+bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, int buf,
+                                           unsigned int len[SCALER_MAX_PLANES]) {
+    if (!queueBuffer(buftype, [buf, len](v4l2_buffer &buffer) {
+            buffer.memory = V4L2_MEMORY_DMABUF;
+            buffer.length = 1;
+            buffer.m.planes[0].m.fd = buf;
+            buffer.m.planes[0].length = len[0];
+        })) {
         ALOGERR("failed QBUF(%s, fd=%d, len=%d", getBufTypeString(buftype), buf, len[0]);
         return false;
     }
@@ -231,8 +217,7 @@
     return true;
 }
 
-bool LibScalerForJpeg::Device::dequeueBuffer(unsigned int buftype, unsigned int memtype)
-{
+bool LibScalerForJpeg::Device::dequeueBuffer(unsigned int buftype, unsigned int memtype) {
     v4l2_buffer buffer{};
     v4l2_plane plane[SCALER_MAX_PLANES];
 
@@ -244,7 +229,7 @@
 
     buffer.m.planes = plane;
 
-    if (ioctl(mFd, VIDIOC_DQBUF, &buffer) < 0 ) {
+    if (ioctl(mFd, VIDIOC_DQBUF, &buffer) < 0) {
         ALOGERR("failed DQBUF(%s)", getBufTypeString(buftype));
         return false;
     }
diff --git a/libhwjpeg/LibScalerForJpeg.h b/libhwjpeg/LibScalerForJpeg.h
index f8914d7..4c90e43 100644
--- a/libhwjpeg/LibScalerForJpeg.h
+++ b/libhwjpeg/LibScalerForJpeg.h
@@ -16,16 +16,16 @@
 #ifndef __HARDWARE_EXYNOS_LIBSCALERFORJPEG_H__
 #define __HARDWARE_EXYNOS_LIBSCALERFORJPEG_H__
 
-#include <functional>
-
 #include <linux/videodev2.h>
 
+#include <functional>
+
 #include "ThumbnailScaler.h"
 
 class LibScalerForJpeg : public ThumbnailScaler {
 public:
-    LibScalerForJpeg() { }
-    ~LibScalerForJpeg() { }
+    LibScalerForJpeg() {}
+    ~LibScalerForJpeg() {}
 
     bool SetSrcImage(unsigned int width, unsigned int height, unsigned int v4l2_format) {
         return mSrcImage.set(width, height, v4l2_format);
@@ -35,10 +35,13 @@
         return mDstImage.set(width, height, v4l2_format);
     }
 
-    bool RunStream(int srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, size_t dstLen);
-    bool RunStream(char *srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, size_t dstLen);
+    bool RunStream(int srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf,
+                   size_t dstLen);
+    bool RunStream(char *srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf,
+                   size_t dstLen);
 
     bool available() { return mDevice.mFd >= 0; }
+
 private:
     struct Device {
         int mFd;
@@ -46,12 +49,15 @@
         Device();
         ~Device();
         bool requestBuffers(unsigned int buftype, unsigned int memtype, unsigned int count);
-        bool setFormat(unsigned int buftype, unsigned int format, unsigned int width, unsigned int height, unsigned int planelen[SCALER_MAX_PLANES]);
+        bool setFormat(unsigned int buftype, unsigned int format, unsigned int width,
+                       unsigned int height, unsigned int planelen[SCALER_MAX_PLANES]);
         bool streamOn(unsigned int buftype);
         bool streamOff(unsigned int buftype);
         bool queueBuffer(unsigned int buftype, std::function<void(v4l2_buffer &)> bufferFiller);
-        bool queueBuffer(unsigned int buftype, int buf[SCALER_MAX_PLANES], unsigned int len[SCALER_MAX_PLANES]);
-        bool queueBuffer(unsigned int buftype, char *buf[SCALER_MAX_PLANES], unsigned int len[SCALER_MAX_PLANES]);
+        bool queueBuffer(unsigned int buftype, int buf[SCALER_MAX_PLANES],
+                         unsigned int len[SCALER_MAX_PLANES]);
+        bool queueBuffer(unsigned int buftype, char *buf[SCALER_MAX_PLANES],
+                         unsigned int len[SCALER_MAX_PLANES]);
         bool queueBuffer(unsigned int buftype, int buf, unsigned int len[SCALER_MAX_PLANES]);
         bool dequeueBuffer(unsigned int buftype, unsigned int memtype);
     };
@@ -66,24 +72,26 @@
         unsigned int planeLen[SCALER_MAX_PLANES];
 
         Image(Device &dev, unsigned int w, unsigned int h, unsigned int f, unsigned int buftype)
-            : mDevice(dev), width(w), height(h), format(f), bufferType(buftype)
-        { }
+              : mDevice(dev), width(w), height(h), format(f), bufferType(buftype) {}
 
         bool set(unsigned int width, unsigned int height, unsigned int format);
         bool begin(unsigned int memtype);
         bool cancelBuffer();
 
         template <class tBuf>
-        bool queueBuffer(tBuf buf) { return mDevice.queueBuffer(bufferType, buf, planeLen); }
+        bool queueBuffer(tBuf buf) {
+            return mDevice.queueBuffer(bufferType, buf, planeLen);
+        }
         bool dequeueBuffer() { return mDevice.dequeueBuffer(bufferType, memoryType); }
 
-        bool same(unsigned int w, unsigned int h, unsigned int f) { return width == w && height == h && format == f; }
+        bool same(unsigned int w, unsigned int h, unsigned int f) {
+            return width == w && height == h && format == f;
+        }
     };
 
-    template<class T>
+    template <class T>
     bool queue(T srcBuf[SCALER_MAX_PLANES], int dstBuf) {
-        if (!mSrcImage.queueBuffer(srcBuf))
-            return false;
+        if (!mSrcImage.queueBuffer(srcBuf)) return false;
 
         if (!mDstImage.queueBuffer(dstBuf)) {
             mSrcImage.cancelBuffer();
diff --git a/libhwjpeg/ThumbnailScaler.cpp b/libhwjpeg/ThumbnailScaler.cpp
index 4d6e5de..3f4edcf 100644
--- a/libhwjpeg/ThumbnailScaler.cpp
+++ b/libhwjpeg/ThumbnailScaler.cpp
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
+#include "ThumbnailScaler.h"
+
 #include <log/log.h>
 
-#include "ThumbnailScaler.h"
 #include "LibScalerForJpeg.h"
 
-ThumbnailScaler *ThumbnailScaler::createInstance()
-{
+ThumbnailScaler *ThumbnailScaler::createInstance() {
     ALOGD("Created thumbnail scaler: legacy V4L2 Scaler");
     return new LibScalerForJpeg();
 }
diff --git a/libhwjpeg/ThumbnailScaler.h b/libhwjpeg/ThumbnailScaler.h
index cb23365..14d6e7d 100644
--- a/libhwjpeg/ThumbnailScaler.h
+++ b/libhwjpeg/ThumbnailScaler.h
@@ -6,14 +6,16 @@
 class ThumbnailScaler {
 public:
     const static unsigned int SCALER_MAX_PLANES = 3;
-    ThumbnailScaler() { }
-    virtual ~ThumbnailScaler() { }
+    ThumbnailScaler() {}
+    virtual ~ThumbnailScaler() {}
 
     virtual bool SetSrcImage(unsigned int width, unsigned int height, unsigned int v4l2_format) = 0;
     virtual bool SetDstImage(unsigned int width, unsigned int height, unsigned int v4l2_format) = 0;
 
-    virtual bool RunStream(int srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, size_t dstLen) = 0;
-    virtual bool RunStream(char *srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, size_t dstLen) = 0;
+    virtual bool RunStream(int srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf,
+                           size_t dstLen) = 0;
+    virtual bool RunStream(char *srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES],
+                           int dstBuf, size_t dstLen) = 0;
 
     static ThumbnailScaler *createInstance();
 
diff --git a/libhwjpeg/hwjpeg-base.cpp b/libhwjpeg/hwjpeg-base.cpp
index e593c02..f319d50 100644
--- a/libhwjpeg/hwjpeg-base.cpp
+++ b/libhwjpeg/hwjpeg-base.cpp
@@ -15,52 +15,41 @@
  * limitations under the License.
  */
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-
-#include <linux/videodev2.h>
-#include <linux/v4l2-controls.h>
-
 #include <exynos-hwjpeg.h>
+#include <fcntl.h>
+#include <linux/v4l2-controls.h>
+#include <linux/videodev2.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include "hwjpeg-internal.h"
 
-CHWJpegBase::CHWJpegBase(const char *path)
-         : m_iFD(-1), m_uiDeviceCaps(0), m_uiAuxFlags(0)
-{
+CHWJpegBase::CHWJpegBase(const char *path) : m_iFD(-1), m_uiDeviceCaps(0), m_uiAuxFlags(0) {
     m_iFD = open(path, O_RDWR);
-    if (m_iFD < 0)
-        ALOGERR("Failed to open '%s'", path);
+    if (m_iFD < 0) ALOGERR("Failed to open '%s'", path);
 }
 
-CHWJpegBase::~CHWJpegBase()
-{
-    if (m_iFD >= 0)
-        close(m_iFD);
+CHWJpegBase::~CHWJpegBase() {
+    if (m_iFD >= 0) close(m_iFD);
 }
 
-void CHWJpegBase::SetAuxFlags(unsigned int auxflags)
-{
+void CHWJpegBase::SetAuxFlags(unsigned int auxflags) {
     ALOGW_IF(!!(m_uiAuxFlags & auxflags),
-            "Configuration auxiliary flags %#x overrides previous flags %#x",
-            auxflags , m_uiAuxFlags);
+             "Configuration auxiliary flags %#x overrides previous flags %#x", auxflags,
+             m_uiAuxFlags);
 
     m_uiAuxFlags |= auxflags;
 }
 
-void CHWJpegBase::ClearAuxFlags(unsigned int auxflags)
-{
-
+void CHWJpegBase::ClearAuxFlags(unsigned int auxflags) {
     ALOGW_IF(!!(m_uiAuxFlags & auxflags) && ((m_uiAuxFlags & auxflags) != auxflags),
-            "Clearing auxiliary flags %#x overrides previous flags %#x",
-            auxflags, m_uiAuxFlags);
+             "Clearing auxiliary flags %#x overrides previous flags %#x", auxflags, m_uiAuxFlags);
 
     m_uiAuxFlags &= ~auxflags;
 }
 
-bool CStopWatch::Start()
-{
+bool CStopWatch::Start() {
     int ret = clock_gettime(CLOCK_MONOTONIC, &m_tBegin);
     if (ret) {
         ALOGERR("Failed to get current clock");
@@ -71,8 +60,7 @@
     return true;
 }
 
-unsigned long CStopWatch::GetElapsed()
-{
+unsigned long CStopWatch::GetElapsed() {
     timespec tp;
     int ret = clock_gettime(CLOCK_MONOTONIC, &tp);
     if (ret) {
@@ -81,13 +69,11 @@
     }
 
     unsigned long elapsed = (tp.tv_sec - m_tBegin.tv_sec) * 1000000;
-    return (m_tBegin.tv_nsec > tp.tv_nsec)
-        ? elapsed - (m_tBegin.tv_nsec - tp.tv_nsec) / 1000
-        : elapsed + (tp.tv_nsec - m_tBegin.tv_nsec) / 1000;
+    return (m_tBegin.tv_nsec > tp.tv_nsec) ? elapsed - (m_tBegin.tv_nsec - tp.tv_nsec) / 1000
+                                           : elapsed + (tp.tv_nsec - m_tBegin.tv_nsec) / 1000;
 }
 
-unsigned long CStopWatch::GetElapsedUpdate()
-{
+unsigned long CStopWatch::GetElapsedUpdate() {
     timespec tp;
     int ret = clock_gettime(CLOCK_MONOTONIC, &tp);
     if (ret) {
@@ -96,17 +82,15 @@
     }
 
     unsigned long elapsed = (tp.tv_sec - m_tBegin.tv_sec) * 1000000;
-    elapsed = (m_tBegin.tv_nsec > tp.tv_nsec)
-        ? elapsed - (m_tBegin.tv_nsec - tp.tv_nsec) / 1000
-        : elapsed + (tp.tv_nsec - m_tBegin.tv_nsec) / 1000;
+    elapsed = (m_tBegin.tv_nsec > tp.tv_nsec) ? elapsed - (m_tBegin.tv_nsec - tp.tv_nsec) / 1000
+                                              : elapsed + (tp.tv_nsec - m_tBegin.tv_nsec) / 1000;
 
     m_tBegin = tp;
     return elapsed;
 }
 
-bool WriteToFile(const char *path, const char *data, size_t len)
-{
-    int fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWGRP );
+bool WriteToFile(const char *path, const char *data, size_t len) {
+    int fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWGRP);
     if (fd < 0) {
         ALOGERR("Failed to open '%s' for write/create", path);
         return false;
@@ -124,15 +108,15 @@
     return true;
 }
 
-bool WriteToFile(const char *path, int dmabuf, size_t len)
-{
-    char *p = reinterpret_cast<char *>(mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, dmabuf, 0));
+bool WriteToFile(const char *path, int dmabuf, size_t len) {
+    char *p = reinterpret_cast<char *>(
+            mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, dmabuf, 0));
     if (p == MAP_FAILED) {
         ALOGERR("Filed to map the given dmabuf fd %d", dmabuf);
         return false;
     }
 
-    int fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWGRP );
+    int fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWGRP);
     if (fd < 0) {
         ALOGERR("Failed to open '%s' for write/create", path);
         munmap(p, len);
diff --git a/libhwjpeg/hwjpeg-internal.h b/libhwjpeg/hwjpeg-internal.h
index 8113871..bb14a35 100644
--- a/libhwjpeg/hwjpeg-internal.h
+++ b/libhwjpeg/hwjpeg-internal.h
@@ -22,18 +22,18 @@
 #error "LOG_TAG is not defined!"
 #endif
 
+#include <log/log.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <unistd.h>
+
 #include <cerrno>
 #include <cstring>
 
-#include <unistd.h>
-#include <log/log.h>
-#include <time.h>
-#include <sys/ioctl.h>
-
 #ifdef __GNUC__
-#  define __UNUSED__ __attribute__((__unused__))
+#define __UNUSED__ __attribute__((__unused__))
 #else
-#  define __UNUSED__
+#define __UNUSED__
 #endif
 
 #ifndef ALOGERR
@@ -41,14 +41,16 @@
 #endif
 
 #define V4L2_CID_JPEG_SEC_COMP_QUALITY (V4L2_CID_JPEG_CLASS_BASE + 20)
-#define V4L2_CID_JPEG_QTABLES2         (V4L2_CID_JPEG_CLASS_BASE + 22)
-#define V4L2_CID_JPEG_HWFC_ENABLE      (V4L2_CID_JPEG_CLASS_BASE + 25)
+#define V4L2_CID_JPEG_QTABLES2 (V4L2_CID_JPEG_CLASS_BASE + 22)
+#define V4L2_CID_JPEG_HWFC_ENABLE (V4L2_CID_JPEG_CLASS_BASE + 25)
+#define V4L2_CID_JPEG_PADDING (V4L2_CID_JPEG_CLASS_BASE + 26)
+#define V4L2_CID_JPEG_SEC_PADDING (V4L2_CID_JPEG_CLASS_BASE + 27)
 
-#define TO_MAIN_SIZE(val)   ((val) & 0xFFFF)
-#define TO_THUMB_SIZE(val)  (((val) & 0xFFFF) << 16)
+#define TO_MAIN_SIZE(val) ((val)&0xFFFF)
+#define TO_THUMB_SIZE(val) (((val)&0xFFFF) << 16)
 #define TO_IMAGE_SIZE(main, thumb) (TO_MAIN_SIZE(main) | TO_THUMB_SIZE(thumb))
 
-#define PTR_TO_ULONG(ptr)   reinterpret_cast<unsigned long>(ptr)
+#define PTR_TO_ULONG(ptr) reinterpret_cast<unsigned long>(ptr)
 #define PTR_DIFF(ptr1, ptr2) (reinterpret_cast<size_t>(ptr2) - reinterpret_cast<size_t>(ptr1))
 
 #define ARRSIZE(v) (sizeof(v) / sizeof(v[0]))
@@ -74,10 +76,10 @@
 
 class CStopWatch {
     timespec m_tBegin;
+
 public:
     CStopWatch(bool start = false) {
-        if (start)
-            Start();
+        if (start) Start();
     }
     bool Start();
     unsigned long GetElapsed();
diff --git a/libhwjpeg/hwjpeg-v4l2.cpp b/libhwjpeg/hwjpeg-v4l2.cpp
index bfa1a52..c364554 100644
--- a/libhwjpeg/hwjpeg-v4l2.cpp
+++ b/libhwjpeg/hwjpeg-v4l2.cpp
@@ -15,14 +15,15 @@
  * limitations under the License.
  */
 
-#include <linux/videodev2.h>
-#include <linux/v4l2-controls.h>
-
 #include <exynos-hwjpeg.h>
-#include "hwjpeg-internal.h"
+#include <linux/v4l2-controls.h>
+#include <linux/videodev2.h>
 
-CHWJpegV4L2Compressor::CHWJpegV4L2Compressor(): CHWJpegCompressor("/dev/video12")
-{
+#include "hwjpeg-internal.h"
+#include "log/log_main.h"
+
+CHWJpegV4L2Compressor::CHWJpegV4L2Compressor()
+      : CHWJpegCompressor("/dev/video12"), file_lock_(FileLock(GetDeviceFD())) {
     memset(&m_v4l2Format, 0, sizeof(m_v4l2Format));
     memset(&m_v4l2SrcBuffer, 0, sizeof(m_v4l2SrcBuffer));
     memset(&m_v4l2DstBuffer, 0, sizeof(m_v4l2DstBuffer));
@@ -63,27 +64,42 @@
     ALOGD("CHWJpegV4L2Compressor Created: %p, FD %d", this, GetDeviceFD());
 }
 
-CHWJpegV4L2Compressor::~CHWJpegV4L2Compressor()
-{
+CHWJpegV4L2Compressor::~CHWJpegV4L2Compressor() {
     StopStreaming();
 
     ALOGD("CHWJpegV4L2Compressor Destroyed: %p, FD %d", this, GetDeviceFD());
 }
 
-bool CHWJpegV4L2Compressor::SetChromaSampFactor(
-                    unsigned int horizontal, unsigned int vertical)
-{
+int CHWJpegV4L2Compressor::lock() {
+    return file_lock_.lock();
+}
+
+int CHWJpegV4L2Compressor::unlock() {
+    return file_lock_.unlock();
+}
+
+bool CHWJpegV4L2Compressor::SetChromaSampFactor(unsigned int horizontal, unsigned int vertical) {
     __s32 value;
     switch ((horizontal << 4) | vertical) {
-        case 0x00: value = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; break;
-        case 0x11: value = V4L2_JPEG_CHROMA_SUBSAMPLING_444; break;
-        case 0x21: value = V4L2_JPEG_CHROMA_SUBSAMPLING_422; break;
-        case 0x22: value = V4L2_JPEG_CHROMA_SUBSAMPLING_420; break;
-        case 0x41: value = V4L2_JPEG_CHROMA_SUBSAMPLING_411; break;
+        case 0x00:
+            value = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
+            break;
+        case 0x11:
+            value = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
+            break;
+        case 0x21:
+            value = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
+            break;
+        case 0x22:
+            value = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
+            break;
+        case 0x41:
+            value = V4L2_JPEG_CHROMA_SUBSAMPLING_411;
+            break;
         case 0x12:
         default:
-           ALOGE("Unsupported chroma subsampling %ux%u", horizontal, vertical);
-           return false;
+            ALOGE("Unsupported chroma subsampling %ux%u", horizontal, vertical);
+            return false;
     }
 
     m_v4l2Controls[HWJPEG_CTRL_CHROMFACTOR].id = V4L2_CID_JPEG_CHROMA_SUBSAMPLING;
@@ -93,17 +109,14 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::SetQuality(
-        unsigned int quality_factor, unsigned int quality_factor2)
-{
+bool CHWJpegV4L2Compressor::SetQuality(unsigned int quality_factor, unsigned int quality_factor2) {
     if (quality_factor > 100) {
         ALOGE("Unsupported quality factor %u", quality_factor);
         return false;
     }
 
     if (quality_factor2 > 100) {
-        ALOGE("Unsupported quality factor %u for the secondary image",
-                 quality_factor2);
+        ALOGE("Unsupported quality factor %u for the secondary image", quality_factor2);
         return false;
     }
 
@@ -122,8 +135,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::SetQuality(const unsigned char qtable[])
-{
+bool CHWJpegV4L2Compressor::SetQuality(const unsigned char qtable[]) {
     v4l2_ext_controls ctrls;
     v4l2_ext_control ctrl;
 
@@ -146,10 +158,54 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::SetImageFormat(unsigned int v4l2_fmt,
-                                           unsigned int width, unsigned int height,
-                                           unsigned int width2, unsigned int height2)
-{
+bool CHWJpegV4L2Compressor::SetPadding(unsigned char padding[], unsigned int num_planes) {
+    if (num_planes > 3 || num_planes < 1) {
+        ALOGE("Attempting to set padding for incorrect number of buffers");
+        return false;
+    }
+
+    unsigned int padding_value = 0;
+
+    for (int i = num_planes - 1; i >= 0; i--) {
+        padding_value <<= 8;
+        padding_value |= padding[i];
+    }
+
+    m_v4l2Controls[HWJPEG_CTRL_PADDING].id = V4L2_CID_JPEG_PADDING;
+    m_v4l2Controls[HWJPEG_CTRL_PADDING].value = static_cast<__s32>(padding_value);
+    m_uiControlsToSet |= 1 << HWJPEG_CTRL_PADDING;
+
+    return true;
+}
+
+bool CHWJpegV4L2Compressor::SetPadding2(unsigned char padding[], unsigned int num_planes) {
+    if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) {
+        ALOGE("Back-to-back compression is not suppored by H/W");
+        return false;
+    }
+
+    if (num_planes > 3 || num_planes < 1) {
+        ALOGE("Attempting to set padding for incorrect number of buffers");
+        return false;
+    }
+
+    unsigned int padding_value = 0;
+
+    for (int i = num_planes - 1; i >= 0; i--) {
+        padding_value <<= 8;
+        padding_value |= padding[i];
+    }
+
+    m_v4l2Controls[HWJPEG_CTRL_PADDING2].id = V4L2_CID_JPEG_SEC_PADDING;
+    m_v4l2Controls[HWJPEG_CTRL_PADDING2].value = static_cast<__s32>(padding_value);
+    m_uiControlsToSet |= 1 << HWJPEG_CTRL_PADDING2;
+
+    return true;
+}
+
+bool CHWJpegV4L2Compressor::SetImageFormat(unsigned int v4l2_fmt, unsigned int width,
+                                           unsigned int height, unsigned int width2,
+                                           unsigned int height2) {
     if ((m_v4l2Format.fmt.pix_mp.pixelformat == v4l2_fmt) &&
         (m_v4l2Format.fmt.pix_mp.width == TO_IMAGE_SIZE(width, width2)) &&
         (m_v4l2Format.fmt.pix_mp.height == TO_IMAGE_SIZE(height, height2)))
@@ -164,8 +220,7 @@
     return TryFormat();
 }
 
-bool CHWJpegV4L2Compressor::GetImageBufferSizes(size_t buf_sizes[], unsigned int *num_buffers)
-{
+bool CHWJpegV4L2Compressor::GetImageBufferSizes(size_t buf_sizes[], unsigned int *num_buffers) {
     if (buf_sizes) {
         for (unsigned int i = 0; i < m_v4l2Format.fmt.pix_mp.num_planes; i++)
             buf_sizes[i] = m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage;
@@ -174,7 +229,7 @@
     if (num_buffers) {
         if (*num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) {
             ALOGE("The size array length %u is smaller than the number of required buffers %u",
-                    *num_buffers, m_v4l2Format.fmt.pix_mp.num_planes);
+                  *num_buffers, m_v4l2Format.fmt.pix_mp.num_planes);
             return false;
         }
 
@@ -185,19 +240,18 @@
 }
 
 bool CHWJpegV4L2Compressor::SetImageBuffer(char *buffers[], size_t len_buffers[],
-                                           unsigned int num_buffers)
-{
+                                           unsigned int num_buffers) {
     if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) {
-        ALOGE("The number of buffers %u is smaller than the required %u",
-                num_buffers,m_v4l2Format.fmt.pix_mp.num_planes);
+        ALOGE("The number of buffers %u is smaller than the required %u", num_buffers,
+              m_v4l2Format.fmt.pix_mp.num_planes);
         return false;
     }
 
     for (unsigned int i = 0; i < m_v4l2Format.fmt.pix_mp.num_planes; i++) {
         m_v4l2SrcPlanes[i].m.userptr = reinterpret_cast<unsigned long>(buffers[i]);
         if (len_buffers[i] < m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage) {
-            ALOGE("The size of the buffer[%u] %zu is smaller than required %u",
-                    i, len_buffers[i], m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage);
+            ALOGE("The size of the buffer[%u] %zu is smaller than required %u", i, len_buffers[i],
+                  m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage);
             return false;
         }
         m_v4l2SrcPlanes[i].bytesused = m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage;
@@ -212,19 +266,18 @@
 }
 
 bool CHWJpegV4L2Compressor::SetImageBuffer(int buffers[], size_t len_buffers[],
-                                           unsigned int num_buffers)
-{
+                                           unsigned int num_buffers) {
     if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) {
-        ALOGE("The number of buffers %u is smaller than the required %u",
-                num_buffers,m_v4l2Format.fmt.pix_mp.num_planes);
+        ALOGE("The number of buffers %u is smaller than the required %u", num_buffers,
+              m_v4l2Format.fmt.pix_mp.num_planes);
         return false;
     }
 
     for (unsigned int i = 0; i < m_v4l2Format.fmt.pix_mp.num_planes; i++) {
         m_v4l2SrcPlanes[i].m.fd = buffers[i];
         if (len_buffers[i] < m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage) {
-            ALOGE("The size of the buffer[%u] %zu is smaller than required %u",
-                    i, len_buffers[i], m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage);
+            ALOGE("The size of the buffer[%u] %zu is smaller than required %u", i, len_buffers[i],
+                  m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage);
             return false;
         }
         m_v4l2SrcPlanes[i].bytesused = m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage;
@@ -238,23 +291,22 @@
     return true;
 }
 
- bool CHWJpegV4L2Compressor::SetImageBuffer2(char *buffers[], size_t len_buffers[],
-                                                    unsigned int num_buffers)
-{
+bool CHWJpegV4L2Compressor::SetImageBuffer2(char *buffers[], size_t len_buffers[],
+                                            unsigned int num_buffers) {
     if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) {
         ALOGE("Back-to-back compression is not suppored by H/W");
         return false;
     }
 
     if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) {
-        ALOGE("The number of buffers %u is smaller than the required %u (secondary)",
-                num_buffers,m_v4l2Format.fmt.pix_mp.num_planes);
+        ALOGE("The number of buffers %u is smaller than the required %u (secondary)", num_buffers,
+              m_v4l2Format.fmt.pix_mp.num_planes);
         return false;
     }
 
     unsigned int ibuf = 0;
     for (unsigned int i = m_v4l2Format.fmt.pix_mp.num_planes;
-                                i < (m_v4l2Format.fmt.pix_mp.num_planes * 2); i++, ibuf++) {
+         i < (m_v4l2Format.fmt.pix_mp.num_planes * 2); i++, ibuf++) {
         m_v4l2SrcPlanes[i].m.userptr = reinterpret_cast<unsigned long>(buffers[ibuf]);
         // size check is ignored for the secondary image buffers
         m_v4l2SrcPlanes[i].bytesused = len_buffers[ibuf];
@@ -267,23 +319,22 @@
     return true;
 }
 
- bool CHWJpegV4L2Compressor::SetImageBuffer2(int buffers[], size_t len_buffers[],
-                                                    unsigned int num_buffers)
-{
+bool CHWJpegV4L2Compressor::SetImageBuffer2(int buffers[], size_t len_buffers[],
+                                            unsigned int num_buffers) {
     if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) {
         ALOGE("Back-to-back compression is not suppored by H/W");
         return false;
     }
 
     if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) {
-        ALOGE("The number of buffers %u is smaller than the required %u (secondary)",
-                num_buffers,m_v4l2Format.fmt.pix_mp.num_planes);
+        ALOGE("The number of buffers %u is smaller than the required %u (secondary)", num_buffers,
+              m_v4l2Format.fmt.pix_mp.num_planes);
         return false;
     }
 
     unsigned int ibuf = 0;
     for (unsigned int i = m_v4l2Format.fmt.pix_mp.num_planes;
-                                i < (m_v4l2Format.fmt.pix_mp.num_planes * 2); i++, ibuf++) {
+         i < (m_v4l2Format.fmt.pix_mp.num_planes * 2); i++, ibuf++) {
         m_v4l2SrcPlanes[i].m.fd = buffers[ibuf];
         // size check is ignored for the secondary image buffers
         m_v4l2SrcPlanes[i].bytesused = len_buffers[ibuf];
@@ -297,8 +348,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::SetJpegBuffer(char *buffer, size_t len_buffer)
-{
+bool CHWJpegV4L2Compressor::SetJpegBuffer(char *buffer, size_t len_buffer) {
     m_v4l2DstPlanes[0].m.userptr = reinterpret_cast<unsigned long>(buffer);
     m_v4l2DstPlanes[0].length = len_buffer;
     m_v4l2DstBuffer.memory = V4L2_MEMORY_USERPTR;
@@ -306,8 +356,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::SetJpegBuffer(int buffer, size_t len_buffer, int offset)
-{
+bool CHWJpegV4L2Compressor::SetJpegBuffer(int buffer, size_t len_buffer, int offset) {
     m_v4l2DstPlanes[0].m.fd = buffer;
     m_v4l2DstPlanes[0].length = len_buffer;
     m_v4l2DstPlanes[0].data_offset = offset;
@@ -316,8 +365,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::SetJpegBuffer2(char *buffer, size_t len_buffer)
-{
+bool CHWJpegV4L2Compressor::SetJpegBuffer2(char *buffer, size_t len_buffer) {
     if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) {
         ALOGE("Back-to-back compression is not suppored by H/W");
         return false;
@@ -329,8 +377,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::SetJpegBuffer2(int buffer, size_t len_buffer)
-{
+bool CHWJpegV4L2Compressor::SetJpegBuffer2(int buffer, size_t len_buffer) {
     if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) {
         ALOGE("Back-to-back compression is not suppored by H/W");
         return false;
@@ -342,11 +389,9 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::StopStreaming()
-{
+bool CHWJpegV4L2Compressor::StopStreaming() {
     if (TestFlag(HWJPEG_FLAG_STREAMING)) {
-        if (!StreamOff())
-            return false;
+        if (!StreamOff()) return false;
         ClearFlag(HWJPEG_FLAG_STREAMING);
     }
 
@@ -355,19 +400,16 @@
 
     // It is OK to skip DQBUF because STREAMOFF dequeues all queued buffers
     if (TestFlag(HWJPEG_FLAG_REQBUFS)) {
-        if (!ReqBufs(0))
-            return false;
+        if (!ReqBufs(0)) return false;
         ClearFlag(HWJPEG_FLAG_REQBUFS);
     }
 
     return true;
 }
 
-ssize_t CHWJpegV4L2Compressor::Compress(size_t *secondary_stream_size, bool block_mode)
-{
+ssize_t CHWJpegV4L2Compressor::Compress(size_t *secondary_stream_size, bool block_mode) {
     if (TestFlag(HWJPEG_FLAG_PIX_FMT)) {
-        if (!StopStreaming() || !SetFormat())
-            return -1;
+        if (!StopStreaming() || !SetFormat()) return -1;
     }
 
     if (!TestFlag(HWJPEG_FLAG_SRC_BUFFER)) {
@@ -384,7 +426,8 @@
     m_v4l2DstBuffer.length = 1;
     if (IsB2BCompression()) {
         if (!TestFlag(HWJPEG_FLAG_SRC_BUFFER2 | HWJPEG_FLAG_DST_BUFFER2)) {
-            ALOGE("Either of source or destination buffer of secondary image is not specified (%#x)",
+            ALOGE("Either of source or destination buffer of secondary image is not specified "
+                  "(%#x)",
                   GetFlags());
             return -1;
         }
@@ -399,14 +442,12 @@
     if (!!(GetAuxFlags() & EXYNOS_HWJPEG_AUXOPT_DST_NOCACHECLEAN))
         m_v4l2DstBuffer.flags |= V4L2_BUF_FLAG_NO_CACHE_CLEAN;
 
-    if (!ReqBufs() || !StreamOn() || !UpdateControls() || !QBuf())
-        return -1;
+    if (!ReqBufs() || !StreamOn() || !UpdateControls() || !QBuf()) return -1;
 
     return block_mode ? DQBuf(secondary_stream_size) : 0;
 }
 
-bool CHWJpegV4L2Compressor::TryFormat()
-{
+bool CHWJpegV4L2Compressor::TryFormat() {
     if (ioctl(GetDeviceFD(), VIDIOC_TRY_FMT, &m_v4l2Format) < 0) {
         ALOGERR("Failed to TRY_FMT for compression");
         return false;
@@ -415,8 +456,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::SetFormat()
-{
+bool CHWJpegV4L2Compressor::SetFormat() {
     if (ioctl(GetDeviceFD(), VIDIOC_S_FMT, &m_v4l2Format) < 0) {
         ALOGERR("Failed to S_FMT for image to compress");
         return false;
@@ -440,12 +480,10 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::UpdateControls()
-{
+bool CHWJpegV4L2Compressor::UpdateControls() {
     bool enable_hwfc = !!(GetAuxFlags() & EXYNOS_HWJPEG_AUXOPT_ENABLE_HWFC);
 
-    if ((m_uiControlsToSet == 0) && (enable_hwfc == m_bEnableHWFC))
-        return true;
+    if ((m_uiControlsToSet == 0) && (enable_hwfc == m_bEnableHWFC)) return true;
 
     v4l2_ext_controls ctrls;
     v4l2_ext_control ctrl[HWJPEG_CTRL_NUM];
@@ -481,14 +519,12 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::ReqBufs(unsigned int count)
-{
+bool CHWJpegV4L2Compressor::ReqBufs(unsigned int count) {
     // - count > 0 && REQBUFS is set: Just return true
     // - count > 0 && REQBUFS is unset: REQBUFS(count) is required
     // - count == 0 && REQBUFS is set: REQBUFS(0) is required
     // - count == 0 && REQBUFS is unset: Just return true;
-    if ((count > 0) == TestFlag(HWJPEG_FLAG_REQBUFS))
-        return true;
+    if ((count > 0) == TestFlag(HWJPEG_FLAG_REQBUFS)) return true;
 
     v4l2_requestbuffers reqbufs;
 
@@ -523,10 +559,8 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::StreamOn()
-{
-    if (TestFlag(HWJPEG_FLAG_STREAMING))
-        return true;
+bool CHWJpegV4L2Compressor::StreamOn() {
+    if (TestFlag(HWJPEG_FLAG_STREAMING)) return true;
 
     if (!TestFlag(HWJPEG_FLAG_REQBUFS)) {
         ALOGE("Trying to STREAMON before REQBUFS");
@@ -549,10 +583,8 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::StreamOff()
-{
-    if (!TestFlag(HWJPEG_FLAG_STREAMING))
-        return true;
+bool CHWJpegV4L2Compressor::StreamOff() {
+    if (!TestFlag(HWJPEG_FLAG_STREAMING)) return true;
 
     // error during stream off do not need further handling because of nothing to do
     if (ioctl(GetDeviceFD(), VIDIOC_STREAMOFF, &m_v4l2SrcBuffer.type) < 0)
@@ -566,8 +598,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::QBuf()
-{
+bool CHWJpegV4L2Compressor::QBuf() {
     if (!TestFlag(HWJPEG_FLAG_REQBUFS)) {
         ALOGE("QBuf is not permitted until REQBUFS is performed");
         return false;
@@ -592,8 +623,7 @@
     return true;
 }
 
-ssize_t CHWJpegV4L2Compressor::DQBuf(size_t *secondary_stream_size)
-{
+ssize_t CHWJpegV4L2Compressor::DQBuf(size_t *secondary_stream_size) {
     bool failed = false;
     v4l2_buffer buffer_src, buffer_dst;
     v4l2_plane planes_src[6], planes_dst[2];
@@ -627,8 +657,7 @@
 
     ClearFlag(HWJPEG_FLAG_QBUF_OUT | HWJPEG_FLAG_QBUF_CAP);
 
-    if (failed)
-        return -1;
+    if (failed) return -1;
 
     if (!!((buffer_src.flags | buffer_dst.flags) & V4L2_BUF_FLAG_ERROR)) {
         ALOGE("Error occurred during compression");
@@ -646,14 +675,12 @@
     return GetStreamSize(secondary_stream_size);
 }
 
-ssize_t CHWJpegV4L2Compressor::WaitForCompression(size_t *secondary_stream_size)
-{
+ssize_t CHWJpegV4L2Compressor::WaitForCompression(size_t *secondary_stream_size) {
     return DQBuf(secondary_stream_size);
 }
 
 bool CHWJpegV4L2Compressor::GetImageBuffers(int buffers[], size_t len_buffers[],
-                                            unsigned int num_buffers)
-{
+                                            unsigned int num_buffers) {
     if (m_v4l2SrcBuffer.memory != V4L2_MEMORY_DMABUF) {
         ALOGE("Current image buffer type is not dma-buf but attempted to retrieve dma-buf buffers");
         return false;
@@ -661,7 +688,7 @@
 
     if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) {
         ALOGE("Number of planes are %u but attemts to retrieve %u buffers",
-                m_v4l2Format.fmt.pix_mp.num_planes, num_buffers);
+              m_v4l2Format.fmt.pix_mp.num_planes, num_buffers);
         return false;
     }
 
@@ -674,8 +701,7 @@
 }
 
 bool CHWJpegV4L2Compressor::GetImageBuffers(char *buffers[], size_t len_buffers[],
-                                            unsigned int num_buffers)
-{
+                                            unsigned int num_buffers) {
     if (m_v4l2SrcBuffer.memory != V4L2_MEMORY_USERPTR) {
         ALOGE("Current image buffer type is not userptr but attempted to retrieve userptr buffers");
         return false;
@@ -683,7 +709,7 @@
 
     if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) {
         ALOGE("Number of planes are %u but attemts to retrieve %u buffers",
-                m_v4l2Format.fmt.pix_mp.num_planes, num_buffers);
+              m_v4l2Format.fmt.pix_mp.num_planes, num_buffers);
         return false;
     }
 
@@ -695,8 +721,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::GetJpegBuffer(int *buffer, size_t *len_buffer)
-{
+bool CHWJpegV4L2Compressor::GetJpegBuffer(int *buffer, size_t *len_buffer) {
     if (m_v4l2DstBuffer.memory != V4L2_MEMORY_DMABUF) {
         ALOGE("Current jpeg buffer type is not dma-buf but attempted to retrieve dma-buf buffer");
         return false;
@@ -708,8 +733,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Compressor::GetJpegBuffer(char **buffer, size_t *len_buffer)
-{
+bool CHWJpegV4L2Compressor::GetJpegBuffer(char **buffer, size_t *len_buffer) {
     if (m_v4l2DstBuffer.memory != V4L2_MEMORY_USERPTR) {
         ALOGE("Current jpeg buffer type is not userptr but attempted to retrieve userptr buffer");
         return false;
@@ -721,8 +745,7 @@
     return true;
 }
 
-void CHWJpegV4L2Compressor::Release()
-{
+void CHWJpegV4L2Compressor::Release() {
     StopStreaming();
 }
 
@@ -730,8 +753,7 @@
 /********* D E C O M P R E S S I O N   S U P P O R T **************************/
 /******************************************************************************/
 
-CHWJpegV4L2Decompressor::CHWJpegV4L2Decompressor() : CHWJpegDecompressor("/dev/video12")
-{
+CHWJpegV4L2Decompressor::CHWJpegV4L2Decompressor() : CHWJpegDecompressor("/dev/video12") {
     m_v4l2Format.type = 0; // inidication of uninitialized state
 
     memset(&m_v4l2DstBuffer, 0, sizeof(m_v4l2DstBuffer));
@@ -748,21 +770,18 @@
     }
 }
 
-CHWJpegV4L2Decompressor::~CHWJpegV4L2Decompressor()
-{
+CHWJpegV4L2Decompressor::~CHWJpegV4L2Decompressor() {
     CancelCapture();
 }
 
-bool CHWJpegV4L2Decompressor::PrepareCapture()
-{
+bool CHWJpegV4L2Decompressor::PrepareCapture() {
     if (m_v4l2DstBuffer.length < m_v4l2Format.fmt.pix.sizeimage) {
-        ALOGE("The size of the buffer %u is smaller than required %u",
-              m_v4l2DstBuffer.length, m_v4l2Format.fmt.pix.sizeimage);
+        ALOGE("The size of the buffer %u is smaller than required %u", m_v4l2DstBuffer.length,
+              m_v4l2Format.fmt.pix.sizeimage);
         return false;
     }
 
-    if (TestFlag(HWJPEG_FLAG_CAPTURE_READY))
-        return true;
+    if (TestFlag(HWJPEG_FLAG_CAPTURE_READY)) return true;
 
     v4l2_requestbuffers reqbufs;
 
@@ -788,10 +807,8 @@
     return true;
 }
 
-void CHWJpegV4L2Decompressor::CancelCapture()
-{
-    if (!TestFlag(HWJPEG_FLAG_CAPTURE_READY))
-        return;
+void CHWJpegV4L2Decompressor::CancelCapture() {
+    if (!TestFlag(HWJPEG_FLAG_CAPTURE_READY)) return;
 
     v4l2_requestbuffers reqbufs;
 
@@ -805,14 +822,12 @@
     ClearFlag(HWJPEG_FLAG_CAPTURE_READY);
 }
 
-bool CHWJpegV4L2Decompressor::SetImageFormat(unsigned int v4l2_fmt,
-                                         unsigned int width, unsigned int height)
-{
+bool CHWJpegV4L2Decompressor::SetImageFormat(unsigned int v4l2_fmt, unsigned int width,
+                                             unsigned int height) {
     // Test if new format is the same as the current configured format
     if (m_v4l2Format.type != 0) {
         v4l2_pix_format *p = &m_v4l2Format.fmt.pix;
-        if ((p->pixelformat == v4l2_fmt) &&
-            (p->width == width) && (p->height == height))
+        if ((p->pixelformat == v4l2_fmt) && (p->width == width) && (p->height == height))
             return true;
     }
 
@@ -826,16 +841,14 @@
     m_v4l2Format.fmt.pix.height = height;
 
     if (ioctl(GetDeviceFD(), VIDIOC_S_FMT, &m_v4l2Format) < 0) {
-        ALOGERR("Failed to S_FMT for decompressed image (%08X,%ux%u)",
-                v4l2_fmt, width, height);
+        ALOGERR("Failed to S_FMT for decompressed image (%08X,%ux%u)", v4l2_fmt, width, height);
         return false;
     }
 
     return true;
 }
 
-bool CHWJpegV4L2Decompressor::SetImageBuffer(char *buffer, size_t len_buffer)
-{
+bool CHWJpegV4L2Decompressor::SetImageBuffer(char *buffer, size_t len_buffer) {
     m_v4l2DstBuffer.m.userptr = reinterpret_cast<unsigned long>(buffer);
     m_v4l2DstBuffer.bytesused = m_v4l2Format.fmt.pix.sizeimage;
     m_v4l2DstBuffer.length = len_buffer;
@@ -844,8 +857,7 @@
     return true;
 }
 
-bool CHWJpegV4L2Decompressor::SetImageBuffer(int buffer, size_t len_buffer)
-{
+bool CHWJpegV4L2Decompressor::SetImageBuffer(int buffer, size_t len_buffer) {
     m_v4l2DstBuffer.m.fd = buffer;
     m_v4l2DstBuffer.bytesused = m_v4l2Format.fmt.pix.sizeimage;
     m_v4l2DstBuffer.length = len_buffer;
@@ -854,10 +866,8 @@
     return true;
 }
 
-bool CHWJpegV4L2Decompressor::PrepareStream()
-{
-    if (TestFlag(HWJPEG_FLAG_OUTPUT_READY))
-        return true;
+bool CHWJpegV4L2Decompressor::PrepareStream() {
+    if (TestFlag(HWJPEG_FLAG_OUTPUT_READY)) return true;
 
     /*
      * S_FMT for output stream is unneccessary because the driver assumes that
@@ -893,10 +903,8 @@
     return true;
 }
 
-void CHWJpegV4L2Decompressor::CancelStream()
-{
-    if (!TestFlag(HWJPEG_FLAG_OUTPUT_READY))
-        return;
+void CHWJpegV4L2Decompressor::CancelStream() {
+    if (!TestFlag(HWJPEG_FLAG_OUTPUT_READY)) return;
 
     v4l2_requestbuffers rb;
     memset(&rb, 0, sizeof(rb));
@@ -911,8 +919,7 @@
     ClearFlag(HWJPEG_FLAG_OUTPUT_READY);
 }
 
-bool CHWJpegV4L2Decompressor::QBufAndWait(const char *buffer, size_t len)
-{
+bool CHWJpegV4L2Decompressor::QBufAndWait(const char *buffer, size_t len) {
     v4l2_buffer buf;
     memset(&buf, 0, sizeof(buf));
     buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
@@ -952,8 +959,7 @@
     return ret;
 }
 
-bool CHWJpegV4L2Decompressor::Decompress(const char *buffer, size_t len)
-{
+bool CHWJpegV4L2Decompressor::Decompress(const char *buffer, size_t len) {
     if (m_v4l2Format.type == 0) {
         ALOGE("Decompressed image format is not specified");
         return false;
@@ -966,11 +972,9 @@
 
     // Do not change the order of PrepareCapture() and PrepareStream().
     // Otherwise, decompression will fail.
-    if (!PrepareCapture() || !PrepareStream())
-        return false;
+    if (!PrepareCapture() || !PrepareStream()) return false;
 
-    if (!QBufAndWait(buffer, len))
-        return false;
+    if (!QBufAndWait(buffer, len)) return false;
 
     return true;
 }
diff --git a/libhwjpeg/include/ExynosJpegApi.h b/libhwjpeg/include/ExynosJpegApi.h
index a82b65b..dcf06b3 100644
--- a/libhwjpeg/include/ExynosJpegApi.h
+++ b/libhwjpeg/include/ExynosJpegApi.h
@@ -33,7 +33,7 @@
 #endif
 
 #define JPEG_BUF_TYPE_USER_PTR 1
-#define JPEG_BUF_TYPE_DMA_BUF  2
+#define JPEG_BUF_TYPE_DMA_BUF 2
 
 // CUSTOM V4L2 4CC FORMATS FOR LEGACY JPEG LIBRARY AND DRIVERS
 #ifndef V4L2_PIX_FMT_JPEG_444
@@ -78,11 +78,12 @@
     int m_nStreamSize;
 
     bool __EnsureFormatIsApplied();
+
 protected:
     enum {
-        STATE_SIZE_CHANGED      = 1 << 0,
-        STATE_PIXFMT_CHANGED    = 1 << 1,
-        STATE_BASE_MAX          = 1 << 16,
+        STATE_SIZE_CHANGED = 1 << 0,
+        STATE_PIXFMT_CHANGED = 1 << 1,
+        STATE_BASE_MAX = 1 << 16,
     };
 
     unsigned int GetDeviceCapabilities() { return m_hwjpeg.GetDeviceCapabilities(); }
@@ -95,16 +96,29 @@
     bool TestStateEither(unsigned int state) { return (m_uiState & state) != 0; }
 
     virtual bool EnsureFormatIsApplied() { return __EnsureFormatIsApplied(); }
+
 public:
-    ExynosJpegEncoder(): m_hwjpeg(),
-          m_iInBufType(JPEG_BUF_TYPE_USER_PTR), m_iOutBufType(JPEG_BUF_TYPE_USER_PTR), m_uiState(0),
-          m_nQFactor(0), m_nWidth(0), m_nHeight(0), m_v4l2Format(0), m_jpegFormat(0), m_nStreamSize(0)
-    {
+    ExynosJpegEncoder()
+          : m_hwjpeg(),
+            m_iInBufType(JPEG_BUF_TYPE_USER_PTR),
+            m_iOutBufType(JPEG_BUF_TYPE_USER_PTR),
+            m_uiState(0),
+            m_nQFactor(0),
+            m_nWidth(0),
+            m_nHeight(0),
+            m_v4l2Format(0),
+            m_jpegFormat(0),
+            m_nStreamSize(0) {
         /* To detect setInBuf() call without format setting */
         SetState(STATE_SIZE_CHANGED | STATE_PIXFMT_CHANGED);
     }
     virtual ~ExynosJpegEncoder() { destroy(); }
 
+    // Acquire exclusive lock to V4L2 device. This is a blocking call.
+    int lock();
+    // Release exclusive lock to V4L2 device.
+    int unlock();
+
     // Return 0 on success, -1 on error
     int flagCreate() { return m_hwjpeg.Okay() ? 0 : -1; }
     virtual int create(void) { return flagCreate(); }
@@ -113,7 +127,7 @@
     int setCache(int __unused val) { return 0; }
 
     void *getJpegConfig() { return reinterpret_cast<void *>(this); }
-    int setJpegConfig(void* pConfig);
+    int setJpegConfig(void *pConfig);
 
     int checkInBufType(void) { return m_iInBufType; }
     int checkOutBufType(void) { return m_iOutBufType; }
@@ -155,26 +169,24 @@
 
     int setQuality(int iQuality) {
         if (m_nQFactor != iQuality) {
-            if (!m_hwjpeg.SetQuality(static_cast<unsigned int>(iQuality)))
-                return -1;
+            if (!m_hwjpeg.SetQuality(static_cast<unsigned int>(iQuality))) return -1;
             m_nQFactor = iQuality;
         }
         return 0;
     }
 
     int setQuality(const unsigned char q_table[]);
+    int setPadding(unsigned char *padding, unsigned int num_planes);
 
     int setColorBufSize(int *piBufSize, int iSize);
     int getJpegSize(void) { return m_nStreamSize; }
 
     int encode(void) {
-        if (!__EnsureFormatIsApplied())
-            return false;
+        if (!__EnsureFormatIsApplied()) return false;
 
         m_nStreamSize = static_cast<int>(m_hwjpeg.Compress());
         return (m_nStreamSize < 0) ? -1 : 0;
     }
-
 };
 
 #endif //__HARDWARE_EXYNOS_EXYNOS_JPEG_API_H__
diff --git a/libhwjpeg/include/ExynosJpegEncoderForCamera.h b/libhwjpeg/include/ExynosJpegEncoderForCamera.h
index a50d884..e7a2eec 100644
--- a/libhwjpeg/include/ExynosJpegEncoderForCamera.h
+++ b/libhwjpeg/include/ExynosJpegEncoderForCamera.h
@@ -18,18 +18,18 @@
 #ifndef __HARDWARE_EXYNOS_JPEG_ENCODER_FOR_CAMERA_H__
 #define __HARDWARE_EXYNOS_JPEG_ENCODER_FOR_CAMERA_H__
 
-#include <memory>
-
+#include <ExynosExif.h>
+#include <hardware/exynos/ExynosExif.h>
 #include <pthread.h>
 
-#include <ExynosExif.h>
+#include <memory>
+
 #include "ExynosJpegApi.h"
-#include <hardware/exynos/ExynosExif.h>
 
 class CAppMarkerWriter; // defined in libhwjpeg/AppMarkerWriter.h
-class ThumbnailScaler; // defined in libhwjpeg/thumbnail_scaler.h
+class ThumbnailScaler;  // defined in libhwjpeg/thumbnail_scaler.h
 
-class ExynosJpegEncoderForCamera: public ExynosJpegEncoder {
+class ExynosJpegEncoderForCamera : public ExynosJpegEncoder {
     enum {
         STATE_THUMBSIZE_CHANGED = STATE_BASE_MAX << 0,
         STATE_HWFC_ENABLED = STATE_BASE_MAX << 1,
@@ -64,7 +64,7 @@
 
     union {
         char *m_pThumbnailImageBuffer[3]; // checkInBufType() == JPEG_BUF_TYPE_USER_PTR
-        int m_fdThumbnailImageBuffer[3]; // checkInBufType() == JPEG_BUF_TYPE_DMA_BUF
+        int m_fdThumbnailImageBuffer[3];  // checkInBufType() == JPEG_BUF_TYPE_DMA_BUF
     };
     size_t m_szThumbnailImageLen[3];
 
@@ -76,10 +76,11 @@
     app_info_t m_appInfo[15];
 
     bool AllocThumbBuffer(int v4l2Format); /* For single compression */
-    bool AllocThumbJpegBuffer(); /* For BTB compression */
+    bool AllocThumbJpegBuffer();           /* For BTB compression */
     bool GenerateThumbnailImage();
     size_t CompressThumbnail();
-    size_t CompressThumbnailOnly(size_t limit, int quality, unsigned int v4l2Format, int src_buftype);
+    size_t CompressThumbnailOnly(size_t limit, int quality, unsigned int v4l2Format,
+                                 int src_buftype);
     size_t RemoveTrailingDummies(char *base, size_t len);
     ssize_t FinishCompression(size_t mainlen, size_t thumblen);
     bool ProcessExif(char *base, size_t limit, exif_attribute_t *exifInfo, extra_appinfo_t *extra);
@@ -87,28 +88,35 @@
     bool PrepareCompression(bool thumbnail);
 
     // IsThumbGenerationNeeded - true if thumbnail image needed to be generated from the main image
-    //                           It also implies that a worker thread is generated to generate thumbnail concurrently.
+    //                           It also implies that a worker thread is generated to generate
+    //                           thumbnail concurrently.
     inline bool IsThumbGenerationNeeded() { return !TestState(STATE_NO_CREATE_THUMBIMAGE); }
     inline void NoThumbGenerationNeeded() { SetState(STATE_NO_CREATE_THUMBIMAGE); }
     inline void ThumbGenerationNeeded() { ClearState(STATE_NO_CREATE_THUMBIMAGE); }
 
     inline bool IsBTBCompressionSupported() {
         return !!(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION) &&
-                    !TestState(STATE_NO_BTBCOMP);
+                !TestState(STATE_NO_BTBCOMP);
     }
+
 protected:
     virtual bool EnsureFormatIsApplied();
+
 public:
     ExynosJpegEncoderForCamera(bool bBTBComp = true);
     virtual ~ExynosJpegEncoderForCamera();
 
-    int encode(int *size, exif_attribute_t *exifInfo, char** pcJpegBuffer, debug_attribute_t *debugInfo = 0);
-    int encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, char** pcJpegBuffer, debug_attribute_t *debugInfo = 0);
-    int encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, char** pcJpegBuffer, extra_appinfo_t *appInfo = 0);
+    int encode(int *size, exif_attribute_t *exifInfo, char **pcJpegBuffer,
+               debug_attribute_t *debugInfo = 0);
+    int encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, char **pcJpegBuffer,
+               debug_attribute_t *debugInfo = 0);
+    int encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, char **pcJpegBuffer,
+               extra_appinfo_t *appInfo = 0);
     int setInBuf2(int *piBuf, int *iSize);
     int setInBuf2(char **pcBuf, int *iSize);
     int setThumbnailSize(int w, int h);
     int setThumbnailQuality(int quality);
+    int setThumbnailPadding(unsigned char *padding, unsigned int num_planes);
 
     void setExtScalerNum(int csc_hwscaler_id) { m_iHWScalerID = csc_hwscaler_id; }
 
diff --git a/libhwjpeg/include/FileLock.h b/libhwjpeg/include/FileLock.h
new file mode 100644
index 0000000..b308aa7
--- /dev/null
+++ b/libhwjpeg/include/FileLock.h
@@ -0,0 +1,16 @@
+#include "android-base/thread_annotations.h"
+
+// Encapsulates advisory file lock for a given field descriptor
+class CAPABILITY("mutex") FileLock {
+public:
+    FileLock(int fd);
+    ~FileLock() = default;
+
+    // Acquires advisory file lock. This will block.
+    int lock() ACQUIRE();
+    // Releases advisory file lock.
+    int unlock() RELEASE();
+
+private:
+    int fd_;
+};
\ No newline at end of file
diff --git a/libhwjpeg/include/exynos-hwjpeg.h b/libhwjpeg/include/exynos-hwjpeg.h
index 04ffed4..45114b5 100644
--- a/libhwjpeg/include/exynos-hwjpeg.h
+++ b/libhwjpeg/include/exynos-hwjpeg.h
@@ -18,46 +18,38 @@
 #ifndef __EXYNOS_HWJPEG_H__
 #define __EXYNOS_HWJPEG_H__
 
+#include <linux/videodev2.h>
+
 #include <cstddef> // size_t
-/*
- * exynos-hwjpeg.h does not include videodev2.h because Exynos HAL code may
- * define its version of videodev2.h that may differ from <linux/videodev2.h>
- * of the current Linux version.
- * To prevent conflict different versions of videodev2.h, this header file does
- * not include videodev2.h even though it depends on the data types defined in
- * videodev2.h.
- * Therefore, the source files that include this header file, they should
- * include their proper version of videodev2.h.
- */
-#ifndef VIDEO_MAX_PLANES
-#error 'linux/videodev2.h' should be included before 'exynos-hwjpeg.h'
-#endif
 
 #if VIDEO_MAX_PLANES < 6
 #error VIDEO_MAX_PLANES should not be smaller than 6
 #endif
 
+#include "FileLock.h"
+#include "android-base/thread_annotations.h"
+
 // Exynos JPEG specific device capabilities
 // Defined in the driver. Not in videodev2.h
-#define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION       0x0100
-#define V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION     0x0200
-#define V4L2_CAP_EXYNOS_JPEG_HWFC                0x0400
-#define V4L2_CAP_EXYNOS_JPEG_HWFC_EMBEDDED       0x0800
-#define V4L2_CAP_EXYNOS_JPEG_MAX_STREAMSIZE      0x1000
+#define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION 0x0100
+#define V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION 0x0200
+#define V4L2_CAP_EXYNOS_JPEG_HWFC 0x0400
+#define V4L2_CAP_EXYNOS_JPEG_HWFC_EMBEDDED 0x0800
+#define V4L2_CAP_EXYNOS_JPEG_MAX_STREAMSIZE 0x1000
 #define V4L2_CAP_EXYNOS_JPEG_NO_STREAMBASE_ALIGN 0x2000
-#define V4L2_CAP_EXYNOS_JPEG_NO_IMAGEBASE_ALIGN  0x4000
-#define V4L2_CAP_EXYNOS_JPEG_NO_BUFFER_OVERRUN   0x8000
+#define V4L2_CAP_EXYNOS_JPEG_NO_IMAGEBASE_ALIGN 0x4000
+#define V4L2_CAP_EXYNOS_JPEG_NO_BUFFER_OVERRUN 0x8000
 #define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION_FROM_SOS 0x10000
-#define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION_CROP  0x20000
-#define V4L2_CAP_EXYNOS_JPEG_DOWNSCALING         0x40000
-#define V4L2_CAP_EXYNOS_JPEG_DMABUF_OFFSET       0x80000
+#define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION_CROP 0x20000
+#define V4L2_CAP_EXYNOS_JPEG_DOWNSCALING 0x40000
+#define V4L2_CAP_EXYNOS_JPEG_DMABUF_OFFSET 0x80000
 // EXYNOS HWJPEG specific auxiliary option flags
 // The flags are common to all derived classes of CHWJpegCompressor
 // but if a derived class does not support for a specified flag,
 // it is discarded and ignored silently.
-#define EXYNOS_HWJPEG_AUXOPT_ENABLE_HWFC        (1 << 4)
-#define EXYNOS_HWJPEG_AUXOPT_SRC_NOCACHECLEAN   (1 << 8)
-#define EXYNOS_HWJPEG_AUXOPT_DST_NOCACHECLEAN   (1 << 9)
+#define EXYNOS_HWJPEG_AUXOPT_ENABLE_HWFC (1 << 4)
+#define EXYNOS_HWJPEG_AUXOPT_SRC_NOCACHECLEAN (1 << 8)
+#define EXYNOS_HWJPEG_AUXOPT_DST_NOCACHECLEAN (1 << 9)
 
 /*
  * CHWJpegBase - The base class of JPEG compression and decompression
@@ -81,15 +73,19 @@
      *
      */
     unsigned int m_uiAuxFlags;
+
 protected:
     CHWJpegBase(const char *path);
     virtual ~CHWJpegBase();
     int GetDeviceFD() { return m_iFD; }
     void SetDeviceCapabilities(unsigned int cap) { m_uiDeviceCaps = cap; }
     unsigned int GetAuxFlags() { return m_uiAuxFlags; }
+
 public:
     unsigned int GetDeviceCapabilities() { return m_uiDeviceCaps; }
-    bool IsDeviceCapability(unsigned int cap_flags) { return (m_uiDeviceCaps & cap_flags) == cap_flags; }
+    bool IsDeviceCapability(unsigned int cap_flags) {
+        return (m_uiDeviceCaps & cap_flags) == cap_flags;
+    }
 
     /*
      * Okay - Test if the object is correctly initialized
@@ -144,6 +140,7 @@
 class CHWJpegCompressor : public CHWJpegBase {
     size_t m_nLastStreamSize;
     size_t m_nLastThumbStreamSize;
+
 protected:
     void SetStreamSize(size_t main_size, size_t secondary_size = 0) {
         m_nLastStreamSize = main_size;
@@ -151,20 +148,23 @@
     }
 
     ssize_t GetStreamSize(size_t *secondary_size) {
-        if (secondary_size)
-            *secondary_size = m_nLastThumbStreamSize;
+        if (secondary_size) *secondary_size = m_nLastThumbStreamSize;
         return static_cast<ssize_t>(m_nLastStreamSize);
     }
+
 public:
-    CHWJpegCompressor(const char *path): CHWJpegBase(path), m_nLastStreamSize(0), m_nLastThumbStreamSize(0) { }
+    CHWJpegCompressor(const char *path)
+          : CHWJpegBase(path), m_nLastStreamSize(0), m_nLastThumbStreamSize(0) {}
 
     /*
      * SetImageFormat - Configure uncompressed image format, width and height
      * @v4l2_fmt[in] : Image pixel format defined in <linux/videodev2.h>
      * @width[in]      : Width of the primary uncompressed image in the number of pixels
      * @height[in]     : Height of the primary uncompressed image in the number of pixels
-     * @sec_width[in]  : Width of the secondary uncompressed image in the number of pixels (optional)
-     * @sec_height[in] : Height of the secondary uncompressed image in the number of pixels (optional)
+     * @sec_width[in]  : Width of the secondary uncompressed image in the number of pixels
+     * (optional)
+     * @sec_height[in] : Height of the secondary uncompressed image in the number of pixels
+     * (optional)
      * @return : true if configuration of image pixel format and size is successful.
      *           false, otherwise.
      *
@@ -172,7 +172,7 @@
      * to configure different image formats for them.
      */
     virtual bool SetImageFormat(unsigned int v4l2_fmt, unsigned int width, unsigned int height,
-                              unsigned int sec_width = 0, unsigned int sec_height = 0) = 0;
+                                unsigned int sec_width = 0, unsigned int sec_height = 0) = 0;
 
     /*
      * GetImageBufferSizes - Ask the required buffer sizes for the given image format
@@ -196,7 +196,8 @@
     virtual bool SetChromaSampFactor(unsigned int horizontal, unsigned int vertical) = 0;
     /*
      * SetQuality - Configure quality factor for JPEG compression
-     * @quality_factor[in]  : JPEG compression quality factor between 1 and 100 for the primary image
+     * @quality_factor[in]  : JPEG compression quality factor between 1 and 100 for the primary
+     * image
      * @quality_factor2[in] : JPEG compression quality factor for the secondary image (optional)
      * @return: true if quality factors are configured successfully.
      *          false, otherwise.
@@ -214,6 +215,24 @@
      */
     virtual bool SetQuality(const unsigned char __unused qtable[]) { return false; };
     /*
+     * SetPadding - Configures padding per plane for primary image
+     * @padding[in]     : Padding per plane
+     * @num_planes[in]  : Number of planes. This should match the number of elements in @padding
+     * @return          : true if padding is congured successfully.
+     *                    false, otherwise.
+     */
+    virtual bool SetPadding(unsigned char padding[], unsigned int num_planes) = 0;
+    /*
+     * SetPadding2 - Configures padding per plane for thumbnail image
+     * @padding[in]     : padding per plane
+     * @num_planes[in]  : Number of planes. This should match the number of elements in @padding
+     * @return          : true if padding is congured successfully.
+     *                    false, otherwise.
+     */
+    virtual bool SetPadding2(unsigned char __unused padding[], unsigned int __unused num_planes) {
+        return false;
+    }
+    /*
      * SetImageBuffer - Configure the uncompressed primary image buffers (userptr)
      * @buffers[in]     : addresses of the buffers
      * @len_buffers[in] : sizes of the buffers
@@ -221,7 +240,8 @@
      * @return          : true if buffer configuration is successful.
      *                    false, otherwise.
      */
-    virtual bool SetImageBuffer(char *buffers[], size_t len_buffers[], unsigned int num_buffers) = 0;
+    virtual bool SetImageBuffer(char *buffers[], size_t len_buffers[],
+                                unsigned int num_buffers) = 0;
     /*
      * SetImageBuffer - Configure the uncompressed primary image buffers (dmabuf)
      * @buffers[in]     : file descriptors of the buffers exported by dma-buf
@@ -239,7 +259,10 @@
      * @return          : true if buffer configuration is successful.
      *                    false, otherwise.
      */
-    virtual bool SetImageBuffer2(char __unused *buffers[], size_t __unused len_buffers[], unsigned int __unused num_buffers) { return false; }
+    virtual bool SetImageBuffer2(char __unused *buffers[], size_t __unused len_buffers[],
+                                 unsigned int __unused num_buffers) {
+        return false;
+    }
     /*
      * SetImageBuffer2 - Configure the uncompressed secondary image buffers (dmabuf)
      * @buffers[in]     : file descriptors of the buffers exported by dma-buf
@@ -248,7 +271,10 @@
      * @return          : true if buffer configuration is successful.
      *                    false, otherwise.
      */
-    virtual bool SetImageBuffer2(int __unused buffers[], size_t __unused len_buffers[], unsigned int __unused num_buffers) { return false; }
+    virtual bool SetImageBuffer2(int __unused buffers[], size_t __unused len_buffers[],
+                                 unsigned int __unused num_buffers) {
+        return false;
+    }
     /*
      * SetJpegBuffer - Configure the buffer of JPEG stream of the primary image (userptr)
      * @buffer [in]     : The address of the buffer
@@ -311,7 +337,9 @@
      * returns and the returned size will be the stream sizes obtained by the last call to
      * Compress().
      */
-    virtual ssize_t WaitForCompression(size_t __unused *secondary_stream_size = NULL) { return GetStreamSize(secondary_stream_size); }
+    virtual ssize_t WaitForCompression(size_t __unused *secondary_stream_size = NULL) {
+        return GetStreamSize(secondary_stream_size);
+    }
     /*
      * GetImageBuffers - Retrieve the configured uncompressed image buffer information (dmabuf)
      * @buffers[out]: The file descriptors of the buffers exported by dma-buf
@@ -322,7 +350,10 @@
      * DEPREDCATED. DO NOT USE THIS FUNCTION.
      * This function is just provided to support the legacy ExynosJpegEncoder API.
      */
-    virtual bool GetImageBuffers(int __unused buffers[], size_t __unused len_buffers[], unsigned int __unused num_buffers) { return false; }
+    virtual bool GetImageBuffers(int __unused buffers[], size_t __unused len_buffers[],
+                                 unsigned int __unused num_buffers) {
+        return false;
+    }
     /*
      * GetImageBuffers - Retrieve the configured uncompressed image buffer information (userptr)
      * @buffers[out]: The addresses of the buffers
@@ -333,7 +364,10 @@
      * DEPREDCATED. DO NOT USE THIS FUNCTION.
      * This function is just provided to support the legacy ExynosJpegEncoder API.
      */
-    virtual bool GetImageBuffers(char __unused *buffers[], size_t __unused len_buffers[], unsigned int __unused num_buffers) { return false; }
+    virtual bool GetImageBuffers(char __unused *buffers[], size_t __unused len_buffers[],
+                                 unsigned int __unused num_buffers) {
+        return false;
+    }
     /*
      * GetJpegBuffers - Retrieve the configured JPEG stream image buffer information (dmabuf)
      * @buffers[out]: The file descriptor of the buffer exported by dma-buf
@@ -353,11 +387,13 @@
      * DEPREDCATED. DO NOT USE THIS FUNCTION.
      * This function is just provided to support the legacy ExynosJpegEncoder API.
      */
-    virtual bool GetJpegBuffer(char __unused **buffers, size_t __unused *len_buffer) { return false; }
+    virtual bool GetJpegBuffer(char __unused **buffers, size_t __unused *len_buffer) {
+        return false;
+    }
     /*
      * Release - release the buffers acquired by CHWJpegCompressor
      */
-    virtual void Release() { }
+    virtual void Release() {}
 };
 
 /*
@@ -381,8 +417,8 @@
  */
 class CHWJpegDecompressor : public CHWJpegBase {
 public:
-    CHWJpegDecompressor(const char *path) : CHWJpegBase(path) { }
-    virtual ~CHWJpegDecompressor() { }
+    CHWJpegDecompressor(const char *path) : CHWJpegBase(path) {}
+    virtual ~CHWJpegDecompressor() {}
     /*
      * SetImageFormat - Configure decompressed image pixel format
      * @v4l2_fmt[in] : Image pixel format defined in <linux/videodev2.h>
@@ -424,7 +460,9 @@
      * @width[in] : The number of horizontal pixels of the compressed image
      * @height[in] : The number of vertical pixels of the compressed image
      */
-    virtual bool SetStreamPixelSize(unsigned int __unused width, unsigned int __unused height) { return true; }
+    virtual bool SetStreamPixelSize(unsigned int __unused width, unsigned int __unused height) {
+        return true;
+    }
 
     /*
      * SetChromaSampFactor - Configure the chroma subsampling factor for JPEG stream
@@ -441,7 +479,10 @@
      * If it is required to specify chroma subsampling factors separately, you should
      * override SetChromaSampFactor().
      */
-    virtual bool SetChromaSampFactor(unsigned int __unused horizontal, unsigned int __unused vertical) { return true; }
+    virtual bool SetChromaSampFactor(unsigned int __unused horizontal,
+                                     unsigned int __unused vertical) {
+        return true;
+    }
 
     /*
      * SetDQT - Configure the address of DQT
@@ -484,8 +525,9 @@
 
 class CHWJpegFlagManager {
     unsigned int m_uiHWConfigFlags;
+
 public:
-    CHWJpegFlagManager() : m_uiHWConfigFlags(0) { }
+    CHWJpegFlagManager() : m_uiHWConfigFlags(0) {}
     void SetFlag(unsigned int flag) { m_uiHWConfigFlags |= flag; }
     void ClearFlag(unsigned int flag) { m_uiHWConfigFlags &= ~flag; }
     bool TestFlag(unsigned int flag) { return (m_uiHWConfigFlags & flag) == flag; }
@@ -497,7 +539,7 @@
 };
 */
 
-#define TO_SEC_IMG_SIZE(val)    (((val) >> 16) & 0xFFFF)
+#define TO_SEC_IMG_SIZE(val) (((val) >> 16) & 0xFFFF)
 
 class CHWJpegV4L2Compressor : public CHWJpegCompressor, private CHWJpegFlagManager {
     enum {
@@ -505,20 +547,22 @@
         HWJPEG_CTRL_QFACTOR,
         HWJPEG_CTRL_QFACTOR2,
         HWJPEG_CTRL_HWFC,
+        HWJPEG_CTRL_PADDING,
+        HWJPEG_CTRL_PADDING2,
         HWJPEG_CTRL_NUM,
     };
 
-    enum  {
-        HWJPEG_FLAG_PIX_FMT     = 0x1, // Set if unapplied image format exists
+    enum {
+        HWJPEG_FLAG_PIX_FMT = 0x1, // Set if unapplied image format exists
 
-        HWJPEG_FLAG_QBUF_OUT    = 0x100, // Set if the image buffer is queued
-        HWJPEG_FLAG_QBUF_CAP    = 0x200, // Set if the JPEG stream buffer is queued
-        HWJPEG_FLAG_REQBUFS     = 0x400,
-        HWJPEG_FLAG_STREAMING   = 0x800,
+        HWJPEG_FLAG_QBUF_OUT = 0x100, // Set if the image buffer is queued
+        HWJPEG_FLAG_QBUF_CAP = 0x200, // Set if the JPEG stream buffer is queued
+        HWJPEG_FLAG_REQBUFS = 0x400,
+        HWJPEG_FLAG_STREAMING = 0x800,
 
-        HWJPEG_FLAG_SRC_BUFFER  = 0x10000, // Set if SetImageBuffer() is invoked successfully
+        HWJPEG_FLAG_SRC_BUFFER = 0x10000,  // Set if SetImageBuffer() is invoked successfully
         HWJPEG_FLAG_SRC_BUFFER2 = 0x20000, // Set if SetImageBuffer2() is invoked successfully
-        HWJPEG_FLAG_DST_BUFFER  = 0x40000, // Set if SetJpegBuffer() is invoked successfully
+        HWJPEG_FLAG_DST_BUFFER = 0x40000,  // Set if SetJpegBuffer() is invoked successfully
         HWJPEG_FLAG_DST_BUFFER2 = 0x80000, // Set if SetJpegBuffer2() is invoked successfully
     };
 
@@ -532,7 +576,7 @@
     // Only valid after Compression() successes.
     unsigned int m_uiHWDelay;
 
-    v4l2_format m_v4l2Format; // v4l2 format for the source image
+    v4l2_format m_v4l2Format;    // v4l2 format for the source image
     v4l2_buffer m_v4l2SrcBuffer; // v4l2 source buffer
     v4l2_plane m_v4l2SrcPlanes[6];
     v4l2_buffer m_v4l2DstBuffer;
@@ -540,9 +584,11 @@
 
     bool m_bEnableHWFC;
 
+    FileLock file_lock_;
+
     bool IsB2BCompression() {
         return (TO_SEC_IMG_SIZE(m_v4l2Format.fmt.pix_mp.width) +
-                    TO_SEC_IMG_SIZE(m_v4l2Format.fmt.pix_mp.height)) != 0;
+                TO_SEC_IMG_SIZE(m_v4l2Format.fmt.pix_mp.height)) != 0;
     }
 
     // V4L2 Helpers
@@ -555,21 +601,28 @@
     bool QBuf();
     ssize_t DQBuf(size_t *secondary_stream_size);
     bool StopStreaming();
+
 public:
     CHWJpegV4L2Compressor();
     virtual ~CHWJpegV4L2Compressor();
 
+    // Acquires exclusive lock to V4L2 device. This must be called before starting image
+    // configuration. This is a blocking call.
+    int lock();
+    // Releases exclusive lock to V4L2 device. This should be called after encoding is complete.
+    int unlock();
+
     unsigned int GetHWDelay() { return m_uiHWDelay; }
 
     // SetChromaSampFactor can be called during streaming
-    virtual bool SetChromaSampFactor(unsigned int horizontal,
-                                     unsigned int vertical);
-    virtual bool SetQuality(unsigned int quality_factor,
-                            unsigned int quality_factor2 = 0);
+    virtual bool SetChromaSampFactor(unsigned int horizontal, unsigned int vertical);
+    virtual bool SetQuality(unsigned int quality_factor, unsigned int quality_factor2 = 0);
     virtual bool SetQuality(const unsigned char qtable[]);
+    virtual bool SetPadding(unsigned char padding[], unsigned int num_planes);
+    virtual bool SetPadding2(unsigned char padding[], unsigned int num_planes);
 
     virtual bool SetImageFormat(unsigned int v4l2_fmt, unsigned int width, unsigned int height,
-                              unsigned int sec_width = 0, unsigned sec_height = 0);
+                                unsigned int sec_width = 0, unsigned sec_height = 0);
     virtual bool GetImageBufferSizes(size_t buf_sizes[], unsigned int *num_bufffers);
     virtual bool SetImageBuffer(char *buffers[], size_t len_buffers[], unsigned int num_buffers);
     virtual bool SetImageBuffer(int buffers[], size_t len_buffers[], unsigned int num_buffers);
@@ -589,8 +642,8 @@
 };
 
 class CHWJpegV4L2Decompressor : public CHWJpegDecompressor, private CHWJpegFlagManager {
-    enum  {
-        HWJPEG_FLAG_OUTPUT_READY  = 0x10, /* the output stream is ready */
+    enum {
+        HWJPEG_FLAG_OUTPUT_READY = 0x10,  /* the output stream is ready */
         HWJPEG_FLAG_CAPTURE_READY = 0x20, /* the capture stream is ready */
     };
 
@@ -605,6 +658,7 @@
     bool PrepareStream();
     void CancelStream();
     bool QBufAndWait(const char *buffer, size_t len);
+
 public:
     CHWJpegV4L2Decompressor();
     virtual ~CHWJpegV4L2Decompressor();
diff --git a/libhwjpeg/include/hwjpeglib-exynos.h b/libhwjpeg/include/hwjpeglib-exynos.h
index ba95320..5d23630 100644
--- a/libhwjpeg/include/hwjpeglib-exynos.h
+++ b/libhwjpeg/include/hwjpeglib-exynos.h
@@ -25,16 +25,19 @@
  * hwjpeg_decompress_ptr - handle of decompressor instance
  */
 typedef struct hwjpeg_decompressor_struct {
-    unsigned int image_width;           /* width of the compressed image */
-    unsigned int image_height;          /* height of the compressed image */
-    unsigned char num_components;       /* number of components of the compressed image */
-    unsigned char chroma_h_samp_factor; /* horizontal chroma sampling factor of the compressed image */
-    unsigned char chroma_v_samp_factor; /* vertical chroma sampling factor of the compressed image */
-    unsigned char scale_factor;         /* down-scaling factor during decompression: one of 1, 2, 4 and 8 */
+    unsigned int image_width;     /* width of the compressed image */
+    unsigned int image_height;    /* height of the compressed image */
+    unsigned char num_components; /* number of components of the compressed image */
+    unsigned char
+            chroma_h_samp_factor; /* horizontal chroma sampling factor of the compressed image */
+    unsigned char
+            chroma_v_samp_factor; /* vertical chroma sampling factor of the compressed image */
+    unsigned char scale_factor; /* down-scaling factor during decompression: one of 1, 2, 4 and 8 */
 
-    unsigned int output_width;          /* width of the output image (image_width/scale_factor) */
-    unsigned int output_height;         /* height of the output image (image_height/scale_factor) */
-    __u32 output_format;                /* 4CC style format identifier of the output image defined in videodev2.h */
+    unsigned int output_width;  /* width of the output image (image_width/scale_factor) */
+    unsigned int output_height; /* height of the output image (image_height/scale_factor) */
+    __u32 output_format; /* 4CC style format identifier of the output image defined in videodev2.h
+                          */
 } *hwjpeg_decompress_ptr;
 
 /*
@@ -79,7 +82,8 @@
  * @dummybytes: The available dummy bytes after @insize.
  * @return: false on failure
  */
-bool hwjpeg_mem_src(hwjpeg_decompress_ptr cinfo, unsigned char *inbuffer, size_t insize, size_t dummybytes);
+bool hwjpeg_mem_src(hwjpeg_decompress_ptr cinfo, unsigned char *inbuffer, size_t insize,
+                    size_t dummybytes);
 
 /*
  * hwjpeg_config_image_format - configure output image format
@@ -100,7 +104,8 @@
  * @num_buffers: The number of elements in @outsizes and @outbuffer
  * @return: false on failure.
  */
-bool hwjpeg_mem_dst(hwjpeg_decompress_ptr cinfo, unsigned char *outbuffer[], size_t outsize[], unsigned int num_buffers);
+bool hwjpeg_mem_dst(hwjpeg_decompress_ptr cinfo, unsigned char *outbuffer[], size_t outsize[],
+                    unsigned int num_buffers);
 
 /*
  * hwjpeg_dmabuf_dst - configure the buffer to store decompressed image
@@ -113,7 +118,8 @@
  * @num_buffers: The number of elements in @outsizes and @outfd
  * @return: false on failure.
  */
-bool hwjpeg_dmabuf_dst(hwjpeg_decompress_ptr cinfo, int outfd[], size_t outsize[], unsigned int num_buffers);
+bool hwjpeg_dmabuf_dst(hwjpeg_decompress_ptr cinfo, int outfd[], size_t outsize[],
+                       unsigned int num_buffers);
 
 /*
  * hwjpeg_set_downscale_factor - configure the downscaling factor during decompression
@@ -171,7 +177,7 @@
  */
 void hwjpeg_destroy_decompress(hwjpeg_decompress_ptr cinfo);
 
-}; /* extern "C" */
+};     /* extern "C" */
 #endif /* __cplusplus */
 
 #endif /*__HARDWARE_SAMSUNG_EXYNOS7420_HWJPEGDECOMPRESSOR_H__*/
diff --git a/libhwjpeg/libhwjpeg-exynos.cpp b/libhwjpeg/libhwjpeg-exynos.cpp
index 1bfa55a..5f6dd6e 100644
--- a/libhwjpeg/libhwjpeg-exynos.cpp
+++ b/libhwjpeg/libhwjpeg-exynos.cpp
@@ -15,28 +15,26 @@
  * limitations under the License.
  */
 
-#include <cstdio>
-
-#include <cstring>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-
-#include <linux/videodev2.h>
-
 #include <exynos-hwjpeg.h>
+#include <fcntl.h>
 #include <hwjpeglib-exynos.h>
+#include <linux/videodev2.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <cstring>
 
 #include "hwjpeg-internal.h"
 
 #define ALOGERR(fmt, args...) ((void)ALOG(LOG_ERROR, LOG_TAG, fmt " [%s]", ##args, strerror(errno)))
 
-#define ROUND_DOWN(val, denom)  ((val) & ~((denom) - 1))
-#define ROUND_UP(val, denom)  ROUND_DOWN((val) + (denom) - 1, denom)
-#define TO_MASK(val) ((val) - 1)
+#define ROUND_DOWN(val, denom) ((val) & ~((denom)-1))
+#define ROUND_UP(val, denom) ROUND_DOWN((val) + (denom)-1, denom)
+#define TO_MASK(val) ((val)-1)
 
 class CJpegStreamParser {
 private:
@@ -51,18 +49,18 @@
     size_t GetLength(unsigned char *addr);
     bool ParseFrame(unsigned char *addr);
 
-    off_t GetOffset(unsigned char *addr) {
+    ptrdiff_t GetOffset(unsigned char *addr) {
         unsigned long beg = reinterpret_cast<unsigned long>(m_pStreamBase);
         unsigned long cur = reinterpret_cast<unsigned long>(addr);
-        return static_cast<off_t>(cur - beg);
+        return static_cast<ptrdiff_t>(cur - beg);
     }
 
 public:
     unsigned char m_iHorizontalFactor;
     unsigned char m_iVerticalFactor;
 
-    CJpegStreamParser() : m_pStreamBase(NULL), m_nStreamSize(0) { }
-    ~CJpegStreamParser() { }
+    CJpegStreamParser() : m_pStreamBase(NULL), m_nStreamSize(0) {}
+    ~CJpegStreamParser() {}
 
     bool Parse(unsigned char *streambase, size_t length);
 
@@ -72,8 +70,7 @@
     unsigned int GetNumComponents() { return m_nComponents; }
 };
 
-void CJpegStreamParser::Initialize()
-{
+void CJpegStreamParser::Initialize() {
     m_nComponents = 0;
     m_nWidth = 0;
     m_nHeight = 0;
@@ -81,14 +78,12 @@
     m_iVerticalFactor = 1;
 }
 
-size_t CJpegStreamParser::GetLength(unsigned char *addr)
-{
+size_t CJpegStreamParser::GetLength(unsigned char *addr) {
     size_t len = static_cast<size_t>(*addr++) * 0x100;
     return len + *addr;
 }
 
-bool CJpegStreamParser::Parse(unsigned char *streambase, size_t length)
-{
+bool CJpegStreamParser::Parse(unsigned char *streambase, size_t length) {
     Initialize();
 
     m_pStreamBase = streambase;
@@ -117,6 +112,7 @@
         }
 
         unsigned char marker = *addr++;
+        filelen -= 2;
 
         if ((marker != 0xC4) && ((marker & 0xF0) == 0xC0)) { // SOFn
             if (marker != 0xC0) {
@@ -124,18 +120,17 @@
                 return false;
             }
 
-            if (filelen < GetLength(addr)) {
+            if (filelen < 2 || filelen < GetLength(addr)) {
                 ALOGE("Too small SOF0 segment");
                 return false;
             }
 
-            if (!ParseFrame(addr))
-                return false;
+            if (!ParseFrame(addr)) return false;
 
-            return true; // this is the successful exit point
+            return true;             // this is the successful exit point
         } else if (marker == 0xD9) { // EOI
             // This will not meet.
-            ALOGE("Unexpected EOI found at %lu\n", GetOffset(addr - 2));
+            ALOGE("Unexpected EOI found at %td\n", GetOffset(addr - 2));
             return false;
         } else {
             if ((marker == 0xCC) || (marker == 0xDC)) { // DAC and DNL
@@ -143,14 +138,19 @@
                 return false;
             }
 
-            if (filelen < GetLength(addr)) {
+            if (filelen < 2 || filelen < GetLength(addr)) {
                 ALOGE("Corrupted JPEG stream");
                 return false;
             }
         }
 
-        if (GetLength(addr) == 0) {
-            ALOGE("Invalid length 0 is read at offset %lu", GetOffset(addr));
+        if (filelen < 2 || GetLength(addr) == 0) {
+            ALOGE("Invalid length 0 is read at offset %td", GetOffset(addr));
+            return false;
+        }
+
+        if (filelen < GetLength(addr)) {
+            ALOGE("Corrupted JPEG Stream");
             return false;
         }
 
@@ -165,8 +165,7 @@
     return false;
 }
 
-bool CJpegStreamParser::ParseFrame(unsigned char *addr)
-{ // 2 bytes of length
+bool CJpegStreamParser::ParseFrame(unsigned char *addr) { // 2 bytes of length
     // 1 byte of bits per sample
     // 2 bytes of height
     // 2 bytes of width
@@ -217,7 +216,7 @@
     return true;
 }
 
-class CLibhwjpegDecompressor: public hwjpeg_decompressor_struct {
+class CLibhwjpegDecompressor : public hwjpeg_decompressor_struct {
     enum {
         HWJPG_FLAG_NEED_MUNMAP = 1,
     };
@@ -231,6 +230,7 @@
     size_t m_nDummyBytes;
 
     CJpegStreamParser m_jpegStreamParser;
+
 public:
     CLibhwjpegDecompressor() : m_flags(0) {
         // members of hwjpeg_decompressor_struct
@@ -243,7 +243,7 @@
         output_width = 0;
         output_height = 0;
         m_bPrepared = false;
-	m_pStreamBuffer = NULL;
+        m_pStreamBuffer = NULL;
 
         output_format = V4L2_PIX_FMT_RGB32;
 
@@ -290,8 +290,7 @@
         m_nDummyBytes = 0;
 
         m_pStreamBuffer = reinterpret_cast<unsigned char *>(
-                mmap(NULL, m_nStreamLength,
-                    PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0));
+                mmap(NULL, m_nStreamLength, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0));
         if (m_pStreamBuffer == MAP_FAILED) {
             m_pStreamBuffer = NULL;
             close(fd);
@@ -332,8 +331,8 @@
         m_nDummyBytes = dummybytes;
 
         m_pStreamBuffer = reinterpret_cast<unsigned char *>(
-                mmap(NULL, m_nStreamLength + m_nDummyBytes,
-                    PROT_READ | PROT_WRITE, MAP_SHARED, buffer, 0));
+                mmap(NULL, m_nStreamLength + m_nDummyBytes, PROT_READ | PROT_WRITE, MAP_SHARED,
+                     buffer, 0));
         if (m_pStreamBuffer == MAP_FAILED) {
             m_pStreamBuffer = NULL;
             ALOGERR("Failed to mmap %zu bytes of dmabuf fd %d", m_nStreamLength, buffer);
@@ -373,15 +372,13 @@
     bool IsEnoughStreamBuffer() { return true; }
 };
 
-bool CLibhwjpegDecompressor::PrepareDecompression()
-{
+bool CLibhwjpegDecompressor::PrepareDecompression() {
     if (!m_hwjpeg) {
         ALOGE("device node is not opened!");
         return false;
     }
 
-    if ((scale_factor != 1) && (scale_factor != 2) &&
-            (scale_factor != 4) && (scale_factor != 8)) {
+    if ((scale_factor != 1) && (scale_factor != 2) && (scale_factor != 4) && (scale_factor != 8)) {
         ALOGE("Invalid downscaling factor %d", scale_factor);
         return false;
     }
@@ -391,8 +388,7 @@
         return false;
     }
 
-    if (!m_jpegStreamParser.Parse(m_pStreamBuffer, m_nStreamLength))
-        return false;
+    if (!m_jpegStreamParser.Parse(m_pStreamBuffer, m_nStreamLength)) return false;
 
     image_width = m_jpegStreamParser.GetWidth();
     image_height = m_jpegStreamParser.GetHeight();
@@ -401,9 +397,10 @@
     chroma_v_samp_factor = m_jpegStreamParser.m_iVerticalFactor;
 
     if (((image_width % (chroma_h_samp_factor * scale_factor)) != 0) ||
-            ((image_height % (chroma_v_samp_factor * scale_factor)) != 0)) {
-        ALOGE("Downscaling by factor %d of compressed image size %dx%d(chroma %d:%d) is not supported",
-                scale_factor, image_width, image_height, chroma_h_samp_factor, chroma_v_samp_factor);
+        ((image_height % (chroma_v_samp_factor * scale_factor)) != 0)) {
+        ALOGE("Downscaling by factor %d of compressed image size %dx%d(chroma %d:%d) is not "
+              "supported",
+              scale_factor, image_width, image_height, chroma_h_samp_factor, chroma_v_samp_factor);
         return false;
     }
 
@@ -416,7 +413,8 @@
     }
 
     if (!m_hwjpeg->SetImageFormat(output_format, output_width, output_height)) {
-        ALOGE("Failed to configure image format (%ux%u/%08X)", output_width, output_height, output_format);
+        ALOGE("Failed to configure image format (%ux%u/%08X)", output_width, output_height,
+              output_format);
         return false;
     }
 
@@ -425,8 +423,7 @@
     return true;
 }
 
-bool CLibhwjpegDecompressor::Decompress()
-{
+bool CLibhwjpegDecompressor::Decompress() {
     if (!m_bPrepared) {
         ALOGE("JPEG header is not parsed");
         return false;
@@ -447,77 +444,64 @@
     return true;
 }
 
-hwjpeg_decompress_ptr hwjpeg_create_decompress()
-{
+hwjpeg_decompress_ptr hwjpeg_create_decompress() {
     hwjpeg_decompress_ptr p = new CLibhwjpegDecompressor();
-    if (!p)
-        ALOGE("Failed to create decompress struct");
+    if (!p) ALOGE("Failed to create decompress struct");
     return p;
 }
 
-bool hwjpeg_file_src(hwjpeg_decompress_ptr cinfo, const char *path)
-{
+bool hwjpeg_file_src(hwjpeg_decompress_ptr cinfo, const char *path) {
     CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo);
     return decomp->SetStreamPath(path);
 }
 
-void hwjpeg_config_image_format(hwjpeg_decompress_ptr cinfo, __u32 v4l2_pix_fmt)
-{
+void hwjpeg_config_image_format(hwjpeg_decompress_ptr cinfo, __u32 v4l2_pix_fmt) {
     cinfo->output_format = v4l2_pix_fmt;
 }
 
-bool hwjpeg_dmabuf_src(hwjpeg_decompress_ptr cinfo, int infd, size_t insize, size_t dummybytes)
-{
+bool hwjpeg_dmabuf_src(hwjpeg_decompress_ptr cinfo, int infd, size_t insize, size_t dummybytes) {
     CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo);
     return decomp->SetStreamBuffer(infd, insize, dummybytes);
 }
 
-bool hwjpeg_mem_src(hwjpeg_decompress_ptr cinfo,
-        unsigned char *inbuffer, size_t insize, size_t dummybytes)
-{
+bool hwjpeg_mem_src(hwjpeg_decompress_ptr cinfo, unsigned char *inbuffer, size_t insize,
+                    size_t dummybytes) {
     CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo);
     return decomp->SetStreamBuffer(inbuffer, insize, dummybytes);
 }
 
-bool hwjpeg_mem_dst(hwjpeg_decompress_ptr cinfo,
-        unsigned char *outbuffer[], size_t outsize[], unsigned int num_buffers)
-{
+bool hwjpeg_mem_dst(hwjpeg_decompress_ptr cinfo, unsigned char *outbuffer[], size_t outsize[],
+                    unsigned int num_buffers) {
     CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo);
     return decomp->SetImageBuffer(outbuffer, outsize, num_buffers);
 }
 
-bool hwjpeg_dmabuf_dst(hwjpeg_decompress_ptr cinfo,
-        int outfd[], size_t outsize[], unsigned int num_buffers)
-{
+bool hwjpeg_dmabuf_dst(hwjpeg_decompress_ptr cinfo, int outfd[], size_t outsize[],
+                       unsigned int num_buffers) {
     CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo);
     return decomp->SetImageBuffer(outfd, outsize, num_buffers);
 }
 
-void hwjpeg_set_downscale_factor(hwjpeg_decompress_ptr cinfo, unsigned int factor)
-{
+void hwjpeg_set_downscale_factor(hwjpeg_decompress_ptr cinfo, unsigned int factor) {
     cinfo->scale_factor = factor;
 }
 
-bool hwjpeg_read_header(hwjpeg_decompress_ptr cinfo)
-{
+bool hwjpeg_read_header(hwjpeg_decompress_ptr cinfo) {
     CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo);
     return decomp->PrepareDecompression();
 }
 
-bool hwjpeg_start_decompress(hwjpeg_decompress_ptr cinfo)
-{
+bool hwjpeg_start_decompress(hwjpeg_decompress_ptr cinfo) {
     CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo);
     return decomp->Decompress();
 }
 
-void hwjpeg_destroy_decompress(hwjpeg_decompress_ptr cinfo)
-{
+void hwjpeg_destroy_decompress(hwjpeg_decompress_ptr cinfo) {
     CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo);
     delete decomp;
 }
 
-bool hwjpeg_has_enough_stream_buffer(hwjpeg_decompress_ptr cinfo)
-{
+bool hwjpeg_has_enough_stream_buffer(hwjpeg_decompress_ptr cinfo) {
     CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo);
     return decomp->IsEnoughStreamBuffer();
 }