| 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.h" | 
| 6 | 6 | 
| 7 #include <map> | 7 #include <map> | 
| 8 #include <set> | 8 #include <set> | 
| 9 | 9 | 
|  | 10 #include "base/bind.h" | 
| 10 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" | 
| 11 #include "base/message_loop/message_loop.h" | 12 #include "base/message_loop/message_loop.h" | 
| 12 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" | 
| 13 #include "base/stl_util.h" | 14 #include "base/stl_util.h" | 
|  | 15 #include "base/thread_task_runner_handle.h" | 
| 14 #include "device/usb/usb_context.h" | 16 #include "device/usb/usb_context.h" | 
| 15 #include "device/usb/usb_device_impl.h" | 17 #include "device/usb/usb_device_impl.h" | 
| 16 #include "device/usb/usb_error.h" | 18 #include "device/usb/usb_error.h" | 
| 17 #include "third_party/libusb/src/libusb/libusb.h" | 19 #include "third_party/libusb/src/libusb/libusb.h" | 
| 18 | 20 | 
| 19 namespace device { | 21 namespace device { | 
| 20 | 22 | 
| 21 namespace { | 23 namespace { | 
| 22 | 24 | 
| 23 base::LazyInstance<scoped_ptr<UsbService> >::Leaky g_usb_service_instance = | 25 base::LazyInstance<scoped_ptr<UsbService> >::Leaky g_usb_service_instance = | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
| 40   // device::UsbService implementation | 42   // device::UsbService implementation | 
| 41   scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override; | 43   scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override; | 
| 42   void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override; | 44   void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override; | 
| 43 | 45 | 
| 44   // base::MessageLoop::DestructionObserver implementation. | 46   // base::MessageLoop::DestructionObserver implementation. | 
| 45   void WillDestroyCurrentMessageLoop() override; | 47   void WillDestroyCurrentMessageLoop() override; | 
| 46 | 48 | 
| 47   // Enumerate USB devices from OS and update devices_ map. | 49   // Enumerate USB devices from OS and update devices_ map. | 
| 48   void RefreshDevices(); | 50   void RefreshDevices(); | 
| 49 | 51 | 
|  | 52   // Adds a new UsbDevice to the devices_ map based on the given libusb device. | 
|  | 53   scoped_refptr<UsbDeviceImpl> AddDevice(PlatformUsbDevice platform_device); | 
|  | 54 | 
|  | 55   // Handle hotplug events from libusb. | 
|  | 56   static int LIBUSB_CALL HotplugCallback(libusb_context* context, | 
|  | 57                                          PlatformUsbDevice device, | 
|  | 58                                          libusb_hotplug_event event, | 
|  | 59                                          void* user_data); | 
|  | 60   // These functions release a reference to the provided platform device. | 
|  | 61   void OnDeviceAdded(PlatformUsbDevice platform_device); | 
|  | 62   void OnDeviceRemoved(PlatformUsbDevice platform_device); | 
|  | 63 | 
| 50   scoped_refptr<UsbContext> context_; | 64   scoped_refptr<UsbContext> context_; | 
| 51   scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 65   scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 
| 52   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; | 66   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; | 
| 53 | 67 | 
| 54   // TODO(reillyg): Figure out a better solution. | 68   // TODO(reillyg): Figure out a better solution for device IDs. | 
| 55   uint32 next_unique_id_; | 69   uint32 next_unique_id_; | 
| 56 | 70 | 
|  | 71   // When available the device list will be updated when new devices are | 
|  | 72   // connected instead of only when a full enumeration is requested. | 
|  | 73   // TODO(reillyg): Support this on all platforms. crbug.com/411715 | 
|  | 74   bool hotplug_enabled_; | 
|  | 75   libusb_hotplug_callback_handle hotplug_handle_; | 
|  | 76 | 
| 57   // The map from unique IDs to UsbDevices. | 77   // The map from unique IDs to UsbDevices. | 
| 58   typedef std::map<uint32, scoped_refptr<UsbDeviceImpl> > DeviceMap; | 78   typedef std::map<uint32, scoped_refptr<UsbDeviceImpl> > DeviceMap; | 
| 59   DeviceMap devices_; | 79   DeviceMap devices_; | 
| 60 | 80 | 
| 61   // The map from PlatformUsbDevices to UsbDevices. | 81   // The map from PlatformUsbDevices to UsbDevices. | 
| 62   typedef std::map<PlatformUsbDevice, scoped_refptr<UsbDeviceImpl> > | 82   typedef std::map<PlatformUsbDevice, scoped_refptr<UsbDeviceImpl> > | 
| 63       PlatformDeviceMap; | 83       PlatformDeviceMap; | 
| 64   PlatformDeviceMap platform_devices_; | 84   PlatformDeviceMap platform_devices_; | 
| 65 | 85 | 
| 66   DISALLOW_COPY_AND_ASSIGN(UsbServiceImpl); | 86   DISALLOW_COPY_AND_ASSIGN(UsbServiceImpl); | 
| 67 }; | 87 }; | 
| 68 | 88 | 
| 69 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) { | 89 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) { | 
| 70   DCHECK(CalledOnValidThread()); | 90   DCHECK(CalledOnValidThread()); | 
| 71   RefreshDevices(); | 91   RefreshDevices(); | 
| 72   DeviceMap::iterator it = devices_.find(unique_id); | 92   DeviceMap::iterator it = devices_.find(unique_id); | 
| 73   if (it != devices_.end()) { | 93   if (it != devices_.end()) { | 
| 74     return it->second; | 94     return it->second; | 
| 75   } | 95   } | 
| 76   return NULL; | 96   return NULL; | 
| 77 } | 97 } | 
| 78 | 98 | 
| 79 void UsbServiceImpl::GetDevices( | 99 void UsbServiceImpl::GetDevices( | 
| 80     std::vector<scoped_refptr<UsbDevice> >* devices) { | 100     std::vector<scoped_refptr<UsbDevice> >* devices) { | 
| 81   DCHECK(CalledOnValidThread()); | 101   DCHECK(CalledOnValidThread()); | 
| 82   STLClearObject(devices); | 102   STLClearObject(devices); | 
| 83   RefreshDevices(); |  | 
| 84 | 103 | 
| 85   for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) { | 104   if (!hotplug_enabled_) { | 
| 86     devices->push_back(it->second); | 105     RefreshDevices(); | 
|  | 106   } | 
|  | 107 | 
|  | 108   for (const auto& map_entry : devices_) { | 
|  | 109     devices->push_back(map_entry.second); | 
| 87   } | 110   } | 
| 88 } | 111 } | 
| 89 | 112 | 
| 90 void UsbServiceImpl::WillDestroyCurrentMessageLoop() { | 113 void UsbServiceImpl::WillDestroyCurrentMessageLoop() { | 
| 91   DCHECK(CalledOnValidThread()); | 114   DCHECK(CalledOnValidThread()); | 
| 92   g_usb_service_instance.Get().reset(NULL); | 115   g_usb_service_instance.Get().reset(NULL); | 
| 93 } | 116 } | 
| 94 | 117 | 
| 95 UsbServiceImpl::UsbServiceImpl( | 118 UsbServiceImpl::UsbServiceImpl( | 
| 96     PlatformUsbContext context, | 119     PlatformUsbContext context, | 
| 97     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | 120     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | 
| 98     : context_(new UsbContext(context)), | 121     : context_(new UsbContext(context)), | 
| 99       ui_task_runner_(ui_task_runner), | 122       ui_task_runner_(ui_task_runner), | 
| 100       next_unique_id_(0) { | 123       next_unique_id_(0), | 
|  | 124       hotplug_enabled_(false) { | 
| 101   base::MessageLoop::current()->AddDestructionObserver(this); | 125   base::MessageLoop::current()->AddDestructionObserver(this); | 
|  | 126   task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 
|  | 127   int rv = libusb_hotplug_register_callback( | 
|  | 128       context_->context(), | 
|  | 129       static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | | 
|  | 130                                         LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), | 
|  | 131       LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, | 
|  | 132       LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, | 
|  | 133       &UsbServiceImpl::HotplugCallback, this, &hotplug_handle_); | 
|  | 134   if (rv == LIBUSB_SUCCESS) { | 
|  | 135     hotplug_enabled_ = true; | 
|  | 136   } | 
| 102 } | 137 } | 
| 103 | 138 | 
| 104 UsbServiceImpl::~UsbServiceImpl() { | 139 UsbServiceImpl::~UsbServiceImpl() { | 
| 105   base::MessageLoop::current()->RemoveDestructionObserver(this); | 140   base::MessageLoop::current()->RemoveDestructionObserver(this); | 
| 106   for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) { | 141   if (hotplug_enabled_) { | 
| 107     it->second->OnDisconnect(); | 142     libusb_hotplug_deregister_callback(context_->context(), hotplug_handle_); | 
|  | 143   } | 
|  | 144   for (const auto& map_entry : devices_) { | 
|  | 145     map_entry.second->OnDisconnect(); | 
| 108   } | 146   } | 
| 109 } | 147 } | 
| 110 | 148 | 
| 111 void UsbServiceImpl::RefreshDevices() { | 149 void UsbServiceImpl::RefreshDevices() { | 
| 112   DCHECK(CalledOnValidThread()); | 150   DCHECK(CalledOnValidThread()); | 
| 113 | 151 | 
| 114   libusb_device** platform_devices = NULL; | 152   libusb_device** platform_devices = NULL; | 
| 115   const ssize_t device_count = | 153   const ssize_t device_count = | 
| 116       libusb_get_device_list(context_->context(), &platform_devices); | 154       libusb_get_device_list(context_->context(), &platform_devices); | 
| 117   if (device_count < 0) { | 155   if (device_count < 0) { | 
| 118     VLOG(1) << "Failed to get device list: " | 156     VLOG(1) << "Failed to get device list: " | 
| 119             << ConvertPlatformUsbErrorToString(device_count); | 157             << ConvertPlatformUsbErrorToString(device_count); | 
| 120   } | 158   } | 
| 121 | 159 | 
| 122   std::set<UsbDevice*> connected_devices; | 160   std::set<UsbDevice*> connected_devices; | 
| 123   std::vector<PlatformUsbDevice> disconnected_devices; | 161   std::vector<PlatformUsbDevice> disconnected_devices; | 
| 124 | 162 | 
| 125   // Populates new devices. | 163   // Populates new devices. | 
| 126   for (ssize_t i = 0; i < device_count; ++i) { | 164   for (ssize_t i = 0; i < device_count; ++i) { | 
| 127     if (!ContainsKey(platform_devices_, platform_devices[i])) { | 165     if (!ContainsKey(platform_devices_, platform_devices[i])) { | 
| 128       libusb_device_descriptor descriptor; | 166       scoped_refptr<UsbDeviceImpl> new_device = AddDevice(platform_devices[i]); | 
| 129       const int rv = | 167       if (new_device) { | 
| 130           libusb_get_device_descriptor(platform_devices[i], &descriptor); | 168         connected_devices.insert(new_device.get()); | 
| 131       // This test is needed. A valid vendor/produce pair is required. |  | 
| 132       if (rv != LIBUSB_SUCCESS) { |  | 
| 133         VLOG(1) << "Failed to get device descriptor: " |  | 
| 134                 << ConvertPlatformUsbErrorToString(rv); |  | 
| 135         continue; |  | 
| 136       } | 169       } | 
| 137 |  | 
| 138       uint32 unique_id; |  | 
| 139       do { |  | 
| 140         unique_id = ++next_unique_id_; |  | 
| 141       } while (devices_.find(unique_id) != devices_.end()); |  | 
| 142 |  | 
| 143       scoped_refptr<UsbDeviceImpl> new_device( |  | 
| 144           new UsbDeviceImpl(context_, |  | 
| 145                             ui_task_runner_, |  | 
| 146                             platform_devices[i], |  | 
| 147                             descriptor.idVendor, |  | 
| 148                             descriptor.idProduct, |  | 
| 149                             unique_id)); |  | 
| 150       platform_devices_[platform_devices[i]] = new_device; |  | 
| 151       devices_[unique_id] = new_device; |  | 
| 152       connected_devices.insert(new_device.get()); |  | 
| 153     } else { | 170     } else { | 
| 154       connected_devices.insert(platform_devices_[platform_devices[i]].get()); | 171       connected_devices.insert(platform_devices_[platform_devices[i]].get()); | 
| 155     } | 172     } | 
| 156   } | 173   } | 
| 157 | 174 | 
| 158   // Find disconnected devices. | 175   // Find disconnected devices. | 
| 159   for (PlatformDeviceMap::iterator it = platform_devices_.begin(); | 176   for (PlatformDeviceMap::iterator it = platform_devices_.begin(); | 
| 160        it != platform_devices_.end(); | 177        it != platform_devices_.end(); | 
| 161        ++it) { | 178        ++it) { | 
| 162     if (!ContainsKey(connected_devices, it->second.get())) { | 179     if (!ContainsKey(connected_devices, it->second.get())) { | 
| 163       disconnected_devices.push_back(it->first); | 180       disconnected_devices.push_back(it->first); | 
| 164       devices_.erase(it->second->unique_id()); | 181       devices_.erase(it->second->unique_id()); | 
| 165       it->second->OnDisconnect(); | 182       it->second->OnDisconnect(); | 
| 166     } | 183     } | 
| 167   } | 184   } | 
| 168 | 185 | 
| 169   // Remove disconnected devices from platform_devices_. | 186   // Remove disconnected devices from platform_devices_. | 
| 170   for (size_t i = 0; i < disconnected_devices.size(); ++i) { | 187   for (size_t i = 0; i < disconnected_devices.size(); ++i) { | 
| 171     // UsbDevice will be destroyed after this. The corresponding | 188     // UsbDevice will be destroyed after this. The corresponding | 
| 172     // PlatformUsbDevice will be unref'ed during this process. | 189     // PlatformUsbDevice will be unref'ed during this process. | 
| 173     platform_devices_.erase(disconnected_devices[i]); | 190     platform_devices_.erase(disconnected_devices[i]); | 
| 174   } | 191   } | 
| 175 | 192 | 
| 176   libusb_free_device_list(platform_devices, true); | 193   libusb_free_device_list(platform_devices, true); | 
| 177 } | 194 } | 
| 178 | 195 | 
|  | 196 scoped_refptr<UsbDeviceImpl> UsbServiceImpl::AddDevice( | 
|  | 197     PlatformUsbDevice platform_device) { | 
|  | 198   libusb_device_descriptor descriptor; | 
|  | 199   int rv = libusb_get_device_descriptor(platform_device, &descriptor); | 
|  | 200   if (rv == LIBUSB_SUCCESS) { | 
|  | 201     uint32 unique_id; | 
|  | 202     do { | 
|  | 203       unique_id = ++next_unique_id_; | 
|  | 204     } while (devices_.find(unique_id) != devices_.end()); | 
|  | 205 | 
|  | 206     scoped_refptr<UsbDeviceImpl> new_device(new UsbDeviceImpl( | 
|  | 207         context_, ui_task_runner_, platform_device, descriptor.idVendor, | 
|  | 208         descriptor.idProduct, unique_id)); | 
|  | 209     platform_devices_[platform_device] = new_device; | 
|  | 210     devices_[unique_id] = new_device; | 
|  | 211     return new_device; | 
|  | 212   } else { | 
|  | 213     VLOG(1) << "Failed to get device descriptor: " | 
|  | 214             << ConvertPlatformUsbErrorToString(rv); | 
|  | 215     return nullptr; | 
|  | 216   } | 
|  | 217 } | 
|  | 218 | 
|  | 219 // static | 
|  | 220 int LIBUSB_CALL UsbServiceImpl::HotplugCallback(libusb_context* context, | 
|  | 221                                                 PlatformUsbDevice device, | 
|  | 222                                                 libusb_hotplug_event event, | 
|  | 223                                                 void* user_data) { | 
|  | 224   // It is safe to access the UsbServiceImpl* here because libusb takes a lock | 
|  | 225   // around registering, deregistering and calling hotplug callback functions | 
|  | 226   // and so guarantees that this function will not be called by the event | 
|  | 227   // processing thread after it has been deregistered. | 
|  | 228   UsbServiceImpl* self = reinterpret_cast<UsbServiceImpl*>(user_data); | 
|  | 229   switch (event) { | 
|  | 230     case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: | 
|  | 231       libusb_ref_device(device);  // Released in OnDeviceAdded. | 
|  | 232       if (self->task_runner_->BelongsToCurrentThread()) { | 
|  | 233         self->OnDeviceAdded(device); | 
|  | 234       } else { | 
|  | 235         self->task_runner_->PostTask( | 
|  | 236             FROM_HERE, base::Bind(&UsbServiceImpl::OnDeviceAdded, | 
|  | 237                                   base::Unretained(self), device)); | 
|  | 238       } | 
|  | 239       break; | 
|  | 240     case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: | 
|  | 241       libusb_ref_device(device);  // Released in OnDeviceRemoved. | 
|  | 242       if (self->task_runner_->BelongsToCurrentThread()) { | 
|  | 243         self->OnDeviceRemoved(device); | 
|  | 244       } else { | 
|  | 245         self->task_runner_->PostTask( | 
|  | 246             FROM_HERE, base::Bind(&UsbServiceImpl::OnDeviceRemoved, | 
|  | 247                                   base::Unretained(self), device)); | 
|  | 248       } | 
|  | 249       break; | 
|  | 250     default: | 
|  | 251       NOTREACHED(); | 
|  | 252   } | 
|  | 253 | 
|  | 254   return 0; | 
|  | 255 } | 
|  | 256 | 
|  | 257 void UsbServiceImpl::OnDeviceAdded(PlatformUsbDevice platform_device) { | 
|  | 258   DCHECK(CalledOnValidThread()); | 
|  | 259   DCHECK(!ContainsKey(platform_devices_, platform_device)); | 
|  | 260 | 
|  | 261   AddDevice(platform_device); | 
|  | 262   libusb_unref_device(platform_device); | 
|  | 263 } | 
|  | 264 | 
|  | 265 void UsbServiceImpl::OnDeviceRemoved(PlatformUsbDevice platform_device) { | 
|  | 266   DCHECK(CalledOnValidThread()); | 
|  | 267 | 
|  | 268   PlatformDeviceMap::iterator it = platform_devices_.find(platform_device); | 
|  | 269   if (it != platform_devices_.end()) { | 
|  | 270     scoped_refptr<UsbDeviceImpl> device = it->second; | 
|  | 271     DeviceMap::iterator dev_it = devices_.find(device->unique_id()); | 
|  | 272     if (dev_it != devices_.end()) { | 
|  | 273       devices_.erase(dev_it); | 
|  | 274     } else { | 
|  | 275       NOTREACHED(); | 
|  | 276     } | 
|  | 277     device->OnDisconnect(); | 
|  | 278     platform_devices_.erase(it); | 
|  | 279   } else { | 
|  | 280     NOTREACHED(); | 
|  | 281   } | 
|  | 282 | 
|  | 283   libusb_unref_device(platform_device); | 
|  | 284 } | 
|  | 285 | 
| 179 // static | 286 // static | 
| 180 UsbService* UsbService::GetInstance( | 287 UsbService* UsbService::GetInstance( | 
| 181     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 288     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 
| 182   UsbService* instance = g_usb_service_instance.Get().get(); | 289   UsbService* instance = g_usb_service_instance.Get().get(); | 
| 183   if (!instance) { | 290   if (!instance) { | 
| 184     PlatformUsbContext context = NULL; | 291     PlatformUsbContext context = NULL; | 
| 185 | 292 | 
| 186     const int rv = libusb_init(&context); | 293     const int rv = libusb_init(&context); | 
| 187     if (rv != LIBUSB_SUCCESS) { | 294     if (rv != LIBUSB_SUCCESS) { | 
| 188       VLOG(1) << "Failed to initialize libusb: " | 295       VLOG(1) << "Failed to initialize libusb: " | 
| 189               << ConvertPlatformUsbErrorToString(rv); | 296               << ConvertPlatformUsbErrorToString(rv); | 
| 190       return NULL; | 297       return NULL; | 
| 191     } | 298     } | 
| 192     if (!context) | 299     if (!context) | 
| 193       return NULL; | 300       return NULL; | 
| 194 | 301 | 
| 195     instance = new UsbServiceImpl(context, ui_task_runner); | 302     instance = new UsbServiceImpl(context, ui_task_runner); | 
| 196     g_usb_service_instance.Get().reset(instance); | 303     g_usb_service_instance.Get().reset(instance); | 
| 197   } | 304   } | 
| 198   return instance; | 305   return instance; | 
| 199 } | 306 } | 
| 200 | 307 | 
| 201 // static | 308 // static | 
| 202 void UsbService::SetInstanceForTest(UsbService* instance) { | 309 void UsbService::SetInstanceForTest(UsbService* instance) { | 
| 203   g_usb_service_instance.Get().reset(instance); | 310   g_usb_service_instance.Get().reset(instance); | 
| 204 } | 311 } | 
| 205 | 312 | 
| 206 }  // namespace device | 313 }  // namespace device | 
| OLD | NEW | 
|---|