Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(386)

Unified Diff: ui/events/ozone/evdev/event_factory.cc

Issue 150633005: evdev: Support device hotplug with udev (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fewer memory leaks Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/events/ozone/evdev/event_factory.cc
diff --git a/ui/events/ozone/evdev/event_factory.cc b/ui/events/ozone/evdev/event_factory.cc
index cc928197d7eaec071d270182d7a3c9efffb3d2ac..822aedc850966b67c069ce6a6dc5dcb8da6d5a44 100644
--- a/ui/events/ozone/evdev/event_factory.cc
+++ b/ui/events/ozone/evdev/event_factory.cc
@@ -43,6 +43,8 @@ bool IsTouchScreen(const EventDeviceInfo& devinfo) {
#if defined(USE_UDEV)
+const char kSubsystemInput[] = "input";
+
// Severity levels from syslog.h. We can't include it directly as it
// conflicts with base/logging.h
enum {
@@ -84,6 +86,20 @@ scoped_udev UdevConnect() {
return scoped_udev(udev);
}
+// Start monitoring input device changes.
+scoped_udev_monitor UdevCreateMonitor(struct udev* udev) {
+ struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (monitor) {
+ udev_monitor_filter_add_match_subsystem_devtype(
+ monitor, kSubsystemInput, NULL);
+
+ if (udev_monitor_enable_receiving(monitor))
+ LOG(ERROR) << "failed to start receiving events from udev";
+ }
+
+ return scoped_udev_monitor(monitor);
+}
+
// Enumerate all input devices using udev. Calls device_callback per device.
bool UdevEnumerateInputDevices(
struct udev* udev,
@@ -92,7 +108,7 @@ bool UdevEnumerateInputDevices(
if (!enumerate)
return false;
- udev_enumerate_add_match_subsystem(enumerate.get(), "input");
+ udev_enumerate_add_match_subsystem(enumerate.get(), kSubsystemInput);
udev_enumerate_scan_devices(enumerate.get());
struct udev_list_entry* devices =
@@ -121,9 +137,82 @@ bool UdevEnumerateInputDevices(
} // namespace
+#if defined(USE_UDEV)
+
+typedef base::Callback<void(const base::FilePath&)> DeviceCallback;
+
+// Watcher class for input device changes.
+//
+// This monitors the udev netlink socket with MessagePumpLibevent and turns
+// the device change events into callbacks.
+//
+// The udev monitor should already be configured to filter the events
+// and enabled. This class only deals with IO from the socket.
+class UdevWatcher : public base::MessagePumpLibevent::Watcher {
+ public:
+ UdevWatcher(struct udev_monitor* monitor,
+ DeviceCallback device_added,
+ DeviceCallback device_removed)
+ : monitor_(monitor),
+ device_added_(device_added),
+ device_removed_(device_removed) {}
+
+ ~UdevWatcher() { Stop(); }
+
+ // Start watching the socket.
+ bool Start() {
+ int fd = udev_monitor_get_fd(monitor_);
+ if (fd < 0)
+ return false;
+
+ return base::MessagePumpOzone::Current()->WatchFileDescriptor(
+ fd, true, base::MessagePumpLibevent::WATCH_READ, &controller_, this);
+ }
+
+ // Stop watching the socket.
+ void Stop() { controller_.StopWatchingFileDescriptor(); }
+
+ void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
+ // The netlink socket should never become disconnected. There's no need
+ // to handle broken connections here.
+
+ scoped_udev_device device(udev_monitor_receive_device(monitor_));
+ if (!device)
+ return;
+
+ const char* path = udev_device_get_devnode(device.get());
+ const char* action = udev_device_get_action(device.get());
+ if (!path || !action)
+ return;
+
+ if (!strcmp(action, "add") || !strcmp(action, "change"))
+ device_added_.Run(base::FilePath(path));
+ else if (!strcmp(action, "remove"))
+ device_removed_.Run(base::FilePath(path));
+ }
+
+ void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE { NOTREACHED(); }
+
+ private:
+ struct udev_monitor* monitor_;
+ base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+
+ // Callbacks for device changes.
+ DeviceCallback device_added_;
+ DeviceCallback device_removed_;
+};
+
+#endif // defined(USE_UDEV)
+
EventFactoryEvdev::EventFactoryEvdev() {}
-EventFactoryEvdev::~EventFactoryEvdev() { STLDeleteValues(&converters_); }
+EventFactoryEvdev::~EventFactoryEvdev() {
+#if defined(USE_UDEV)
+ if (watcher_)
+ watcher_->Stop();
+#endif
+ STLDeleteValues(&converters_);
+}
void EventFactoryEvdev::AttachInputDevice(const base::FilePath& path) {
TRACE_EVENT1("ozone", "AttachInputDevice", "path", path.value());
@@ -147,7 +236,7 @@ void EventFactoryEvdev::AttachInputDevice(const base::FilePath& path) {
return;
}
- // TODO(spang) Add more device types. Support hot-plugging.
+ // TODO(spang) Add more device types.
scoped_ptr<EventConverterEvdev> converter;
if (IsTouchScreen(devinfo))
converter.reset(new TouchEventConverterEvdev(fd, path));
@@ -155,15 +244,20 @@ void EventFactoryEvdev::AttachInputDevice(const base::FilePath& path) {
converter.reset(new KeyEventConverterEvdev(fd, path, &modifiers_));
if (converter) {
+ delete converters_[path];
converters_[path] = converter.release();
sadrul 2014/01/30 22:10:36 Can we store scoped_ptr<>s in converters_?
spang 2014/01/31 17:33:00 Don't think so. scoped_ptr<> is not copyable and s
sadrul 2014/01/31 21:00:59 It looks like we have one std::map that stores sco
spang 2014/01/31 22:02:07 It is easy to forget, and I'm not super happy with
} else {
close(fd);
}
}
-void EventFactoryEvdev::StartProcessingEvents() {
- base::ThreadRestrictions::AssertIOAllowed();
+void EventFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
+ TRACE_EVENT1("ozone", "DetachInputDevice", "path", path.value());
+ delete converters_[path];
+ converters_.erase(path);
+}
+void EventFactoryEvdev::StartProcessingEvents() {
#if defined(USE_UDEV)
// Scan for input devices using udev.
StartProcessingEventsUdev();
@@ -190,12 +284,28 @@ void EventFactoryEvdev::StartProcessingEventsUdev() {
LOG(ERROR) << "failed to connect to udev";
return;
}
+ if (!StartMonitoringDevicesUdev())
+ LOG(ERROR) << "failed to start monitoring device changes via udev";
if (!UdevEnumerateInputDevices(
udev_.get(),
base::Bind(&EventFactoryEvdev::AttachInputDevice,
base::Unretained(this))))
LOG(ERROR) << "failed to enumerate input devices via udev";
}
-#endif
+
+bool EventFactoryEvdev::StartMonitoringDevicesUdev() {
+ udev_monitor_ = UdevCreateMonitor(udev_.get());
+ if (!udev_monitor_)
+ return false;
+
+ watcher_.reset(new UdevWatcher(
+ udev_monitor_.get(),
+ base::Bind(&EventFactoryEvdev::AttachInputDevice, base::Unretained(this)),
+ base::Bind(&EventFactoryEvdev::DetachInputDevice,
+ base::Unretained(this))));
+ return watcher_->Start();
+}
+
+#endif // defined(USE_UDEV)
} // namespace ui

Powered by Google App Engine
This is Rietveld 408576698