Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / usb / usb_service.cc
blob221ccbbb2a81947c8c4bd4998a9689afbce2d04e
1 // Copyright (c) 2012 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 "chrome/browser/usb/usb_service.h"
7 #include <set>
8 #include <vector>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/stl_util.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/usb/usb_context.h"
18 #include "chrome/browser/usb/usb_device.h"
19 #include "chrome/browser/usb/usb_device_handle.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/notification_observer.h"
22 #include "content/public/browser/notification_registrar.h"
23 #include "content/public/browser/notification_service.h"
24 #include "third_party/libusb/src/libusb/libusb.h"
26 namespace content {
28 class NotificationDetails;
29 class NotificationSource;
31 } // namespace content
33 using content::BrowserThread;
34 using std::vector;
36 namespace {
38 // This is the one and only instance of UsbService. The reason not to use
39 // Singleton is: 1. Singleton focuses on solving race conditions and at-exit
40 // deletion, none of them are needed here, and 2. Singleton does not provide
41 // a way to clear the pointer after the instance being destroyed.
42 UsbService* g_usb_service_instance = NULL;
43 bool g_usb_service_instance_destroyed = false;
45 class ExitObserver : public content::NotificationObserver {
46 public:
47 ExitObserver() {
48 BrowserThread::PostTask(
49 BrowserThread::UI, FROM_HERE,
50 base::Bind(&content::NotificationRegistrar::Add,
51 base::Unretained(&registrar_), this,
52 chrome::NOTIFICATION_APP_TERMINATING,
53 content::NotificationService::AllSources()));
56 private:
57 // content::NotificationObserver
58 virtual void Observe(int type,
59 const content::NotificationSource& source,
60 const content::NotificationDetails& details) OVERRIDE {
61 if (type == chrome::NOTIFICATION_APP_TERMINATING) {
62 BrowserThread::DeleteSoon(BrowserThread::FILE,
63 FROM_HERE,
64 g_usb_service_instance);
65 delete this;
68 content::NotificationRegistrar registrar_;
71 } // namespace
73 UsbService::UsbService(PlatformUsbContext context)
74 : context_(new UsbContext(context)),
75 next_unique_id_(0) {
76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
79 UsbService::~UsbService() {
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
82 // Prevents creating a new UsbService.
83 g_usb_service_instance_destroyed = true;
84 g_usb_service_instance = NULL;
86 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
87 it->second->OnDisconnect();
91 UsbService* UsbService::GetInstance() {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
93 if (g_usb_service_instance_destroyed)
94 return NULL;
96 if (!g_usb_service_instance) {
97 PlatformUsbContext context = NULL;
98 if (libusb_init(&context) != LIBUSB_SUCCESS)
99 return NULL;
100 if (!context)
101 return NULL;
103 g_usb_service_instance = new UsbService(context);
105 // Will be deleted upon NOTIFICATION_APP_TERMINATING.
106 new ExitObserver();
109 return g_usb_service_instance;
112 void UsbService::GetDevices(std::vector<scoped_refptr<UsbDevice> >* devices) {
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
114 STLClearObject(devices);
115 RefreshDevices();
117 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
118 devices->push_back(it->second);
122 scoped_refptr<UsbDevice> UsbService::GetDeviceById(uint32 unique_id) {
123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
124 RefreshDevices();
126 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
127 if (it->second->unique_id() == unique_id) return it->second;
129 return NULL;
132 void UsbService::RefreshDevices() {
133 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
135 libusb_device** platform_devices = NULL;
136 const ssize_t device_count =
137 libusb_get_device_list(context_->context(), &platform_devices);
139 std::set<UsbDevice*> connected_devices;
140 vector<PlatformUsbDevice> disconnected_devices;
142 // Populates new devices.
143 for (ssize_t i = 0; i < device_count; ++i) {
144 if (!ContainsKey(devices_, platform_devices[i])) {
145 libusb_device_descriptor descriptor;
146 // This test is needed. A valid vendor/produce pair is required.
147 if (0 != libusb_get_device_descriptor(platform_devices[i], &descriptor))
148 continue;
149 UsbDevice* new_device = new UsbDevice(context_,
150 platform_devices[i],
151 descriptor.idVendor,
152 descriptor.idProduct,
153 ++next_unique_id_);
154 devices_[platform_devices[i]] = new_device;
155 connected_devices.insert(new_device);
156 } else {
157 connected_devices.insert(devices_[platform_devices[i]].get());
161 // Find disconnected devices.
162 for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
163 if (!ContainsKey(connected_devices, it->second)) {
164 disconnected_devices.push_back(it->first);
168 // Remove disconnected devices from devices_.
169 for (size_t i = 0; i < disconnected_devices.size(); ++i) {
170 // UsbDevice will be destroyed after this. The corresponding
171 // PlatformUsbDevice will be unref'ed during this process.
172 devices_.erase(disconnected_devices[i]);
175 libusb_free_device_list(platform_devices, true);