Merge "hwc2: Add support for Secure Display"
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index 1d9d85a..f40f324 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -543,9 +543,11 @@
    * Commit the params set via Perform(). Also resets the properties after commit. Needs to be
    * called every frame.
    * [input]: synchronous: Determines if the call should block until a h/w flip
+   * [input]: retain_planes: Retains already staged planes. Useful when not explicitly programming
+   *          planes but still need the previously staged ones to not be unstaged
    * [return]: Error code if the API fails, 0 on success.
    */
-  virtual int Commit(bool synchronous) = 0;
+  virtual int Commit(bool synchronous, bool retain_planes) = 0;
   /*
    * Validate the params set via Perform().
    * [return]: Error code if the API fails, 0 on success.
diff --git a/libgralloc1/gr_buf_mgr.cpp b/libgralloc1/gr_buf_mgr.cpp
index 3c00ca7..59afe19 100644
--- a/libgralloc1/gr_buf_mgr.cpp
+++ b/libgralloc1/gr_buf_mgr.cpp
@@ -124,7 +124,7 @@
   std::lock_guard<std::mutex> buffer_lock(buffer_lock_);
   if (shared && (max_buf_index >= 0)) {
     // Allocate one and duplicate/copy the handles for each descriptor
-    if (AllocateBuffer(*descriptors[UINT(max_buf_index)], &out_buffers[max_buf_index])) {
+    if (AllocateBufferLocked(*descriptors[UINT(max_buf_index)], &out_buffers[max_buf_index])) {
       return GRALLOC1_ERROR_NO_RESOURCES;
     }
 
@@ -140,7 +140,7 @@
     // Buffer sharing is not feasible.
     // Allocate separate buffer for each descriptor
     for (i = 0; i < num_descriptors; i++) {
-      if (AllocateBuffer(*descriptors[i], &out_buffers[i])) {
+      if (AllocateBufferLocked(*descriptors[i], &out_buffers[i])) {
         return GRALLOC1_ERROR_NO_RESOURCES;
       }
     }
@@ -447,8 +447,8 @@
   return buffer_type;
 }
 
-int BufferManager::AllocateBuffer(const BufferDescriptor &descriptor, buffer_handle_t *handle,
-                                  unsigned int bufferSize) {
+int BufferManager::AllocateBufferLocked(const BufferDescriptor &descriptor, buffer_handle_t *handle,
+                                        unsigned int bufferSize) {
   if (!handle)
     return -EINVAL;
 
@@ -739,22 +739,6 @@
 
       // TODO(user): Break out similar functionality, preferably moving to a common lib.
 
-    case GRALLOC1_MODULE_PERFORM_ALLOCATE_BUFFER: {
-      int width = va_arg(args, int);
-      int height = va_arg(args, int);
-      int format = va_arg(args, int);
-      uint64_t p_usage = va_arg(args, uint64_t);
-      uint64_t c_usage = va_arg(args, uint64_t);
-      buffer_handle_t *hnd = va_arg(args, buffer_handle_t*);
-      gralloc1_producer_usage_t producer_usage = static_cast<gralloc1_producer_usage_t>(p_usage);
-      gralloc1_consumer_usage_t consumer_usage = static_cast<gralloc1_consumer_usage_t>(c_usage);
-      BufferDescriptor descriptor(width, height, format, producer_usage, consumer_usage);
-      unsigned int size;
-      unsigned int alignedw, alignedh;
-      GetBufferSizeAndDimensions(GetBufferInfo(descriptor), &size, &alignedw, &alignedh);
-      AllocateBuffer(descriptor, hnd, size);
-    } break;
-
     case GRALLOC1_MODULE_PERFORM_GET_INTERLACE_FLAG: {
       private_handle_t *hnd = va_arg(args, private_handle_t *);
       int *flag = va_arg(args, int *);
diff --git a/libgralloc1/gr_buf_mgr.h b/libgralloc1/gr_buf_mgr.h
index 861a7a7..e021afd 100644
--- a/libgralloc1/gr_buf_mgr.h
+++ b/libgralloc1/gr_buf_mgr.h
@@ -73,8 +73,8 @@
   BufferManager();
   gralloc1_error_t MapBuffer(private_handle_t const *hnd);
   int GetBufferType(int format);
-  int AllocateBuffer(const BufferDescriptor &descriptor, buffer_handle_t *handle,
-                     unsigned int bufferSize = 0);
+  int AllocateBufferLocked(const BufferDescriptor &descriptor, buffer_handle_t *handle,
+                           unsigned int bufferSize = 0);
   uint32_t GetDataAlignment(int format, gralloc1_producer_usage_t prod_usage,
                        gralloc1_consumer_usage_t cons_usage);
   int GetHandleFlags(int format, gralloc1_producer_usage_t prod_usage,
diff --git a/libgralloc1/gralloc_priv.h b/libgralloc1/gralloc_priv.h
index cec4af0..ef1bbc3 100644
--- a/libgralloc1/gralloc_priv.h
+++ b/libgralloc1/gralloc_priv.h
@@ -99,8 +99,7 @@
 #define GRALLOC_MODULE_PERFORM_SET_IGC 12
 #define GRALLOC_MODULE_PERFORM_SET_SINGLE_BUFFER_MODE 13
 #define GRALLOC1_MODULE_PERFORM_GET_BUFFER_SIZE_AND_DIMENSIONS 14
-#define GRALLOC1_MODULE_PERFORM_ALLOCATE_BUFFER 15
-#define GRALLOC1_MODULE_PERFORM_GET_INTERLACE_FLAG 16
+#define GRALLOC1_MODULE_PERFORM_GET_INTERLACE_FLAG 15
 
 // OEM specific HAL formats
 #define HAL_PIXEL_FORMAT_RGBA_5551 6
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 83d912e..87ca401 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -366,3 +366,25 @@
     return err;
 }
 
+// returns 0 if composer is up
+extern "C" int waitForComposerInit() {
+    int status = false;
+    sp<IQService> binder = getBinder();
+    if (binder == NULL) {
+        sleep(2);
+        binder = getBinder();
+    }
+
+    if (binder != NULL) {
+        Parcel inParcel, outParcel;
+        binder->dispatch(IQService::GET_COMPOSER_STATUS, &inParcel, &outParcel);
+        status = !!outParcel.readInt32();
+        if (!status) {
+            sleep(2);
+            binder->dispatch(IQService::GET_COMPOSER_STATUS, &inParcel, &outParcel);
+            status = !!outParcel.readInt32();
+        }
+    }
+
+    return !status;
+}
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 6512bf5..c692699 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -160,4 +160,6 @@
 
 }; //namespace
 
+
+extern "C" int waitForComposerInit();
 #endif
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 8985dd6..610cd4e 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -76,6 +76,7 @@
         SET_COLOR_MODE = 34, // Overrides the QDCM mode on the display
         GET_HDR_CAPABILITIES = 35, // Get HDR capabilities for legacy HWC interface
         SET_COLOR_MODE_BY_ID = 36, // Overrides the QDCM mode using the given mode ID
+        GET_COMPOSER_STATUS = 37, // Get composer init status-true if primary display init is done
         COMMAND_LIST_END = 400,
     };
 
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index bd09a38..345aeb2 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -353,7 +353,7 @@
       drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id,
                                 &connector_info_.modes[current_mode_index_]);
       drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
-      if (drm_atomic_intf_->Commit(true /* synchronous */)) {
+      if (drm_atomic_intf_->Commit(true /* synchronous */, false /* retain_planes*/)) {
         DRM_LOGI("Setting up CRTC %d, Connector %d for %s failed", token_.crtc_id,
           token_.conn_id, device_name_);
         return kErrorResources;
@@ -669,7 +669,7 @@
 
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::ON);
-  int ret = drm_atomic_intf_->Commit(true /* synchronous */);
+  int ret = drm_atomic_intf_->Commit(true /* synchronous */, true /* retain_planes */);
   if (ret) {
     DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
@@ -678,6 +678,7 @@
 }
 
 DisplayError HWDeviceDRM::PowerOff() {
+  DTRACE_SCOPED();
   if (!drm_atomic_intf_) {
     DLOGE("DRM Atomic Interface is null!");
     return kErrorUndefined;
@@ -685,7 +686,7 @@
 
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::OFF);
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 0);
-  int ret = drm_atomic_intf_->Commit(true /* synchronous */);
+  int ret = drm_atomic_intf_->Commit(true /* synchronous */, false /* retain_planes */);
   if (ret) {
     DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
@@ -694,9 +695,10 @@
 }
 
 DisplayError HWDeviceDRM::Doze() {
+  DTRACE_SCOPED();
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::DOZE);
-  int ret = drm_atomic_intf_->Commit(false /* synchronous */);
+  int ret = drm_atomic_intf_->Commit(true /* synchronous */, true /* retain_planes */);
   if (ret) {
     DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
@@ -706,8 +708,16 @@
 }
 
 DisplayError HWDeviceDRM::DozeSuspend() {
+  DTRACE_SCOPED();
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id,
                             DRMPowerMode::DOZE_SUSPEND);
+  int ret = drm_atomic_intf_->Commit(true /* synchronous */, true /* retain_planes */);
+  if (ret) {
+    DLOGE("Failed with error: %d", ret);
+    return kErrorHardware;
+  }
+
   return kErrorNone;
 }
 
@@ -976,7 +986,7 @@
   DTRACE_SCOPED();
   SetupAtomic(hw_layers, false /* validate */);
 
-  int ret = drm_atomic_intf_->Commit(false /* synchronous */);
+  int ret = drm_atomic_intf_->Commit(false /* synchronous */, false /* retain_planes*/);
   if (ret) {
     DLOGE("%s failed with error %d crtc %d", __FUNCTION__, ret, token_.crtc_id);
     return kErrorHardware;
@@ -1008,7 +1018,8 @@
 }
 
 DisplayError HWDeviceDRM::Flush() {
-  int ret = drm_atomic_intf_->Commit(false /* synchronous */);
+  DTRACE_SCOPED();
+  int ret = drm_atomic_intf_->Commit(false /* synchronous */, false /* retain_planes*/);
   if (ret) {
     DLOGE("failed with error %d", ret);
     return kErrorHardware;
diff --git a/sdm/libs/core/drm/hw_tv_drm.cpp b/sdm/libs/core/drm/hw_tv_drm.cpp
index d19b706..bd9ddc2 100644
--- a/sdm/libs/core/drm/hw_tv_drm.cpp
+++ b/sdm/libs/core/drm/hw_tv_drm.cpp
@@ -110,14 +110,19 @@
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
 
   // Commit to setup pipeline with mode, which then tells us the topology etc
-  if (drm_atomic_intf_->Commit(true /* synchronous */)) {
+  if (drm_atomic_intf_->Commit(true /* synchronous */, false /* retain_planes*/)) {
     DLOGE("Setting up CRTC %d, Connector %d for %s failed", token_.crtc_id,
           token_.conn_id, device_name_);
     return kErrorResources;
   }
 
-  // Reload connector info for updated info after 1st commit
+  // Reload connector info for updated info after 1st commit and validate
   drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
+  if (index >= connector_info_.modes.size()) {
+    DLOGE("Invalid mode index %d mode size %d", index, UINT32(connector_info_.modes.size()));
+    return kErrorNotSupported;
+  }
+
   DLOGI("Setup CRTC %d, Connector %d for %s", token_.crtc_id, token_.conn_id, device_name_);
 
   current_mode_index_ = index;
@@ -172,7 +177,7 @@
 DisplayError HWTVDRM::PowerOff() {
   DTRACE_SCOPED();
 
-  int ret = drm_atomic_intf_->Commit(true /* synchronous */);
+  int ret = drm_atomic_intf_->Commit(true /* synchronous */, false /* retain_planes*/);
   if (ret) {
     DLOGE("%s failed with error %d", __FUNCTION__, ret);
     return kErrorHardware;
diff --git a/sdm/libs/hwc2/hwc_buffer_allocator.cpp b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
index c32a236..62b64be 100644
--- a/sdm/libs/hwc2/hwc_buffer_allocator.cpp
+++ b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
@@ -59,12 +59,26 @@
     return kErrorResources;
   }
 
+  CreateBufferDescriptor_ = reinterpret_cast<GRALLOC1_PFN_CREATE_DESCRIPTOR>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_CREATE_DESCRIPTOR));
+  DestroyBufferDescriptor_ = reinterpret_cast<GRALLOC1_PFN_DESTROY_DESCRIPTOR>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR));
+  AllocateBuffer_ = reinterpret_cast<GRALLOC1_PFN_ALLOCATE>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_ALLOCATE));
   ReleaseBuffer_ = reinterpret_cast<GRALLOC1_PFN_RELEASE>(
       gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_RELEASE));
+  SetBufferDimensions_ = reinterpret_cast<GRALLOC1_PFN_SET_DIMENSIONS>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_SET_DIMENSIONS));
+  SetBufferFormat_ = reinterpret_cast<GRALLOC1_PFN_SET_FORMAT>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_SET_FORMAT));
+  SetConsumerUsage_ = reinterpret_cast<GRALLOC1_PFN_SET_CONSUMER_USAGE>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_SET_CONSUMER_USAGE));
+  SetProducerUsage_ = reinterpret_cast<GRALLOC1_PFN_SET_PRODUCER_USAGE>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_SET_PRODUCER_USAGE));
+  LockBuffer_ = reinterpret_cast<GRALLOC1_PFN_LOCK>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_LOCK));
   Perform_ = reinterpret_cast<GRALLOC1_PFN_PERFORM>(
       gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_PERFORM));
-  Lock_ = reinterpret_cast<GRALLOC1_PFN_LOCK>(
-      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_LOCK));
 
   return kErrorNone;
 }
@@ -81,6 +95,7 @@
 }
 
 DisplayError HWCBufferAllocator::AllocateBuffer(BufferInfo *buffer_info) {
+  DisplayError sdm_err = kErrorNone;
   const BufferConfig &buffer_config = buffer_info->buffer_config;
   AllocatedBufferInfo *alloc_buffer_info = &buffer_info->alloc_buffer_info;
   uint32_t width = buffer_config.width;
@@ -109,29 +124,58 @@
     alloc_flags |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
   }
 
-  uint64_t producer_usage = alloc_flags;
-  uint64_t consumer_usage = (alloc_flags | GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
-  // CreateBuffer
+  gralloc1_producer_usage_t producer_usage = static_cast<gralloc1_producer_usage_t>(alloc_flags);
+  gralloc1_consumer_usage_t consumer_usage = static_cast<gralloc1_consumer_usage_t>(alloc_flags |
+                                             GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
+  gralloc1_buffer_descriptor_t descriptor_id = {};
+  buffer_handle_t buf = nullptr;
   private_handle_t *hnd = nullptr;
-  Perform_(gralloc_device_, GRALLOC1_MODULE_PERFORM_ALLOCATE_BUFFER, width, height, format,
-           producer_usage, consumer_usage, &hnd);
 
-  if (hnd) {
-    alloc_buffer_info->fd = hnd->fd;
-    alloc_buffer_info->stride = UINT32(hnd->width);
-    alloc_buffer_info->size = hnd->size;
-  } else {
-    DLOGE("Failed to allocate memory");
-    return kErrorMemory;
+  // CreateBuffer
+  if (CreateBufferDescriptor_(gralloc_device_, &descriptor_id) != GRALLOC1_ERROR_NONE) {
+    DLOGE("CreateBufferDescriptor failed gr_device=%p", gralloc_device_);
+    return kErrorParameters;
+  }
+  if (SetBufferDimensions_(gralloc_device_, descriptor_id, width, height) != GRALLOC1_ERROR_NONE) {
+    DLOGE("SetBufferDimensions failed gr_device=%x desc=%d", gralloc_device_, descriptor_id);
+    sdm_err = kErrorParameters;
+    goto CleanupOnError;
+  }
+  if (SetBufferFormat_(gralloc_device_, descriptor_id, format) != GRALLOC1_ERROR_NONE) {
+    DLOGE("SetBufferFormat failed gr_device=%x desc=%d", gralloc_device_, descriptor_id);
+    sdm_err = kErrorParameters;
+    goto CleanupOnError;
+  }
+  if (SetConsumerUsage_(gralloc_device_, descriptor_id, consumer_usage) != GRALLOC1_ERROR_NONE) {
+    DLOGE("SetConsumerUsage failed gr_device=%x desc=%d", gralloc_device_, descriptor_id);
+    sdm_err = kErrorParameters;
+    goto CleanupOnError;
+  }
+  if (SetProducerUsage_(gralloc_device_, descriptor_id, producer_usage) != GRALLOC1_ERROR_NONE) {
+    DLOGE("SetProducerUsage failed gr_device=%x desc=%d", gralloc_device_, descriptor_id);
+    sdm_err = kErrorParameters;
+    goto CleanupOnError;
+  }
+  if (AllocateBuffer_(gralloc_device_, 1, &descriptor_id, &buf) != GRALLOC1_ERROR_NONE) {
+    DLOGE("AllocateBuffer failed gr_device=%x desc=%d", gralloc_device_, descriptor_id);
+    sdm_err = kErrorMemory;
+    goto CleanupOnError;
   }
 
+  hnd = (private_handle_t *)buf;  // NOLINT
+  alloc_buffer_info->fd = hnd->fd;
+  alloc_buffer_info->stride = UINT32(hnd->width);
+  alloc_buffer_info->size = hnd->size;
+
   buffer_info->private_data = reinterpret_cast<void *>(hnd);
-  return kErrorNone;
+CleanupOnError:
+  DestroyBufferDescriptor_(gralloc_device_, descriptor_id);
+  return sdm_err;
 }
 
 DisplayError HWCBufferAllocator::FreeBuffer(BufferInfo *buffer_info) {
   DisplayError err = kErrorNone;
-  buffer_handle_t hnd = static_cast<private_handle_t *>(buffer_info->private_data);
+  buffer_handle_t hnd = static_cast<buffer_handle_t>(buffer_info->private_data);
   ReleaseBuffer_(gralloc_device_, hnd);
   AllocatedBufferInfo *alloc_buffer_info = &buffer_info->alloc_buffer_info;
 
@@ -389,8 +433,8 @@
         .width = 0,
         .height = 0
   };
-  Lock_(gralloc_device_, handle, GRALLOC1_PRODUCER_USAGE_CPU_READ, GRALLOC1_CONSUMER_USAGE_NONE,
-        &accessRegion, &buffer_ptr, acquire_fence);
+  LockBuffer_(gralloc_device_, handle, GRALLOC1_PRODUCER_USAGE_CPU_READ,
+              GRALLOC1_CONSUMER_USAGE_NONE, &accessRegion, &buffer_ptr, acquire_fence);
   if (!buffer_ptr) {
     return kErrorUndefined;
   }
diff --git a/sdm/libs/hwc2/hwc_buffer_allocator.h b/sdm/libs/hwc2/hwc_buffer_allocator.h
index 8101d85..8a73ccb 100644
--- a/sdm/libs/hwc2/hwc_buffer_allocator.h
+++ b/sdm/libs/hwc2/hwc_buffer_allocator.h
@@ -64,10 +64,17 @@
 
  private:
   gralloc1_device_t *gralloc_device_ = nullptr;
-  const hw_module_t *module_;
+  const hw_module_t *module_ = nullptr;
+  GRALLOC1_PFN_CREATE_DESCRIPTOR CreateBufferDescriptor_ = nullptr;
+  GRALLOC1_PFN_DESTROY_DESCRIPTOR DestroyBufferDescriptor_ = nullptr;
+  GRALLOC1_PFN_ALLOCATE AllocateBuffer_ = nullptr;
   GRALLOC1_PFN_RELEASE ReleaseBuffer_ = nullptr;
+  GRALLOC1_PFN_SET_DIMENSIONS SetBufferDimensions_ = nullptr;
+  GRALLOC1_PFN_SET_FORMAT SetBufferFormat_ = nullptr;
+  GRALLOC1_PFN_SET_CONSUMER_USAGE SetConsumerUsage_ = nullptr;
+  GRALLOC1_PFN_SET_PRODUCER_USAGE SetProducerUsage_ = nullptr;
+  GRALLOC1_PFN_LOCK LockBuffer_ = nullptr;
   GRALLOC1_PFN_PERFORM Perform_ = nullptr;
-  GRALLOC1_PFN_LOCK Lock_ = nullptr;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 89de074..e0396b6 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -212,6 +212,7 @@
     return status;
   }
 
+  is_composer_up_ = true;
   struct rlimit fd_limit = {};
   getrlimit(RLIMIT_NOFILE, &fd_limit);
   fd_limit.rlim_cur = fd_limit.rlim_cur * 2;
@@ -1014,6 +1015,10 @@
       status = SetColorModeById(input_parcel);
       break;
 
+    case qService::IQService::GET_COMPOSER_STATUS:
+      output_parcel->writeInt32(getComposerStatus());
+      break;
+
     default:
       DLOGW("QService command = %d is not supported", command);
       return -EINVAL;
@@ -1022,6 +1027,10 @@
   return status;
 }
 
+android::status_t HWCSession::getComposerStatus() {
+  return is_composer_up_;
+}
+
 android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel
                                                                   *input_parcel,
                                                                   android::Parcel *output_parcel) {
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 4dbcf9b..18c652d 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -223,6 +223,7 @@
   android::status_t SetColorModeOverride(const android::Parcel *input_parcel);
 
   android::status_t SetColorModeById(const android::Parcel *input_parcel);
+  android::status_t getComposerStatus();
 
   void Refresh(hwc2_display_t display);
   void HotPlug(hwc2_display_t display, HWC2::Connection state);
@@ -243,6 +244,7 @@
   qService::QService *qservice_ = nullptr;
   HWCSocketHandler socket_handler_;
   bool hdmi_is_primary_ = false;
+  bool is_composer_up_ = false;
   Locker callbacks_lock_;
 };