Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(414)

Side by Side Diff: device/usb/usb_service_impl.cc

Issue 980023002: Move device/usb classes from the FILE thread to UI thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed first round of rocket@ feedback. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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, &reg_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, &reg_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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698