Merge "sdm: hwc2: Add static uevent thread."
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 7f39d7f..43f71ed 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -35,6 +35,8 @@
#include <algorithm>
#include <string>
#include <bitset>
+#include <thread>
+#include <memory>
#include "hwc_buffer_allocator.h"
#include "hwc_buffer_sync_handler.h"
@@ -66,8 +68,55 @@
};
namespace sdm {
+
+static HWCUEvent g_hwc_uevent_;
Locker HWCSession::locker_;
+void * HWCUEvent::UEventThread(HWCUEvent *hwc_event) {
+ 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;
+ }
+
+ while (1) {
+ char uevent_data[PAGE_SIZE] = {};
+
+ // keep last 2 zeroes to ensure double 0 termination
+ int length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
+
+ // 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);
+ } else {
+ DLOGW("UEvent dropped. No uevent listener.");
+ }
+ }
+ }
+ pthread_exit(0);
+
+ return NULL;
+}
+
+HWCUEvent::HWCUEvent() {
+ std::thread thread(HWCUEvent::UEventThread, this);
+ thread.detach();
+}
+
+void HWCUEvent::Register(HWCUEventHandler *event_handler) {
+ DLOGI("Set uevent listener = %p", event_handler);
+
+ std::lock_guard<std::mutex> obj(mutex_);
+ event_handler_ = event_handler;
+}
+
HWCSession::HWCSession(const hw_module_t *module) {
hwc2_device_t::common.tag = HARDWARE_DEVICE_TAG;
hwc2_device_t::common.version = HWC_DEVICE_API_VERSION_2_0;
@@ -146,8 +195,7 @@
}
}
- std::thread uevent_thread(HWCUeventThread, this);
- uevent_thread_.swap(uevent_thread);
+ g_hwc_uevent_.Register(this);
return 0;
}
@@ -167,10 +215,7 @@
color_mgr_->DestroyColorManager();
}
- DLOGD("Terminating uevent thread");
- uevent_thread_exit_ = true;
- // todo(user): add a local event to interrupt thread execution and join.
- uevent_thread_.detach();
+ g_hwc_uevent_.Register(nullptr);
DisplayError error = CoreInterface::DestroyCore();
if (error != kErrorNone) {
@@ -1238,52 +1283,26 @@
return (ret ? -EINVAL : 0);
}
-void *HWCSession::HWCUeventThread(void *context) {
- if (context) {
- return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
- }
-
- return NULL;
-}
-
-void *HWCSession::HWCUeventThreadHandler() {
- static char uevent_data[PAGE_SIZE];
- int length = 0;
- 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;
- }
-
- while (!uevent_thread_exit_) {
- // keep last 2 zeroes to ensure double 0 termination
- length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
-
- if (strcasestr(HWC_UEVENT_SWITCH_HDMI, uevent_data)) {
- DLOGI("Uevent HDMI = %s", uevent_data);
- int connected = GetEventValue(uevent_data, length, "SWITCH_STATE=");
- if (connected >= 0) {
- DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
- if (HotPlugHandler(connected) == -1) {
- DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
- }
+void HWCSession::UEvent(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=");
+ if (connected >= 0) {
+ DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
+ if (HotPlugHandler(connected) == -1) {
+ DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
}
- } else if (strcasestr(HWC_UEVENT_GRAPHICS_FB0, uevent_data)) {
- DLOGI("Uevent FB0 = %s", uevent_data);
- int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE=");
- if (panel_reset == 0) {
- callbacks_.Refresh(0);
- reset_panel_ = true;
- }
- } else if (strcasestr(uevent_data, HWC_UEVENT_DRM_EXT_HOTPLUG)) {
- HandleExtHPD(uevent_data, length);
}
+ } else if (strcasestr(uevent_data, HWC_UEVENT_GRAPHICS_FB0)) {
+ DLOGI("Uevent FB0 = %s", uevent_data);
+ int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE=");
+ if (panel_reset == 0) {
+ callbacks_.Refresh(0);
+ reset_panel_ = true;
+ }
+ } else if (strcasestr(uevent_data, HWC_UEVENT_DRM_EXT_HOTPLUG)) {
+ HandleExtHPD(uevent_data, length);
}
- pthread_exit(0);
-
- return NULL;
}
void HWCSession::HandleExtHPD(const char *uevent_data, int length) {
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index cd9831d..825d605 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -23,7 +23,6 @@
#include <vendor/display/config/1.0/IDisplayConfig.h>
#include <core/core_interface.h>
#include <utils/locker.h>
-#include <thread>
#include "hwc_callbacks.h"
#include "hwc_layers.h"
@@ -39,7 +38,29 @@
using ::vendor::display::config::V1_0::IDisplayConfig;
using ::android::hardware::Return;
-class HWCSession : hwc2_device_t, public IDisplayConfig, public qClient::BnQClient {
+// Create a singleton uevent listener thread valid for life of hardware composer process.
+// This thread blocks on uevents poll inside uevent library implementation. This poll exits
+// 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 {
+ public:
+ virtual ~HWCUEventHandler() {}
+ virtual void UEvent(const char *uevent_data, int length) = 0;
+};
+
+class HWCUEvent {
+ public:
+ HWCUEvent();
+ static void *UEventThread(HWCUEvent *hwc_event);
+ void Register(HWCUEventHandler *event_handler);
+
+ private:
+ std::mutex mutex_;
+ HWCUEventHandler *event_handler_ = nullptr;
+};
+
+class HWCSession : hwc2_device_t, HWCUEventHandler, IDisplayConfig, public qClient::BnQClient {
public:
struct HWCModuleMethods : public hw_module_methods_t {
HWCModuleMethods() { hw_module_methods_t::open = HWCSession::Open; }
@@ -120,9 +141,8 @@
int32_t *outCapabilities);
static hwc2_function_pointer_t GetFunction(struct hwc2_device *device, int32_t descriptor);
- // Uevent thread
- static void *HWCUeventThread(void *context);
- void *HWCUeventThreadHandler();
+ // Uevent handler
+ virtual void UEvent(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);
@@ -192,9 +212,6 @@
CoreInterface *core_intf_ = nullptr;
HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {nullptr};
HWCCallbacks callbacks_;
- std::thread uevent_thread_;
- bool uevent_thread_exit_ = false;
- const char *uevent_thread_name_ = "HWC_UeventThread";
HWCBufferAllocator buffer_allocator_;
HWCBufferSyncHandler buffer_sync_handler_;
HWCColorManager *color_mgr_ = nullptr;