OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "device/usb/usb_service_linux.h" | 5 #include "device/usb/usb_service_linux.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/files/file.h" | 12 #include "base/files/file.h" |
13 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
14 #include "base/files/file_util.h" | 14 #include "base/files/file_util.h" |
15 #include "base/location.h" | 15 #include "base/location.h" |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "base/memory/ptr_util.h" | 17 #include "base/memory/ptr_util.h" |
18 #include "base/memory/weak_ptr.h" | 18 #include "base/memory/weak_ptr.h" |
19 #include "base/scoped_observer.h" | 19 #include "base/scoped_observer.h" |
20 #include "base/single_thread_task_runner.h" | |
21 #include "base/stl_util.h" | 20 #include "base/stl_util.h" |
22 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
23 #include "base/strings/utf_string_conversions.h" | 22 #include "base/strings/utf_string_conversions.h" |
| 23 #include "base/threading/sequenced_task_runner_handle.h" |
24 #include "base/threading/thread_restrictions.h" | 24 #include "base/threading/thread_restrictions.h" |
25 #include "build/build_config.h" | 25 #include "build/build_config.h" |
26 #include "components/device_event_log/device_event_log.h" | 26 #include "components/device_event_log/device_event_log.h" |
27 #include "device/base/device_monitor_linux.h" | 27 #include "device/udev_linux/udev_watcher.h" |
28 #include "device/usb/usb_device_handle.h" | 28 #include "device/usb/usb_device_handle.h" |
29 #include "device/usb/usb_device_linux.h" | 29 #include "device/usb/usb_device_linux.h" |
30 #include "device/usb/webusb_descriptors.h" | 30 #include "device/usb/webusb_descriptors.h" |
31 | 31 |
32 namespace device { | 32 namespace device { |
33 | 33 |
34 namespace { | 34 namespace { |
35 | 35 |
36 // Standard USB requests and descriptor types: | 36 // Standard USB requests and descriptor types: |
37 const uint16_t kUsbVersion2_1 = 0x0210; | 37 const uint16_t kUsbVersion2_1 = 0x0210; |
(...skipping 22 matching lines...) Expand all Loading... |
60 if (device_handle) { | 60 if (device_handle) { |
61 ReadWebUsbDescriptors( | 61 ReadWebUsbDescriptors( |
62 device_handle, base::Bind(&OnReadDescriptors, callback, device_handle)); | 62 device_handle, base::Bind(&OnReadDescriptors, callback, device_handle)); |
63 } else { | 63 } else { |
64 callback.Run(false /* failure */); | 64 callback.Run(false /* failure */); |
65 } | 65 } |
66 } | 66 } |
67 | 67 |
68 } // namespace | 68 } // namespace |
69 | 69 |
70 class UsbServiceLinux::FileThreadHelper : public DeviceMonitorLinux::Observer { | 70 class UsbServiceLinux::FileThreadHelper : public UdevWatcher::Observer { |
71 public: | 71 public: |
72 FileThreadHelper(base::WeakPtr<UsbServiceLinux> service, | 72 FileThreadHelper(base::WeakPtr<UsbServiceLinux> service); |
73 scoped_refptr<base::SingleThreadTaskRunner> task_runner); | |
74 ~FileThreadHelper() override; | 73 ~FileThreadHelper() override; |
75 | 74 |
76 void Start(); | 75 void Start(); |
77 | 76 |
78 private: | 77 private: |
79 // DeviceMonitorLinux::Observer: | 78 // UdevWatcher::Observer |
80 void OnDeviceAdded(udev_device* udev_device) override; | 79 void OnDeviceAdded(ScopedUdevDevicePtr device) override; |
81 void OnDeviceRemoved(udev_device* device) override; | 80 void OnDeviceRemoved(ScopedUdevDevicePtr device) override; |
82 | 81 |
83 base::ThreadChecker thread_checker_; | 82 std::unique_ptr<UdevWatcher> watcher_; |
84 ScopedObserver<DeviceMonitorLinux, DeviceMonitorLinux::Observer> observer_; | |
85 | 83 |
86 // |service_| can only be checked for validity on |task_runner_|'s thread. | 84 // |service_| can only be checked for validity on |task_runner_|'s sequence. |
87 base::WeakPtr<UsbServiceLinux> service_; | 85 base::WeakPtr<UsbServiceLinux> service_; |
88 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 86 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 87 |
| 88 base::SequenceChecker sequence_checker_; |
89 | 89 |
90 DISALLOW_COPY_AND_ASSIGN(FileThreadHelper); | 90 DISALLOW_COPY_AND_ASSIGN(FileThreadHelper); |
91 }; | 91 }; |
92 | 92 |
93 UsbServiceLinux::FileThreadHelper::FileThreadHelper( | 93 UsbServiceLinux::FileThreadHelper::FileThreadHelper( |
94 base::WeakPtr<UsbServiceLinux> service, | 94 base::WeakPtr<UsbServiceLinux> service) |
95 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | 95 : service_(service), task_runner_(base::SequencedTaskRunnerHandle::Get()) { |
96 : observer_(this), service_(service), task_runner_(std::move(task_runner)) { | 96 // Detaches from the sequence on which this object was created. It will be |
97 thread_checker_.DetachFromThread(); | 97 // bound to its owning sequence when Start() is called. |
| 98 sequence_checker_.DetachFromSequence(); |
98 } | 99 } |
99 | 100 |
100 UsbServiceLinux::FileThreadHelper::~FileThreadHelper() { | 101 UsbServiceLinux::FileThreadHelper::~FileThreadHelper() { |
101 DCHECK(thread_checker_.CalledOnValidThread()); | 102 DCHECK(sequence_checker_.CalledOnValidSequence()); |
102 } | 103 } |
103 | 104 |
104 // static | 105 // static |
105 void UsbServiceLinux::FileThreadHelper::Start() { | 106 void UsbServiceLinux::FileThreadHelper::Start() { |
| 107 DCHECK(sequence_checker_.CalledOnValidSequence()); |
106 base::ThreadRestrictions::AssertIOAllowed(); | 108 base::ThreadRestrictions::AssertIOAllowed(); |
107 DCHECK(thread_checker_.CalledOnValidThread()); | |
108 | 109 |
109 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance(); | 110 watcher_ = UdevWatcher::StartWatching(this); |
110 observer_.Add(monitor); | 111 watcher_->EnumerateExistingDevices(); |
111 monitor->Enumerate( | |
112 base::Bind(&FileThreadHelper::OnDeviceAdded, base::Unretained(this))); | |
113 task_runner_->PostTask(FROM_HERE, | 112 task_runner_->PostTask(FROM_HERE, |
114 base::Bind(&UsbServiceLinux::HelperStarted, service_)); | 113 base::Bind(&UsbServiceLinux::HelperStarted, service_)); |
115 } | 114 } |
116 | 115 |
117 void UsbServiceLinux::FileThreadHelper::OnDeviceAdded( | 116 void UsbServiceLinux::FileThreadHelper::OnDeviceAdded( |
118 udev_device* udev_device) { | 117 ScopedUdevDevicePtr device) { |
119 const char* subsystem = udev_device_get_subsystem(udev_device); | 118 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 119 const char* subsystem = udev_device_get_subsystem(device.get()); |
120 if (!subsystem || strcmp(subsystem, "usb") != 0) | 120 if (!subsystem || strcmp(subsystem, "usb") != 0) |
121 return; | 121 return; |
122 | 122 |
123 const char* value = udev_device_get_devnode(udev_device); | 123 const char* value = udev_device_get_devnode(device.get()); |
124 if (!value) | 124 if (!value) |
125 return; | 125 return; |
126 std::string device_path = value; | 126 std::string device_path = value; |
127 | 127 |
128 const char* sysfs_path = udev_device_get_syspath(udev_device); | 128 const char* sysfs_path = udev_device_get_syspath(device.get()); |
129 if (!sysfs_path) | 129 if (!sysfs_path) |
130 return; | 130 return; |
131 | 131 |
132 base::FilePath descriptors_path = | 132 base::FilePath descriptors_path = |
133 base::FilePath(sysfs_path).Append("descriptors"); | 133 base::FilePath(sysfs_path).Append("descriptors"); |
134 std::string descriptors_str; | 134 std::string descriptors_str; |
135 if (!base::ReadFileToString(descriptors_path, &descriptors_str)) | 135 if (!base::ReadFileToString(descriptors_path, &descriptors_str)) |
136 return; | 136 return; |
137 | 137 |
138 UsbDeviceDescriptor descriptor; | 138 UsbDeviceDescriptor descriptor; |
139 if (!descriptor.Parse(std::vector<uint8_t>(descriptors_str.begin(), | 139 if (!descriptor.Parse(std::vector<uint8_t>(descriptors_str.begin(), |
140 descriptors_str.end()))) { | 140 descriptors_str.end()))) { |
141 return; | 141 return; |
142 } | 142 } |
143 | 143 |
144 if (descriptor.device_class == kDeviceClassHub) { | 144 if (descriptor.device_class == kDeviceClassHub) { |
145 // Don't try to enumerate hubs. We never want to connect to a hub. | 145 // Don't try to enumerate hubs. We never want to connect to a hub. |
146 return; | 146 return; |
147 } | 147 } |
148 | 148 |
149 std::string manufacturer; | 149 std::string manufacturer; |
150 value = udev_device_get_sysattr_value(udev_device, "manufacturer"); | 150 value = udev_device_get_sysattr_value(device.get(), "manufacturer"); |
151 if (value) | 151 if (value) |
152 manufacturer = value; | 152 manufacturer = value; |
153 | 153 |
154 std::string product; | 154 std::string product; |
155 value = udev_device_get_sysattr_value(udev_device, "product"); | 155 value = udev_device_get_sysattr_value(device.get(), "product"); |
156 if (value) | 156 if (value) |
157 product = value; | 157 product = value; |
158 | 158 |
159 std::string serial_number; | 159 std::string serial_number; |
160 value = udev_device_get_sysattr_value(udev_device, "serial"); | 160 value = udev_device_get_sysattr_value(device.get(), "serial"); |
161 if (value) | 161 if (value) |
162 serial_number = value; | 162 serial_number = value; |
163 | 163 |
164 unsigned active_configuration = 0; | 164 unsigned active_configuration = 0; |
165 value = udev_device_get_sysattr_value(udev_device, "bConfigurationValue"); | 165 value = udev_device_get_sysattr_value(device.get(), "bConfigurationValue"); |
166 if (value) | 166 if (value) |
167 base::StringToUint(value, &active_configuration); | 167 base::StringToUint(value, &active_configuration); |
168 | 168 |
169 task_runner_->PostTask( | 169 task_runner_->PostTask( |
170 FROM_HERE, base::Bind(&UsbServiceLinux::OnDeviceAdded, service_, | 170 FROM_HERE, base::Bind(&UsbServiceLinux::OnDeviceAdded, service_, |
171 device_path, descriptor, manufacturer, product, | 171 device_path, descriptor, manufacturer, product, |
172 serial_number, active_configuration)); | 172 serial_number, active_configuration)); |
173 } | 173 } |
174 | 174 |
175 void UsbServiceLinux::FileThreadHelper::OnDeviceRemoved(udev_device* device) { | 175 void UsbServiceLinux::FileThreadHelper::OnDeviceRemoved( |
176 DCHECK(thread_checker_.CalledOnValidThread()); | 176 ScopedUdevDevicePtr device) { |
177 const char* device_path = udev_device_get_devnode(device); | 177 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 178 const char* device_path = udev_device_get_devnode(device.get()); |
178 if (device_path) { | 179 if (device_path) { |
179 task_runner_->PostTask( | 180 task_runner_->PostTask( |
180 FROM_HERE, base::Bind(&UsbServiceLinux::OnDeviceRemoved, service_, | 181 FROM_HERE, base::Bind(&UsbServiceLinux::OnDeviceRemoved, service_, |
181 std::string(device_path))); | 182 std::string(device_path))); |
182 } | 183 } |
183 } | 184 } |
184 | 185 |
185 UsbServiceLinux::UsbServiceLinux( | 186 UsbServiceLinux::UsbServiceLinux() |
186 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_in) | 187 : UsbService(CreateBlockingTaskRunner()), weak_factory_(this) { |
187 : UsbService(std::move(blocking_task_runner_in)), weak_factory_(this) { | 188 helper_ = base::MakeUnique<FileThreadHelper>(weak_factory_.GetWeakPtr()); |
188 helper_ = base::MakeUnique<FileThreadHelper>(weak_factory_.GetWeakPtr(), | |
189 task_runner()); | |
190 blocking_task_runner()->PostTask( | 189 blocking_task_runner()->PostTask( |
191 FROM_HERE, | 190 FROM_HERE, |
192 base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get()))); | 191 base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get()))); |
193 } | 192 } |
194 | 193 |
195 UsbServiceLinux::~UsbServiceLinux() { | 194 UsbServiceLinux::~UsbServiceLinux() { |
196 DCHECK(!helper_); | 195 DCHECK(!helper_); |
197 } | 196 } |
198 | 197 |
199 void UsbServiceLinux::Shutdown() { | 198 void UsbServiceLinux::Shutdown() { |
(...skipping 23 matching lines...) Expand all Loading... |
223 USB_LOG(ERROR) << "Got duplicate add event for path: " << device_path; | 222 USB_LOG(ERROR) << "Got duplicate add event for path: " << device_path; |
224 return; | 223 return; |
225 } | 224 } |
226 | 225 |
227 // Devices that appear during initial enumeration are gathered into the first | 226 // Devices that appear during initial enumeration are gathered into the first |
228 // result returned by GetDevices() and prevent device add/remove notifications | 227 // result returned by GetDevices() and prevent device add/remove notifications |
229 // from being sent. | 228 // from being sent. |
230 if (!enumeration_ready()) | 229 if (!enumeration_ready()) |
231 ++first_enumeration_countdown_; | 230 ++first_enumeration_countdown_; |
232 | 231 |
233 scoped_refptr<UsbDeviceLinux> device(new UsbDeviceLinux( | 232 scoped_refptr<UsbDeviceLinux> device( |
234 device_path, descriptor, manufacturer, product, serial_number, | 233 new UsbDeviceLinux(device_path, descriptor, manufacturer, product, |
235 active_configuration, blocking_task_runner())); | 234 serial_number, active_configuration)); |
236 devices_by_path_[device->device_path()] = device; | 235 devices_by_path_[device->device_path()] = device; |
237 if (device->usb_version() >= kUsbVersion2_1) { | 236 if (device->usb_version() >= kUsbVersion2_1) { |
238 device->Open(base::Bind(&OnDeviceOpenedToReadDescriptors, | 237 device->Open(base::Bind(&OnDeviceOpenedToReadDescriptors, |
239 base::Bind(&UsbServiceLinux::DeviceReady, | 238 base::Bind(&UsbServiceLinux::DeviceReady, |
240 weak_factory_.GetWeakPtr(), device))); | 239 weak_factory_.GetWeakPtr(), device))); |
241 } else { | 240 } else { |
242 DeviceReady(device, true /* success */); | 241 DeviceReady(device, true /* success */); |
243 } | 242 } |
244 } | 243 } |
245 | 244 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 result.reserve(devices().size()); | 314 result.reserve(devices().size()); |
316 for (const auto& map_entry : devices()) | 315 for (const auto& map_entry : devices()) |
317 result.push_back(map_entry.second); | 316 result.push_back(map_entry.second); |
318 for (const auto& callback : enumeration_callbacks_) | 317 for (const auto& callback : enumeration_callbacks_) |
319 callback.Run(result); | 318 callback.Run(result); |
320 enumeration_callbacks_.clear(); | 319 enumeration_callbacks_.clear(); |
321 } | 320 } |
322 } | 321 } |
323 | 322 |
324 } // namespace device | 323 } // namespace device |
OLD | NEW |