1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/hid/device_monitor_linux.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/threading/thread_restrictions.h"
17 const char kUdevName
[] = "udev";
18 const char kUdevActionAdd
[] = "add";
19 const char kUdevActionRemove
[] = "remove";
21 // The instance will be reset when message loop destroys.
22 base::LazyInstance
<scoped_ptr
<DeviceMonitorLinux
> >::Leaky
23 g_device_monitor_linux_ptr
= LAZY_INSTANCE_INITIALIZER
;
27 DeviceMonitorLinux::DeviceMonitorLinux() : monitor_fd_(-1) {
28 base::ThreadRestrictions::AssertIOAllowed();
29 base::MessageLoop::current()->AddDestructionObserver(this);
31 udev_
.reset(udev_new());
33 LOG(ERROR
) << "Failed to create udev.";
36 monitor_
.reset(udev_monitor_new_from_netlink(udev_
.get(), kUdevName
));
38 LOG(ERROR
) << "Failed to create udev monitor.";
42 int ret
= udev_monitor_enable_receiving(monitor_
.get());
44 LOG(ERROR
) << "Failed to start udev monitoring.";
48 monitor_fd_
= udev_monitor_get_fd(monitor_
.get());
49 if (monitor_fd_
<= 0) {
50 LOG(ERROR
) << "Failed to start udev monitoring.";
54 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
57 base::MessageLoopForIO::WATCH_READ
,
65 DeviceMonitorLinux
* DeviceMonitorLinux::GetInstance() {
67 g_device_monitor_linux_ptr
.Get().reset(new DeviceMonitorLinux());
68 return g_device_monitor_linux_ptr
.Get().get();
72 bool DeviceMonitorLinux::HasInstance() {
73 return g_device_monitor_linux_ptr
.Get().get();
76 void DeviceMonitorLinux::AddObserver(Observer
* observer
) {
77 DCHECK(thread_checker_
.CalledOnValidThread());
79 observers_
.AddObserver(observer
);
82 void DeviceMonitorLinux::RemoveObserver(Observer
* observer
) {
83 DCHECK(thread_checker_
.CalledOnValidThread());
85 observers_
.RemoveObserver(observer
);
88 ScopedUdevDevicePtr
DeviceMonitorLinux::GetDeviceFromPath(
89 const std::string
& path
) {
90 DCHECK(thread_checker_
.CalledOnValidThread());
91 ScopedUdevDevicePtr
device(
92 udev_device_new_from_syspath(udev_
.get(), path
.c_str()));
96 void DeviceMonitorLinux::Enumerate(const EnumerateCallback
& callback
) {
97 DCHECK(thread_checker_
.CalledOnValidThread());
98 ScopedUdevEnumeratePtr
enumerate(udev_enumerate_new(udev_
.get()));
101 LOG(ERROR
) << "Failed to enumerate devices.";
105 if (udev_enumerate_scan_devices(enumerate
.get()) != 0) {
106 LOG(ERROR
) << "Failed to enumerate devices.";
110 // This list is managed by |enumerate|.
111 udev_list_entry
* devices
= udev_enumerate_get_list_entry(enumerate
.get());
112 for (udev_list_entry
* i
= devices
; i
!= NULL
;
113 i
= udev_list_entry_get_next(i
)) {
114 ScopedUdevDevicePtr
device(
115 udev_device_new_from_syspath(udev_
.get(), udev_list_entry_get_name(i
)));
117 callback
.Run(device
.get());
121 void DeviceMonitorLinux::WillDestroyCurrentMessageLoop() {
122 DCHECK(thread_checker_
.CalledOnValidThread());
123 g_device_monitor_linux_ptr
.Get().reset(NULL
);
126 void DeviceMonitorLinux::OnFileCanReadWithoutBlocking(int fd
) {
127 DCHECK(thread_checker_
.CalledOnValidThread());
128 DCHECK_EQ(monitor_fd_
, fd
);
130 ScopedUdevDevicePtr
device(udev_monitor_receive_device(monitor_
.get()));
134 std::string
action(udev_device_get_action(device
.get()));
135 if (action
== kUdevActionAdd
)
136 FOR_EACH_OBSERVER(Observer
, observers_
, OnDeviceAdded(device
.get()));
137 else if (action
== kUdevActionRemove
)
138 FOR_EACH_OBSERVER(Observer
, observers_
, OnDeviceRemoved(device
.get()));
141 void DeviceMonitorLinux::OnFileCanWriteWithoutBlocking(int fd
) {}
143 DeviceMonitorLinux::~DeviceMonitorLinux() {
144 DCHECK(thread_checker_
.CalledOnValidThread());
145 base::MessageLoop::current()->RemoveDestructionObserver(this);
146 monitor_watcher_
.StopWatchingFileDescriptor();
150 } // namespace device