| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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_linux.h" | 5 #include "device/usb/usb_service_linux.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/files/file.h" | 12 #include "base/files/file.h" |
| 13 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
| 14 #include "base/files/file_util.h" | 14 #include "base/files/file_util.h" |
| 15 #include "base/location.h" | 15 #include "base/location.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/memory/ptr_util.h" | 17 #include "base/memory/ptr_util.h" |
| 18 #include "base/memory/weak_ptr.h" | 18 #include "base/memory/weak_ptr.h" |
| 19 #include "base/scoped_observer.h" | 19 #include "base/scoped_observer.h" |
| 20 #include "base/single_thread_task_runner.h" | |
| 21 #include "base/stl_util.h" | 20 #include "base/stl_util.h" |
| 22 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
| 23 #include "base/strings/utf_string_conversions.h" | 22 #include "base/strings/utf_string_conversions.h" |
| 23 #include "base/threading/sequenced_task_runner_handle.h" |
| 24 #include "base/threading/thread_restrictions.h" | 24 #include "base/threading/thread_restrictions.h" |
| 25 #include "build/build_config.h" | 25 #include "build/build_config.h" |
| 26 #include "components/device_event_log/device_event_log.h" | 26 #include "components/device_event_log/device_event_log.h" |
| 27 #include "device/base/device_monitor_linux.h" | 27 #include "device/udev_linux/udev_watcher.h" |
| 28 #include "device/usb/usb_device_handle.h" | 28 #include "device/usb/usb_device_handle.h" |
| 29 #include "device/usb/usb_device_linux.h" | 29 #include "device/usb/usb_device_linux.h" |
| 30 #include "device/usb/webusb_descriptors.h" | 30 #include "device/usb/webusb_descriptors.h" |
| 31 | 31 |
| 32 namespace device { | 32 namespace device { |
| 33 | 33 |
| 34 namespace { | 34 namespace { |
| 35 | 35 |
| 36 // Standard USB requests and descriptor types: | 36 // Standard USB requests and descriptor types: |
| 37 const uint16_t kUsbVersion2_1 = 0x0210; | 37 const uint16_t kUsbVersion2_1 = 0x0210; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 60 if (device_handle) { | 60 if (device_handle) { |
| 61 ReadWebUsbDescriptors( | 61 ReadWebUsbDescriptors( |
| 62 device_handle, base::Bind(&OnReadDescriptors, callback, device_handle)); | 62 device_handle, base::Bind(&OnReadDescriptors, callback, device_handle)); |
| 63 } else { | 63 } else { |
| 64 callback.Run(false /* failure */); | 64 callback.Run(false /* failure */); |
| 65 } | 65 } |
| 66 } | 66 } |
| 67 | 67 |
| 68 } // namespace | 68 } // namespace |
| 69 | 69 |
| 70 class UsbServiceLinux::FileThreadHelper : public DeviceMonitorLinux::Observer { | 70 class UsbServiceLinux::FileThreadHelper : public UdevWatcher::Observer { |
| 71 public: | 71 public: |
| 72 FileThreadHelper(base::WeakPtr<UsbServiceLinux> service, | 72 FileThreadHelper(base::WeakPtr<UsbServiceLinux> service); |
| 73 scoped_refptr<base::SingleThreadTaskRunner> task_runner); | |
| 74 ~FileThreadHelper() override; | 73 ~FileThreadHelper() override; |
| 75 | 74 |
| 76 void Start(); | 75 void Start(); |
| 77 | 76 |
| 78 private: | 77 private: |
| 79 // DeviceMonitorLinux::Observer: | 78 // UdevWatcher::Observer |
| 80 void OnDeviceAdded(udev_device* udev_device) override; | 79 void OnDeviceAdded(ScopedUdevDevicePtr device) override; |
| 81 void OnDeviceRemoved(udev_device* device) override; | 80 void OnDeviceRemoved(ScopedUdevDevicePtr device) override; |
| 82 | 81 |
| 83 base::ThreadChecker thread_checker_; | 82 std::unique_ptr<UdevWatcher> watcher_; |
| 84 ScopedObserver<DeviceMonitorLinux, DeviceMonitorLinux::Observer> observer_; | |
| 85 | 83 |
| 86 // |service_| can only be checked for validity on |task_runner_|'s thread. | 84 // |service_| can only be checked for validity on |task_runner_|'s sequence. |
| 87 base::WeakPtr<UsbServiceLinux> service_; | 85 base::WeakPtr<UsbServiceLinux> service_; |
| 88 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 86 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 87 |
| 88 base::SequenceChecker sequence_checker_; |
| 89 | 89 |
| 90 DISALLOW_COPY_AND_ASSIGN(FileThreadHelper); | 90 DISALLOW_COPY_AND_ASSIGN(FileThreadHelper); |
| 91 }; | 91 }; |
| 92 | 92 |
| 93 UsbServiceLinux::FileThreadHelper::FileThreadHelper( | 93 UsbServiceLinux::FileThreadHelper::FileThreadHelper( |
| 94 base::WeakPtr<UsbServiceLinux> service, | 94 base::WeakPtr<UsbServiceLinux> service) |
| 95 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | 95 : service_(service), task_runner_(base::SequencedTaskRunnerHandle::Get()) { |
| 96 : observer_(this), service_(service), task_runner_(std::move(task_runner)) { | 96 // Detaches from the sequence on which this object was created. It will be |
| 97 thread_checker_.DetachFromThread(); | 97 // bound to its owning sequence when Start() is called. |
| 98 sequence_checker_.DetachFromSequence(); |
| 98 } | 99 } |
| 99 | 100 |
| 100 UsbServiceLinux::FileThreadHelper::~FileThreadHelper() { | 101 UsbServiceLinux::FileThreadHelper::~FileThreadHelper() { |
| 101 DCHECK(thread_checker_.CalledOnValidThread()); | 102 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 102 } | 103 } |
| 103 | 104 |
| 104 // static | 105 // static |
| 105 void UsbServiceLinux::FileThreadHelper::Start() { | 106 void UsbServiceLinux::FileThreadHelper::Start() { |
| 107 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 106 base::ThreadRestrictions::AssertIOAllowed(); | 108 base::ThreadRestrictions::AssertIOAllowed(); |
| 107 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 108 | 109 |
| 109 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance(); | 110 watcher_ = UdevWatcher::StartWatching(this); |
| 110 observer_.Add(monitor); | 111 watcher_->EnumerateExistingDevices(); |
| 111 monitor->Enumerate( | |
| 112 base::Bind(&FileThreadHelper::OnDeviceAdded, base::Unretained(this))); | |
| 113 task_runner_->PostTask(FROM_HERE, | 112 task_runner_->PostTask(FROM_HERE, |
| 114 base::Bind(&UsbServiceLinux::HelperStarted, service_)); | 113 base::Bind(&UsbServiceLinux::HelperStarted, service_)); |
| 115 } | 114 } |
| 116 | 115 |
| 117 void UsbServiceLinux::FileThreadHelper::OnDeviceAdded( | 116 void UsbServiceLinux::FileThreadHelper::OnDeviceAdded( |
| 118 udev_device* udev_device) { | 117 ScopedUdevDevicePtr device) { |
| 119 const char* subsystem = udev_device_get_subsystem(udev_device); | 118 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 119 const char* subsystem = udev_device_get_subsystem(device.get()); |
| 120 if (!subsystem || strcmp(subsystem, "usb") != 0) | 120 if (!subsystem || strcmp(subsystem, "usb") != 0) |
| 121 return; | 121 return; |
| 122 | 122 |
| 123 const char* value = udev_device_get_devnode(udev_device); | 123 const char* value = udev_device_get_devnode(device.get()); |
| 124 if (!value) | 124 if (!value) |
| 125 return; | 125 return; |
| 126 std::string device_path = value; | 126 std::string device_path = value; |
| 127 | 127 |
| 128 const char* sysfs_path = udev_device_get_syspath(udev_device); | 128 const char* sysfs_path = udev_device_get_syspath(device.get()); |
| 129 if (!sysfs_path) | 129 if (!sysfs_path) |
| 130 return; | 130 return; |
| 131 | 131 |
| 132 base::FilePath descriptors_path = | 132 base::FilePath descriptors_path = |
| 133 base::FilePath(sysfs_path).Append("descriptors"); | 133 base::FilePath(sysfs_path).Append("descriptors"); |
| 134 std::string descriptors_str; | 134 std::string descriptors_str; |
| 135 if (!base::ReadFileToString(descriptors_path, &descriptors_str)) | 135 if (!base::ReadFileToString(descriptors_path, &descriptors_str)) |
| 136 return; | 136 return; |
| 137 | 137 |
| 138 UsbDeviceDescriptor descriptor; | 138 UsbDeviceDescriptor descriptor; |
| 139 if (!descriptor.Parse(std::vector<uint8_t>(descriptors_str.begin(), | 139 if (!descriptor.Parse(std::vector<uint8_t>(descriptors_str.begin(), |
| 140 descriptors_str.end()))) { | 140 descriptors_str.end()))) { |
| 141 return; | 141 return; |
| 142 } | 142 } |
| 143 | 143 |
| 144 if (descriptor.device_class == kDeviceClassHub) { | 144 if (descriptor.device_class == kDeviceClassHub) { |
| 145 // Don't try to enumerate hubs. We never want to connect to a hub. | 145 // Don't try to enumerate hubs. We never want to connect to a hub. |
| 146 return; | 146 return; |
| 147 } | 147 } |
| 148 | 148 |
| 149 std::string manufacturer; | 149 std::string manufacturer; |
| 150 value = udev_device_get_sysattr_value(udev_device, "manufacturer"); | 150 value = udev_device_get_sysattr_value(device.get(), "manufacturer"); |
| 151 if (value) | 151 if (value) |
| 152 manufacturer = value; | 152 manufacturer = value; |
| 153 | 153 |
| 154 std::string product; | 154 std::string product; |
| 155 value = udev_device_get_sysattr_value(udev_device, "product"); | 155 value = udev_device_get_sysattr_value(device.get(), "product"); |
| 156 if (value) | 156 if (value) |
| 157 product = value; | 157 product = value; |
| 158 | 158 |
| 159 std::string serial_number; | 159 std::string serial_number; |
| 160 value = udev_device_get_sysattr_value(udev_device, "serial"); | 160 value = udev_device_get_sysattr_value(device.get(), "serial"); |
| 161 if (value) | 161 if (value) |
| 162 serial_number = value; | 162 serial_number = value; |
| 163 | 163 |
| 164 unsigned active_configuration = 0; | 164 unsigned active_configuration = 0; |
| 165 value = udev_device_get_sysattr_value(udev_device, "bConfigurationValue"); | 165 value = udev_device_get_sysattr_value(device.get(), "bConfigurationValue"); |
| 166 if (value) | 166 if (value) |
| 167 base::StringToUint(value, &active_configuration); | 167 base::StringToUint(value, &active_configuration); |
| 168 | 168 |
| 169 task_runner_->PostTask( | 169 task_runner_->PostTask( |
| 170 FROM_HERE, base::Bind(&UsbServiceLinux::OnDeviceAdded, service_, | 170 FROM_HERE, base::Bind(&UsbServiceLinux::OnDeviceAdded, service_, |
| 171 device_path, descriptor, manufacturer, product, | 171 device_path, descriptor, manufacturer, product, |
| 172 serial_number, active_configuration)); | 172 serial_number, active_configuration)); |
| 173 } | 173 } |
| 174 | 174 |
| 175 void UsbServiceLinux::FileThreadHelper::OnDeviceRemoved(udev_device* device) { | 175 void UsbServiceLinux::FileThreadHelper::OnDeviceRemoved( |
| 176 DCHECK(thread_checker_.CalledOnValidThread()); | 176 ScopedUdevDevicePtr device) { |
| 177 const char* device_path = udev_device_get_devnode(device); | 177 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 178 const char* device_path = udev_device_get_devnode(device.get()); |
| 178 if (device_path) { | 179 if (device_path) { |
| 179 task_runner_->PostTask( | 180 task_runner_->PostTask( |
| 180 FROM_HERE, base::Bind(&UsbServiceLinux::OnDeviceRemoved, service_, | 181 FROM_HERE, base::Bind(&UsbServiceLinux::OnDeviceRemoved, service_, |
| 181 std::string(device_path))); | 182 std::string(device_path))); |
| 182 } | 183 } |
| 183 } | 184 } |
| 184 | 185 |
| 185 UsbServiceLinux::UsbServiceLinux( | 186 UsbServiceLinux::UsbServiceLinux( |
| 186 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_in) | 187 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_in) |
| 187 : UsbService(std::move(blocking_task_runner_in)), weak_factory_(this) { | 188 : UsbService(std::move(blocking_task_runner_in)), weak_factory_(this) { |
| 188 helper_ = base::MakeUnique<FileThreadHelper>(weak_factory_.GetWeakPtr(), | 189 helper_ = base::MakeUnique<FileThreadHelper>(weak_factory_.GetWeakPtr()); |
| 189 task_runner()); | |
| 190 blocking_task_runner()->PostTask( | 190 blocking_task_runner()->PostTask( |
| 191 FROM_HERE, | 191 FROM_HERE, |
| 192 base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get()))); | 192 base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get()))); |
| 193 } | 193 } |
| 194 | 194 |
| 195 UsbServiceLinux::~UsbServiceLinux() { | 195 UsbServiceLinux::~UsbServiceLinux() { |
| 196 DCHECK(!helper_); | 196 DCHECK(!helper_); |
| 197 } | 197 } |
| 198 | 198 |
| 199 void UsbServiceLinux::Shutdown() { | 199 void UsbServiceLinux::Shutdown() { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 223 USB_LOG(ERROR) << "Got duplicate add event for path: " << device_path; | 223 USB_LOG(ERROR) << "Got duplicate add event for path: " << device_path; |
| 224 return; | 224 return; |
| 225 } | 225 } |
| 226 | 226 |
| 227 // Devices that appear during initial enumeration are gathered into the first | 227 // Devices that appear during initial enumeration are gathered into the first |
| 228 // result returned by GetDevices() and prevent device add/remove notifications | 228 // result returned by GetDevices() and prevent device add/remove notifications |
| 229 // from being sent. | 229 // from being sent. |
| 230 if (!enumeration_ready()) | 230 if (!enumeration_ready()) |
| 231 ++first_enumeration_countdown_; | 231 ++first_enumeration_countdown_; |
| 232 | 232 |
| 233 scoped_refptr<UsbDeviceLinux> device(new UsbDeviceLinux( | 233 scoped_refptr<UsbDeviceLinux> device( |
| 234 device_path, descriptor, manufacturer, product, serial_number, | 234 new UsbDeviceLinux(device_path, descriptor, manufacturer, product, |
| 235 active_configuration, blocking_task_runner())); | 235 serial_number, active_configuration)); |
| 236 devices_by_path_[device->device_path()] = device; | 236 devices_by_path_[device->device_path()] = device; |
| 237 if (device->usb_version() >= kUsbVersion2_1) { | 237 if (device->usb_version() >= kUsbVersion2_1) { |
| 238 device->Open(base::Bind(&OnDeviceOpenedToReadDescriptors, | 238 device->Open(base::Bind(&OnDeviceOpenedToReadDescriptors, |
| 239 base::Bind(&UsbServiceLinux::DeviceReady, | 239 base::Bind(&UsbServiceLinux::DeviceReady, |
| 240 weak_factory_.GetWeakPtr(), device))); | 240 weak_factory_.GetWeakPtr(), device))); |
| 241 } else { | 241 } else { |
| 242 DeviceReady(device, true /* success */); | 242 DeviceReady(device, true /* success */); |
| 243 } | 243 } |
| 244 } | 244 } |
| 245 | 245 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 result.reserve(devices().size()); | 315 result.reserve(devices().size()); |
| 316 for (const auto& map_entry : devices()) | 316 for (const auto& map_entry : devices()) |
| 317 result.push_back(map_entry.second); | 317 result.push_back(map_entry.second); |
| 318 for (const auto& callback : enumeration_callbacks_) | 318 for (const auto& callback : enumeration_callbacks_) |
| 319 callback.Run(result); | 319 callback.Run(result); |
| 320 enumeration_callbacks_.clear(); | 320 enumeration_callbacks_.clear(); |
| 321 } | 321 } |
| 322 } | 322 } |
| 323 | 323 |
| 324 } // namespace device | 324 } // namespace device |
| OLD | NEW |