sdm: Enable HPD after uevent_init()

Ensure UEventThread is ready to listen to events before enabling HPD
to avoid HDMI connect/disconnect events getting missed during bootup

Change-Id: Icddff4e911570117ca03f54da1af5b2ddbb1e61f
CRs-Fixed: 2057902
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index adf147c..d13958d 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -72,16 +72,25 @@
 static HWCUEvent g_hwc_uevent_;
 Locker HWCSession::locker_;
 
-void * HWCUEvent::UEventThread(HWCUEvent *hwc_event) {
+void HWCUEvent::UEventThread(HWCUEvent *hwc_uevent) {
   const char *uevent_thread_name = "HWC_UeventThread";
 
   prctl(PR_SET_NAME, uevent_thread_name, 0, 0, 0);
   setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
 
-  if (!uevent_init()) {
-    DLOGE("Failed to init uevent");
-    pthread_exit(0);
-    return NULL;
+  int status = uevent_init();
+  if (!status) {
+    std::unique_lock<std::mutex> caller_lock(hwc_uevent->mutex_);
+    hwc_uevent->caller_cv_.notify_one();
+    DLOGE("Failed to init uevent with err %d", status);
+    return;
+  }
+
+  {
+    // Signal caller thread that worker thread is ready to listen to events.
+    std::unique_lock<std::mutex> caller_lock(hwc_uevent->mutex_);
+    hwc_uevent->init_done_ = true;
+    hwc_uevent->caller_cv_.notify_one();
   }
 
   while (1) {
@@ -92,29 +101,28 @@
 
     // scope of lock to this block only, so that caller is free to set event handler to nullptr;
     {
-      std::lock_guard<std::mutex> guard(hwc_event->mutex_);
-      if (hwc_event->event_handler_) {
-        hwc_event->event_handler_->UEvent(uevent_data, length);
+      std::lock_guard<std::mutex> guard(hwc_uevent->mutex_);
+      if (hwc_uevent->uevent_listener_) {
+        hwc_uevent->uevent_listener_->UEventHandler(uevent_data, length);
       } else {
         DLOGW("UEvent dropped. No uevent listener.");
       }
     }
   }
-  pthread_exit(0);
-
-  return NULL;
 }
 
 HWCUEvent::HWCUEvent() {
+  std::unique_lock<std::mutex> caller_lock(mutex_);
   std::thread thread(HWCUEvent::UEventThread, this);
   thread.detach();
+  caller_cv_.wait(caller_lock);
 }
 
-void HWCUEvent::Register(HWCUEventHandler *event_handler) {
-  DLOGI("Set uevent listener = %p", event_handler);
+void HWCUEvent::Register(HWCUEventListener *uevent_listener) {
+  DLOGI("Set uevent listener = %p", uevent_listener);
 
   std::lock_guard<std::mutex> obj(mutex_);
-  event_handler_ = event_handler;
+  uevent_listener_ = uevent_listener;
 }
 
 HWCSession::HWCSession(const hw_module_t *module) {
@@ -130,6 +138,10 @@
   int status = -EINVAL;
   const char *qservice_name = "display.qservice";
 
+  if (!g_hwc_uevent_.InitDone()) {
+    return status;
+  }
+
   // Start QService and connect to it.
   qService::QService::init();
   android::sp<qService::IQService> iqservice = android::interface_cast<qService::IQService>(
@@ -153,10 +165,13 @@
     return -EINVAL;
   }
 
+  g_hwc_uevent_.Register(this);
+
   // If HDMI display is primary display, defer display creation until hotplug event is received.
   HWDisplayInterfaceInfo hw_disp_info = {};
   error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
   if (error != kErrorNone) {
+    g_hwc_uevent_.Register(nullptr);
     CoreInterface::DestroyCore();
     DLOGE("Primary display type not recognized. Error = %d", error);
     return -EINVAL;
@@ -181,6 +196,7 @@
   }
 
   if (status) {
+    g_hwc_uevent_.Register(nullptr);
     CoreInterface::DestroyCore();
     return status;
   }
@@ -195,8 +211,6 @@
     }
   }
 
-  g_hwc_uevent_.Register(this);
-
   return 0;
 }
 
@@ -1287,7 +1301,7 @@
   return (ret ? -EINVAL : 0);
 }
 
-void HWCSession::UEvent(const char *uevent_data, int length) {
+void HWCSession::UEventHandler(const char *uevent_data, int length) {
   if (strcasestr(uevent_data, HWC_UEVENT_SWITCH_HDMI)) {
     DLOGI("Uevent HDMI = %s", uevent_data);
     int connected = GetEventValue(uevent_data, length, "SWITCH_STATE=");
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 825d605..7d2a30c 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -43,24 +43,27 @@
 // only when there is a valid uevent, it can not be interrupted otherwise. Tieing life cycle
 // of this thread with HWC session cause HWC deinitialization to wait infinitely for the
 // thread to exit.
-class HWCUEventHandler {
+class HWCUEventListener {
  public:
-  virtual ~HWCUEventHandler() {}
-  virtual void UEvent(const char *uevent_data, int length) = 0;
+  virtual ~HWCUEventListener() {}
+  virtual void UEventHandler(const char *uevent_data, int length) = 0;
 };
 
 class HWCUEvent {
  public:
   HWCUEvent();
-  static void *UEventThread(HWCUEvent *hwc_event);
-  void Register(HWCUEventHandler *event_handler);
+  static void UEventThread(HWCUEvent *hwc_event);
+  void Register(HWCUEventListener *uevent_listener);
+  inline bool InitDone() { return init_done_; }
 
  private:
   std::mutex mutex_;
-  HWCUEventHandler *event_handler_ = nullptr;
+  std::condition_variable caller_cv_;
+  HWCUEventListener *uevent_listener_ = nullptr;
+  bool init_done_ = false;
 };
 
-class HWCSession : hwc2_device_t, HWCUEventHandler, IDisplayConfig, public qClient::BnQClient {
+class HWCSession : hwc2_device_t, HWCUEventListener, IDisplayConfig, public qClient::BnQClient {
  public:
   struct HWCModuleMethods : public hw_module_methods_t {
     HWCModuleMethods() { hw_module_methods_t::open = HWCSession::Open; }
@@ -142,7 +145,7 @@
   static hwc2_function_pointer_t GetFunction(struct hwc2_device *device, int32_t descriptor);
 
   // Uevent handler
-  virtual void UEvent(const char *uevent_data, int length);
+  virtual void UEventHandler(const char *uevent_data, int length);
   int GetEventValue(const char *uevent_data, int length, const char *event_info);
   void HandleExtHPD(const char *uevent_data, int length);
   int HotPlugHandler(bool connected);