OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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_impl.h" | 5 #include "device/usb/usb_service_impl.h" |
6 | 6 |
| 7 #include <algorithm> |
7 #include <set> | 8 #include <set> |
8 | 9 |
9 #include "base/bind.h" | 10 #include "base/bind.h" |
10 #include "base/location.h" | 11 #include "base/location.h" |
11 #include "base/memory/weak_ptr.h" | 12 #include "base/memory/weak_ptr.h" |
12 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
13 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
| 15 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/utf_string_conversions.h" |
14 #include "base/thread_task_runner_handle.h" | 17 #include "base/thread_task_runner_handle.h" |
15 #include "components/device_event_log/device_event_log.h" | 18 #include "components/device_event_log/device_event_log.h" |
16 #include "device/usb/usb_error.h" | 19 #include "device/usb/usb_error.h" |
| 20 #include "third_party/libusb/src/libusb/libusb.h" |
17 | 21 |
18 #if defined(OS_WIN) | 22 #if defined(OS_WIN) |
19 #include <setupapi.h> | 23 #include <setupapi.h> |
20 #include <usbiodef.h> | 24 #include <usbiodef.h> |
21 | 25 |
22 #include "base/scoped_observer.h" | |
23 #include "base/strings/string_util.h" | 26 #include "base/strings/string_util.h" |
24 #include "device/core/device_monitor_win.h" | |
25 #endif // OS_WIN | 27 #endif // OS_WIN |
26 | 28 |
| 29 #if defined(USE_UDEV) |
| 30 #include "device/udev_linux/scoped_udev.h" |
| 31 #endif // USE_UDEV |
| 32 |
27 namespace device { | 33 namespace device { |
28 | 34 |
| 35 namespace { |
| 36 |
| 37 #if defined(USE_UDEV) |
| 38 |
| 39 void ReadDeviceStrings(PlatformUsbDevice platform_device, |
| 40 libusb_device_descriptor* descriptor, |
| 41 base::string16* manufacturer_string, |
| 42 base::string16* product_string, |
| 43 base::string16* serial_number, |
| 44 std::string* device_node) { |
| 45 ScopedUdevPtr udev(udev_new()); |
| 46 ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev.get())); |
| 47 |
| 48 udev_enumerate_add_match_subsystem(enumerate.get(), "usb"); |
| 49 if (udev_enumerate_scan_devices(enumerate.get()) != 0) { |
| 50 return; |
| 51 } |
| 52 std::string bus_number = |
| 53 base::IntToString(libusb_get_bus_number(platform_device)); |
| 54 std::string device_address = |
| 55 base::IntToString(libusb_get_device_address(platform_device)); |
| 56 udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get()); |
| 57 for (udev_list_entry* i = devices; i != NULL; |
| 58 i = udev_list_entry_get_next(i)) { |
| 59 ScopedUdevDevicePtr device( |
| 60 udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i))); |
| 61 if (device) { |
| 62 const char* value = udev_device_get_sysattr_value(device.get(), "busnum"); |
| 63 if (!value || bus_number != value) { |
| 64 continue; |
| 65 } |
| 66 value = udev_device_get_sysattr_value(device.get(), "devnum"); |
| 67 if (!value || device_address != value) { |
| 68 continue; |
| 69 } |
| 70 |
| 71 value = udev_device_get_devnode(device.get()); |
| 72 if (value) { |
| 73 *device_node = value; |
| 74 } |
| 75 value = udev_device_get_sysattr_value(device.get(), "manufacturer"); |
| 76 if (value) { |
| 77 *manufacturer_string = base::UTF8ToUTF16(value); |
| 78 } |
| 79 value = udev_device_get_sysattr_value(device.get(), "product"); |
| 80 if (value) { |
| 81 *product_string = base::UTF8ToUTF16(value); |
| 82 } |
| 83 value = udev_device_get_sysattr_value(device.get(), "serial"); |
| 84 if (value) { |
| 85 *serial_number = base::UTF8ToUTF16(value); |
| 86 } |
| 87 break; |
| 88 } |
| 89 } |
| 90 } |
| 91 |
| 92 #else |
| 93 |
| 94 uint16 ReadDeviceLanguage(PlatformUsbDeviceHandle handle) { |
| 95 uint16 language_id = 0x0409; |
| 96 uint8 buffer[256]; |
| 97 int size = |
| 98 libusb_get_string_descriptor(handle, 0, 0, &buffer[0], sizeof(buffer)); |
| 99 if (size < 0) { |
| 100 USB_LOG(EVENT) << "Failed to get supported string languages: " |
| 101 << ConvertPlatformUsbErrorToString(size); |
| 102 } else if (size >= 4) { |
| 103 // Just pick the first supported language. |
| 104 language_id = buffer[2] | (buffer[3] << 8); |
| 105 } else { |
| 106 USB_LOG(EVENT) << "List of available string languages invalid."; |
| 107 } |
| 108 |
| 109 return language_id; |
| 110 } |
| 111 |
| 112 void ReadDeviceString(PlatformUsbDeviceHandle handle, |
| 113 uint8 string_id, |
| 114 uint16 language_id, |
| 115 base::string16* string) { |
| 116 if (string_id == 0) { |
| 117 return; |
| 118 } |
| 119 |
| 120 uint8 buffer[256]; |
| 121 int size = libusb_get_string_descriptor(handle, string_id, language_id, |
| 122 &buffer[0], sizeof(buffer)); |
| 123 if (size < 0) { |
| 124 USB_LOG(EVENT) << "Failed to read string " << (int)string_id |
| 125 << " from the device: " |
| 126 << ConvertPlatformUsbErrorToString(size); |
| 127 } else if (size > 2) { |
| 128 *string = base::string16(reinterpret_cast<base::char16*>(&buffer[2]), |
| 129 size / 2 - 1); |
| 130 } else { |
| 131 USB_LOG(EVENT) << "String descriptor " << string_id << " is invalid."; |
| 132 } |
| 133 } |
| 134 |
| 135 void ReadDeviceStrings(PlatformUsbDevice platform_device, |
| 136 libusb_device_descriptor* descriptor, |
| 137 base::string16* manufacturer_string, |
| 138 base::string16* product_string, |
| 139 base::string16* serial_number, |
| 140 std::string* device_node) { |
| 141 if (descriptor->iManufacturer == 0 && descriptor->iProduct == 0 && |
| 142 descriptor->iSerialNumber == 0) { |
| 143 // Don't bother distrubing the device if it doesn't have any string |
| 144 // descriptors we care about. |
| 145 return; |
| 146 } |
| 147 |
| 148 PlatformUsbDeviceHandle handle; |
| 149 int rv = libusb_open(platform_device, &handle); |
| 150 if (rv != LIBUSB_SUCCESS) { |
| 151 USB_LOG(EVENT) << "Failed to open device to read string descriptors: " |
| 152 << ConvertPlatformUsbErrorToString(rv); |
| 153 return; |
| 154 } |
| 155 |
| 156 uint16 language_id = ReadDeviceLanguage(handle); |
| 157 ReadDeviceString(handle, descriptor->iManufacturer, language_id, |
| 158 manufacturer_string); |
| 159 ReadDeviceString(handle, descriptor->iProduct, language_id, product_string); |
| 160 ReadDeviceString(handle, descriptor->iSerialNumber, language_id, |
| 161 serial_number); |
| 162 libusb_close(handle); |
| 163 } |
| 164 |
| 165 #endif // USE_UDEV |
| 166 |
29 #if defined(OS_WIN) | 167 #if defined(OS_WIN) |
30 | 168 |
31 namespace { | |
32 | |
33 // Wrapper around a HDEVINFO that automatically destroys it. | 169 // Wrapper around a HDEVINFO that automatically destroys it. |
34 class ScopedDeviceInfoList { | 170 class ScopedDeviceInfoList { |
35 public: | 171 public: |
36 explicit ScopedDeviceInfoList(HDEVINFO handle) : handle_(handle) {} | 172 explicit ScopedDeviceInfoList(HDEVINFO handle) : handle_(handle) {} |
37 | 173 |
38 ~ScopedDeviceInfoList() { | 174 ~ScopedDeviceInfoList() { |
39 if (valid()) { | 175 if (valid()) { |
40 SetupDiDestroyDeviceInfoList(handle_); | 176 SetupDiDestroyDeviceInfoList(handle_); |
41 } | 177 } |
42 } | 178 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 dev_info_set_ = dev_info_set; | 210 dev_info_set_ = dev_info_set; |
75 } | 211 } |
76 | 212 |
77 PSP_DEVINFO_DATA get() { return &dev_info_data_; } | 213 PSP_DEVINFO_DATA get() { return &dev_info_data_; } |
78 | 214 |
79 private: | 215 private: |
80 HDEVINFO dev_info_set_ = INVALID_HANDLE_VALUE; | 216 HDEVINFO dev_info_set_ = INVALID_HANDLE_VALUE; |
81 SP_DEVINFO_DATA dev_info_data_; | 217 SP_DEVINFO_DATA dev_info_data_; |
82 }; | 218 }; |
83 | 219 |
84 } // namespace | 220 bool IsWinUsbInterface(const std::string& device_path) { |
85 | 221 ScopedDeviceInfoList dev_info_list(SetupDiCreateDeviceInfoList(NULL, NULL)); |
86 // This class lives on the application main thread so that it can listen for | 222 if (!dev_info_list.valid()) { |
87 // device change notification window messages. It registers for notifications | 223 USB_PLOG(ERROR) << "Failed to create a device information set"; |
88 // that may indicate new devices that the UsbService will enumerate. | 224 return false; |
89 class UsbServiceImpl::UIThreadHelper final | |
90 : private DeviceMonitorWin::Observer { | |
91 public: | |
92 UIThreadHelper(base::WeakPtr<UsbServiceImpl> usb_service) | |
93 : task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
94 usb_service_(usb_service), | |
95 device_observer_(this) {} | |
96 | |
97 ~UIThreadHelper() {} | |
98 | |
99 void Start() { | |
100 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces(); | |
101 if (device_monitor) { | |
102 device_observer_.Add(device_monitor); | |
103 } | |
104 } | 225 } |
105 | 226 |
106 private: | 227 // This will add the device to |dev_info_list| so we can query driver info. |
107 void OnDeviceAdded(const GUID& class_guid, | 228 if (!SetupDiOpenDeviceInterfaceA(dev_info_list.get(), device_path.c_str(), 0, |
108 const std::string& device_path) override { | 229 NULL)) { |
109 // Only the root node of a composite USB device has the class GUID | 230 USB_PLOG(ERROR) << "Failed to get device interface data for " |
110 // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded. | 231 << device_path; |
111 // This first pass filter will catch anything that's sitting on the USB bus | 232 return false; |
112 // (including devices on 3rd party USB controllers) to avoid the more | |
113 // expensive driver check that needs to be done on the FILE thread. | |
114 if (device_path.find("usb") != std::string::npos) { | |
115 task_runner_->PostTask( | |
116 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevicesIfWinUsbDevice, | |
117 usb_service_, device_path)); | |
118 } | |
119 } | 233 } |
120 | 234 |
121 void OnDeviceRemoved(const GUID& class_guid, | 235 ScopedDeviceInfo dev_info; |
122 const std::string& device_path) override { | 236 if (!SetupDiEnumDeviceInfo(dev_info_list.get(), 0, dev_info.get())) { |
123 // The root USB device node is removed last | 237 USB_PLOG(ERROR) << "Failed to get device info for " << device_path; |
124 if (class_guid == GUID_DEVINTERFACE_USB_DEVICE) { | 238 return false; |
125 task_runner_->PostTask( | 239 } |
126 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevices, usb_service_)); | 240 dev_info.set_valid(dev_info_list.get()); |
127 } | 241 |
| 242 DWORD reg_data_type; |
| 243 BYTE buffer[256]; |
| 244 if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list.get(), dev_info.get(), |
| 245 SPDRP_SERVICE, ®_data_type, |
| 246 &buffer[0], sizeof buffer, NULL)) { |
| 247 USB_PLOG(ERROR) << "Failed to get device service property"; |
| 248 return false; |
| 249 } |
| 250 if (reg_data_type != REG_SZ) { |
| 251 USB_LOG(ERROR) << "Unexpected data type for driver service: " |
| 252 << reg_data_type; |
| 253 return false; |
128 } | 254 } |
129 | 255 |
130 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 256 USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << "."; |
131 base::WeakPtr<UsbServiceImpl> usb_service_; | 257 if (base::strncasecmp("WinUSB", (const char*)&buffer[0], sizeof "WinUSB") == |
132 ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_; | 258 0) { |
133 }; | 259 return true; |
| 260 } |
| 261 return false; |
| 262 } |
134 | 263 |
135 #endif // OS_WIN | 264 #endif // OS_WIN |
136 | 265 |
| 266 } // namespace |
| 267 |
137 // static | 268 // static |
138 UsbService* UsbServiceImpl::Create( | 269 UsbService* UsbServiceImpl::Create( |
139 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 270 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) { |
140 PlatformUsbContext context = NULL; | 271 PlatformUsbContext context = NULL; |
141 const int rv = libusb_init(&context); | 272 const int rv = libusb_init(&context); |
142 if (rv != LIBUSB_SUCCESS) { | 273 if (rv != LIBUSB_SUCCESS) { |
143 USB_LOG(ERROR) << "Failed to initialize libusb: " | 274 USB_LOG(ERROR) << "Failed to initialize libusb: " |
144 << ConvertPlatformUsbErrorToString(rv); | 275 << ConvertPlatformUsbErrorToString(rv); |
145 return nullptr; | 276 return nullptr; |
146 } | 277 } |
147 if (!context) { | 278 if (!context) { |
148 return nullptr; | 279 return nullptr; |
149 } | 280 } |
150 | 281 |
151 return new UsbServiceImpl(context, ui_task_runner); | 282 return new UsbServiceImpl(context, blocking_task_runner); |
152 } | |
153 | |
154 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) { | |
155 DCHECK(CalledOnValidThread()); | |
156 RefreshDevices(); | |
157 DeviceMap::iterator it = devices_.find(unique_id); | |
158 if (it != devices_.end()) { | |
159 return it->second; | |
160 } | |
161 return NULL; | |
162 } | |
163 | |
164 void UsbServiceImpl::GetDevices( | |
165 std::vector<scoped_refptr<UsbDevice> >* devices) { | |
166 DCHECK(CalledOnValidThread()); | |
167 STLClearObject(devices); | |
168 | |
169 if (!hotplug_enabled_) { | |
170 RefreshDevices(); | |
171 } | |
172 | |
173 for (const auto& map_entry : devices_) { | |
174 devices->push_back(map_entry.second); | |
175 } | |
176 } | 283 } |
177 | 284 |
178 UsbServiceImpl::UsbServiceImpl( | 285 UsbServiceImpl::UsbServiceImpl( |
179 PlatformUsbContext context, | 286 PlatformUsbContext context, |
180 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | 287 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) |
181 : context_(new UsbContext(context)), | 288 : context_(new UsbContext(context)), |
182 ui_task_runner_(ui_task_runner), | 289 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
183 next_unique_id_(0), | 290 blocking_task_runner_(blocking_task_runner), |
184 hotplug_enabled_(false), | 291 #if defined(OS_WIN) |
| 292 device_observer_(this), |
| 293 #endif |
185 weak_factory_(this) { | 294 weak_factory_(this) { |
186 task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 295 base::MessageLoop::current()->AddDestructionObserver(this); |
| 296 |
187 int rv = libusb_hotplug_register_callback( | 297 int rv = libusb_hotplug_register_callback( |
188 context_->context(), | 298 context_->context(), |
189 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | | 299 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | |
190 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), | 300 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), |
191 LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, | 301 LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, |
192 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, | 302 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, |
193 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_); | 303 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_); |
194 if (rv == LIBUSB_SUCCESS) { | 304 if (rv == LIBUSB_SUCCESS) { |
195 hotplug_enabled_ = true; | 305 hotplug_enabled_ = true; |
| 306 |
| 307 // libusb will call the hotplug callback for each device currently |
| 308 // enumerated. Once this is complete enumeration_ready_ can be set to true |
| 309 // but we must first wait for any tasks posted to blocking_task_runner_ to |
| 310 // complete. |
| 311 blocking_task_runner_->PostTaskAndReply( |
| 312 FROM_HERE, base::Bind(&base::DoNothing), |
| 313 base::Bind(&UsbServiceImpl::RefreshDevicesComplete, |
| 314 weak_factory_.GetWeakPtr(), nullptr, 0)); |
196 } else { | 315 } else { |
| 316 RefreshDevices(""); |
197 #if defined(OS_WIN) | 317 #if defined(OS_WIN) |
198 ui_thread_helper_ = new UIThreadHelper(weak_factory_.GetWeakPtr()); | 318 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces(); |
199 ui_task_runner_->PostTask(FROM_HERE, | 319 if (device_monitor) { |
200 base::Bind(&UIThreadHelper::Start, | 320 device_observer_.Add(device_monitor); |
201 base::Unretained(ui_thread_helper_))); | 321 } |
202 #endif // OS_WIN | 322 #endif // OS_WIN |
203 } | 323 } |
204 } | 324 } |
205 | 325 |
206 UsbServiceImpl::~UsbServiceImpl() { | 326 UsbServiceImpl::~UsbServiceImpl() { |
| 327 base::MessageLoop::current()->RemoveDestructionObserver(this); |
| 328 |
207 if (hotplug_enabled_) { | 329 if (hotplug_enabled_) { |
208 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_); | 330 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_); |
209 } | 331 } |
210 #if defined(OS_WIN) | |
211 if (ui_thread_helper_) { | |
212 ui_task_runner_->DeleteSoon(FROM_HERE, ui_thread_helper_); | |
213 } | |
214 #endif // OS_WIN | |
215 for (const auto& map_entry : devices_) { | 332 for (const auto& map_entry : devices_) { |
216 map_entry.second->OnDisconnect(); | 333 map_entry.second->OnDisconnect(); |
217 } | 334 } |
218 } | 335 } |
219 | 336 |
220 void UsbServiceImpl::RefreshDevices() { | 337 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) { |
221 DCHECK(CalledOnValidThread()); | 338 DCHECK(CalledOnValidThread()); |
| 339 DeviceMap::iterator it = devices_.find(unique_id); |
| 340 if (it != devices_.end()) { |
| 341 return it->second; |
| 342 } |
| 343 return NULL; |
| 344 } |
| 345 |
| 346 void UsbServiceImpl::GetDevices(const GetDevicesCallback& callback) { |
| 347 DCHECK(CalledOnValidThread()); |
| 348 |
| 349 if (!enumeration_ready_) { |
| 350 // On startup wait for the first enumeration, |
| 351 pending_enumerations_.push_back(callback); |
| 352 } else if (hotplug_enabled_) { |
| 353 // The device list is updated live when hotplug events are supported. |
| 354 std::vector<scoped_refptr<UsbDevice>> devices; |
| 355 for (const auto& map_entry : devices_) { |
| 356 devices.push_back(map_entry.second); |
| 357 } |
| 358 callback.Run(devices); |
| 359 } else { |
| 360 // Only post one re-enumeration task at a time. |
| 361 if (pending_enumerations_.empty()) { |
| 362 RefreshDevices(""); |
| 363 } |
| 364 pending_enumerations_.push_back(callback); |
| 365 } |
| 366 } |
| 367 |
| 368 #if defined(OS_WIN) |
| 369 |
| 370 void UsbServiceImpl::OnDeviceAdded(const GUID& class_guid, |
| 371 const std::string& device_path) { |
| 372 // Only the root node of a composite USB device has the class GUID |
| 373 // GUID_DEVINTERFACE_USB_DEVICE but we want to wait until WinUSB is loaded. |
| 374 // This first pass filter will catch anything that's sitting on the USB bus |
| 375 // (including devices on 3rd party USB controllers) to avoid the more |
| 376 // expensive driver check that needs to be done on the FILE thread. |
| 377 if (device_path.find("usb") != std::string::npos) { |
| 378 RefreshDevices(device_path); |
| 379 } |
| 380 } |
| 381 |
| 382 void UsbServiceImpl::OnDeviceRemoved(const GUID& class_guid, |
| 383 const std::string& device_path) { |
| 384 // The root USB device node is removed last |
| 385 if (class_guid == GUID_DEVINTERFACE_USB_DEVICE) { |
| 386 RefreshDevices(""); |
| 387 } |
| 388 } |
| 389 |
| 390 #endif // OS_WIN |
| 391 |
| 392 void UsbServiceImpl::WillDestroyCurrentMessageLoop() { |
| 393 DCHECK(CalledOnValidThread()); |
| 394 delete this; |
| 395 } |
| 396 |
| 397 void UsbServiceImpl::RefreshDevices(const std::string& new_device_path) { |
| 398 DCHECK(CalledOnValidThread()); |
| 399 |
| 400 std::set<PlatformUsbDevice> current_devices; |
| 401 for (const auto& map_entry : platform_devices_) { |
| 402 current_devices.insert(map_entry.first); |
| 403 } |
| 404 blocking_task_runner_->PostTask( |
| 405 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevicesOnBlockingThread, |
| 406 weak_factory_.GetWeakPtr(), new_device_path, |
| 407 task_runner_, context_, current_devices)); |
| 408 } |
| 409 |
| 410 // static |
| 411 void UsbServiceImpl::RefreshDevicesOnBlockingThread( |
| 412 base::WeakPtr<UsbServiceImpl> usb_service, |
| 413 const std::string& new_device_path, |
| 414 scoped_refptr<base::SequencedTaskRunner> task_runner, |
| 415 scoped_refptr<UsbContext> usb_context, |
| 416 const std::set<PlatformUsbDevice>& previous_devices) { |
| 417 if (!new_device_path.empty()) { |
| 418 #if defined(OS_WIN) |
| 419 if (!IsWinUsbInterface(new_device_path)) { |
| 420 // Wait to call libusb_get_device_list until libusb will be able to find |
| 421 // a WinUSB interface for the device. |
| 422 return; |
| 423 } |
| 424 #endif // defined(OS_WIN) |
| 425 } |
222 | 426 |
223 libusb_device** platform_devices = NULL; | 427 libusb_device** platform_devices = NULL; |
224 const ssize_t device_count = | 428 const ssize_t device_count = |
225 libusb_get_device_list(context_->context(), &platform_devices); | 429 libusb_get_device_list(usb_context->context(), &platform_devices); |
226 if (device_count < 0) { | 430 if (device_count < 0) { |
227 USB_LOG(ERROR) << "Failed to get device list: " | 431 USB_LOG(ERROR) << "Failed to get device list: " |
228 << ConvertPlatformUsbErrorToString(device_count); | 432 << ConvertPlatformUsbErrorToString(device_count); |
229 } | 433 task_runner->PostTask(FROM_HERE, |
230 | 434 base::Bind(&UsbServiceImpl::RefreshDevicesComplete, |
231 std::set<UsbDevice*> connected_devices; | 435 usb_service, nullptr, 0)); |
232 std::vector<PlatformUsbDevice> disconnected_devices; | 436 return; |
233 | 437 } |
234 // Populates new devices. | 438 |
| 439 // Find new devices. |
235 for (ssize_t i = 0; i < device_count; ++i) { | 440 for (ssize_t i = 0; i < device_count; ++i) { |
236 if (!ContainsKey(platform_devices_, platform_devices[i])) { | 441 PlatformUsbDevice platform_device = platform_devices[i]; |
237 scoped_refptr<UsbDeviceImpl> new_device = AddDevice(platform_devices[i]); | 442 if (previous_devices.find(platform_device) == previous_devices.end()) { |
238 if (new_device) { | 443 libusb_ref_device(platform_device); |
239 connected_devices.insert(new_device.get()); | 444 AddDeviceOnBlockingThread(usb_service, task_runner, platform_device); |
240 } | 445 } |
241 } else { | 446 } |
242 connected_devices.insert(platform_devices_[platform_devices[i]].get()); | 447 |
243 } | 448 // |platform_devices| will be freed in this callback. |
244 } | 449 task_runner->PostTask( |
245 | 450 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevicesComplete, |
246 // Find disconnected devices. | 451 usb_service, platform_devices, device_count)); |
247 for (const auto& map_entry : platform_devices_) { | 452 } |
248 PlatformUsbDevice platform_device = map_entry.first; | 453 |
249 scoped_refptr<UsbDeviceImpl> device = map_entry.second; | 454 // static |
250 if (!ContainsKey(connected_devices, device.get())) { | 455 void UsbServiceImpl::AddDeviceOnBlockingThread( |
251 disconnected_devices.push_back(platform_device); | 456 base::WeakPtr<UsbServiceImpl> usb_service, |
252 devices_.erase(device->unique_id()); | 457 scoped_refptr<base::SequencedTaskRunner> task_runner, |
253 | |
254 NotifyDeviceRemoved(device); | |
255 device->OnDisconnect(); | |
256 } | |
257 } | |
258 | |
259 // Remove disconnected devices from platform_devices_. | |
260 for (const PlatformUsbDevice& platform_device : disconnected_devices) { | |
261 // UsbDevice will be destroyed after this. The corresponding | |
262 // PlatformUsbDevice will be unref'ed during this process. | |
263 platform_devices_.erase(platform_device); | |
264 } | |
265 | |
266 libusb_free_device_list(platform_devices, true); | |
267 } | |
268 | |
269 #if defined(OS_WIN) | |
270 void UsbServiceImpl::RefreshDevicesIfWinUsbDevice( | |
271 const std::string& device_path) { | |
272 ScopedDeviceInfoList dev_info_list(SetupDiCreateDeviceInfoList(NULL, NULL)); | |
273 if (!dev_info_list.valid()) { | |
274 USB_PLOG(ERROR) << "Failed to create a device information set"; | |
275 return; | |
276 } | |
277 | |
278 // This will add the device to |dev_info_list| so we can query driver info. | |
279 if (!SetupDiOpenDeviceInterfaceA(dev_info_list.get(), device_path.c_str(), 0, | |
280 NULL)) { | |
281 USB_PLOG(ERROR) << "Failed to get device interface data for " | |
282 << device_path; | |
283 return; | |
284 } | |
285 | |
286 ScopedDeviceInfo dev_info; | |
287 if (!SetupDiEnumDeviceInfo(dev_info_list.get(), 0, dev_info.get())) { | |
288 USB_PLOG(ERROR) << "Failed to get device info for " << device_path; | |
289 return; | |
290 } | |
291 dev_info.set_valid(dev_info_list.get()); | |
292 | |
293 DWORD reg_data_type; | |
294 BYTE buffer[256]; | |
295 if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list.get(), dev_info.get(), | |
296 SPDRP_SERVICE, ®_data_type, | |
297 &buffer[0], sizeof buffer, NULL)) { | |
298 USB_PLOG(ERROR) << "Failed to get device service property"; | |
299 return; | |
300 } | |
301 if (reg_data_type != REG_SZ) { | |
302 USB_LOG(ERROR) << "Unexpected data type for driver service: " | |
303 << reg_data_type; | |
304 return; | |
305 } | |
306 | |
307 USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << "."; | |
308 if (base::strncasecmp("WinUSB", (const char*)&buffer[0], sizeof "WinUSB") == | |
309 0) { | |
310 RefreshDevices(); | |
311 } | |
312 } | |
313 #endif // OS_WIN | |
314 | |
315 scoped_refptr<UsbDeviceImpl> UsbServiceImpl::AddDevice( | |
316 PlatformUsbDevice platform_device) { | 458 PlatformUsbDevice platform_device) { |
317 libusb_device_descriptor descriptor; | 459 libusb_device_descriptor descriptor; |
318 int rv = libusb_get_device_descriptor(platform_device, &descriptor); | 460 int rv = libusb_get_device_descriptor(platform_device, &descriptor); |
319 if (rv == LIBUSB_SUCCESS) { | 461 if (rv == LIBUSB_SUCCESS) { |
320 uint32 unique_id; | 462 base::string16 manufacturer_string; |
321 do { | 463 base::string16 product_string; |
322 unique_id = ++next_unique_id_; | 464 base::string16 serial_number; |
323 } while (devices_.find(unique_id) != devices_.end()); | 465 std::string device_node; |
324 | 466 ReadDeviceStrings(platform_device, &descriptor, &manufacturer_string, |
325 scoped_refptr<UsbDeviceImpl> new_device(new UsbDeviceImpl( | 467 &product_string, &serial_number, &device_node); |
326 context_, ui_task_runner_, platform_device, descriptor.idVendor, | 468 |
327 descriptor.idProduct, unique_id)); | 469 task_runner->PostTask( |
328 platform_devices_[platform_device] = new_device; | 470 FROM_HERE, base::Bind(&UsbServiceImpl::AddDevice, usb_service, |
329 devices_[unique_id] = new_device; | 471 platform_device, descriptor.idVendor, |
330 NotifyDeviceAdded(new_device); | 472 descriptor.idProduct, manufacturer_string, |
331 return new_device; | 473 product_string, serial_number, device_node)); |
332 } else { | 474 } else { |
333 USB_LOG(EVENT) << "Failed to get device descriptor: " | 475 USB_LOG(EVENT) << "Failed to get device descriptor: " |
334 << ConvertPlatformUsbErrorToString(rv); | 476 << ConvertPlatformUsbErrorToString(rv); |
335 return nullptr; | 477 libusb_unref_device(platform_device); |
336 } | 478 } |
| 479 } |
| 480 |
| 481 void UsbServiceImpl::RefreshDevicesComplete(libusb_device** platform_devices, |
| 482 ssize_t device_count) { |
| 483 if (platform_devices) { |
| 484 // Mark devices seen in this enumeration. |
| 485 for (ssize_t i = 0; i < device_count; ++i) { |
| 486 const PlatformDeviceMap::iterator it = |
| 487 platform_devices_.find(platform_devices[i]); |
| 488 if (it != platform_devices_.end()) { |
| 489 it->second->set_visited(true); |
| 490 } |
| 491 } |
| 492 |
| 493 // Remove devices not seen in this enumeration. |
| 494 for (PlatformDeviceMap::iterator it = platform_devices_.begin(); |
| 495 it != platform_devices_.end(); |
| 496 /* incremented internally */) { |
| 497 PlatformDeviceMap::iterator current = it++; |
| 498 const scoped_refptr<UsbDeviceImpl>& device = current->second; |
| 499 if (device->was_visited()) { |
| 500 device->set_visited(false); |
| 501 } else { |
| 502 RemoveDevice(device); |
| 503 } |
| 504 } |
| 505 |
| 506 libusb_free_device_list(platform_devices, true); |
| 507 } |
| 508 |
| 509 enumeration_ready_ = true; |
| 510 |
| 511 if (!pending_enumerations_.empty()) { |
| 512 std::vector<scoped_refptr<UsbDevice>> devices; |
| 513 for (const auto& map_entry : devices_) { |
| 514 devices.push_back(map_entry.second); |
| 515 } |
| 516 |
| 517 std::vector<GetDevicesCallback> pending_enumerations; |
| 518 pending_enumerations.swap(pending_enumerations_); |
| 519 for (const GetDevicesCallback& callback : pending_enumerations) { |
| 520 callback.Run(devices); |
| 521 } |
| 522 } |
| 523 } |
| 524 |
| 525 void UsbServiceImpl::AddDevice(PlatformUsbDevice platform_device, |
| 526 uint16 vendor_id, |
| 527 uint16 product_id, |
| 528 base::string16 manufacturer_string, |
| 529 base::string16 product_string, |
| 530 base::string16 serial_number, |
| 531 std::string device_node) { |
| 532 uint32 unique_id; |
| 533 do { |
| 534 unique_id = ++next_unique_id_; |
| 535 } while (devices_.find(unique_id) != devices_.end()); |
| 536 |
| 537 scoped_refptr<UsbDeviceImpl> device( |
| 538 new UsbDeviceImpl(context_, platform_device, vendor_id, product_id, |
| 539 unique_id, manufacturer_string, product_string, |
| 540 serial_number, blocking_task_runner_)); |
| 541 |
| 542 platform_devices_[platform_device] = device; |
| 543 devices_[unique_id] = device; |
| 544 |
| 545 USB_LOG(USER) << "USB device added: vendor=" << device->vendor_id() << " \"" |
| 546 << device->manufacturer_string() |
| 547 << "\", product=" << device->product_id() << " \"" |
| 548 << device->product_string() << "\", serial=\"" |
| 549 << device->serial_number() |
| 550 << "\", uniqueId=" << device->unique_id(); |
| 551 |
| 552 if (enumeration_ready_) { |
| 553 NotifyDeviceAdded(device); |
| 554 } |
| 555 |
| 556 libusb_unref_device(platform_device); |
| 557 } |
| 558 |
| 559 void UsbServiceImpl::RemoveDevice(scoped_refptr<UsbDeviceImpl> device) { |
| 560 platform_devices_.erase(device->platform_device()); |
| 561 devices_.erase(device->unique_id()); |
| 562 |
| 563 USB_LOG(USER) << "USB device removed: uniqueId=" << device->unique_id(); |
| 564 |
| 565 NotifyDeviceRemoved(device); |
| 566 device->OnDisconnect(); |
337 } | 567 } |
338 | 568 |
339 // static | 569 // static |
340 int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context, | 570 int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context, |
341 PlatformUsbDevice device, | 571 PlatformUsbDevice device, |
342 libusb_hotplug_event event, | 572 libusb_hotplug_event event, |
343 void* user_data) { | 573 void* user_data) { |
344 // It is safe to access the UsbServiceImpl* here because libusb takes a lock | 574 // It is safe to access the UsbServiceImpl* here because libusb takes a lock |
345 // around registering, deregistering and calling hotplug callback functions | 575 // around registering, deregistering and calling hotplug callback functions |
346 // and so guarantees that this function will not be called by the event | 576 // and so guarantees that this function will not be called by the event |
347 // processing thread after it has been deregistered. | 577 // processing thread after it has been deregistered. |
348 UsbServiceImpl* self = reinterpret_cast<UsbServiceImpl*>(user_data); | 578 UsbServiceImpl* self = reinterpret_cast<UsbServiceImpl*>(user_data); |
349 switch (event) { | 579 switch (event) { |
350 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: | 580 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: |
351 libusb_ref_device(device); // Released in OnDeviceAdded. | 581 libusb_ref_device(device); // Released in OnPlatformDeviceAdded. |
352 if (self->task_runner_->BelongsToCurrentThread()) { | 582 if (self->task_runner_->BelongsToCurrentThread()) { |
353 self->OnDeviceAdded(device); | 583 self->OnPlatformDeviceAdded(device); |
354 } else { | 584 } else { |
355 self->task_runner_->PostTask( | 585 self->task_runner_->PostTask( |
356 FROM_HERE, base::Bind(&UsbServiceImpl::OnDeviceAdded, | 586 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceAdded, |
357 base::Unretained(self), device)); | 587 base::Unretained(self), device)); |
358 } | 588 } |
359 break; | 589 break; |
360 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: | 590 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: |
361 libusb_ref_device(device); // Released in OnDeviceRemoved. | 591 libusb_ref_device(device); // Released in OnPlatformDeviceRemoved. |
362 if (self->task_runner_->BelongsToCurrentThread()) { | 592 if (self->task_runner_->BelongsToCurrentThread()) { |
363 self->OnDeviceRemoved(device); | 593 self->OnPlatformDeviceRemoved(device); |
364 } else { | 594 } else { |
365 self->task_runner_->PostTask( | 595 self->task_runner_->PostTask( |
366 FROM_HERE, base::Bind(&UsbServiceImpl::OnDeviceRemoved, | 596 FROM_HERE, base::Bind(&UsbServiceImpl::OnPlatformDeviceRemoved, |
367 base::Unretained(self), device)); | 597 base::Unretained(self), device)); |
368 } | 598 } |
369 break; | 599 break; |
370 default: | 600 default: |
371 NOTREACHED(); | 601 NOTREACHED(); |
372 } | 602 } |
373 | 603 |
374 return 0; | 604 return 0; |
375 } | 605 } |
376 | 606 |
377 void UsbServiceImpl::OnDeviceAdded(PlatformUsbDevice platform_device) { | 607 void UsbServiceImpl::OnPlatformDeviceAdded(PlatformUsbDevice platform_device) { |
378 DCHECK(CalledOnValidThread()); | 608 DCHECK(CalledOnValidThread()); |
379 DCHECK(!ContainsKey(platform_devices_, platform_device)); | 609 DCHECK(!ContainsKey(platform_devices_, platform_device)); |
| 610 blocking_task_runner_->PostTask( |
| 611 FROM_HERE, |
| 612 base::Bind(&UsbServiceImpl::AddDeviceOnBlockingThread, |
| 613 weak_factory_.GetWeakPtr(), task_runner_, platform_device)); |
380 | 614 |
381 AddDevice(platform_device); | 615 // libusb_unref_device(platform_device) is called by the task above. |
382 libusb_unref_device(platform_device); | |
383 } | 616 } |
384 | 617 |
385 void UsbServiceImpl::OnDeviceRemoved(PlatformUsbDevice platform_device) { | 618 void UsbServiceImpl::OnPlatformDeviceRemoved( |
| 619 PlatformUsbDevice platform_device) { |
386 DCHECK(CalledOnValidThread()); | 620 DCHECK(CalledOnValidThread()); |
387 | |
388 PlatformDeviceMap::iterator it = platform_devices_.find(platform_device); | 621 PlatformDeviceMap::iterator it = platform_devices_.find(platform_device); |
389 if (it != platform_devices_.end()) { | 622 if (it != platform_devices_.end()) { |
390 scoped_refptr<UsbDeviceImpl> device = it->second; | 623 scoped_refptr<UsbDeviceImpl> device = it->second; |
391 DeviceMap::iterator dev_it = devices_.find(device->unique_id()); | 624 // Serialize with calls to AddDeviceOnBlockingThread. |
392 if (dev_it != devices_.end()) { | 625 blocking_task_runner_->PostTaskAndReply( |
393 devices_.erase(dev_it); | 626 FROM_HERE, base::Bind(&base::DoNothing), |
394 } else { | 627 base::Bind(&UsbServiceImpl::RemoveDevice, weak_factory_.GetWeakPtr(), |
395 NOTREACHED(); | 628 device)); |
396 } | |
397 platform_devices_.erase(it); | |
398 | |
399 NotifyDeviceRemoved(device); | |
400 device->OnDisconnect(); | |
401 } else { | 629 } else { |
402 NOTREACHED(); | 630 NOTREACHED(); |
403 } | 631 } |
404 | 632 |
405 libusb_unref_device(platform_device); | 633 libusb_unref_device(platform_device); |
406 } | 634 } |
407 | 635 |
408 } // namespace device | 636 } // namespace device |
OLD | NEW |