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

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: Adjusted JavaScript style. 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
« no previous file with comments | « device/usb/usb_service_impl.h ('k') | extensions/browser/api/hid/hid_apitest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 final 31 class UsbServiceImpl::UIThreadHelper final
110 : private DeviceMonitorWin::Observer { 32 : private DeviceMonitorWin::Observer {
111 public: 33 public:
112 UIThreadHelper(base::WeakPtr<UsbServiceImpl> usb_service) 34 UIThreadHelper(base::WeakPtr<UsbServiceImpl> usb_service)
113 : task_runner_(base::ThreadTaskRunnerHandle::Get()), 35 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
(...skipping 20 matching lines...) Expand all
134 task_runner_->PostTask( 56 task_runner_->PostTask(
135 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevices, usb_service_)); 57 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevices, usb_service_));
136 } 58 }
137 59
138 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 60 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
139 base::WeakPtr<UsbServiceImpl> usb_service_; 61 base::WeakPtr<UsbServiceImpl> usb_service_;
140 ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_; 62 ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
141 }; 63 };
142 #endif 64 #endif
143 65
66 // static
67 UsbService* UsbServiceImpl::Create(
68 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
69 PlatformUsbContext context = NULL;
70 const int rv = libusb_init(&context);
71 if (rv != LIBUSB_SUCCESS) {
72 VLOG(1) << "Failed to initialize libusb: "
73 << ConvertPlatformUsbErrorToString(rv);
74 return nullptr;
75 }
76 if (!context) {
77 return nullptr;
78 }
79
80 return new UsbServiceImpl(context, ui_task_runner);
81 }
82
144 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) { 83 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) {
145 DCHECK(CalledOnValidThread()); 84 DCHECK(CalledOnValidThread());
146 RefreshDevices(); 85 RefreshDevices();
147 DeviceMap::iterator it = devices_.find(unique_id); 86 DeviceMap::iterator it = devices_.find(unique_id);
148 if (it != devices_.end()) { 87 if (it != devices_.end()) {
149 return it->second; 88 return it->second;
150 } 89 }
151 return NULL; 90 return NULL;
152 } 91 }
153 92
154 void UsbServiceImpl::GetDevices( 93 void UsbServiceImpl::GetDevices(
155 std::vector<scoped_refptr<UsbDevice> >* devices) { 94 std::vector<scoped_refptr<UsbDevice> >* devices) {
156 DCHECK(CalledOnValidThread()); 95 DCHECK(CalledOnValidThread());
157 STLClearObject(devices); 96 STLClearObject(devices);
158 97
159 if (!hotplug_enabled_) { 98 if (!hotplug_enabled_) {
160 RefreshDevices(); 99 RefreshDevices();
161 } 100 }
162 101
163 for (const auto& map_entry : devices_) { 102 for (const auto& map_entry : devices_) {
164 devices->push_back(map_entry.second); 103 devices->push_back(map_entry.second);
165 } 104 }
166 } 105 }
167 106
168 void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
169 DCHECK(CalledOnValidThread());
170 g_usb_service_instance.Get().reset(NULL);
171 }
172
173 UsbServiceImpl::UsbServiceImpl( 107 UsbServiceImpl::UsbServiceImpl(
174 PlatformUsbContext context, 108 PlatformUsbContext context,
175 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) 109 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
176 : context_(new UsbContext(context)), 110 : context_(new UsbContext(context)),
177 ui_task_runner_(ui_task_runner), 111 ui_task_runner_(ui_task_runner),
178 next_unique_id_(0), 112 next_unique_id_(0),
179 hotplug_enabled_(false), 113 hotplug_enabled_(false),
180 weak_factory_(this) { 114 weak_factory_(this) {
181 base::MessageLoop::current()->AddDestructionObserver(this);
182 task_runner_ = base::ThreadTaskRunnerHandle::Get(); 115 task_runner_ = base::ThreadTaskRunnerHandle::Get();
183 int rv = libusb_hotplug_register_callback( 116 int rv = libusb_hotplug_register_callback(
184 context_->context(), 117 context_->context(),
185 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | 118 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
186 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), 119 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
187 LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, 120 LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
188 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, 121 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
189 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_); 122 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_);
190 if (rv == LIBUSB_SUCCESS) { 123 if (rv == LIBUSB_SUCCESS) {
191 hotplug_enabled_ = true; 124 hotplug_enabled_ = true;
192 } else { 125 } else {
193 #if defined(OS_WIN) 126 #if defined(OS_WIN)
194 ui_thread_helper_ = new UIThreadHelper(weak_factory_.GetWeakPtr()); 127 ui_thread_helper_ = new UIThreadHelper(weak_factory_.GetWeakPtr());
195 ui_task_runner_->PostTask(FROM_HERE, 128 ui_task_runner_->PostTask(FROM_HERE,
196 base::Bind(&UIThreadHelper::Start, 129 base::Bind(&UIThreadHelper::Start,
197 base::Unretained(ui_thread_helper_))); 130 base::Unretained(ui_thread_helper_)));
198 #endif // OS_WIN 131 #endif // OS_WIN
199 } 132 }
200 } 133 }
201 134
202 UsbServiceImpl::~UsbServiceImpl() { 135 UsbServiceImpl::~UsbServiceImpl() {
203 base::MessageLoop::current()->RemoveDestructionObserver(this);
204 if (hotplug_enabled_) { 136 if (hotplug_enabled_) {
205 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_); 137 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_);
206 } 138 }
207 #if defined(OS_WIN) 139 #if defined(OS_WIN)
208 if (ui_thread_helper_) { 140 if (ui_thread_helper_) {
209 ui_task_runner_->DeleteSoon(FROM_HERE, ui_thread_helper_); 141 ui_task_runner_->DeleteSoon(FROM_HERE, ui_thread_helper_);
210 } 142 }
211 #endif // OS_WIN 143 #endif // OS_WIN
212 for (const auto& map_entry : devices_) { 144 for (const auto& map_entry : devices_) {
213 map_entry.second->OnDisconnect(); 145 map_entry.second->OnDisconnect();
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 281
350 NotifyDeviceRemoved(device); 282 NotifyDeviceRemoved(device);
351 device->OnDisconnect(); 283 device->OnDisconnect();
352 } else { 284 } else {
353 NOTREACHED(); 285 NOTREACHED();
354 } 286 }
355 287
356 libusb_unref_device(platform_device); 288 libusb_unref_device(platform_device);
357 } 289 }
358 290
359 void UsbService::Observer::OnDeviceAdded(scoped_refptr<UsbDevice> device) {
360 }
361
362 void UsbService::Observer::OnDeviceRemoved(scoped_refptr<UsbDevice> device) {
363 }
364
365 // static
366 UsbService* UsbService::GetInstance(
367 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
368 UsbService* instance = g_usb_service_instance.Get().get();
369 if (!instance) {
370 PlatformUsbContext context = NULL;
371
372 const int rv = libusb_init(&context);
373 if (rv != LIBUSB_SUCCESS) {
374 VLOG(1) << "Failed to initialize libusb: "
375 << ConvertPlatformUsbErrorToString(rv);
376 return NULL;
377 }
378 if (!context)
379 return NULL;
380
381 instance = new UsbServiceImpl(context, ui_task_runner);
382 g_usb_service_instance.Get().reset(instance);
383 }
384 return instance;
385 }
386
387 // static
388 void UsbService::SetInstanceForTest(UsbService* instance) {
389 g_usb_service_instance.Get().reset(instance);
390 }
391
392 UsbService::UsbService() {
393 }
394
395 UsbService::~UsbService() {
396 }
397
398 void UsbService::AddObserver(Observer* observer) {
399 DCHECK(CalledOnValidThread());
400 observer_list_.AddObserver(observer);
401 }
402
403 void UsbService::RemoveObserver(Observer* observer) {
404 DCHECK(CalledOnValidThread());
405 observer_list_.RemoveObserver(observer);
406 }
407
408 void UsbService::NotifyDeviceAdded(scoped_refptr<UsbDevice> device) {
409 DCHECK(CalledOnValidThread());
410 FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceAdded(device));
411 }
412
413 void UsbService::NotifyDeviceRemoved(scoped_refptr<UsbDevice> device) {
414 DCHECK(CalledOnValidThread());
415 FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceRemoved(device));
416 }
417
418 } // namespace device 291 } // namespace device
OLDNEW
« no previous file with comments | « device/usb/usb_service_impl.h ('k') | extensions/browser/api/hid/hid_apitest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698