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

Unified Diff: chrome/browser/usb/usb_service.cc

Issue 16316004: Separate usb device handle from usb device. (deprecate) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Windows compile and a bug. Created 7 years, 6 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/usb/usb_service.cc
diff --git a/chrome/browser/usb/usb_service.cc b/chrome/browser/usb/usb_service.cc
index 038786debf85048856500ce8f184578faade605f..61b4597bc9ef3053e5413e5d1ca2988ae4eafa38 100644
--- a/chrome/browser/usb/usb_service.cc
+++ b/chrome/browser/usb/usb_service.cc
@@ -4,13 +4,15 @@
#include "chrome/browser/usb/usb_service.h"
+#include <set>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/stl_util.h"
-#include "chrome/browser/usb/usb_device.h"
+#include "chrome/browser/usb/usb_device_handle.h"
+#include "content/public/browser/browser_thread.h"
#include "third_party/libusb/src/libusb/libusb.h"
#if defined(OS_CHROMEOS)
@@ -20,61 +22,137 @@
#endif // defined(OS_CHROMEOS)
using std::vector;
+using std::set;
+using content::BrowserThread;
-// The UsbEventHandler works around a design flaw in the libusb interface. There
-// is currently no way to signal to libusb that any caller into one of the event
+// The UsbEventDispatcher dispatches USB events on separate thread. There is
+// currently no way to signal to libusb that any caller into one of the event
// handler calls should return without handling any events.
-class UsbEventHandler : public base::PlatformThread::Delegate {
+class UsbEventDispatcher : public base::PlatformThread::Delegate {
public:
- explicit UsbEventHandler(PlatformUsbContext context)
- : running_(true), context_(context) {
- base::PlatformThread::CreateNonJoinable(0, this);
+ explicit UsbEventDispatcher(PlatformUsbContext context)
+ : running_(true), context_(context), thread_handle_(0) {
+ base::PlatformThread::Create(0, this, &thread_handle_);
}
- virtual ~UsbEventHandler() {}
+ virtual ~UsbEventDispatcher() {}
virtual void ThreadMain() OVERRIDE {
- base::PlatformThread::SetName("UsbEventHandler");
-
- DLOG(INFO) << "UsbEventHandler started.";
+ base::PlatformThread::SetName("UsbEventDispatcher");
+ struct timeval tv;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ DVLOG(1) << "UsbEventDispatcher started.";
while (running_) {
- libusb_handle_events(context_);
+ libusb_handle_events_timeout(context_, &tv);
}
- DLOG(INFO) << "UsbEventHandler shutting down.";
- libusb_exit(context_);
+ DVLOG(1) << "UsbEventDispatcher shutting down.";
delete this;
}
void Stop() {
running_ = false;
+ base::PlatformThread::Join(thread_handle_);
}
private:
bool running_;
PlatformUsbContext context_;
+ base::PlatformThreadHandle thread_handle_;
+ DISALLOW_COPY_AND_ASSIGN(UsbEventDispatcher);
+};
+
+// UsbDevice class uniquely represents a USB devices recognized by libusb and
+// maintains all its opened handles. It is assigned with an unique id by
+// UsbService. Once the device is disconnected it will invalidate all the
+// UsbDeviceHandle objects attached to it. The class is only visible to
+// UsbService and other classes need to access the device using its unique id.
+class UsbDevice : public base::RefCounted<UsbDevice> {
+ public:
+ explicit UsbDevice(PlatformUsbDevice device,
+ int unique_id);
+ PlatformUsbDevice device() const { return device_; }
+ int unique_id() const { return unique_id_; }
+
+ scoped_refptr<UsbDeviceHandle> OpenDevice(UsbService* service);
+ void CloseDeviceHandle(UsbDeviceHandle* device);
+
+ private:
+ virtual ~UsbDevice();
+ friend class base::RefCounted<UsbDevice>;
+ std::vector<scoped_refptr<UsbDeviceHandle> > handles_;
+ PlatformUsbDevice device_;
+ const int unique_id_;
- DISALLOW_EVIL_CONSTRUCTORS(UsbEventHandler);
+ DISALLOW_COPY_AND_ASSIGN(UsbDevice);
};
-UsbService::UsbService() {
+UsbDevice::UsbDevice(
+ PlatformUsbDevice device,
+ int unique_id) : device_(device), unique_id_(unique_id) {
+ libusb_ref_device(device_);
+}
+
+UsbDevice::~UsbDevice() {
+ libusb_unref_device(device_);
+
+ // Device is lost.
+ // Invalidates all the opened handle.
+ for (vector<scoped_refptr<UsbDeviceHandle> >::iterator it = handles_.begin();
+ it != handles_.end();
+ ++it) {
+ it->get()->InternalClose();
+ }
+ STLClearObject(&handles_);
+}
+
+scoped_refptr<UsbDeviceHandle>
+UsbDevice::OpenDevice(UsbService* service) {
+ PlatformUsbDeviceHandle handle;
+ if (0 == libusb_open(device_, &handle)) {
+ scoped_refptr<UsbDeviceHandle> wrapper =
+ make_scoped_refptr(new UsbDeviceHandle(service, unique_id_, handle));
+ handles_.push_back(wrapper);
+ return wrapper;
+ }
+ return scoped_refptr<UsbDeviceHandle>();
+}
+
+void UsbDevice::CloseDeviceHandle(UsbDeviceHandle* device) {
+ device->InternalClose();
+ for (vector<scoped_refptr<UsbDeviceHandle> >::iterator it = handles_.begin();
+ it != handles_.end();
+ ++it) {
+ if (it->get() == device) {
+ handles_.erase(it);
+ return;
+ }
+ }
+}
+
+UsbService::UsbService()
+ : next_unique_id_(1) {
libusb_init(&context_);
- event_handler_ = new UsbEventHandler(context_);
+ event_dispatcher_ = new UsbEventDispatcher(context_);
}
UsbService::~UsbService() {}
-void UsbService::Cleanup() {
- event_handler_->Stop();
- event_handler_ = NULL;
+void UsbService::Shutdown() {
+ event_dispatcher_->Stop();
+ devices_.clear();
+ libusb_exit(context_);
}
void UsbService::FindDevices(const uint16 vendor_id,
const uint16 product_id,
- int interface_id,
- vector<scoped_refptr<UsbDevice> >* devices,
+ const int interface_id,
+ vector<int>* devices,
const base::Callback<void()>& callback) {
- DCHECK(event_handler_) << "FindDevices called after event handler stopped.";
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(event_dispatcher_)
+ << "FindDevices called after event handler stopped.";
#if defined(OS_CHROMEOS)
// ChromeOS builds on non-ChromeOS machines (dev) should not attempt to
// use permission broker.
@@ -94,6 +172,7 @@ void UsbService::FindDevices(const uint16 vendor_id,
base::Unretained(this),
vendor_id,
product_id,
+ interface_id,
devices,
callback));
} else {
@@ -106,9 +185,10 @@ void UsbService::FindDevices(const uint16 vendor_id,
void UsbService::FindDevicesImpl(const uint16 vendor_id,
const uint16 product_id,
- vector<scoped_refptr<UsbDevice> >* devices,
+ vector<int>* devices,
const base::Callback<void()>& callback,
bool success) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::ScopedClosureRunner run_callback(callback);
devices->clear();
@@ -119,67 +199,84 @@ void UsbService::FindDevicesImpl(const uint16 vendor_id,
if (!success)
return;
- DeviceVector enumerated_devices;
- EnumerateDevices(&enumerated_devices);
- if (enumerated_devices.empty())
- return;
+ EnumerateDevices();
- for (unsigned int i = 0; i < enumerated_devices.size(); ++i) {
- PlatformUsbDevice device = enumerated_devices[i].device();
- if (DeviceMatches(device, vendor_id, product_id)) {
- UsbDevice* const wrapper = LookupOrCreateDevice(device);
- if (wrapper)
- devices->push_back(wrapper);
+ for (DeviceMap::iterator it = devices_.begin();
+ it != devices_.end(); ++it) {
+ if (DeviceMatches(it->first, vendor_id, product_id)) {
+ devices->push_back(it->second->unique_id());
}
}
}
-void UsbService::CloseDevice(scoped_refptr<UsbDevice> device) {
- DCHECK(event_handler_) << "CloseDevice called after event handler stopped.";
-
- PlatformUsbDevice platform_device = libusb_get_device(device->handle());
- if (!ContainsKey(devices_, platform_device)) {
- LOG(WARNING) << "CloseDevice called for device we're not tracking!";
- return;
+void UsbService::OpenDevice(
+ int device,
+ const base::Callback<void(scoped_refptr<UsbDeviceHandle>)>& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ EnumerateDevices();
+ for (DeviceMap::iterator it = devices_.begin();
+ it != devices_.end(); ++it) {
+ if (it->second->unique_id() == device) {
+ callback.Run(it->second->OpenDevice(this));
+ return;
+ }
}
-
- devices_.erase(platform_device);
- libusb_close(device->handle());
-}
-
-UsbService::RefCountedPlatformUsbDevice::RefCountedPlatformUsbDevice(
- PlatformUsbDevice device) : device_(device) {
- libusb_ref_device(device_);
-}
-
-UsbService::RefCountedPlatformUsbDevice::RefCountedPlatformUsbDevice(
- const RefCountedPlatformUsbDevice& other) : device_(other.device_) {
- libusb_ref_device(device_);
+ callback.Run(NULL);
}
-UsbService::RefCountedPlatformUsbDevice::~RefCountedPlatformUsbDevice() {
- libusb_unref_device(device_);
+void UsbService::CloseDeviceHandle(scoped_refptr<UsbDeviceHandle> device,
+ const base::Callback<void()>& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ int id = device->device();
+
+ for (DeviceMap::iterator it = devices_.begin();
+ it != devices_.end(); ++it) {
+ if (it->second->unique_id() == id) {
+ it->second->CloseDeviceHandle(device);
+ break;
+ }
+ }
+ callback.Run();
}
-PlatformUsbDevice UsbService::RefCountedPlatformUsbDevice::device() {
- return device_;
+void UsbService::ScheduleEnumerateDevice() {
+ // TODO(ikarienator): Throttle it.
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&UsbService::EnumerateDevices, base::Unretained(this)));
}
-void UsbService::EnumerateDevices(DeviceVector* output) {
- STLClearObject(output);
-
+void UsbService::EnumerateDevices() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
libusb_device** devices = NULL;
const ssize_t device_count = libusb_get_device_list(context_, &devices);
if (device_count < 0)
return;
+ set<int> connected_devices;
+ vector<PlatformUsbDevice> disconnected_devices;
+
+ // Populates new devices.
for (int i = 0; i < device_count; ++i) {
- libusb_device* device = devices[i];
- libusb_ref_device(device);
- output->push_back(RefCountedPlatformUsbDevice(device));
+ connected_devices.insert(LookupOrCreateDevice(devices[i]));
}
-
libusb_free_device_list(devices, true);
+
+ // Find disconnected devices.
+ for (DeviceMap::iterator it = devices_.begin();
+ it != devices_.end(); ++it) {
+ if (!ContainsKey(connected_devices, it->second->unique_id())) {
+ disconnected_devices.push_back(it->first);
+ }
+ }
+
+ // Remove disconnected devices from devices_.
+ for (size_t i = 0; i < disconnected_devices.size(); ++i) {
+ // This should delete those devices and invalidate their handles.
+ // It might take long.
+ devices_.erase(disconnected_devices[i]);
+ }
}
bool UsbService::DeviceMatches(PlatformUsbDevice device,
@@ -191,16 +288,11 @@ bool UsbService::DeviceMatches(PlatformUsbDevice device,
return descriptor.idVendor == vendor_id && descriptor.idProduct == product_id;
}
-UsbDevice* UsbService::LookupOrCreateDevice(PlatformUsbDevice device) {
+int UsbService::LookupOrCreateDevice(PlatformUsbDevice device) {
if (!ContainsKey(devices_, device)) {
- libusb_device_handle* handle = NULL;
- if (libusb_open(device, &handle)) {
- LOG(WARNING) << "Could not open device.";
- return NULL;
- }
-
- UsbDevice* wrapper = new UsbDevice(this, handle);
- devices_[device] = wrapper;
+ devices_[device] =
+ make_scoped_refptr(new UsbDevice(device, next_unique_id_));
+ ++next_unique_id_;
}
- return devices_[device].get();
+ return devices_[device]->unique_id();
}

Powered by Google App Engine
This is Rietveld 408576698