summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/BUILD.gn6
-rw-r--r--chrome/browser/DEPS2
-rw-r--r--chrome/browser/browser_process_impl.cc5
-rw-r--r--chrome/browser/browser_process_impl.h5
-rw-r--r--chrome/browser/chrome_device_client.cc19
-rw-r--r--chrome/browser/chrome_device_client.h27
-rw-r--r--chrome/browser/devtools/device/usb/DEPS3
-rw-r--r--chrome/browser/devtools/device/usb/android_usb_device.cc5
-rw-r--r--chrome/chrome_browser.gypi8
-rw-r--r--components/usb_service/DEPS2
-rw-r--r--components/usb_service/usb_device_handle_impl.cc174
-rw-r--r--components/usb_service/usb_device_handle_impl.h28
-rw-r--r--components/usb_service/usb_device_impl.cc33
-rw-r--r--components/usb_service/usb_device_impl.h8
-rw-r--r--components/usb_service/usb_service.h13
-rw-r--r--components/usb_service/usb_service_impl.cc22
-rw-r--r--device/core/BUILD.gn10
-rw-r--r--device/core/core.gyp22
-rw-r--r--device/core/device_client.cc38
-rw-r--r--device/core/device_client.h39
-rw-r--r--device/test/usb_test_gadget_impl.cc2
-rw-r--r--extensions/browser/api/usb/DEPS1
-rw-r--r--extensions/browser/api/usb/usb_api.cc7
-rw-r--r--extensions/browser/api/usb_private/DEPS1
-rw-r--r--extensions/browser/api/usb_private/usb_private_api.cc6
-rw-r--r--extensions/shell/app_shell.gyp3
-rw-r--r--extensions/shell/browser/DEPS2
-rw-r--r--extensions/shell/browser/shell_browser_main_parts.cc3
-rw-r--r--extensions/shell/browser/shell_browser_main_parts.h2
-rw-r--r--extensions/shell/browser/shell_device_client.cc23
-rw-r--r--extensions/shell/browser/shell_device_client.h31
31 files changed, 410 insertions, 140 deletions
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e1222c3..5ee0844 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -156,7 +156,6 @@ static_library("browser") {
"//components/storage_monitor",
"//components/translate/content/browser",
"//components/url_matcher",
- "//components/usb_service",
"//components/visitedlink/browser",
"//components/visitedlink/common",
"//components/web_modal",
@@ -450,6 +449,10 @@ static_library("browser") {
# Non-mobile.
sources += rebase_path(gypi_values.chrome_browser_non_mobile_sources,
".", "//chrome")
+ deps += [
+ "//components/usb_service",
+ "//device/core",
+ ]
}
if (is_android) {
@@ -464,7 +467,6 @@ static_library("browser") {
"//third_party/libaddressinput",
"//components/feedback",
"//components/storage_monitor",
- "//components/usb_service",
"//components/web_modal",
]
} else {
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index d8d9246..0b17801 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -70,6 +70,7 @@ include_rules = [
"+components/translate/core/browser",
"+components/translate/core/common",
"+components/url_matcher",
+ "+components/usb_service",
"+components/user_manager",
"+components/user_prefs",
"+components/web_modal",
@@ -78,6 +79,7 @@ include_rules = [
"+content/test/net",
"+courgette",
"+device/bluetooth",
+ "+device/core",
"+device/media_transfer_protocol",
"+extensions/browser",
"+extensions/common",
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 06301fd..ffa2082 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -106,6 +106,7 @@
#if defined(OS_ANDROID)
#include "components/gcm_driver/gcm_driver_android.h"
#else
+#include "chrome/browser/chrome_device_client.h"
#include "chrome/browser/services/gcm/gcm_desktop_utils.h"
#include "components/gcm_driver/gcm_client_factory.h"
#endif
@@ -194,6 +195,10 @@ BrowserProcessImpl::BrowserProcessImpl(
InitIdleMonitor();
#endif
+#if !defined(OS_ANDROID)
+ device_client_.reset(new ChromeDeviceClient);
+#endif
+
#if defined(ENABLE_EXTENSIONS)
apps::AppsClient::Set(ChromeAppsClient::GetInstance());
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 8fd4ce5..937f813 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -21,6 +21,7 @@
#include "base/timer/timer.h"
#include "chrome/browser/browser_process.h"
+class ChromeDeviceClient;
class ChromeNetLog;
class ChromeResourceDispatcherHostDelegate;
class RemoteDebuggingServer;
@@ -300,6 +301,10 @@ class BrowserProcessImpl : public BrowserProcess,
scoped_ptr<gcm::GCMDriver> gcm_driver_;
+#if !defined(OS_ANDROID)
+ scoped_ptr<ChromeDeviceClient> device_client_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(BrowserProcessImpl);
};
diff --git a/chrome/browser/chrome_device_client.cc b/chrome/browser/chrome_device_client.cc
new file mode 100644
index 0000000..941e777
--- /dev/null
+++ b/chrome/browser/chrome_device_client.cc
@@ -0,0 +1,19 @@
+// 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 "chrome/browser/chrome_device_client.h"
+
+#include "base/logging.h"
+#include "components/usb_service/usb_service.h"
+#include "content/public/browser/browser_thread.h"
+
+ChromeDeviceClient::ChromeDeviceClient() {}
+
+ChromeDeviceClient::~ChromeDeviceClient() {}
+
+usb_service::UsbService* ChromeDeviceClient::GetUsbService() {
+ return usb_service::UsbService::GetInstance(
+ content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::UI));
+}
diff --git a/chrome/browser/chrome_device_client.h b/chrome/browser/chrome_device_client.h
new file mode 100644
index 0000000..d8814dc
--- /dev/null
+++ b/chrome/browser/chrome_device_client.h
@@ -0,0 +1,27 @@
+// 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 CHROME_BROWSER_CHROME_DEVICE_CLIENT_H_
+#define CHROME_BROWSER_CHROME_DEVICE_CLIENT_H_
+
+#include "device/core/device_client.h"
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+
+// Implementation of device::DeviceClient that returns //device service
+// singletons appropriate for use within the Chrome application.
+class ChromeDeviceClient : device::DeviceClient {
+ public:
+ ChromeDeviceClient();
+ virtual ~ChromeDeviceClient();
+
+ // device::DeviceClient implementation
+ virtual usb_service::UsbService* GetUsbService() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChromeDeviceClient);
+};
+
+#endif // CHROME_BROWSER_CHROME_DEVICE_CLIENT_H_
diff --git a/chrome/browser/devtools/device/usb/DEPS b/chrome/browser/devtools/device/usb/DEPS
deleted file mode 100644
index fc9564a..0000000
--- a/chrome/browser/devtools/device/usb/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+components/usb_service"
-]
diff --git a/chrome/browser/devtools/device/usb/android_usb_device.cc b/chrome/browser/devtools/device/usb/android_usb_device.cc
index 3a2bee1..51aed47 100644
--- a/chrome/browser/devtools/device/usb/android_usb_device.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_device.cc
@@ -21,6 +21,7 @@
#include "components/usb_service/usb_service.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/rsa_private_key.h"
+#include "device/core/device_client.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/socket/stream_socket.h"
@@ -224,7 +225,7 @@ static void OpenAndroidDeviceOnFileThread(
static int CountOnFileThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- UsbService* service = UsbService::GetInstance();
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
UsbDevices usb_devices;
if (service != NULL)
service->GetDevices(&usb_devices);
@@ -249,7 +250,7 @@ static void EnumerateOnFileThread(
scoped_refptr<base::MessageLoopProxy> caller_message_loop_proxy) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- UsbService* service = UsbService::GetInstance();
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
UsbDevices usb_devices;
if (service != NULL)
service->GetDevices(&usb_devices);
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 4fc4663..6de6837 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2279,6 +2279,8 @@
'chrome_browser_non_mobile_sources': [
'browser/chrome_browser_field_trials_desktop.cc',
'browser/chrome_browser_field_trials_desktop.h',
+ 'browser/chrome_device_client.cc',
+ 'browser/chrome_device_client.h',
],
'chrome_browser_supervised_user_sources': [
'browser/supervised_user/custodian_profile_downloader_service.cc',
@@ -2911,7 +2913,6 @@
'../components/components.gyp:storage_monitor',
'../components/components.gyp:translate_content_browser',
'../components/components.gyp:url_matcher',
- '../components/components.gyp:usb_service',
'../components/components.gyp:visitedlink_browser',
'../components/components.gyp:visitedlink_common',
'../components/components.gyp:web_modal',
@@ -3236,6 +3237,10 @@
'sources': [ '<@(chrome_browser_mobile_sources)' ],
}, { # OS!="android" and OS!="ios"
'sources': [ '<@(chrome_browser_non_mobile_sources)' ],
+ 'dependencies': [
+ '../components/components.gyp:usb_service',
+ '../device/core/core.gyp:device_core',
+ ]
}],
['OS=="android"', {
'dependencies': [
@@ -3248,7 +3253,6 @@
'dependencies!': [
'../components/components.gyp:feedback_component',
'../components/components.gyp:storage_monitor',
- '../components/components.gyp:usb_service',
'../components/components.gyp:web_modal',
'../third_party/libaddressinput/libaddressinput.gyp:libaddressinput',
],
diff --git a/components/usb_service/DEPS b/components/usb_service/DEPS
index f416680..c114bca 100644
--- a/components/usb_service/DEPS
+++ b/components/usb_service/DEPS
@@ -1,8 +1,6 @@
include_rules = [
"+chromeos",
- "+content/public/browser",
-
"-net",
"+net/base",
diff --git a/components/usb_service/usb_device_handle_impl.cc b/components/usb_service/usb_device_handle_impl.cc
index 73b04b9..5823085 100644
--- a/components/usb_service/usb_device_handle_impl.cc
+++ b/components/usb_service/usb_device_handle_impl.cc
@@ -7,20 +7,20 @@
#include <algorithm>
#include <vector>
-#include "base/message_loop/message_loop.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
#include "components/usb_service/usb_context.h"
#include "components/usb_service/usb_device_impl.h"
#include "components/usb_service/usb_error.h"
#include "components/usb_service/usb_interface.h"
#include "components/usb_service/usb_service.h"
-#include "content/public/browser/browser_thread.h"
#include "third_party/libusb/src/libusb/libusb.h"
-using content::BrowserThread;
-
namespace usb_service {
typedef libusb_device* PlatformUsbDevice;
@@ -103,24 +103,8 @@ static UsbTransferStatus ConvertTransferStatus(
}
}
-static void LIBUSB_CALL
-PlatformTransferCompletionCallback(PlatformUsbTransferHandle transfer) {
- BrowserThread::PostTask(BrowserThread::FILE,
- FROM_HERE,
- base::Bind(HandleTransferCompletion, transfer));
-}
-
} // namespace
-void HandleTransferCompletion(PlatformUsbTransferHandle transfer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- UsbDeviceHandleImpl* const device_handle =
- reinterpret_cast<UsbDeviceHandleImpl*>(transfer->user_data);
- CHECK(device_handle) << "Device handle is closed before transfer finishes.";
- device_handle->TransferComplete(transfer);
- libusb_free_transfer(transfer);
-}
-
class UsbDeviceHandleImpl::InterfaceClaimer
: public base::RefCountedThreadSafe<UsbDeviceHandleImpl::InterfaceClaimer> {
public:
@@ -170,10 +154,12 @@ struct UsbDeviceHandleImpl::Transfer {
Transfer();
~Transfer();
+ void Complete(UsbTransferStatus status, size_t bytes_transferred);
+
UsbTransferType transfer_type;
scoped_refptr<net::IOBuffer> buffer;
scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface;
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner;
size_t length;
UsbTransferCallback callback;
};
@@ -185,6 +171,16 @@ UsbDeviceHandleImpl::Transfer::Transfer()
UsbDeviceHandleImpl::Transfer::~Transfer() {
}
+void UsbDeviceHandleImpl::Transfer::Complete(UsbTransferStatus status,
+ size_t bytes_transferred) {
+ if (task_runner->RunsTasksOnCurrentThread()) {
+ callback.Run(status, buffer, bytes_transferred);
+ } else {
+ task_runner->PostTask(
+ FROM_HERE, base::Bind(callback, status, buffer, bytes_transferred));
+ }
+}
+
UsbDeviceHandleImpl::UsbDeviceHandleImpl(
scoped_refptr<UsbContext> context,
UsbDeviceImpl* device,
@@ -193,8 +189,8 @@ UsbDeviceHandleImpl::UsbDeviceHandleImpl(
: device_(device),
handle_(handle),
interfaces_(interfaces),
- context_(context) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ context_(context),
+ task_runner_(base::ThreadTaskRunnerHandle::Get()) {
DCHECK(handle) << "Cannot create device with NULL handle.";
DCHECK(interfaces_.get()) << "Unable to list interfaces";
}
@@ -216,7 +212,18 @@ void UsbDeviceHandleImpl::Close() {
device_->Close(this);
}
-void UsbDeviceHandleImpl::TransferComplete(PlatformUsbTransferHandle handle) {
+/* static */
+void LIBUSB_CALL UsbDeviceHandleImpl::PlatformTransferCallback(
+ PlatformUsbTransferHandle transfer) {
+ UsbDeviceHandleImpl* device_handle =
+ reinterpret_cast<UsbDeviceHandleImpl*>(transfer->user_data);
+ device_handle->task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &UsbDeviceHandleImpl::CompleteTransfer, device_handle, transfer));
+}
+
+void UsbDeviceHandleImpl::CompleteTransfer(PlatformUsbTransferHandle handle) {
DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed";
Transfer transfer = transfers_[handle];
@@ -229,7 +236,6 @@ void UsbDeviceHandleImpl::TransferComplete(PlatformUsbTransferHandle handle) {
DCHECK(transfer.length >= actual_length)
<< "data too big for our buffer (libusb failure?)";
- scoped_refptr<net::IOBuffer> buffer = transfer.buffer;
switch (transfer.transfer_type) {
case USB_TRANSFER_CONTROL:
// If the transfer is a control transfer we do not expose the control
@@ -246,9 +252,9 @@ void UsbDeviceHandleImpl::TransferComplete(PlatformUsbTransferHandle handle) {
new net::IOBuffer(static_cast<int>(
std::max(actual_length, static_cast<size_t>(1))));
memcpy(resized_buffer->data(),
- buffer->data() + LIBUSB_CONTROL_SETUP_SIZE,
+ transfer.buffer->data() + LIBUSB_CONTROL_SETUP_SIZE,
actual_length);
- buffer = resized_buffer;
+ transfer.buffer = resized_buffer;
}
}
break;
@@ -268,8 +274,8 @@ void UsbDeviceHandleImpl::TransferComplete(PlatformUsbTransferHandle handle) {
if (actual_length < packet_buffer_start) {
CHECK(packet_buffer_start + packet->actual_length <=
transfer.length);
- memmove(buffer->data() + actual_length,
- buffer->data() + packet_buffer_start,
+ memmove(transfer.buffer->data() + actual_length,
+ transfer.buffer->data() + packet_buffer_start,
packet->actual_length);
}
actual_length += packet->actual_length;
@@ -289,12 +295,8 @@ void UsbDeviceHandleImpl::TransferComplete(PlatformUsbTransferHandle handle) {
break;
}
- transfer.message_loop_proxy->PostTask(
- FROM_HERE,
- base::Bind(transfer.callback,
- ConvertTransferStatus(handle->status),
- buffer,
- actual_length));
+ transfer.Complete(ConvertTransferStatus(handle->status), actual_length);
+ libusb_free_transfer(handle);
// Must release interface first before actually delete this.
transfer.claimed_interface = NULL;
@@ -552,20 +554,12 @@ void UsbDeviceHandleImpl::ControlTransfer(
libusb_fill_control_transfer(transfer,
handle_,
reinterpret_cast<uint8*>(resized_buffer->data()),
- PlatformTransferCompletionCallback,
+ &UsbDeviceHandleImpl::PlatformTransferCallback,
this,
timeout);
- BrowserThread::PostTask(BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&UsbDeviceHandleImpl::SubmitTransfer,
- this,
- transfer,
- USB_TRANSFER_CONTROL,
- resized_buffer,
- resized_length,
- base::MessageLoopProxy::current(),
- callback));
+ PostOrSubmitTransfer(
+ transfer, USB_TRANSFER_CONTROL, resized_buffer, resized_length, callback);
}
void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction,
@@ -586,20 +580,11 @@ void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction,
new_endpoint,
reinterpret_cast<uint8*>(buffer->data()),
static_cast<int>(length),
- PlatformTransferCompletionCallback,
+ &UsbDeviceHandleImpl::PlatformTransferCallback,
this,
timeout);
- BrowserThread::PostTask(BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&UsbDeviceHandleImpl::SubmitTransfer,
- this,
- transfer,
- USB_TRANSFER_BULK,
- make_scoped_refptr(buffer),
- length,
- base::MessageLoopProxy::current(),
- callback));
+ PostOrSubmitTransfer(transfer, USB_TRANSFER_BULK, buffer, length, callback);
}
void UsbDeviceHandleImpl::InterruptTransfer(
@@ -621,19 +606,12 @@ void UsbDeviceHandleImpl::InterruptTransfer(
new_endpoint,
reinterpret_cast<uint8*>(buffer->data()),
static_cast<int>(length),
- PlatformTransferCompletionCallback,
+ &UsbDeviceHandleImpl::PlatformTransferCallback,
this,
timeout);
- BrowserThread::PostTask(BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&UsbDeviceHandleImpl::SubmitTransfer,
- this,
- transfer,
- USB_TRANSFER_INTERRUPT,
- make_scoped_refptr(buffer),
- length,
- base::MessageLoopProxy::current(),
- callback));
+
+ PostOrSubmitTransfer(
+ transfer, USB_TRANSFER_INTERRUPT, buffer, length, callback);
}
void UsbDeviceHandleImpl::IsochronousTransfer(
@@ -662,21 +640,13 @@ void UsbDeviceHandleImpl::IsochronousTransfer(
reinterpret_cast<uint8*>(buffer->data()),
static_cast<int>(length),
packets,
- PlatformTransferCompletionCallback,
+ &UsbDeviceHandleImpl::PlatformTransferCallback,
this,
timeout);
libusb_set_iso_packet_lengths(transfer, packet_length);
- BrowserThread::PostTask(BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&UsbDeviceHandleImpl::SubmitTransfer,
- this,
- transfer,
- USB_TRANSFER_ISOCHRONOUS,
- make_scoped_refptr(buffer),
- length,
- base::MessageLoopProxy::current(),
- callback));
+ PostOrSubmitTransfer(
+ transfer, USB_TRANSFER_ISOCHRONOUS, buffer, length, callback);
}
void UsbDeviceHandleImpl::RefreshEndpointMap() {
@@ -704,27 +674,52 @@ UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
return NULL;
}
+void UsbDeviceHandleImpl::PostOrSubmitTransfer(
+ PlatformUsbTransferHandle transfer,
+ UsbTransferType transfer_type,
+ net::IOBuffer* buffer,
+ size_t length,
+ const UsbTransferCallback& callback) {
+ if (task_runner_->RunsTasksOnCurrentThread()) {
+ SubmitTransfer(transfer,
+ transfer_type,
+ buffer,
+ length,
+ base::ThreadTaskRunnerHandle::Get(),
+ callback);
+ } else {
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&UsbDeviceHandleImpl::SubmitTransfer,
+ this,
+ transfer,
+ transfer_type,
+ make_scoped_refptr(buffer),
+ length,
+ base::ThreadTaskRunnerHandle::Get(),
+ callback));
+ }
+}
+
void UsbDeviceHandleImpl::SubmitTransfer(
PlatformUsbTransferHandle handle,
UsbTransferType transfer_type,
net::IOBuffer* buffer,
const size_t length,
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const UsbTransferCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!device_) {
- message_loop_proxy->PostTask(
- FROM_HERE,
- base::Bind(
- callback, USB_TRANSFER_DISCONNECT, make_scoped_refptr(buffer), 0));
- }
Transfer transfer;
transfer.transfer_type = transfer_type;
transfer.buffer = buffer;
transfer.length = length;
transfer.callback = callback;
- transfer.message_loop_proxy = message_loop_proxy;
+ transfer.task_runner = task_runner;
+
+ if (!device_) {
+ transfer.Complete(USB_TRANSFER_DISCONNECT, 0);
+ return;
+ }
// It's OK for this method to return NULL. libusb_submit_transfer will fail if
// it requires an interface we didn't claim.
@@ -735,10 +730,7 @@ void UsbDeviceHandleImpl::SubmitTransfer(
transfers_[handle] = transfer;
} else {
VLOG(1) << "Failed to submit transfer: " << ConvertErrorToString(rv);
- message_loop_proxy->PostTask(
- FROM_HERE,
- base::Bind(
- callback, USB_TRANSFER_ERROR, make_scoped_refptr(buffer), 0));
+ transfer.Complete(USB_TRANSFER_ERROR, 0);
}
}
diff --git a/components/usb_service/usb_device_handle_impl.h b/components/usb_service/usb_device_handle_impl.h
index 7d11337..66d6960 100644
--- a/components/usb_service/usb_device_handle_impl.h
+++ b/components/usb_service/usb_device_handle_impl.h
@@ -15,13 +15,10 @@
#include "components/usb_service/usb_device_handle.h"
#include "components/usb_service/usb_interface.h"
#include "net/base/io_buffer.h"
-
-struct libusb_device_handle;
-struct libusb_iso_packet_descriptor;
-struct libusb_transfer;
+#include "third_party/libusb/src/libusb/libusb.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
}
namespace usb_service {
@@ -97,8 +94,6 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
virtual ~UsbDeviceHandleImpl();
private:
- friend void HandleTransferCompletion(PlatformUsbTransferHandle handle);
-
class InterfaceClaimer;
struct Transfer;
@@ -111,6 +106,16 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
scoped_refptr<InterfaceClaimer> GetClaimedInterfaceForEndpoint(
unsigned char endpoint);
+ // If the device's task runner is on the current thread then the transfer will
+ // be submitted directly, otherwise a task to do so it posted. The callback
+ // will be called on the current message loop of the thread where this
+ // function was called.
+ void PostOrSubmitTransfer(PlatformUsbTransferHandle handle,
+ UsbTransferType transfer_type,
+ net::IOBuffer* buffer,
+ size_t length,
+ const UsbTransferCallback& callback);
+
// Submits a transfer and starts tracking it. Retains the buffer and copies
// the completion callback until the transfer finishes, whereupon it invokes
// the callback then releases the buffer.
@@ -118,12 +123,15 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
UsbTransferType transfer_type,
net::IOBuffer* buffer,
const size_t length,
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const UsbTransferCallback& callback);
+ static void LIBUSB_CALL
+ PlatformTransferCallback(PlatformUsbTransferHandle handle);
+
// Invokes the callbacks associated with a given transfer, and removes it from
// the in-flight transfer set.
- void TransferComplete(PlatformUsbTransferHandle transfer);
+ void CompleteTransfer(PlatformUsbTransferHandle transfer);
bool GetSupportedLanguages();
bool GetStringDescriptor(uint8 string_id, base::string16* string);
@@ -154,6 +162,8 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
// before this handle.
scoped_refptr<UsbContext> context_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(UsbDeviceHandleImpl);
diff --git a/components/usb_service/usb_device_impl.cc b/components/usb_service/usb_device_impl.cc
index 243d25d..b6d2a12 100644
--- a/components/usb_service/usb_device_impl.cc
+++ b/components/usb_service/usb_device_impl.cc
@@ -6,12 +6,15 @@
#include <algorithm>
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
#include "components/usb_service/usb_context.h"
#include "components/usb_service/usb_device_handle_impl.h"
#include "components/usb_service/usb_error.h"
#include "components/usb_service/usb_interface_impl.h"
-#include "content/public/browser/browser_thread.h"
#include "third_party/libusb/src/libusb/libusb.h"
#if defined(OS_CHROMEOS)
@@ -20,16 +23,14 @@
#include "chromeos/dbus/permission_broker_client.h"
#endif // defined(OS_CHROMEOS)
-using content::BrowserThread;
-
namespace {
#if defined(OS_CHROMEOS)
void OnRequestUsbAccessReplied(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const base::Callback<void(bool success)>& callback,
bool success) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE, base::Bind(callback, success));
+ task_runner->PostTask(FROM_HERE, base::Bind(callback, success));
}
#endif // defined(OS_CHROMEOS)
@@ -37,14 +38,17 @@ void OnRequestUsbAccessReplied(
namespace usb_service {
-UsbDeviceImpl::UsbDeviceImpl(scoped_refptr<UsbContext> context,
- PlatformUsbDevice platform_device,
- uint16 vendor_id,
- uint16 product_id,
- uint32 unique_id)
+UsbDeviceImpl::UsbDeviceImpl(
+ scoped_refptr<UsbContext> context,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ PlatformUsbDevice platform_device,
+ uint16 vendor_id,
+ uint16 product_id,
+ uint32 unique_id)
: UsbDevice(vendor_id, product_id, unique_id),
platform_device_(platform_device),
- context_(context) {
+ context_(context),
+ ui_task_runner_(ui_task_runner) {
CHECK(platform_device) << "platform_device cannot be NULL";
libusb_ref_device(platform_device);
}
@@ -77,15 +81,16 @@ void UsbDeviceImpl::RequestUsbAccess(
return;
}
- BrowserThread::PostTask(
- BrowserThread::UI,
+ ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&chromeos::PermissionBrokerClient::RequestUsbAccess,
base::Unretained(client),
vendor_id(),
product_id(),
interface_id,
- base::Bind(&OnRequestUsbAccessReplied, callback)));
+ base::Bind(&OnRequestUsbAccessReplied,
+ base::ThreadTaskRunnerHandle::Get(),
+ callback)));
}
}
diff --git a/components/usb_service/usb_device_impl.h b/components/usb_service/usb_device_impl.h
index e27a692..07711bc 100644
--- a/components/usb_service/usb_device_impl.h
+++ b/components/usb_service/usb_device_impl.h
@@ -15,6 +15,10 @@
struct libusb_device;
struct libusb_config_descriptor;
+namespace base {
+class SingleThreadTaskRunner;
+}
+
namespace usb_service {
class UsbDeviceHandleImpl;
@@ -40,6 +44,7 @@ class UsbDeviceImpl : public UsbDevice {
// Called by UsbServiceImpl only;
UsbDeviceImpl(scoped_refptr<UsbContext> context,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
PlatformUsbDevice platform_device,
uint16 vendor_id,
uint16 product_id,
@@ -61,6 +66,9 @@ class UsbDeviceImpl : public UsbDevice {
typedef std::vector<scoped_refptr<UsbDeviceHandleImpl> > HandlesVector;
HandlesVector handles_;
+ // Reference to the UI thread for permission-broker calls.
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+
DISALLOW_COPY_AND_ASSIGN(UsbDeviceImpl);
};
diff --git a/components/usb_service/usb_service.h b/components/usb_service/usb_service.h
index 133cacd..11eac1a 100644
--- a/components/usb_service/usb_service.h
+++ b/components/usb_service/usb_service.h
@@ -12,6 +12,10 @@
#include "base/threading/non_thread_safe.h"
#include "components/usb_service/usb_service_export.h"
+namespace base {
+class SingleThreadTaskRunner;
+}
+
namespace usb_service {
class UsbDevice;
@@ -22,9 +26,12 @@ class UsbDevice;
// competition for the same USB device.
class USB_SERVICE_EXPORT UsbService : public base::NonThreadSafe {
public:
- // Must be called on FILE thread.
- // Returns NULL when failed to initialized.
- static UsbService* GetInstance();
+ // Must be called on a thread with a MessageLoopForIO (for example
+ // BrowserThread::FILE). The UI task runner reference is used to talk to the
+ // PermissionBrokerClient on ChromeOS (UI thread). Returns NULL when
+ // initialization fails.
+ static UsbService* GetInstance(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
static void SetInstanceForTest(UsbService* instance);
diff --git a/components/usb_service/usb_service_impl.cc b/components/usb_service/usb_service_impl.cc
index a77749e..051bead 100644
--- a/components/usb_service/usb_service_impl.cc
+++ b/components/usb_service/usb_service_impl.cc
@@ -9,11 +9,11 @@
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "components/usb_service/usb_context.h"
#include "components/usb_service/usb_device_impl.h"
#include "components/usb_service/usb_error.h"
-#include "content/public/browser/browser_thread.h"
#include "third_party/libusb/src/libusb/libusb.h"
namespace usb_service {
@@ -32,7 +32,9 @@ class UsbServiceImpl
: public UsbService,
private base::MessageLoop::DestructionObserver {
public:
- explicit UsbServiceImpl(PlatformUsbContext context);
+ explicit UsbServiceImpl(
+ PlatformUsbContext context,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
virtual ~UsbServiceImpl();
private:
@@ -48,6 +50,8 @@ class UsbServiceImpl
void RefreshDevices();
scoped_refptr<UsbContext> context_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
// TODO(ikarienator): Figure out a better solution.
uint32 next_unique_id_;
@@ -85,8 +89,12 @@ void UsbServiceImpl::WillDestroyCurrentMessageLoop() {
g_usb_service_instance.Get().reset(NULL);
}
-UsbServiceImpl::UsbServiceImpl(PlatformUsbContext context)
- : context_(new UsbContext(context)), next_unique_id_(0) {
+UsbServiceImpl::UsbServiceImpl(
+ PlatformUsbContext context,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+ : context_(new UsbContext(context)),
+ ui_task_runner_(ui_task_runner),
+ next_unique_id_(0) {
base::MessageLoop::current()->AddDestructionObserver(this);
}
@@ -124,6 +132,7 @@ void UsbServiceImpl::RefreshDevices() {
continue;
}
UsbDeviceImpl* new_device = new UsbDeviceImpl(context_,
+ ui_task_runner_,
platform_devices[i],
descriptor.idVendor,
descriptor.idProduct,
@@ -153,7 +162,8 @@ void UsbServiceImpl::RefreshDevices() {
}
// static
-UsbService* UsbService::GetInstance() {
+UsbService* UsbService::GetInstance(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
UsbService* instance = g_usb_service_instance.Get().get();
if (!instance) {
PlatformUsbContext context = NULL;
@@ -166,7 +176,7 @@ UsbService* UsbService::GetInstance() {
if (!context)
return NULL;
- instance = new UsbServiceImpl(context);
+ instance = new UsbServiceImpl(context, ui_task_runner);
g_usb_service_instance.Get().reset(instance);
}
return instance;
diff --git a/device/core/BUILD.gn b/device/core/BUILD.gn
new file mode 100644
index 0000000..7d1671f
--- /dev/null
+++ b/device/core/BUILD.gn
@@ -0,0 +1,10 @@
+# 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.
+
+source_set("core") {
+ sources = [
+ "device_client.cc",
+ "device_client.h",
+ ]
+}
diff --git a/device/core/core.gyp b/device/core/core.gyp
new file mode 100644
index 0000000..09bd315
--- /dev/null
+++ b/device/core/core.gyp
@@ -0,0 +1,22 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'device_core',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'device_client.cc',
+ 'device_client.h',
+ ],
+ },
+ ],
+}
diff --git a/device/core/device_client.cc b/device/core/device_client.cc
new file mode 100644
index 0000000..ad96b1e
--- /dev/null
+++ b/device/core/device_client.cc
@@ -0,0 +1,38 @@
+// 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 "device/core/device_client.h"
+
+#include "base/logging.h"
+
+namespace device {
+
+namespace {
+
+DeviceClient* g_instance = NULL;
+
+} // namespace
+
+DeviceClient::DeviceClient() {
+ DCHECK(!g_instance);
+ g_instance = this;
+}
+
+DeviceClient::~DeviceClient() {
+ g_instance = NULL;
+}
+
+/* static */
+DeviceClient* DeviceClient::Get() {
+ DCHECK(g_instance);
+ return g_instance;
+}
+
+usb_service::UsbService* DeviceClient::GetUsbService() {
+ // This should never be called by clients which do not support the USB API.
+ NOTREACHED();
+ return NULL;
+}
+
+} // namespace device
diff --git a/device/core/device_client.h b/device/core/device_client.h
new file mode 100644
index 0000000..d8d938b
--- /dev/null
+++ b/device/core/device_client.h
@@ -0,0 +1,39 @@
+// 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 DEVICE_CORE_DEVICE_CLIENT_H_
+#define DEVICE_CORE_DEVICE_CLIENT_H_
+
+#include "base/macros.h"
+
+namespace usb_service {
+class UsbService;
+}
+
+namespace device {
+
+// Interface used by consumers of //device APIs to get pointers to the service
+// singletons appropriate for a given embedding application. For an example see
+// //chrome/browser/chrome_device_client.h.
+class DeviceClient {
+ public:
+ // Construction sets the single instance.
+ DeviceClient();
+
+ // Destruction clears the single instance.
+ ~DeviceClient();
+
+ // Returns the single instance of |this|.
+ static DeviceClient* Get();
+
+ // Returns the UsbService instance for this embedder.
+ virtual usb_service::UsbService* GetUsbService();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeviceClient);
+};
+
+} // namespace device
+
+#endif // DEVICE_CORE_DEVICE_CLIENT_H_
diff --git a/device/test/usb_test_gadget_impl.cc b/device/test/usb_test_gadget_impl.cc
index 59a5faa..e95188b 100644
--- a/device/test/usb_test_gadget_impl.cc
+++ b/device/test/usb_test_gadget_impl.cc
@@ -155,7 +155,7 @@ UsbTestGadgetImpl::UsbTestGadgetImpl() {
session_id_ = base::StringPrintf(
"%s:%p", base::HexEncode(&process_id, sizeof(process_id)).c_str(), this);
- usb_service_ = UsbService::GetInstance();
+ usb_service_ = UsbService::GetInstance(NULL);
}
UsbTestGadgetImpl::~UsbTestGadgetImpl() {
diff --git a/extensions/browser/api/usb/DEPS b/extensions/browser/api/usb/DEPS
index 70ac41d..549aed6 100644
--- a/extensions/browser/api/usb/DEPS
+++ b/extensions/browser/api/usb/DEPS
@@ -1,3 +1,4 @@
include_rules = [
"+components/usb_service",
+ "+device/core"
]
diff --git a/extensions/browser/api/usb/usb_api.cc b/extensions/browser/api/usb/usb_api.cc
index 05cc15e..20ed117 100644
--- a/extensions/browser/api/usb/usb_api.cc
+++ b/extensions/browser/api/usb/usb_api.cc
@@ -11,6 +11,7 @@
#include "base/message_loop/message_loop_proxy.h"
#include "components/usb_service/usb_device_handle.h"
#include "components/usb_service/usb_service.h"
+#include "device/core/device_client.h"
#include "extensions/browser/api/usb/usb_device_resource.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/api/usb.h"
@@ -429,7 +430,7 @@ scoped_refptr<UsbDevice> UsbAsyncApiFunction::GetDeviceOrOrCompleteWithError(
return NULL;
}
- UsbService* service = UsbService::GetInstance();
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
if (!service) {
CompleteWithError(kErrorInitService);
return NULL;
@@ -560,7 +561,7 @@ void UsbFindDevicesFunction::AsyncWorkStart() {
return;
}
- UsbService* service = UsbService::GetInstance();
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
if (!service) {
CompleteWithError(kErrorInitService);
return;
@@ -636,7 +637,7 @@ void UsbGetDevicesFunction::AsyncWorkStart() {
return;
}
- UsbService* service = UsbService::GetInstance();
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
if (!service) {
CompleteWithError(kErrorInitService);
return;
diff --git a/extensions/browser/api/usb_private/DEPS b/extensions/browser/api/usb_private/DEPS
index d8eab5d..1afc5ec 100644
--- a/extensions/browser/api/usb_private/DEPS
+++ b/extensions/browser/api/usb_private/DEPS
@@ -1,4 +1,5 @@
include_rules = [
"+components/usb_service",
+ "+device/core",
"+device/usb",
]
diff --git a/extensions/browser/api/usb_private/usb_private_api.cc b/extensions/browser/api/usb_private/usb_private_api.cc
index 860a13a..22c11ba 100644
--- a/extensions/browser/api/usb_private/usb_private_api.cc
+++ b/extensions/browser/api/usb_private/usb_private_api.cc
@@ -12,6 +12,7 @@
#include "components/usb_service/usb_device_filter.h"
#include "components/usb_service/usb_device_handle.h"
#include "components/usb_service/usb_service.h"
+#include "device/core/device_client.h"
#include "device/usb/usb_ids.h"
#include "extensions/common/api/usb_private.h"
@@ -19,6 +20,7 @@ namespace usb_private = extensions::core_api::usb_private;
namespace GetDevices = usb_private::GetDevices;
namespace GetDeviceInfo = usb_private::GetDeviceInfo;
+using content::BrowserThread;
using usb_service::UsbDevice;
using usb_service::UsbDeviceFilter;
using usb_service::UsbDeviceHandle;
@@ -47,7 +49,7 @@ bool UsbPrivateGetDevicesFunction::Prepare() {
}
void UsbPrivateGetDevicesFunction::AsyncWorkStart() {
- UsbService* service = UsbService::GetInstance();
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
if (!service) {
CompleteWithError(kErrorInitService);
return;
@@ -117,7 +119,7 @@ bool UsbPrivateGetDeviceInfoFunction::Prepare() {
}
void UsbPrivateGetDeviceInfoFunction::AsyncWorkStart() {
- UsbService* service = UsbService::GetInstance();
+ UsbService* service = device::DeviceClient::Get()->GetUsbService();
if (!service) {
CompleteWithError(kErrorInitService);
return;
diff --git a/extensions/shell/app_shell.gyp b/extensions/shell/app_shell.gyp
index ca52ece..1df7adf5 100644
--- a/extensions/shell/app_shell.gyp
+++ b/extensions/shell/app_shell.gyp
@@ -22,6 +22,7 @@
'<(DEPTH)/content/content.gyp:content_gpu',
'<(DEPTH)/content/content.gyp:content_ppapi_plugin',
'<(DEPTH)/content/content_shell_and_tests.gyp:content_shell_lib',
+ '<(DEPTH)/device/core/core.gyp:device_core',
'<(DEPTH)/device/hid/hid.gyp:device_hid',
'<(DEPTH)/extensions/browser/api/api_registration.gyp:extensions_api_registration',
'<(DEPTH)/extensions/common/api/api.gyp:extensions_api',
@@ -71,6 +72,8 @@
'browser/shell_content_browser_client.h',
'browser/shell_desktop_controller.cc',
'browser/shell_desktop_controller.h',
+ 'browser/shell_device_client.cc',
+ 'browser/shell_device_client.h',
'browser/shell_extension_host_delegate.cc',
'browser/shell_extension_host_delegate.h',
'browser/shell_extension_system.cc',
diff --git a/extensions/shell/browser/DEPS b/extensions/shell/browser/DEPS
index 597cad0..a98697b 100644
--- a/extensions/shell/browser/DEPS
+++ b/extensions/shell/browser/DEPS
@@ -14,6 +14,8 @@ include_rules = [
"+content/shell/browser/shell_net_log.h",
# For device backend support.
+ "+components/usb_service",
+ "+device/core",
"+device/hid",
# Only used in API tests that should be moved to extensions/browser/api/...
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc
index 24f7e028..c11fd8e 100644
--- a/extensions/shell/browser/shell_browser_main_parts.cc
+++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -17,6 +17,7 @@
#include "extensions/shell/browser/shell_browser_context.h"
#include "extensions/shell/browser/shell_browser_main_delegate.h"
#include "extensions/shell/browser/shell_desktop_controller.h"
+#include "extensions/shell/browser/shell_device_client.h"
#include "extensions/shell/browser/shell_extension_system.h"
#include "extensions/shell/browser/shell_extension_system_factory.h"
#include "extensions/shell/browser/shell_extensions_browser_client.h"
@@ -105,6 +106,8 @@ void ShellBrowserMainParts::PreMainMessageLoopRun() {
// TODO(jamescook): Initialize user_manager::UserManager.
net_log_.reset(new content::ShellNetLog("app_shell"));
+ device_client_.reset(new ShellDeviceClient);
+
extensions_client_.reset(new ShellExtensionsClient());
ExtensionsClient::Set(extensions_client_.get());
diff --git a/extensions/shell/browser/shell_browser_main_parts.h b/extensions/shell/browser/shell_browser_main_parts.h
index e8e1b20..264a5f3 100644
--- a/extensions/shell/browser/shell_browser_main_parts.h
+++ b/extensions/shell/browser/shell_browser_main_parts.h
@@ -30,6 +30,7 @@ namespace extensions {
class DesktopController;
class ShellBrowserContext;
class ShellBrowserMainDelegate;
+class ShellDeviceClient;
class ShellExtensionsBrowserClient;
class ShellExtensionsClient;
class ShellExtensionSystem;
@@ -69,6 +70,7 @@ class ShellBrowserMainParts : public content::BrowserMainParts {
#endif
scoped_ptr<DesktopController> desktop_controller_;
scoped_ptr<ShellBrowserContext> browser_context_;
+ scoped_ptr<ShellDeviceClient> device_client_;
scoped_ptr<ShellExtensionsClient> extensions_client_;
scoped_ptr<ShellExtensionsBrowserClient> extensions_browser_client_;
scoped_ptr<net::NetLog> net_log_;
diff --git a/extensions/shell/browser/shell_device_client.cc b/extensions/shell/browser/shell_device_client.cc
new file mode 100644
index 0000000..3120c01
--- /dev/null
+++ b/extensions/shell/browser/shell_device_client.cc
@@ -0,0 +1,23 @@
+// 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 "extensions/shell/browser/shell_device_client.h"
+
+#include "base/logging.h"
+#include "components/usb_service/usb_service.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace extensions {
+
+ShellDeviceClient::ShellDeviceClient() {}
+
+ShellDeviceClient::~ShellDeviceClient() {}
+
+usb_service::UsbService* ShellDeviceClient::GetUsbService() {
+ return usb_service::UsbService::GetInstance(
+ content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::UI));
+}
+
+}
diff --git a/extensions/shell/browser/shell_device_client.h b/extensions/shell/browser/shell_device_client.h
new file mode 100644
index 0000000..d34e3ca
--- /dev/null
+++ b/extensions/shell/browser/shell_device_client.h
@@ -0,0 +1,31 @@
+// 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 EXTENSIONS_SHELL_BROWSER_SHELL_DEVICE_CLIENT_H_
+#define EXTENSIONS_SHELL_BROWSER_SHELL_DEVICE_CLIENT_H_
+
+#include "device/core/device_client.h"
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+
+namespace extensions {
+
+// Implementation of device::DeviceClient that returns //device API service
+// singletons appropriate for use within app shell.
+class ShellDeviceClient : device::DeviceClient {
+ public:
+ ShellDeviceClient();
+ virtual ~ShellDeviceClient();
+
+ // device::DeviceClient implementation
+ virtual usb_service::UsbService* GetUsbService() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShellDeviceClient);
+};
+
+}
+
+#endif // EXTENSIONS_SHELL_BROWSER_SHELL_DEVICE_CLIENT_H_