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

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

Issue 800963005: Add browser tests for USB device add/remove events. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 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.h" 5 #include "device/usb/usb_service_impl.h"
6 6
7 #include <map>
8 #include <set> 7 #include <set>
9 8
10 #include "base/bind.h" 9 #include "base/bind.h"
11 #include "base/lazy_instance.h" 10 #include "base/location.h"
12 #include "base/memory/weak_ptr.h" 11 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/single_thread_task_runner.h" 12 #include "base/single_thread_task_runner.h"
15 #include "base/stl_util.h" 13 #include "base/stl_util.h"
16 #include "base/thread_task_runner_handle.h" 14 #include "base/thread_task_runner_handle.h"
17 #include "device/usb/usb_context.h"
18 #include "device/usb/usb_device_impl.h"
19 #include "device/usb/usb_error.h" 15 #include "device/usb/usb_error.h"
20 #include "third_party/libusb/src/libusb/libusb.h"
21 16
22 #if defined(OS_WIN) 17 #if defined(OS_WIN)
23 #include <usbiodef.h> 18 #include <usbiodef.h>
24 19
25 #include "base/scoped_observer.h" 20 #include "base/scoped_observer.h"
26 #include "device/core/device_monitor_win.h" 21 #include "device/core/device_monitor_win.h"
27 #endif // OS_WIN 22 #endif // OS_WIN
28 23
29 namespace device { 24 namespace device {
30 25
31 namespace {
32
33 base::LazyInstance<scoped_ptr<UsbService> >::Leaky g_usb_service_instance =
34 LAZY_INSTANCE_INITIALIZER;
35
36 } // namespace
37
38 typedef struct libusb_device* PlatformUsbDevice;
39 typedef struct libusb_context* PlatformUsbContext;
40
41 class UsbServiceImpl : public UsbService,
42 private base::MessageLoop::DestructionObserver {
43 public:
44 explicit UsbServiceImpl(
45 PlatformUsbContext context,
46 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
47 ~UsbServiceImpl() override;
48
49 private:
50 // device::UsbService implementation
51 scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override;
52 void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override;
53
54 // base::MessageLoop::DestructionObserver implementation.
55 void WillDestroyCurrentMessageLoop() override;
56
57 // Enumerate USB devices from OS and update devices_ map.
58 void RefreshDevices();
59
60 // Adds a new UsbDevice to the devices_ map based on the given libusb device.
61 scoped_refptr<UsbDeviceImpl> AddDevice(PlatformUsbDevice platform_device);
62
63 // Handle hotplug events from libusb.
64 static int LIBUSB_CALL HotplugCallback(libusb_context* context,
65 PlatformUsbDevice device,
66 libusb_hotplug_event event,
67 void* user_data);
68 // These functions release a reference to the provided platform device.
69 void OnDeviceAdded(PlatformUsbDevice platform_device);
70 void OnDeviceRemoved(PlatformUsbDevice platform_device);
71
72 scoped_refptr<UsbContext> context_;
73 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
74 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
75
76 #if defined(OS_WIN)
77 class UIThreadHelper;
78 UIThreadHelper* ui_thread_helper_;
79 #endif // OS_WIN
80
81 // TODO(reillyg): Figure out a better solution for device IDs.
82 uint32 next_unique_id_;
83
84 // When available the device list will be updated when new devices are
85 // connected instead of only when a full enumeration is requested.
86 // TODO(reillyg): Support this on all platforms. crbug.com/411715
87 bool hotplug_enabled_;
88 libusb_hotplug_callback_handle hotplug_handle_;
89
90 // The map from unique IDs to UsbDevices.
91 typedef std::map<uint32, scoped_refptr<UsbDeviceImpl> > DeviceMap;
92 DeviceMap devices_;
93
94 // The map from PlatformUsbDevices to UsbDevices.
95 typedef std::map<PlatformUsbDevice, scoped_refptr<UsbDeviceImpl> >
96 PlatformDeviceMap;
97 PlatformDeviceMap platform_devices_;
98
99 base::WeakPtrFactory<UsbServiceImpl> weak_factory_;
100
101 DISALLOW_COPY_AND_ASSIGN(UsbServiceImpl);
102 };
103
104 #if defined(OS_WIN) 26 #if defined(OS_WIN)
105 // This class lives on the application main thread so that it can listen for 27 // This class lives on the application main thread so that it can listen for
106 // device change notification window messages. It registers for notifications 28 // device change notification window messages. It registers for notifications
107 // regarding devices implementating the "UsbDevice" interface, which represents 29 // regarding devices implementating the "UsbDevice" interface, which represents
108 // most of the devices the UsbService will enumerate. 30 // most of the devices the UsbService will enumerate.
109 class UsbServiceImpl::UIThreadHelper : DeviceMonitorWin::Observer { 31 class UsbServiceImpl::UIThreadHelper : DeviceMonitorWin::Observer {
110 public: 32 public:
111 UIThreadHelper(base::WeakPtr<UsbServiceImpl> usb_service) 33 UIThreadHelper(base::WeakPtr<UsbServiceImpl> usb_service)
112 : task_runner_(base::ThreadTaskRunnerHandle::Get()), 34 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
113 usb_service_(usb_service), 35 usb_service_(usb_service),
(...skipping 19 matching lines...) Expand all
133 task_runner_->PostTask( 55 task_runner_->PostTask(
134 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevices, usb_service_)); 56 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevices, usb_service_));
135 } 57 }
136 58
137 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 59 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
138 base::WeakPtr<UsbServiceImpl> usb_service_; 60 base::WeakPtr<UsbServiceImpl> usb_service_;
139 ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_; 61 ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
140 }; 62 };
141 #endif 63 #endif
142 64
65 // static
66 UsbService* UsbServiceImpl::Create(
67 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
68 PlatformUsbContext context = NULL;
69 const int rv = libusb_init(&context);
70 if (rv != LIBUSB_SUCCESS) {
71 VLOG(1) << "Failed to initialize libusb: "
72 << ConvertPlatformUsbErrorToString(rv);
73 return nullptr;
74 }
75 if (!context) {
76 return nullptr;
77 }
78
79 return new UsbServiceImpl(context, ui_task_runner);
80 }
81
143 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) { 82 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) {
144 DCHECK(CalledOnValidThread()); 83 DCHECK(CalledOnValidThread());
145 RefreshDevices(); 84 RefreshDevices();
146 DeviceMap::iterator it = devices_.find(unique_id); 85 DeviceMap::iterator it = devices_.find(unique_id);
147 if (it != devices_.end()) { 86 if (it != devices_.end()) {
148 return it->second; 87 return it->second;
149 } 88 }
150 return NULL; 89 return NULL;
151 } 90 }
152 91
153 void UsbServiceImpl::GetDevices( 92 void UsbServiceImpl::GetDevices(
154 std::vector<scoped_refptr<UsbDevice> >* devices) { 93 std::vector<scoped_refptr<UsbDevice> >* devices) {
155 DCHECK(CalledOnValidThread()); 94 DCHECK(CalledOnValidThread());
156 STLClearObject(devices); 95 STLClearObject(devices);
157 96
158 if (!hotplug_enabled_) { 97 if (!hotplug_enabled_) {
159 RefreshDevices(); 98 RefreshDevices();
160 } 99 }
161 100
162 for (const auto& map_entry : devices_) { 101 for (const auto& map_entry : devices_) {
163 devices->push_back(map_entry.second); 102 devices->push_back(map_entry.second);
164 } 103 }
165 } 104 }
166 105
167 void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
168 DCHECK(CalledOnValidThread());
169 g_usb_service_instance.Get().reset(NULL);
170 }
171
172 UsbServiceImpl::UsbServiceImpl( 106 UsbServiceImpl::UsbServiceImpl(
173 PlatformUsbContext context, 107 PlatformUsbContext context,
174 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) 108 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
175 : context_(new UsbContext(context)), 109 : context_(new UsbContext(context)),
176 ui_task_runner_(ui_task_runner), 110 ui_task_runner_(ui_task_runner),
177 next_unique_id_(0), 111 next_unique_id_(0),
178 hotplug_enabled_(false), 112 hotplug_enabled_(false),
179 weak_factory_(this) { 113 weak_factory_(this) {
180 base::MessageLoop::current()->AddDestructionObserver(this);
181 task_runner_ = base::ThreadTaskRunnerHandle::Get(); 114 task_runner_ = base::ThreadTaskRunnerHandle::Get();
182 int rv = libusb_hotplug_register_callback( 115 int rv = libusb_hotplug_register_callback(
183 context_->context(), 116 context_->context(),
184 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | 117 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
185 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), 118 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
186 LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, 119 LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
187 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, 120 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
188 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_); 121 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_);
189 if (rv == LIBUSB_SUCCESS) { 122 if (rv == LIBUSB_SUCCESS) {
190 hotplug_enabled_ = true; 123 hotplug_enabled_ = true;
191 } else { 124 } else {
192 #if defined(OS_WIN) 125 #if defined(OS_WIN)
193 ui_thread_helper_ = new UIThreadHelper(weak_factory_.GetWeakPtr()); 126 ui_thread_helper_ = new UIThreadHelper(weak_factory_.GetWeakPtr());
194 ui_task_runner_->PostTask(FROM_HERE, 127 ui_task_runner_->PostTask(FROM_HERE,
195 base::Bind(&UIThreadHelper::Start, 128 base::Bind(&UIThreadHelper::Start,
196 base::Unretained(ui_thread_helper_))); 129 base::Unretained(ui_thread_helper_)));
197 #endif // OS_WIN 130 #endif // OS_WIN
198 } 131 }
199 } 132 }
200 133
201 UsbServiceImpl::~UsbServiceImpl() { 134 UsbServiceImpl::~UsbServiceImpl() {
202 base::MessageLoop::current()->RemoveDestructionObserver(this);
203 if (hotplug_enabled_) { 135 if (hotplug_enabled_) {
204 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_); 136 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_);
205 } 137 }
206 #if defined(OS_WIN) 138 #if defined(OS_WIN)
207 if (ui_thread_helper_) { 139 if (ui_thread_helper_) {
208 ui_task_runner_->DeleteSoon(FROM_HERE, ui_thread_helper_); 140 ui_task_runner_->DeleteSoon(FROM_HERE, ui_thread_helper_);
209 } 141 }
210 #endif // OS_WIN 142 #endif // OS_WIN
211 for (const auto& map_entry : devices_) { 143 for (const auto& map_entry : devices_) {
212 map_entry.second->OnDisconnect(); 144 map_entry.second->OnDisconnect();
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 280
349 NotifyDeviceRemoved(device); 281 NotifyDeviceRemoved(device);
350 device->OnDisconnect(); 282 device->OnDisconnect();
351 } else { 283 } else {
352 NOTREACHED(); 284 NOTREACHED();
353 } 285 }
354 286
355 libusb_unref_device(platform_device); 287 libusb_unref_device(platform_device);
356 } 288 }
357 289
358 void UsbService::Observer::OnDeviceAdded(scoped_refptr<UsbDevice> device) {
359 }
360
361 void UsbService::Observer::OnDeviceRemoved(scoped_refptr<UsbDevice> device) {
362 }
363
364 // static
365 UsbService* UsbService::GetInstance(
366 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
367 UsbService* instance = g_usb_service_instance.Get().get();
368 if (!instance) {
369 PlatformUsbContext context = NULL;
370
371 const int rv = libusb_init(&context);
372 if (rv != LIBUSB_SUCCESS) {
373 VLOG(1) << "Failed to initialize libusb: "
374 << ConvertPlatformUsbErrorToString(rv);
375 return NULL;
376 }
377 if (!context)
378 return NULL;
379
380 instance = new UsbServiceImpl(context, ui_task_runner);
381 g_usb_service_instance.Get().reset(instance);
382 }
383 return instance;
384 }
385
386 // static
387 void UsbService::SetInstanceForTest(UsbService* instance) {
388 g_usb_service_instance.Get().reset(instance);
389 }
390
391 UsbService::UsbService() {
392 }
393
394 UsbService::~UsbService() {
395 }
396
397 void UsbService::AddObserver(Observer* observer) {
398 DCHECK(CalledOnValidThread());
399 observer_list_.AddObserver(observer);
400 }
401
402 void UsbService::RemoveObserver(Observer* observer) {
403 DCHECK(CalledOnValidThread());
404 observer_list_.RemoveObserver(observer);
405 }
406
407 void UsbService::NotifyDeviceAdded(scoped_refptr<UsbDevice> device) {
408 DCHECK(CalledOnValidThread());
409 FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceAdded(device));
410 }
411
412 void UsbService::NotifyDeviceRemoved(scoped_refptr<UsbDevice> device) {
413 DCHECK(CalledOnValidThread());
414 FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceRemoved(device));
415 }
416
417 } // namespace device 290 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698