Add additional UMAs to keep track of unprefixed EME promise results
[chromium-blink-merge.git] / device / usb / usb_service_impl.cc
blobd789e702b68b64fe9bfbb38953015bc5ac94696a
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
3 // found in the LICENSE file.
5 #include "device/usb/usb_service_impl.h"
7 #include <set>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/stl_util.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "device/usb/usb_error.h"
17 #if defined(OS_WIN)
18 #include <usbiodef.h>
20 #include "base/scoped_observer.h"
21 #include "device/core/device_monitor_win.h"
22 #endif // OS_WIN
24 namespace device {
26 #if defined(OS_WIN)
27 // This class lives on the application main thread so that it can listen for
28 // device change notification window messages. It registers for notifications
29 // regarding devices implementating the "UsbDevice" interface, which represents
30 // most of the devices the UsbService will enumerate.
31 class UsbServiceImpl::UIThreadHelper final
32 : private DeviceMonitorWin::Observer {
33 public:
34 UIThreadHelper(base::WeakPtr<UsbServiceImpl> usb_service)
35 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
36 usb_service_(usb_service),
37 device_observer_(this) {}
39 ~UIThreadHelper() {}
41 void Start() {
42 DeviceMonitorWin* device_monitor =
43 DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_USB_DEVICE);
44 if (device_monitor) {
45 device_observer_.Add(device_monitor);
49 private:
50 void OnDeviceAdded(const std::string& device_path) override {
51 task_runner_->PostTask(
52 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevices, usb_service_));
55 void OnDeviceRemoved(const std::string& device_path) override {
56 task_runner_->PostTask(
57 FROM_HERE, base::Bind(&UsbServiceImpl::RefreshDevices, usb_service_));
60 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
61 base::WeakPtr<UsbServiceImpl> usb_service_;
62 ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
64 #endif
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;
76 if (!context) {
77 return nullptr;
80 return new UsbServiceImpl(context, ui_task_runner);
83 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) {
84 DCHECK(CalledOnValidThread());
85 RefreshDevices();
86 DeviceMap::iterator it = devices_.find(unique_id);
87 if (it != devices_.end()) {
88 return it->second;
90 return NULL;
93 void UsbServiceImpl::GetDevices(
94 std::vector<scoped_refptr<UsbDevice> >* devices) {
95 DCHECK(CalledOnValidThread());
96 STLClearObject(devices);
98 if (!hotplug_enabled_) {
99 RefreshDevices();
102 for (const auto& map_entry : devices_) {
103 devices->push_back(map_entry.second);
107 UsbServiceImpl::UsbServiceImpl(
108 PlatformUsbContext context,
109 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
110 : context_(new UsbContext(context)),
111 ui_task_runner_(ui_task_runner),
112 next_unique_id_(0),
113 hotplug_enabled_(false),
114 weak_factory_(this) {
115 task_runner_ = base::ThreadTaskRunnerHandle::Get();
116 int rv = libusb_hotplug_register_callback(
117 context_->context(),
118 static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
119 LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
120 LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
121 LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
122 &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_);
123 if (rv == LIBUSB_SUCCESS) {
124 hotplug_enabled_ = true;
125 } else {
126 #if defined(OS_WIN)
127 ui_thread_helper_ = new UIThreadHelper(weak_factory_.GetWeakPtr());
128 ui_task_runner_->PostTask(FROM_HERE,
129 base::Bind(&UIThreadHelper::Start,
130 base::Unretained(ui_thread_helper_)));
131 #endif // OS_WIN
135 UsbServiceImpl::~UsbServiceImpl() {
136 if (hotplug_enabled_) {
137 libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_);
139 #if defined(OS_WIN)
140 if (ui_thread_helper_) {
141 ui_task_runner_->DeleteSoon(FROM_HERE, ui_thread_helper_);
143 #endif // OS_WIN
144 for (const auto& map_entry : devices_) {
145 map_entry.second->OnDisconnect();
149 void UsbServiceImpl::RefreshDevices() {
150 DCHECK(CalledOnValidThread());
152 libusb_device** platform_devices = NULL;
153 const ssize_t device_count =
154 libusb_get_device_list(context_->context(), &platform_devices);
155 if (device_count < 0) {
156 VLOG(1) << "Failed to get device list: "
157 << ConvertPlatformUsbErrorToString(device_count);
160 std::set<UsbDevice*> connected_devices;
161 std::vector<PlatformUsbDevice> disconnected_devices;
163 // Populates new devices.
164 for (ssize_t i = 0; i < device_count; ++i) {
165 if (!ContainsKey(platform_devices_, platform_devices[i])) {
166 scoped_refptr<UsbDeviceImpl> new_device = AddDevice(platform_devices[i]);
167 if (new_device) {
168 connected_devices.insert(new_device.get());
170 } else {
171 connected_devices.insert(platform_devices_[platform_devices[i]].get());
175 // Find disconnected devices.
176 for (const auto& map_entry : platform_devices_) {
177 PlatformUsbDevice platform_device = map_entry.first;
178 scoped_refptr<UsbDeviceImpl> device = map_entry.second;
179 if (!ContainsKey(connected_devices, device.get())) {
180 disconnected_devices.push_back(platform_device);
181 devices_.erase(device->unique_id());
183 NotifyDeviceRemoved(device);
184 device->OnDisconnect();
188 // Remove disconnected devices from platform_devices_.
189 for (const PlatformUsbDevice& platform_device : disconnected_devices) {
190 // UsbDevice will be destroyed after this. The corresponding
191 // PlatformUsbDevice will be unref'ed during this process.
192 platform_devices_.erase(platform_device);
195 libusb_free_device_list(platform_devices, true);
198 scoped_refptr<UsbDeviceImpl> UsbServiceImpl::AddDevice(
199 PlatformUsbDevice platform_device) {
200 libusb_device_descriptor descriptor;
201 int rv = libusb_get_device_descriptor(platform_device, &descriptor);
202 if (rv == LIBUSB_SUCCESS) {
203 uint32 unique_id;
204 do {
205 unique_id = ++next_unique_id_;
206 } while (devices_.find(unique_id) != devices_.end());
208 scoped_refptr<UsbDeviceImpl> new_device(new UsbDeviceImpl(
209 context_, ui_task_runner_, platform_device, descriptor.idVendor,
210 descriptor.idProduct, unique_id));
211 platform_devices_[platform_device] = new_device;
212 devices_[unique_id] = new_device;
213 NotifyDeviceAdded(new_device);
214 return new_device;
215 } else {
216 VLOG(1) << "Failed to get device descriptor: "
217 << ConvertPlatformUsbErrorToString(rv);
218 return nullptr;
222 // static
223 int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context,
224 PlatformUsbDevice device,
225 libusb_hotplug_event event,
226 void* user_data) {
227 // It is safe to access the UsbServiceImpl* here because libusb takes a lock
228 // around registering, deregistering and calling hotplug callback functions
229 // and so guarantees that this function will not be called by the event
230 // processing thread after it has been deregistered.
231 UsbServiceImpl* self = reinterpret_cast<UsbServiceImpl*>(user_data);
232 switch (event) {
233 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
234 libusb_ref_device(device); // Released in OnDeviceAdded.
235 if (self->task_runner_->BelongsToCurrentThread()) {
236 self->OnDeviceAdded(device);
237 } else {
238 self->task_runner_->PostTask(
239 FROM_HERE, base::Bind(&UsbServiceImpl::OnDeviceAdded,
240 base::Unretained(self), device));
242 break;
243 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
244 libusb_ref_device(device); // Released in OnDeviceRemoved.
245 if (self->task_runner_->BelongsToCurrentThread()) {
246 self->OnDeviceRemoved(device);
247 } else {
248 self->task_runner_->PostTask(
249 FROM_HERE, base::Bind(&UsbServiceImpl::OnDeviceRemoved,
250 base::Unretained(self), device));
252 break;
253 default:
254 NOTREACHED();
257 return 0;
260 void UsbServiceImpl::OnDeviceAdded(PlatformUsbDevice platform_device) {
261 DCHECK(CalledOnValidThread());
262 DCHECK(!ContainsKey(platform_devices_, platform_device));
264 AddDevice(platform_device);
265 libusb_unref_device(platform_device);
268 void UsbServiceImpl::OnDeviceRemoved(PlatformUsbDevice platform_device) {
269 DCHECK(CalledOnValidThread());
271 PlatformDeviceMap::iterator it = platform_devices_.find(platform_device);
272 if (it != platform_devices_.end()) {
273 scoped_refptr<UsbDeviceImpl> device = it->second;
274 DeviceMap::iterator dev_it = devices_.find(device->unique_id());
275 if (dev_it != devices_.end()) {
276 devices_.erase(dev_it);
277 } else {
278 NOTREACHED();
280 platform_devices_.erase(it);
282 NotifyDeviceRemoved(device);
283 device->OnDisconnect();
284 } else {
285 NOTREACHED();
288 libusb_unref_device(platform_device);
291 } // namespace device