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.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 Loading... |
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 Loading... |
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 |
OLD | NEW |