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);