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"
7 #include "base/lazy_instance.h"
8 #include "base/logging.h"
9 #include "base/threading/thread_restrictions.h"
10 #include "device/udev_linux/udev.h"
16 const char kUdevName
[] = "udev";
17 const char kUdevActionAdd
[] = "add";
18 const char kUdevActionRemove
[] = "remove";
20 // The instance will be reset when message loop destroys.
21 base::LazyInstance
<scoped_ptr
<DeviceMonitorLinux
> >::Leaky
22 g_device_monitor_linux_ptr
= LAZY_INSTANCE_INITIALIZER
;
26 DeviceMonitorLinux::DeviceMonitorLinux() : monitor_fd_(-1) {
27 base::ThreadRestrictions::AssertIOAllowed();
28 base::MessageLoop::current()->AddDestructionObserver(this);
30 udev_
.reset(udev_new());
32 LOG(ERROR
) << "Failed to create udev.";
35 monitor_
.reset(udev_monitor_new_from_netlink(udev_
.get(), kUdevName
));
37 LOG(ERROR
) << "Failed to create udev monitor.";
41 int ret
= udev_monitor_enable_receiving(monitor_
.get());
43 LOG(ERROR
) << "Failed to start udev monitoring.";
47 monitor_fd_
= udev_monitor_get_fd(monitor_
.get());
48 if (monitor_fd_
<= 0) {
49 LOG(ERROR
) << "Failed to start udev monitoring.";
53 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
56 base::MessageLoopForIO::WATCH_READ
,
64 DeviceMonitorLinux
* DeviceMonitorLinux::GetInstance() {
66 g_device_monitor_linux_ptr
.Get().reset(new DeviceMonitorLinux());
67 return g_device_monitor_linux_ptr
.Get().get();
71 bool DeviceMonitorLinux::HasInstance() {
72 return g_device_monitor_linux_ptr
.Get().get();
75 void DeviceMonitorLinux::AddObserver(Observer
* observer
) {
76 DCHECK(thread_checker_
.CalledOnValidThread());
78 observers_
.AddObserver(observer
);
81 void DeviceMonitorLinux::RemoveObserver(Observer
* observer
) {
82 DCHECK(thread_checker_
.CalledOnValidThread());
84 observers_
.RemoveObserver(observer
);
87 ScopedUdevDevicePtr
DeviceMonitorLinux::GetDeviceFromPath(
88 const std::string
& path
) {
89 DCHECK(thread_checker_
.CalledOnValidThread());
90 ScopedUdevDevicePtr
device(
91 udev_device_new_from_syspath(udev_
.get(), path
.c_str()));
95 void DeviceMonitorLinux::Enumerate(const EnumerateCallback
& callback
) {
96 DCHECK(thread_checker_
.CalledOnValidThread());
97 ScopedUdevEnumeratePtr
enumerate(udev_enumerate_new(udev_
.get()));
100 LOG(ERROR
) << "Failed to enumerate devices.";
104 if (udev_enumerate_scan_devices(enumerate
.get()) != 0) {
105 LOG(ERROR
) << "Failed to enumerate devices.";
109 // This list is managed by |enumerate|.
110 udev_list_entry
* devices
= udev_enumerate_get_list_entry(enumerate
.get());
111 for (udev_list_entry
* i
= devices
; i
!= NULL
;
112 i
= udev_list_entry_get_next(i
)) {
113 ScopedUdevDevicePtr
device(
114 udev_device_new_from_syspath(udev_
.get(), udev_list_entry_get_name(i
)));
116 callback
.Run(device
.get());
120 void DeviceMonitorLinux::WillDestroyCurrentMessageLoop() {
121 DCHECK(thread_checker_
.CalledOnValidThread());
122 g_device_monitor_linux_ptr
.Get().reset(NULL
);
125 void DeviceMonitorLinux::OnFileCanReadWithoutBlocking(int fd
) {
126 DCHECK(thread_checker_
.CalledOnValidThread());
127 DCHECK_EQ(monitor_fd_
, fd
);
129 ScopedUdevDevicePtr
device(udev_monitor_receive_device(monitor_
.get()));
133 std::string
action(udev_device_get_action(device
.get()));
134 if (action
== kUdevActionAdd
)
135 FOR_EACH_OBSERVER(Observer
, observers_
, OnDeviceAdded(device
.get()));
136 else if (action
== kUdevActionRemove
)
137 FOR_EACH_OBSERVER(Observer
, observers_
, OnDeviceRemoved(device
.get()));
140 void DeviceMonitorLinux::OnFileCanWriteWithoutBlocking(int fd
) {}
142 DeviceMonitorLinux::~DeviceMonitorLinux() {
143 DCHECK(thread_checker_
.CalledOnValidThread());
144 base::MessageLoop::current()->RemoveDestructionObserver(this);
145 monitor_watcher_
.StopWatchingFileDescriptor();
149 } // namespace device