Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(471)

Side by Side Diff: components/usb_service/usb_service_impl.cc

Issue 497363004: Merge components/usb_service into device/usb. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/usb_service/usb_service_export.h ('k') | device/core/device_client.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "components/usb_service/usb_service.h"
6
7 #include <map>
8 #include <set>
9
10 #include "base/lazy_instance.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/stl_util.h"
14 #include "components/usb_service/usb_context.h"
15 #include "components/usb_service/usb_device_impl.h"
16 #include "components/usb_service/usb_error.h"
17 #include "third_party/libusb/src/libusb/libusb.h"
18
19 namespace usb_service {
20
21 namespace {
22
23 base::LazyInstance<scoped_ptr<UsbService> >::Leaky g_usb_service_instance =
24 LAZY_INSTANCE_INITIALIZER;
25
26 } // namespace
27
28 typedef struct libusb_device* PlatformUsbDevice;
29 typedef struct libusb_context* PlatformUsbContext;
30
31 class UsbServiceImpl
32 : public UsbService,
33 private base::MessageLoop::DestructionObserver {
34 public:
35 explicit UsbServiceImpl(
36 PlatformUsbContext context,
37 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
38 virtual ~UsbServiceImpl();
39
40 private:
41 // usb_service::UsbService implementation
42 virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE;
43 virtual void GetDevices(
44 std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE;
45
46 // base::MessageLoop::DestructionObserver implementation.
47 virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
48
49 // Enumerate USB devices from OS and Update devices_ map.
50 void RefreshDevices();
51
52 scoped_refptr<UsbContext> context_;
53 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
54 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
55
56 // TODO(ikarienator): Figure out a better solution.
57 uint32 next_unique_id_;
58
59 // The map from PlatformUsbDevices to UsbDevices.
60 typedef std::map<PlatformUsbDevice, scoped_refptr<UsbDeviceImpl> > DeviceMap;
61 DeviceMap devices_;
62
63 DISALLOW_COPY_AND_ASSIGN(UsbServiceImpl);
64 };
65
66 scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) {
67 DCHECK(CalledOnValidThread());
68 RefreshDevices();
69 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
70 if (it->second->unique_id() == unique_id)
71 return it->second;
72 }
73 return NULL;
74 }
75
76 void UsbServiceImpl::GetDevices(
77 std::vector<scoped_refptr<UsbDevice> >* devices) {
78 DCHECK(CalledOnValidThread());
79 STLClearObject(devices);
80 RefreshDevices();
81
82 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
83 devices->push_back(it->second);
84 }
85 }
86
87 void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
88 DCHECK(CalledOnValidThread());
89 g_usb_service_instance.Get().reset(NULL);
90 }
91
92 UsbServiceImpl::UsbServiceImpl(
93 PlatformUsbContext context,
94 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
95 : context_(new UsbContext(context)),
96 ui_task_runner_(ui_task_runner),
97 next_unique_id_(0) {
98 base::MessageLoop::current()->AddDestructionObserver(this);
99 }
100
101 UsbServiceImpl::~UsbServiceImpl() {
102 base::MessageLoop::current()->RemoveDestructionObserver(this);
103 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
104 it->second->OnDisconnect();
105 }
106 }
107
108 void UsbServiceImpl::RefreshDevices() {
109 DCHECK(CalledOnValidThread());
110
111 libusb_device** platform_devices = NULL;
112 const ssize_t device_count =
113 libusb_get_device_list(context_->context(), &platform_devices);
114 if (device_count < 0) {
115 VLOG(1) << "Failed to get device list: "
116 << ConvertErrorToString(device_count);
117 }
118
119 std::set<UsbDevice*> connected_devices;
120 std::vector<PlatformUsbDevice> disconnected_devices;
121
122 // Populates new devices.
123 for (ssize_t i = 0; i < device_count; ++i) {
124 if (!ContainsKey(devices_, platform_devices[i])) {
125 libusb_device_descriptor descriptor;
126 const int rv =
127 libusb_get_device_descriptor(platform_devices[i], &descriptor);
128 // This test is needed. A valid vendor/produce pair is required.
129 if (rv != LIBUSB_SUCCESS) {
130 VLOG(1) << "Failed to get device descriptor: "
131 << ConvertErrorToString(rv);
132 continue;
133 }
134 UsbDeviceImpl* new_device = new UsbDeviceImpl(context_,
135 ui_task_runner_,
136 platform_devices[i],
137 descriptor.idVendor,
138 descriptor.idProduct,
139 ++next_unique_id_);
140 devices_[platform_devices[i]] = new_device;
141 connected_devices.insert(new_device);
142 } else {
143 connected_devices.insert(devices_[platform_devices[i]].get());
144 }
145 }
146
147 // Find disconnected devices.
148 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
149 if (!ContainsKey(connected_devices, it->second)) {
150 disconnected_devices.push_back(it->first);
151 }
152 }
153
154 // Remove disconnected devices from devices_.
155 for (size_t i = 0; i < disconnected_devices.size(); ++i) {
156 // UsbDevice will be destroyed after this. The corresponding
157 // PlatformUsbDevice will be unref'ed during this process.
158 devices_.erase(disconnected_devices[i]);
159 }
160
161 libusb_free_device_list(platform_devices, true);
162 }
163
164 // static
165 UsbService* UsbService::GetInstance(
166 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
167 UsbService* instance = g_usb_service_instance.Get().get();
168 if (!instance) {
169 PlatformUsbContext context = NULL;
170
171 const int rv = libusb_init(&context);
172 if (rv != LIBUSB_SUCCESS) {
173 VLOG(1) << "Failed to initialize libusb: " << ConvertErrorToString(rv);
174 return NULL;
175 }
176 if (!context)
177 return NULL;
178
179 instance = new UsbServiceImpl(context, ui_task_runner);
180 g_usb_service_instance.Get().reset(instance);
181 }
182 return instance;
183 }
184
185 // static
186 void UsbService::SetInstanceForTest(UsbService* instance) {
187 g_usb_service_instance.Get().reset(instance);
188 }
189
190 } // namespace usb_service
OLDNEW
« no previous file with comments | « components/usb_service/usb_service_export.h ('k') | device/core/device_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698