Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / device / usb / usb_device_impl.cc
blob02ceb6f834afda1f90730081a487e6b7be4da80f
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_device_impl.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "components/device_event_log/device_event_log.h"
17 #include "device/usb/usb_context.h"
18 #include "device/usb/usb_descriptors.h"
19 #include "device/usb/usb_device_handle_impl.h"
20 #include "device/usb/usb_error.h"
21 #include "third_party/libusb/src/libusb/libusb.h"
23 #if defined(OS_CHROMEOS)
24 #include "chromeos/dbus/dbus_thread_manager.h"
25 #include "chromeos/dbus/permission_broker_client.h"
26 #endif // defined(OS_CHROMEOS)
28 #if defined(USE_UDEV)
29 #include "device/udev_linux/scoped_udev.h"
30 #endif // defined(USE_UDEV)
32 namespace device {
34 namespace {
36 #if defined(OS_CHROMEOS)
38 void PostResultOnTaskRunner(
39 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
40 const base::Callback<void(bool success)>& callback,
41 bool success) {
42 task_runner->PostTask(FROM_HERE, base::Bind(callback, success));
45 #endif // defined(OS_CHROMEOS)
47 UsbEndpointDirection GetDirection(
48 const libusb_endpoint_descriptor* descriptor) {
49 switch (descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) {
50 case LIBUSB_ENDPOINT_IN:
51 return USB_DIRECTION_INBOUND;
52 case LIBUSB_ENDPOINT_OUT:
53 return USB_DIRECTION_OUTBOUND;
54 default:
55 NOTREACHED();
56 return USB_DIRECTION_INBOUND;
60 UsbSynchronizationType GetSynchronizationType(
61 const libusb_endpoint_descriptor* descriptor) {
62 switch ((descriptor->bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) >> 2) {
63 case LIBUSB_ISO_SYNC_TYPE_NONE:
64 return USB_SYNCHRONIZATION_NONE;
65 case LIBUSB_ISO_SYNC_TYPE_ASYNC:
66 return USB_SYNCHRONIZATION_ASYNCHRONOUS;
67 case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE:
68 return USB_SYNCHRONIZATION_ADAPTIVE;
69 case LIBUSB_ISO_SYNC_TYPE_SYNC:
70 return USB_SYNCHRONIZATION_SYNCHRONOUS;
71 default:
72 NOTREACHED();
73 return USB_SYNCHRONIZATION_NONE;
77 UsbTransferType GetTransferType(const libusb_endpoint_descriptor* descriptor) {
78 switch (descriptor->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
79 case LIBUSB_TRANSFER_TYPE_CONTROL:
80 return USB_TRANSFER_CONTROL;
81 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
82 return USB_TRANSFER_ISOCHRONOUS;
83 case LIBUSB_TRANSFER_TYPE_BULK:
84 return USB_TRANSFER_BULK;
85 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
86 return USB_TRANSFER_INTERRUPT;
87 default:
88 NOTREACHED();
89 return USB_TRANSFER_CONTROL;
93 UsbUsageType GetUsageType(const libusb_endpoint_descriptor* descriptor) {
94 switch ((descriptor->bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) >> 4) {
95 case LIBUSB_ISO_USAGE_TYPE_DATA:
96 return USB_USAGE_DATA;
97 case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
98 return USB_USAGE_FEEDBACK;
99 case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
100 return USB_USAGE_EXPLICIT_FEEDBACK;
101 default:
102 NOTREACHED();
103 return USB_USAGE_DATA;
107 } // namespace
109 UsbDeviceImpl::UsbDeviceImpl(
110 scoped_refptr<UsbContext> context,
111 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
112 PlatformUsbDevice platform_device,
113 uint16 vendor_id,
114 uint16 product_id,
115 uint32 unique_id)
116 : UsbDevice(vendor_id, product_id, unique_id),
117 platform_device_(platform_device),
118 context_(context),
119 ui_task_runner_(ui_task_runner) {
120 CHECK(platform_device) << "platform_device cannot be NULL";
121 libusb_ref_device(platform_device);
122 RefreshConfiguration();
123 #if defined(USE_UDEV)
124 ScopedUdevPtr udev(udev_new());
125 ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev.get()));
127 udev_enumerate_add_match_subsystem(enumerate.get(), "usb");
128 if (udev_enumerate_scan_devices(enumerate.get()) != 0) {
129 return;
131 std::string bus_number =
132 base::IntToString(libusb_get_bus_number(platform_device));
133 std::string device_address =
134 base::IntToString(libusb_get_device_address(platform_device));
135 udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
136 for (udev_list_entry* i = devices; i != NULL;
137 i = udev_list_entry_get_next(i)) {
138 ScopedUdevDevicePtr device(
139 udev_device_new_from_syspath(udev.get(), udev_list_entry_get_name(i)));
140 if (device) {
141 const char* value = udev_device_get_sysattr_value(device.get(), "busnum");
142 if (!value || bus_number != value) {
143 continue;
145 value = udev_device_get_sysattr_value(device.get(), "devnum");
146 if (!value || device_address != value) {
147 continue;
150 #if defined(OS_CHROMEOS)
151 value = udev_device_get_devnode(device.get());
152 if (value) {
153 devnode_ = value;
155 #endif
156 value = udev_device_get_sysattr_value(device.get(), "manufacturer");
157 if (value) {
158 manufacturer_ = base::UTF8ToUTF16(value);
160 value = udev_device_get_sysattr_value(device.get(), "product");
161 if (value) {
162 product_ = base::UTF8ToUTF16(value);
164 value = udev_device_get_sysattr_value(device.get(), "serial");
165 if (value) {
166 serial_number_ = base::UTF8ToUTF16(value);
168 break;
171 #else
172 strings_cached_ = false;
173 #endif
176 UsbDeviceImpl::~UsbDeviceImpl() {
177 // The destructor must be safe to call from any thread.
178 libusb_unref_device(platform_device_);
181 #if defined(OS_CHROMEOS)
183 void UsbDeviceImpl::CheckUsbAccess(const ResultCallback& callback) {
184 DCHECK(thread_checker_.CalledOnValidThread());
186 chromeos::PermissionBrokerClient* client =
187 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
188 DCHECK(client) << "Could not get permission broker client.";
190 ui_task_runner_->PostTask(
191 FROM_HERE,
192 base::Bind(&chromeos::PermissionBrokerClient::CheckPathAccess,
193 base::Unretained(client), devnode_,
194 base::Bind(&PostResultOnTaskRunner,
195 base::ThreadTaskRunnerHandle::Get(), callback)));
198 void UsbDeviceImpl::RequestUsbAccess(int interface_id,
199 const ResultCallback& callback) {
200 DCHECK(thread_checker_.CalledOnValidThread());
202 chromeos::PermissionBrokerClient* client =
203 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
204 DCHECK(client) << "Could not get permission broker client.";
206 ui_task_runner_->PostTask(
207 FROM_HERE,
208 base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess,
209 base::Unretained(client), devnode_, interface_id,
210 base::Bind(&PostResultOnTaskRunner,
211 base::ThreadTaskRunnerHandle::Get(), callback)));
214 #endif
216 scoped_refptr<UsbDeviceHandle> UsbDeviceImpl::Open() {
217 DCHECK(thread_checker_.CalledOnValidThread());
218 PlatformUsbDeviceHandle handle;
219 const int rv = libusb_open(platform_device_, &handle);
220 if (LIBUSB_SUCCESS == rv) {
221 scoped_refptr<UsbDeviceHandleImpl> device_handle =
222 new UsbDeviceHandleImpl(context_, this, handle);
223 handles_.push_back(device_handle);
224 return device_handle;
225 } else {
226 USB_LOG(EVENT) << "Failed to open device: "
227 << ConvertPlatformUsbErrorToString(rv);
228 return NULL;
232 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) {
233 DCHECK(thread_checker_.CalledOnValidThread());
235 for (HandlesVector::iterator it = handles_.begin(); it != handles_.end();
236 ++it) {
237 if (it->get() == handle.get()) {
238 (*it)->InternalClose();
239 handles_.erase(it);
240 return true;
243 return false;
246 const UsbConfigDescriptor* UsbDeviceImpl::GetConfiguration() {
247 DCHECK(thread_checker_.CalledOnValidThread());
248 return configuration_.get();
251 bool UsbDeviceImpl::GetManufacturer(base::string16* manufacturer) {
252 DCHECK(thread_checker_.CalledOnValidThread());
254 #if !defined(USE_UDEV)
255 if (!strings_cached_) {
256 CacheStrings();
258 #endif
260 *manufacturer = manufacturer_;
261 return !manufacturer_.empty();
264 bool UsbDeviceImpl::GetProduct(base::string16* product) {
265 DCHECK(thread_checker_.CalledOnValidThread());
267 #if !defined(USE_UDEV)
268 if (!strings_cached_) {
269 CacheStrings();
271 #endif
273 *product = product_;
274 return !product_.empty();
277 bool UsbDeviceImpl::GetSerialNumber(base::string16* serial_number) {
278 DCHECK(thread_checker_.CalledOnValidThread());
280 #if !defined(USE_UDEV)
281 if (!strings_cached_) {
282 CacheStrings();
284 #endif
286 *serial_number = serial_number_;
287 return !serial_number_.empty();
290 void UsbDeviceImpl::OnDisconnect() {
291 DCHECK(thread_checker_.CalledOnValidThread());
293 // Swap the list of handles into a local variable because closing all open
294 // handles may release the last reference to this object.
295 HandlesVector handles;
296 swap(handles, handles_);
298 for (const scoped_refptr<UsbDeviceHandleImpl>& handle : handles_) {
299 handle->InternalClose();
303 void UsbDeviceImpl::RefreshConfiguration() {
304 libusb_config_descriptor* platform_config;
305 int rv =
306 libusb_get_active_config_descriptor(platform_device_, &platform_config);
307 if (rv != LIBUSB_SUCCESS) {
308 USB_LOG(EVENT) << "Failed to get config descriptor: "
309 << ConvertPlatformUsbErrorToString(rv);
310 return;
313 configuration_.reset(new UsbConfigDescriptor());
314 configuration_->configuration_value = platform_config->bConfigurationValue;
315 configuration_->self_powered = (platform_config->bmAttributes & 0x40) != 0;
316 configuration_->remote_wakeup = (platform_config->bmAttributes & 0x20) != 0;
317 configuration_->maximum_power = platform_config->MaxPower * 2;
319 for (size_t i = 0; i < platform_config->bNumInterfaces; ++i) {
320 const struct libusb_interface* platform_interface =
321 &platform_config->interface[i];
322 for (int j = 0; j < platform_interface->num_altsetting; ++j) {
323 const struct libusb_interface_descriptor* platform_alt_setting =
324 &platform_interface->altsetting[j];
325 UsbInterfaceDescriptor interface;
327 interface.interface_number = platform_alt_setting->bInterfaceNumber;
328 interface.alternate_setting = platform_alt_setting->bAlternateSetting;
329 interface.interface_class = platform_alt_setting->bInterfaceClass;
330 interface.interface_subclass = platform_alt_setting->bInterfaceSubClass;
331 interface.interface_protocol = platform_alt_setting->bInterfaceProtocol;
333 for (size_t k = 0; k < platform_alt_setting->bNumEndpoints; ++k) {
334 const struct libusb_endpoint_descriptor* platform_endpoint =
335 &platform_alt_setting->endpoint[k];
336 UsbEndpointDescriptor endpoint;
338 endpoint.address = platform_endpoint->bEndpointAddress;
339 endpoint.direction = GetDirection(platform_endpoint);
340 endpoint.maximum_packet_size = platform_endpoint->wMaxPacketSize;
341 endpoint.synchronization_type =
342 GetSynchronizationType(platform_endpoint);
343 endpoint.transfer_type = GetTransferType(platform_endpoint);
344 endpoint.usage_type = GetUsageType(platform_endpoint);
345 endpoint.polling_interval = platform_endpoint->bInterval;
346 endpoint.extra_data = std::vector<uint8_t>(
347 platform_endpoint->extra,
348 platform_endpoint->extra + platform_endpoint->extra_length);
350 interface.endpoints.push_back(endpoint);
353 interface.extra_data = std::vector<uint8_t>(
354 platform_alt_setting->extra,
355 platform_alt_setting->extra + platform_alt_setting->extra_length);
357 configuration_->interfaces.push_back(interface);
361 configuration_->extra_data = std::vector<uint8_t>(
362 platform_config->extra,
363 platform_config->extra + platform_config->extra_length);
365 libusb_free_config_descriptor(platform_config);
368 #if !defined(USE_UDEV)
369 void UsbDeviceImpl::CacheStrings() {
370 DCHECK(thread_checker_.CalledOnValidThread());
371 // This is a non-blocking call as libusb has the descriptor in memory.
372 libusb_device_descriptor desc;
373 const int rv = libusb_get_device_descriptor(platform_device_, &desc);
374 if (rv == LIBUSB_SUCCESS) {
375 scoped_refptr<UsbDeviceHandle> device_handle = Open();
376 if (device_handle.get()) {
377 if (desc.iManufacturer != 0) {
378 device_handle->GetStringDescriptor(desc.iManufacturer, &manufacturer_);
380 if (desc.iProduct != 0) {
381 device_handle->GetStringDescriptor(desc.iProduct, &product_);
383 if (desc.iSerialNumber != 0) {
384 device_handle->GetStringDescriptor(desc.iSerialNumber, &serial_number_);
386 device_handle->Close();
387 } else {
388 USB_LOG(EVENT) << "Failed to open device to cache string descriptors.";
390 } else {
391 USB_LOG(EVENT)
392 << "Failed to read device descriptor to cache string descriptors: "
393 << ConvertPlatformUsbErrorToString(rv);
395 strings_cached_ = true;
397 #endif // !defined(USE_UDEV)
399 } // namespace device