device_monitor_linux.cc 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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.
  4. #include "device/base/device_monitor_linux.h"
  5. #include <memory>
  6. #include <string>
  7. #include "base/bind.h"
  8. #include "base/lazy_instance.h"
  9. #include "base/logging.h"
  10. #include "base/observer_list.h"
  11. #include "base/threading/scoped_blocking_call.h"
  12. #include "device/udev_linux/udev.h"
  13. namespace device {
  14. namespace {
  15. const char kUdevName[] = "udev";
  16. const char kUdevActionAdd[] = "add";
  17. const char kUdevActionRemove[] = "remove";
  18. // The instance will be reset when message loop destroys.
  19. base::LazyInstance<DeviceMonitorLinux>::Leaky g_device_monitor_linux =
  20. LAZY_INSTANCE_INITIALIZER;
  21. } // namespace
  22. DeviceMonitorLinux::DeviceMonitorLinux() : monitor_fd_(-1) {
  23. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  24. base::BlockingType::MAY_BLOCK);
  25. udev_.reset(udev_new());
  26. if (!udev_) {
  27. LOG(ERROR) << "Failed to create udev.";
  28. return;
  29. }
  30. monitor_.reset(udev_monitor_new_from_netlink(udev_.get(), kUdevName));
  31. if (!monitor_) {
  32. LOG(ERROR) << "Failed to create udev monitor.";
  33. return;
  34. }
  35. int ret = udev_monitor_enable_receiving(monitor_.get());
  36. if (ret != 0) {
  37. LOG(ERROR) << "Failed to start udev monitoring.";
  38. return;
  39. }
  40. monitor_fd_ = udev_monitor_get_fd(monitor_.get());
  41. if (monitor_fd_ <= 0) {
  42. LOG(ERROR) << "Failed to get udev monitor FD.";
  43. return;
  44. }
  45. }
  46. // static
  47. DeviceMonitorLinux* DeviceMonitorLinux::GetInstance() {
  48. return g_device_monitor_linux.Pointer();
  49. }
  50. void DeviceMonitorLinux::AddObserver(Observer* observer) {
  51. DCHECK(thread_checker_.CalledOnValidThread());
  52. observers_.AddObserver(observer);
  53. if (monitor_watch_controller_)
  54. return;
  55. monitor_watch_controller_ = base::FileDescriptorWatcher::WatchReadable(
  56. monitor_fd_,
  57. base::BindRepeating(&DeviceMonitorLinux::OnMonitorCanReadWithoutBlocking,
  58. base::Unretained(this)));
  59. }
  60. void DeviceMonitorLinux::RemoveObserver(Observer* observer) {
  61. DCHECK(thread_checker_.CalledOnValidThread());
  62. observers_.RemoveObserver(observer);
  63. if (!observers_.empty())
  64. return;
  65. monitor_watch_controller_.reset();
  66. }
  67. void DeviceMonitorLinux::Enumerate(const EnumerateCallback& callback) {
  68. DCHECK(thread_checker_.CalledOnValidThread());
  69. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  70. base::BlockingType::MAY_BLOCK);
  71. ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev_.get()));
  72. if (!enumerate) {
  73. LOG(ERROR) << "Failed to enumerate devices.";
  74. return;
  75. }
  76. if (udev_enumerate_scan_devices(enumerate.get()) != 0) {
  77. LOG(ERROR) << "Failed to enumerate devices.";
  78. return;
  79. }
  80. // This list is managed by |enumerate|.
  81. udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
  82. for (udev_list_entry* i = devices; i != nullptr;
  83. i = udev_list_entry_get_next(i)) {
  84. ScopedUdevDevicePtr device(
  85. udev_device_new_from_syspath(udev_.get(), udev_list_entry_get_name(i)));
  86. if (device)
  87. callback.Run(device.get());
  88. }
  89. }
  90. DeviceMonitorLinux::~DeviceMonitorLinux() {
  91. // A leaky LazyInstance is never destroyed.
  92. NOTREACHED();
  93. }
  94. void DeviceMonitorLinux::OnMonitorCanReadWithoutBlocking() {
  95. DCHECK(thread_checker_.CalledOnValidThread());
  96. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  97. base::BlockingType::MAY_BLOCK);
  98. ScopedUdevDevicePtr device(udev_monitor_receive_device(monitor_.get()));
  99. if (!device)
  100. return;
  101. std::string action(udev_device_get_action(device.get()));
  102. if (action == kUdevActionAdd) {
  103. for (auto& observer : observers_)
  104. observer.OnDeviceAdded(device.get());
  105. } else if (action == kUdevActionRemove) {
  106. for (auto& observer : observers_)
  107. observer.OnDeviceRemoved(device.get());
  108. }
  109. }
  110. } // namespace device