Commit 89b276fb authored by reillyg's avatar reillyg Committed by Commit bot

Add a service to track devices selected by the user.

apps::SavedDevicesService tracks USB devices that have been selected by
the user in the context of a given extension. Devices that can be
identified accurately after they have been reconnected because they have
a serial number are written out to ExtensionPrefs. All others are only
remembered until they are disconnected.

A new OnDisconnect observer function has been added to UsbDevice to
enable this monitoring.

BUG=346953

Review URL: https://codereview.chromium.org/580963002

Cr-Commit-Position: refs/heads/master@{#295708}
parent bfae6356
......@@ -26,6 +26,10 @@ static_library("apps") {
"launcher.cc",
"launcher.h",
"metrics_names.h",
"saved_devices_service.cc",
"saved_devices_service.h",
"saved_devices_service_factory.cc",
"saved_devices_service_factory.h",
"saved_files_service.cc",
"saved_files_service.h",
"saved_files_service_factory.cc",
......@@ -41,6 +45,7 @@ static_library("apps") {
"//chrome/browser/extensions",
"//chrome/common/extensions/api:api",
"//components/web_modal",
"//device/usb",
"//skia",
]
......
......@@ -9,6 +9,7 @@ include_rules = [
"+components/sessions",
"+components/user_manager",
"+components/web_modal",
"+device/usb",
"+extensions",
"+net/base",
"+skia/ext",
......
......@@ -45,6 +45,10 @@
'launcher.cc',
'launcher.h',
'metrics_names.h',
'saved_devices_service.cc',
'saved_devices_service.h',
'saved_devices_service_factory.cc',
'saved_devices_service_factory.h',
'saved_files_service.cc',
'saved_files_service.h',
'saved_files_service_factory.cc',
......
This diff is collapsed.
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef APPS_SAVED_DEVICES_SERVICE_H_
#define APPS_SAVED_DEVICES_SERVICE_H_
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/threading/thread_checker.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "device/usb/usb_device.h"
class Profile;
namespace base {
class Value;
}
namespace extensions {
class Extension;
}
namespace apps {
// Represents a device that a user has given an app permission to access. It
// will be persisted to disk (in the Preferences file) and so should remain
// serializable.
struct SavedDeviceEntry {
SavedDeviceEntry(uint16_t vendor_id,
uint16_t product_id,
const base::string16& serial_number);
base::Value* ToValue() const;
// The vendor ID of this device.
uint16_t vendor_id;
// The product ID of this device.
uint16_t product_id;
// The serial number (possibly alphanumeric) of this device.
base::string16 serial_number;
};
// Tracks the devices that apps have retained access to both while running and
// when suspended.
class SavedDevicesService : public KeyedService,
public content::NotificationObserver {
public:
// Tracks the devices that a particular extension has retained access to.
// Unlike SavedDevicesService the functions of this class can be called from
// the FILE thread.
class SavedDevices : device::UsbDevice::Observer {
public:
bool IsRegistered(scoped_refptr<device::UsbDevice> device) const;
void RegisterDevice(scoped_refptr<device::UsbDevice> device,
/* optional */ base::string16* serial_number);
private:
friend class SavedDevicesService;
SavedDevices(Profile* profile, const std::string& extension_id);
virtual ~SavedDevices();
// device::UsbDevice::Observer
virtual void OnDisconnect(scoped_refptr<device::UsbDevice> device) OVERRIDE;
Profile* profile_;
const std::string extension_id_;
// Devices with serial numbers are written to the prefs file.
std::vector<SavedDeviceEntry> persistent_devices_;
// Other devices are ephemeral devices and cleared when the extension host
// is destroyed.
std::set<scoped_refptr<device::UsbDevice> > ephemeral_devices_;
DISALLOW_COPY_AND_ASSIGN(SavedDevices);
};
explicit SavedDevicesService(Profile* profile);
virtual ~SavedDevicesService();
static SavedDevicesService* Get(Profile* profile);
// Returns the SavedDevices for |extension_id|, creating it if necessary.
SavedDevices* GetOrInsert(const std::string& extension_id);
std::vector<SavedDeviceEntry> GetAllDevices(
const std::string& extension_id) const;
// Clears the SavedDevices for |extension_id|.
void Clear(const std::string& extension_id);
private:
// content::NotificationObserver.
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// Returns the SavedDevices for |extension_id| or NULL if one does not exist.
SavedDevices* Get(const std::string& extension_id) const;
std::map<std::string, SavedDevices*> extension_id_to_saved_devices_;
Profile* profile_;
content::NotificationRegistrar registrar_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(SavedDevicesService);
};
} // namespace apps
#endif // APPS_SAVED_DEVICES_SERVICE_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "apps/saved_devices_service_factory.h"
#include "apps/saved_devices_service.h"
#include "chrome/browser/profiles/profile.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
namespace apps {
// static
SavedDevicesService* SavedDevicesServiceFactory::GetForProfile(
Profile* profile) {
return static_cast<SavedDevicesService*>(
GetInstance()->GetServiceForBrowserContext(profile, true));
}
// static
SavedDevicesServiceFactory* SavedDevicesServiceFactory::GetInstance() {
return Singleton<SavedDevicesServiceFactory>::get();
}
SavedDevicesServiceFactory::SavedDevicesServiceFactory()
: BrowserContextKeyedServiceFactory(
"SavedDevicesService",
BrowserContextDependencyManager::GetInstance()) {
}
SavedDevicesServiceFactory::~SavedDevicesServiceFactory() {
}
KeyedService* SavedDevicesServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* profile) const {
return new SavedDevicesService(static_cast<Profile*>(profile));
}
} // namespace apps
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef APPS_SAVED_DEVICES_SERVICE_FACTORY_H_
#define APPS_SAVED_DEVICES_SERVICE_FACTORY_H_
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
class Profile;
namespace apps {
class SavedDevicesService;
// BrowserContextKeyedServiceFactory for SavedDevicesService.
class SavedDevicesServiceFactory : public BrowserContextKeyedServiceFactory {
public:
static SavedDevicesService* GetForProfile(Profile* profile);
static SavedDevicesServiceFactory* GetInstance();
private:
SavedDevicesServiceFactory();
virtual ~SavedDevicesServiceFactory();
friend struct DefaultSingletonTraits<SavedDevicesServiceFactory>;
virtual KeyedService* BuildServiceInstanceFor(
content::BrowserContext* profile) const OVERRIDE;
};
} // namespace apps
#endif // APPS_SAVED_DEVICES_SERVICE_FACTORY_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "apps/saved_devices_service.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/values_test_util.h"
#include "chrome/browser/extensions/test_extension_environment.h"
#include "chrome/test/base/testing_profile.h"
#include "device/usb/usb_device.h"
#include "device/usb/usb_device_handle.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/common/extension.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace apps {
namespace {
using device::UsbDevice;
using device::UsbDeviceHandle;
using device::UsbEndpointDirection;
using device::UsbTransferCallback;
using testing::Return;
class MockUsbDeviceHandle : public UsbDeviceHandle {
public:
MockUsbDeviceHandle(const std::string& serial_number)
: UsbDeviceHandle(), serial_number_(serial_number) {}
MOCK_CONST_METHOD0(GetDevice, scoped_refptr<UsbDevice>());
MOCK_METHOD0(Close, void());
MOCK_METHOD10(ControlTransfer,
void(UsbEndpointDirection direction,
TransferRequestType request_type,
TransferRecipient recipient,
uint8 request,
uint16 value,
uint16 index,
net::IOBuffer* buffer,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback));
MOCK_METHOD6(BulkTransfer,
void(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback));
MOCK_METHOD6(InterruptTransfer,
void(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback));
MOCK_METHOD8(IsochronousTransfer,
void(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
const UsbTransferCallback& callback));
MOCK_METHOD0(ResetDevice, bool());
MOCK_METHOD1(ClaimInterface, bool(int interface_number));
MOCK_METHOD1(ReleaseInterface, bool(int interface_number));
MOCK_METHOD2(SetInterfaceAlternateSetting,
bool(int interface_number, int alternate_setting));
MOCK_METHOD1(GetManufacturer, bool(base::string16* manufacturer));
MOCK_METHOD1(GetProduct, bool(base::string16* product));
bool GetSerial(base::string16* serial) OVERRIDE {
if (serial_number_.empty()) {
return false;
}
*serial = base::UTF8ToUTF16(serial_number_);
return true;
}
private:
virtual ~MockUsbDeviceHandle() {}
const std::string serial_number_;
};
class MockUsbDevice : public UsbDevice {
public:
MockUsbDevice(const std::string& serial_number, uint32 unique_id)
: UsbDevice(0, 0, unique_id), serial_number_(serial_number) {}
MOCK_METHOD1(Close, bool(scoped_refptr<UsbDeviceHandle>));
#if defined(OS_CHROMEOS)
MOCK_METHOD2(RequestUsbAccess, void(int, const base::Callback<void(bool)>&));
#endif
MOCK_METHOD0(GetConfiguration, const device::UsbConfigDescriptor&());
scoped_refptr<UsbDeviceHandle> Open() OVERRIDE {
return new MockUsbDeviceHandle(serial_number_);
}
void NotifyDisconnect() { UsbDevice::NotifyDisconnect(); }
private:
virtual ~MockUsbDevice() {}
const std::string serial_number_;
};
}
class SavedDevicesServiceTest : public testing::Test {
protected:
virtual void SetUp() OVERRIDE {
testing::Test::SetUp();
env_.GetExtensionPrefs(); // Force creation before adding extensions.
extension_ = env_.MakeExtension(*base::test::ParseJson(
"{"
" \"app\": {"
" \"background\": {"
" \"scripts\": [\"background.js\"]"
" }"
" },"
" \"permissions\": ["
" \"usb\""
" ]"
"}"));
service_ = SavedDevicesService::Get(env_.profile());
device0 = new MockUsbDevice("ABCDE", 0);
device1 = new MockUsbDevice("", 1);
device2 = new MockUsbDevice("12345", 2);
device3 = new MockUsbDevice("", 3);
}
extensions::TestExtensionEnvironment env_;
const extensions::Extension* extension_;
SavedDevicesService* service_;
scoped_refptr<MockUsbDevice> device0;
scoped_refptr<MockUsbDevice> device1;
scoped_refptr<MockUsbDevice> device2;
scoped_refptr<MockUsbDevice> device3;
};
TEST_F(SavedDevicesServiceTest, RegisterDevices) {
SavedDevicesService::SavedDevices* saved_devices =
service_->GetOrInsert(extension_->id());
base::string16 serial_number(base::ASCIIToUTF16("ABCDE"));
saved_devices->RegisterDevice(device0, &serial_number);
saved_devices->RegisterDevice(device1, NULL);
// This is necessary as writing out registered devices happens in a task on
// the UI thread.
base::RunLoop run_loop;
run_loop.RunUntilIdle();
ASSERT_TRUE(saved_devices->IsRegistered(device0));
ASSERT_TRUE(saved_devices->IsRegistered(device1));
ASSERT_FALSE(saved_devices->IsRegistered(device2));
ASSERT_FALSE(saved_devices->IsRegistered(device3));
std::vector<SavedDeviceEntry> device_entries =
service_->GetAllDevices(extension_->id());
ASSERT_EQ(1U, device_entries.size());
ASSERT_EQ(base::ASCIIToUTF16("ABCDE"), device_entries[0].serial_number);
device1->NotifyDisconnect();
ASSERT_TRUE(saved_devices->IsRegistered(device0));
ASSERT_FALSE(saved_devices->IsRegistered(device1));
ASSERT_FALSE(saved_devices->IsRegistered(device2));
ASSERT_FALSE(saved_devices->IsRegistered(device3));
service_->Clear(extension_->id());
// App is normally restarted, clearing its reference to the SavedDevices.
saved_devices = service_->GetOrInsert(extension_->id());
ASSERT_FALSE(saved_devices->IsRegistered(device0));
device_entries = service_->GetAllDevices(extension_->id());
ASSERT_EQ(0U, device_entries.size());
}
TEST_F(SavedDevicesServiceTest, LoadPrefs) {
scoped_ptr<base::Value> prefs_value = base::test::ParseJson(
"["
" {"
" \"product_id\": 0,"
" \"serial_number\": \"ABCDE\","
" \"type\": \"usb\","
" \"vendor_id\": 0"
" }"
"]");
env_.GetExtensionPrefs()->UpdateExtensionPref(
extension_->id(), "devices", prefs_value.release());
SavedDevicesService::SavedDevices* saved_devices =
service_->GetOrInsert(extension_->id());
ASSERT_TRUE(saved_devices->IsRegistered(device0));
ASSERT_FALSE(saved_devices->IsRegistered(device1));
ASSERT_FALSE(saved_devices->IsRegistered(device2));
ASSERT_FALSE(saved_devices->IsRegistered(device3));
}
} // namespace apps
......@@ -120,7 +120,7 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
virtual void Close() OVERRIDE { device_ = NULL; }
bool ClaimInterface(const int interface_number) {
bool ClaimInterface(int interface_number) {
if (device_->claimed_interfaces_.find(interface_number) !=
device_->claimed_interfaces_.end())
return false;
......@@ -129,7 +129,7 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
return true;
}
bool ReleaseInterface(const int interface_number) {
bool ReleaseInterface(int interface_number) {
if (device_->claimed_interfaces_.find(interface_number) ==
device_->claimed_interfaces_.end())
return false;
......@@ -138,9 +138,8 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
return true;
}
virtual bool SetInterfaceAlternateSetting(
const int interface_number,
const int alternate_setting) OVERRIDE {
virtual bool SetInterfaceAlternateSetting(int interface_number,
int alternate_setting) OVERRIDE {
return true;
}
......@@ -162,22 +161,22 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
}
// Async IO. Can be called on any thread.
virtual void ControlTransfer(const UsbEndpointDirection direction,
const TransferRequestType request_type,
const TransferRecipient recipient,
const uint8 request,
const uint16 value,
const uint16 index,
virtual void ControlTransfer(UsbEndpointDirection direction,
TransferRequestType request_type,
TransferRecipient recipient,
uint8 request,
uint16 value,
uint16 index,
net::IOBuffer* buffer,
const size_t length,
const unsigned int timeout,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback) OVERRIDE {}
virtual void BulkTransfer(const UsbEndpointDirection direction,
const uint8 endpoint,
virtual void BulkTransfer(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
const size_t length,
const unsigned int timeout,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback) OVERRIDE {
if (direction == device::USB_DIRECTION_OUTBOUND) {
if (remaining_body_length_ == 0) {
......@@ -304,22 +303,22 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
query.size));
}
virtual void InterruptTransfer(const UsbEndpointDirection direction,
const uint8 endpoint,
virtual void InterruptTransfer(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
const size_t length,
const unsigned int timeout,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback) OVERRIDE {
}
virtual void IsochronousTransfer(
const UsbEndpointDirection direction,
const uint8 endpoint,
UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
const size_t length,
const unsigned int packets,
const unsigned int packet_length,
const unsigned int timeout,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
const UsbTransferCallback& callback) OVERRIDE {}
protected:
......
......@@ -6,6 +6,7 @@
'chrome_unit_tests_sources': [
'../apps/app_shim/app_shim_host_mac_unittest.cc',
'../apps/app_shim/extension_app_shim_handler_mac_unittest.cc',
'../apps/saved_devices_service_unittest.cc',
'../apps/saved_files_service_unittest.cc',
'../components/autofill/content/renderer/test_password_autofill_agent.cc',
'../components/autofill/content/renderer/test_password_autofill_agent.h',
......
......@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
namespace device {
......@@ -19,6 +20,11 @@ struct UsbConfigDescriptor;
// UsbDeviceHandle must be created from Open() method.
class UsbDevice : public base::RefCountedThreadSafe<UsbDevice> {
public:
class Observer {
public:
virtual void OnDisconnect(scoped_refptr<UsbDevice> device) = 0;
};
// Accessors to basic information.
uint16 vendor_id() const { return vendor_id_; }
uint16 product_id() const { return product_id_; }
......@@ -48,11 +54,14 @@ class UsbDevice : public base::RefCountedThreadSafe<UsbDevice> {
// Blocking method. Must be called on FILE thread.
virtual const UsbConfigDescriptor& GetConfiguration() = 0;
void AddObserver(Observer* obs) { observer_list_.AddObserver(obs); }
void RemoveObserver(Observer* obs) { observer_list_.RemoveObserver(obs); }
protected:
UsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id)
: vendor_id_(vendor_id), product_id_(product_id), unique_id_(unique_id) {}
UsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id);
virtual ~UsbDevice();
virtual ~UsbDevice() {}
void NotifyDisconnect();
private:
friend class base::RefCountedThreadSafe<UsbDevice>;
......@@ -61,6 +70,8 @@ class UsbDevice : public base::RefCountedThreadSafe<UsbDevice> {
const uint16 product_id_;
const uint32 unique_id_;
ObserverList<Observer> observer_list_;
DISALLOW_COPY_AND_ASSIGN(UsbDevice);
};
......
......@@ -51,48 +51,48 @@ class UsbDeviceHandle : public base::RefCountedThreadSafe<UsbDeviceHandle> {
// Device manipulation operations. These methods are blocking and must be
// called on FILE thread.
virtual bool ClaimInterface(const int interface_number) = 0;
virtual bool ReleaseInterface(const int interface_number) = 0;
virtual bool SetInterfaceAlternateSetting(const int interface_number,
const int alternate_setting) = 0;
virtual bool ClaimInterface(int interface_number) = 0;
virtual bool ReleaseInterface(int interface_number) = 0;
virtual bool SetInterfaceAlternateSetting(int interface_number,
int alternate_setting) = 0;
virtual bool ResetDevice() = 0;
virtual bool GetManufacturer(base::string16* manufacturer) = 0;
virtual bool GetProduct(base::string16* product) = 0;
virtual bool GetSerial(base::string16* serial) = 0;
// Async IO. Can be called on any thread.
virtual void ControlTransfer(const UsbEndpointDirection direction,
const TransferRequestType request_type,
const TransferRecipient recipient,
const uint8 request,
const uint16 value,
const uint16 index,
virtual void ControlTransfer(UsbEndpointDirection direction,
TransferRequestType request_type,
TransferRecipient recipient,
uint8 request,
uint16 value,
uint16 index,
net::IOBuffer* buffer,
const size_t length,
const unsigned int timeout,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback) = 0;
virtual void BulkTransfer(const UsbEndpointDirection direction,
const uint8 endpoint,
virtual void BulkTransfer(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
const size_t length,
const unsigned int timeout,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback) = 0;
virtual void InterruptTransfer(const UsbEndpointDirection direction,
const uint8 endpoint,
virtual void InterruptTransfer(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
const size_t length,
const unsigned int timeout,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback) = 0;
virtual void IsochronousTransfer(const UsbEndpointDirection direction,
const uint8 endpoint,
virtual void IsochronousTransfer(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
const size_t length,
const unsigned int packets,
const unsigned int packet_length,
const unsigned int timeout,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
const UsbTransferCallback& callback) = 0;
protected:
......
......@@ -35,48 +35,47 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
public:
virtual scoped_refptr<UsbDevice> GetDevice() const OVERRIDE;
virtual void Close() OVERRIDE;
virtual bool ClaimInterface(const int interface_number) OVERRIDE;
virtual bool ReleaseInterface(const int interface_number) OVERRIDE;
virtual bool SetInterfaceAlternateSetting(
const int interface_number,
const int alternate_setting) OVERRIDE;
virtual bool ClaimInterface(int interface_number) OVERRIDE;
virtual bool ReleaseInterface(int interface_number) OVERRIDE;
virtual bool SetInterfaceAlternateSetting(int interface_number,
int alternate_setting) OVERRIDE;
virtual bool ResetDevice() OVERRIDE;
virtual bool GetManufacturer(base::string16* manufacturer) OVERRIDE;
virtual bool GetProduct(base::string16* product) OVERRIDE;
virtual bool GetSerial(base::string16* serial) OVERRIDE;
virtual void ControlTransfer(const UsbEndpointDirection direction,
const TransferRequestType request_type,
const TransferRecipient recipient,
const uint8 request,
const uint16 value,
const uint16 index,
virtual void ControlTransfer(UsbEndpointDirection direction,
TransferRequestType request_type,
TransferRecipient recipient,
uint8 request,
uint16 value,
uint16 index,
net::IOBuffer* buffer,
const size_t length,
const unsigned int timeout,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback) OVERRIDE;
virtual void BulkTransfer(const UsbEndpointDirection direction,
const uint8 endpoint,
virtual void BulkTransfer(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
const size_t length,
const unsigned int timeout,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback) OVERRIDE;
virtual void InterruptTransfer(const UsbEndpointDirection direction,
const uint8 endpoint,
virtual void InterruptTransfer(UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
const size_t length,
const unsigned int timeout,
size_t length,
unsigned int timeout,
const UsbTransferCallback& callback) OVERRIDE;
virtual void IsochronousTransfer(
const UsbEndpointDirection direction,
const uint8 endpoint,
UsbEndpointDirection direction,
uint8 endpoint,
net::IOBuffer* buffer,
const size_t length,
const unsigned int packets,
const unsigned int packet_length,
const unsigned int timeout,
size_t length,
unsigned int packets,
unsigned int packet_length,
unsigned int timeout,
const UsbTransferCallback& callback) OVERRIDE;
PlatformUsbDeviceHandle handle() const { return handle_; }
......
......@@ -98,6 +98,17 @@ UsbUsageType GetUsageType(const libusb_endpoint_descriptor* descriptor) {
} // namespace
UsbDevice::UsbDevice(uint16 vendor_id, uint16 product_id, uint32 unique_id)
: vendor_id_(vendor_id), product_id_(product_id), unique_id_(unique_id) {
}
UsbDevice::~UsbDevice() {
}
void UsbDevice::NotifyDisconnect() {
FOR_EACH_OBSERVER(Observer, observer_list_, OnDisconnect(this));
}
UsbDeviceImpl::UsbDeviceImpl(
scoped_refptr<UsbContext> context,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
......
......@@ -45,7 +45,7 @@ class UsbServiceImpl : public UsbService,
// base::MessageLoop::DestructionObserver implementation.
virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
// Enumerate USB devices from OS and Update devices_ map.
// Enumerate USB devices from OS and update devices_ map.
void RefreshDevices();
scoped_refptr<UsbContext> context_;
......@@ -55,18 +55,23 @@ class UsbServiceImpl : public UsbService,
// TODO(reillyg): Figure out a better solution.
uint32 next_unique_id_;
// The map from PlatformUsbDevices to UsbDevices.
typedef std::map<PlatformUsbDevice, scoped_refptr<UsbDeviceImpl> > DeviceMap;
// The map from unique IDs to UsbDevices.
typedef std::map<uint32, scoped_refptr<UsbDeviceImpl> > DeviceMap;
DeviceMap devices_;
// The map from PlatformUsbDevices to UsbDevices.
typedef std::map<PlatformUsbDevice, scoped_refptr<UsbDeviceImpl> >
PlatformDeviceMap;
PlatformDeviceMap platform_devices_;
DISALLOW_COPY_AND_ASSIGN(UsbServiceImpl);
};
scoped_refptr<UsbDevice> UsbServiceImpl::GetDeviceById(uint32 unique_id) {
DCHECK(CalledOnValidThread());
RefreshDevices();
for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
if (it->second->unique_id() == unique_id)
DeviceMap::iterator it = devices_.find(unique_id);
if (it != devices_.end()) {
return it->second;
}
return NULL;
......@@ -120,7 +125,7 @@ void UsbServiceImpl::RefreshDevices() {
// Populates new devices.
for (ssize_t i = 0; i < device_count; ++i) {
if (!ContainsKey(devices_, platform_devices[i])) {
if (!ContainsKey(platform_devices_, platform_devices[i])) {
libusb_device_descriptor descriptor;
const int rv =
libusb_get_device_descriptor(platform_devices[i], &descriptor);
......@@ -130,31 +135,43 @@ void UsbServiceImpl::RefreshDevices() {
<< ConvertPlatformUsbErrorToString(rv);
continue;
}
UsbDeviceImpl* new_device = new UsbDeviceImpl(context_,
uint32 unique_id;
do {
unique_id = ++next_unique_id_;
} while (devices_.find(unique_id) != devices_.end());
scoped_refptr<UsbDeviceImpl> new_device(
new UsbDeviceImpl(context_,
ui_task_runner_,
platform_devices[i],
descriptor.idVendor,
descriptor.idProduct,
++next_unique_id_);
devices_[platform_devices[i]] = new_device;
connected_devices.insert(new_device);
unique_id));
platform_devices_[platform_devices[i]] = new_device;
devices_[unique_id] = new_device;
connected_devices.insert(new_device.get());
} else {
connected_devices.insert(devices_[platform_devices[i]].get());
connected_devices.insert(platform_devices_[platform_devices[i]].get());
}
}
// Find disconnected devices.
for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
for (PlatformDeviceMap::iterator it = platform_devices_.begin();
it != platform_devices_.end();
++it) {
if (!ContainsKey(connected_devices, it->second.get())) {
disconnected_devices.push_back(it->first);
devices_.erase(it->second->unique_id());
it->second->OnDisconnect();
}
}
// Remove disconnected devices from devices_.
// Remove disconnected devices from platform_devices_.
for (size_t i = 0; i < disconnected_devices.size(); ++i) {
// UsbDevice will be destroyed after this. The corresponding
// PlatformUsbDevice will be unref'ed during this process.
devices_.erase(disconnected_devices[i]);
platform_devices_.erase(disconnected_devices[i]);
}
libusb_free_device_list(platform_devices, true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment