DrmFramebuffer.cpp \
DrmFramebufferLibDrm.cpp \
GraphicsThread.cpp \
- DrmVsyncThread.cpp
+ DrmVsyncThread.cpp \
+ DrmHotplugThread.cpp
LOCAL_HEADER_LIBRARIES := \
android.hardware.graphics.composer@2.1-hal
namespace V2_1 {
namespace drmfb {
-DrmDevice::DrmDevice(int fd) : mFd(fd) {}
+DrmDevice::DrmDevice(int fd) : mFd(fd), mHotplugThread(*this) {}
DrmDevice::DrmDevice(const std::string& path) : DrmDevice(open(path.c_str(), O_RDWR)) {
if (mFd < 0)
PLOG(ERROR) << "Failed to open DRM device (" << path << ")";
display->report();
}
}
+
+ mHotplugThread.enable();
}
void DrmDevice::disable() {
+ mHotplugThread.disable();
+
mCallback = nullptr;
for (auto& p : mDisplays) {
p.second->disable();
#include <android-base/unique_fd.h>
#include "DrmDisplay.h"
#include "DrmCallback.h"
+#include "DrmHotplugThread.h"
namespace android {
namespace hardware {
std::vector<uint32_t> mCrtcs;
uint32_t mUsedCrtcs = 0; // The CRTCs that are already being used by a display
+ DrmHotplugThread mHotplugThread;
DrmCallback* mCallback = nullptr;
};
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2019 Stephan Gerhold
+
+#define LOG_TAG "drmfb-hotplug"
+
+#include <cutils/uevent.h>
+#include <android-base/unique_fd.h>
+#include <android-base/logging.h>
+#include "DrmHotplugThread.h"
+#include "DrmDevice.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace drmfb {
+
+namespace {
+constexpr int RECEIVE_BUFFER = 1 * 1024 * 1024; // 1 MiB
+constexpr int MESSAGE_BUFFER = 1 * 1024; // 1 KiB
+}
+
+DrmHotplugThread::DrmHotplugThread(DrmDevice& device)
+ : GraphicsThread("drm-hotplug"), mDevice(device) {}
+
+bool DrmHotplugThread::receiveEvent(int fd) {
+ char msg[MESSAGE_BUFFER];
+ auto n = uevent_kernel_multicast_recv(fd, msg, sizeof(msg));
+ if (n < 0)
+ return false;
+
+ bool drm = false;
+ bool hotplug = false;
+ for (auto buf = msg, end = msg + n; buf < end; buf += strlen(buf) + 1) {
+ if (!strcmp(buf, "DEVTYPE=drm_minor"))
+ drm = true;
+ else if (!strcmp(buf, "HOTPLUG=1"))
+ hotplug = true;
+ }
+
+ return drm && hotplug;
+}
+
+void DrmHotplugThread::work(std::unique_lock<std::mutex>& lock) {
+ base::unique_fd fd{uevent_open_socket(RECEIVE_BUFFER, true)};
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open uevent socket";
+ return;
+ }
+
+ loop(lock, [this, &fd] {
+ if (receiveEvent(fd)) {
+ LOG(DEBUG) << "Received hotplug uevent";
+ mDevice.update();
+ }
+ });
+}
+
+} // namespace drmfb
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2019 Stephan Gerhold
+
+#pragma once
+
+#include "GraphicsThread.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace drmfb {
+
+struct DrmDevice;
+
+struct DrmHotplugThread : public GraphicsThread {
+ DrmHotplugThread(DrmDevice& device);
+
+protected:
+ void work(std::unique_lock<std::mutex>& lock) override;
+
+private:
+ bool receiveEvent(int fd);
+
+ DrmDevice& mDevice;
+};
+
+} // namespace drmfb
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
struct DrmVsyncThread : public GraphicsThread {
DrmVsyncThread(DrmDisplay& display);
+
+protected:
void run() override;
private:
if (!mStarted) {
mStarted = true;
- mThread = std::thread(&GraphicsThread::loop, this);
+ mThread = std::thread(&GraphicsThread::main, this);
return;
}
}
mThread.join();
}
-void GraphicsThread::loop() {
+void GraphicsThread::main() {
setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
prctl(PR_SET_NAME, mName.c_str(), 0, 0, 0);
LOG(DEBUG) << "Starting thread " << mName;
std::unique_lock lock{mMutex};
- while (true) {
- if (!mEnabled) {
- mCondition.wait(lock, [this] { return mEnabled || !mStarted; });
- if (!mStarted) {
- LOG(DEBUG) << "Stopping thread " << mName;
- return;
- }
- }
-
- lock.unlock();
- run();
- lock.lock();
+ while (mStarted) {
+ work(lock);
+ mCondition.wait(lock, [this] { return mEnabled || !mStarted; });
}
+
+ LOG(DEBUG) << "Stopping thread " << mName;
+}
+
+void GraphicsThread::work(std::unique_lock<std::mutex>& lock) {
+ loop(lock, [this] { run(); });
}
} // namespace drmfb
void disable();
void stop();
- virtual void run() = 0;
- void loop();
+protected:
+ virtual void run() {};
+ virtual void work(std::unique_lock<std::mutex>& lock);
+
+ template<typename F>
+ void loop(std::unique_lock<std::mutex>& lock, F f) {
+ while (mEnabled) {
+ lock.unlock();
+ f();
+ lock.lock();
+ }
+ }
private:
+ void main();
+
std::mutex mMutex;
std::thread mThread;
std::string mName;