diff options
author | rockot <rockot@chromium.org> | 2015-06-10 22:53:58 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-11 05:54:35 +0000 |
commit | ed800dc138edfa261aa766281b96f736ff9824f6 (patch) | |
tree | acb8cf3be46d24537b8904c9fc2620c0e9b715a2 /device | |
parent | c39c3572e353b8120ae64aaf77d32f52598b740e (diff) | |
download | chromium_src-ed800dc138edfa261aa766281b96f736ff9824f6.zip chromium_src-ed800dc138edfa261aa766281b96f736ff9824f6.tar.gz chromium_src-ed800dc138edfa261aa766281b96f736ff9824f6.tar.bz2 |
Introduce the devices Mojo app
It's a small Mojo app that currently only hosts USB device
services. This CL adds the app along with an apptest suite
(run manually with mojo_runner mojo:devices_apptests).
The app is hooked up to Chrome to run in the browser process,
though there are currently no production code paths which
cause the app to launch.
BUG=498557
Review URL: https://codereview.chromium.org/1165223004
Cr-Commit-Position: refs/heads/master@{#333899}
Diffstat (limited to 'device')
-rw-r--r-- | device/core/device_client.cc | 4 | ||||
-rw-r--r-- | device/core/device_client.h | 5 | ||||
-rw-r--r-- | device/devices_app/BUILD.gn | 65 | ||||
-rw-r--r-- | device/devices_app/DEPS | 4 | ||||
-rw-r--r-- | device/devices_app/OWNERS | 2 | ||||
-rw-r--r-- | device/devices_app/devices_app.cc | 175 | ||||
-rw-r--r-- | device/devices_app/devices_app.gyp | 34 | ||||
-rw-r--r-- | device/devices_app/devices_app.h | 81 | ||||
-rw-r--r-- | device/devices_app/devices_apptest.cc | 56 | ||||
-rw-r--r-- | device/devices_app/main.cc | 14 | ||||
-rw-r--r-- | device/usb/BUILD.gn | 1 | ||||
-rw-r--r-- | device/usb/device_manager_impl.cc | 142 | ||||
-rw-r--r-- | device/usb/device_manager_impl.h | 30 | ||||
-rw-r--r-- | device/usb/device_manager_impl_unittest.cc | 49 | ||||
-rw-r--r-- | device/usb/public/cpp/BUILD.gn | 1 | ||||
-rw-r--r-- | device/usb/public/cpp/device_manager_factory.h | 34 | ||||
-rw-r--r-- | device/usb/usb_context.cc | 1 |
17 files changed, 558 insertions, 140 deletions
diff --git a/device/core/device_client.cc b/device/core/device_client.cc index 2aca216..5202122 100644 --- a/device/core/device_client.cc +++ b/device/core/device_client.cc @@ -35,10 +35,6 @@ UsbService* DeviceClient::GetUsbService() { return NULL; } -void DeviceClient::ConnectToUSBDeviceManager( - mojo::InterfaceRequest<usb::DeviceManager> request) { -} - HidService* DeviceClient::GetHidService() { // This should never be called by clients which do not support the HID API. NOTREACHED(); diff --git a/device/core/device_client.h b/device/core/device_client.h index 00fa179..300f4d6 100644 --- a/device/core/device_client.h +++ b/device/core/device_client.h @@ -34,11 +34,6 @@ class DeviceClient { // Returns the UsbService instance for this embedder. virtual UsbService* GetUsbService(); - // Connects a USB DeviceManager client to a concrete implementation. If - // no such implementation is available the request is dropped. - virtual void ConnectToUSBDeviceManager( - mojo::InterfaceRequest<usb::DeviceManager> request); - // Returns the HidService instance for this embedder. virtual HidService* GetHidService(); diff --git a/device/devices_app/BUILD.gn b/device/devices_app/BUILD.gn new file mode 100644 index 0000000..fa9bd90 --- /dev/null +++ b/device/devices_app/BUILD.gn @@ -0,0 +1,65 @@ +# Copyright 2015 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. + +import("//mojo/public/mojo_application.gni") + +source_set("lib") { + sources = [ + "devices_app.cc", + "devices_app.h", + ] + + deps = [ + "//device/core", + "//device/usb", + "//device/usb/public/cpp", + "//device/usb/public/interfaces", + "//third_party/mojo/src/mojo/public/cpp/bindings", + "//url", + ] + + public_deps = [ + "//base", + "//mojo/application/public/cpp", + "//mojo/application/public/interfaces", + ] +} + +mojo_native_application("devices") { + sources = [ + "main.cc", + ] + + deps = [ + ":lib", + "//base", + "//mojo/application/public/cpp", + ] + + public_deps = [ + ":lib", + ] +} + +mojo_native_application("apptests") { + output_name = "devices_apptests" + + testonly = true + + sources = [ + "devices_apptest.cc", + ] + + deps = [ + "//base", + "//mojo/application/public/cpp:test_support", + ] + + public_deps = [ + ":lib", + "//device/usb/public/interfaces", + ] + + data_deps = [ ":devices" ] +} diff --git a/device/devices_app/DEPS b/device/devices_app/DEPS new file mode 100644 index 0000000..8fbdc29 --- /dev/null +++ b/device/devices_app/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+mojo/application/public", + "+mojo/common", +] diff --git a/device/devices_app/OWNERS b/device/devices_app/OWNERS new file mode 100644 index 0000000..b16946a --- /dev/null +++ b/device/devices_app/OWNERS @@ -0,0 +1,2 @@ +reillyg@chromium.org +rockot@chromium.org diff --git a/device/devices_app/devices_app.cc b/device/devices_app/devices_app.cc new file mode 100644 index 0000000..5d54310 --- /dev/null +++ b/device/devices_app/devices_app.cc @@ -0,0 +1,175 @@ +// Copyright 2015 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/devices_app/devices_app.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/sequenced_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "base/threading/thread.h" +#include "base/time/time.h" +#include "device/core/device_client.h" +#include "device/usb/device_manager_impl.h" +#include "device/usb/public/cpp/device_manager_delegate.h" +#include "device/usb/usb_service.h" +#include "mojo/application/public/cpp/application_connection.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" +#include "url/gurl.h" + +namespace device { + +const char kDevicesMojoAppUrl[] = "system:devices"; + +namespace { + +// The number of seconds to wait without any bound DeviceManagers before +// exiting the app. +const int64 kIdleTimeoutInSeconds = 10; + +// A usb::DeviceManagerDelegate implementation which provides origin-based +// device access control. +class USBDeviceManagerDelegate : public usb::DeviceManagerDelegate { + public: + explicit USBDeviceManagerDelegate(const GURL& remote_url) + : remote_url_(remote_url) {} + ~USBDeviceManagerDelegate() override {} + + private: + // usb::DeviceManagerDelegate: + bool IsDeviceAllowed(const usb::DeviceInfo& device) override { + // Limited set of conditions to allow localhost connection for testing. This + // does not presume to catch all common local host strings. + if (remote_url_.host() == "127.0.0.1" || remote_url_.host() == "localhost") + return true; + + // Also let browser apps and mojo apptests talk to all devices. + if (remote_url_.SchemeIs("system") || + remote_url_ == GURL("mojo://devices_apptests/")) + return true; + + // TODO(rockot/reillyg): Implement origin-based device access control. + return false; + } + + GURL remote_url_; + + DISALLOW_COPY_AND_ASSIGN(USBDeviceManagerDelegate); +}; + +// A DeviceClient implementation to be constructed iff the app is not running +// in an embedder that provides a DeviceClient (i.e. running as a standalone +// Mojo app, not in Chrome). +class AppDeviceClient : public DeviceClient { + public: + explicit AppDeviceClient( + scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) + : usb_service_(UsbService::GetInstance(blocking_task_runner)) {} + ~AppDeviceClient() override {} + + private: + // DeviceClient: + UsbService* GetUsbService() override { return usb_service_; } + + UsbService* usb_service_; +}; + +} // namespace + +// This class insures that a UsbService has been initialized and is accessible +// via the DeviceClient interface. +class DevicesApp::USBServiceInitializer { + public: + USBServiceInitializer() + : blocking_thread_("USB service blocking I/O thread") { + blocking_thread_.Start(); + app_device_client_.reset( + new AppDeviceClient(blocking_thread_.task_runner())); + } + + ~USBServiceInitializer() {} + + private: + scoped_ptr<AppDeviceClient> app_device_client_; + base::Thread blocking_thread_; + + DISALLOW_COPY_AND_ASSIGN(USBServiceInitializer); +}; + +DevicesApp::~DevicesApp() { +} + +// static +scoped_ptr<mojo::ApplicationDelegate> DevicesApp::CreateDelegate( + scoped_refptr<base::SequencedTaskRunner> service_task_runner) { + return scoped_ptr<mojo::ApplicationDelegate>( + new DevicesApp(service_task_runner)); +} + +DevicesApp::DevicesApp( + scoped_refptr<base::SequencedTaskRunner> service_task_runner) + : app_impl_(nullptr), + service_task_runner_(service_task_runner), + active_device_manager_count_(0) { +} + +void DevicesApp::Initialize(mojo::ApplicationImpl* app) { + app_impl_ = app; + if (!service_task_runner_) { + service_initializer_.reset(new USBServiceInitializer); + service_task_runner_ = base::ThreadTaskRunnerHandle::Get(); + } + StartIdleTimer(); +} + +bool DevicesApp::ConfigureIncomingConnection( + mojo::ApplicationConnection* connection) { + connection->AddService<usb::DeviceManager>(this); + return true; +} + +void DevicesApp::Quit() { + service_initializer_.reset(); + app_impl_ = nullptr; +} + +void DevicesApp::Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<usb::DeviceManager> request) { + scoped_ptr<usb::DeviceManagerDelegate> delegate(new USBDeviceManagerDelegate( + GURL(connection->GetRemoteApplicationURL()))); + + // Owned by its message pipe. + usb::DeviceManagerImpl* device_manager = new usb::DeviceManagerImpl( + request.Pass(), delegate.Pass(), service_task_runner_); + device_manager->set_error_handler(this); + + active_device_manager_count_++; + idle_timeout_callback_.Cancel(); +} + +void DevicesApp::OnConnectionError() { + DCHECK_GE(active_device_manager_count_, 0u); + active_device_manager_count_--; + if (active_device_manager_count_ == 0) { + // If the last DeviceManager connection has been dropped, kick off an idle + // timeout to shut ourselves down. + StartIdleTimer(); + } +} + +void DevicesApp::StartIdleTimer() { + // Passing unretained |app_impl_| is safe here because |app_impl_| is + // guaranteed to outlive |this|, and the callback is canceled if |this| is + // destroyed. + idle_timeout_callback_.Reset(base::Bind(&mojo::ApplicationImpl::Terminate, + base::Unretained(app_impl_))); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, idle_timeout_callback_.callback(), + base::TimeDelta::FromSeconds(kIdleTimeoutInSeconds)); +} + +} // namespace device diff --git a/device/devices_app/devices_app.gyp b/device/devices_app/devices_app.gyp new file mode 100644 index 0000000..ac747f3 --- /dev/null +++ b/device/devices_app/devices_app.gyp @@ -0,0 +1,34 @@ +# 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': 'devices_app_lib', + 'type': 'static_library', + 'include_dirs': [ + '../..', + ], + 'sources': [ + 'devices_app.cc', + 'devices_app.h', + ], + 'dependencies': [ + '<(DEPTH)/device/usb/usb.gyp:device_usb', + '<(DEPTH)/device/usb/usb.gyp:device_usb_mojo_bindings_lib', + '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_base', + '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings', + '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings', + ], + 'export_dependent_settings': [ + '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_base', + '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings', + '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings', + ], + }, + ], +} diff --git a/device/devices_app/devices_app.h b/device/devices_app/devices_app.h new file mode 100644 index 0000000..4b04568 --- /dev/null +++ b/device/devices_app/devices_app.h @@ -0,0 +1,81 @@ +// Copyright 2015 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_DEVICES_DEVICES_APP_H_ +#define DEVICE_DEVICES_DEVICES_APP_H_ + +#include "base/cancelable_callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/cpp/interface_factory.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h" + +namespace base { +class SequencedTaskRunner; +} + +namespace mojo { +class ApplicationImpl; +} + +namespace device { + +namespace usb { +class DeviceManager; +} + +extern const char kDevicesMojoAppUrl[]; + +class DevicesApp : public mojo::ApplicationDelegate, + public mojo::InterfaceFactory<usb::DeviceManager>, + public mojo::ErrorHandler { + public: + ~DevicesApp() override; + + // |service_task_runner| is the thread TaskRunner on which the UsbService + // lives. This argument should be removed once UsbService is owned by the + // USB device manager and no longer part of the public device API. If null, + // the app will construct its own DeviceClient and UsbService. + static scoped_ptr<mojo::ApplicationDelegate> CreateDelegate( + scoped_refptr<base::SequencedTaskRunner> service_task_runner); + + private: + class USBServiceInitializer; + + DevicesApp(scoped_refptr<base::SequencedTaskRunner> service_task_runner); + + // mojo::ApplicationDelegate: + void Initialize(mojo::ApplicationImpl* app) override; + bool ConfigureIncomingConnection( + mojo::ApplicationConnection* connection) override; + void Quit() override; + + // mojo::InterfaceFactory<usb::DeviceManager>: + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<usb::DeviceManager> request) override; + + // mojo::ErrorHandler: + void OnConnectionError() override; + + // Sets the app for destruction after a period of idle time. If any top-level + // services (e.g. usb::DeviceManager) are bound before the timeout elapses, + // it's canceled. + void StartIdleTimer(); + + mojo::ApplicationImpl* app_impl_; + scoped_ptr<USBServiceInitializer> service_initializer_; + scoped_refptr<base::SequencedTaskRunner> service_task_runner_; + size_t active_device_manager_count_; + + // Callback used to shut down the app after a period of inactivity. + base::CancelableClosure idle_timeout_callback_; + + DISALLOW_COPY_AND_ASSIGN(DevicesApp); +}; + +} // naespace device + +#endif // DEVICE_DEVICES_DEVICES_APP_H_ diff --git a/device/devices_app/devices_apptest.cc b/device/devices_app/devices_apptest.cc new file mode 100644 index 0000000..f466381 --- /dev/null +++ b/device/devices_app/devices_apptest.cc @@ -0,0 +1,56 @@ +// Copyright 2015 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 "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/run_loop.h" +#include "device/devices_app/devices_app.h" +#include "device/usb/public/interfaces/device_manager.mojom.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "mojo/application/public/cpp/application_test_base.h" + +namespace device { +namespace { + +class DevicesAppTest : public mojo::test::ApplicationTestBase { + public: + DevicesAppTest() {} + ~DevicesAppTest() override {} + + void SetUp() override { + ApplicationTestBase::SetUp(); + mojo::URLRequestPtr request = mojo::URLRequest::New(); + request->url = "mojo:devices"; + application_impl()->ConnectToService(request.Pass(), &usb_device_manager_); + } + + usb::DeviceManager* usb_device_manager() { return usb_device_manager_.get(); } + + private: + usb::DeviceManagerPtr usb_device_manager_; + + DISALLOW_COPY_AND_ASSIGN(DevicesAppTest); +}; + +void OnGetDevices(const base::Closure& continuation, + mojo::Array<usb::DeviceInfoPtr> devices) { + continuation.Run(); +} + +} // namespace + +// Simple test to verify that we can connect to the USB DeviceManager and get +// a response. +TEST_F(DevicesAppTest, GetUSBDevices) { + base::RunLoop loop; + usb::EnumerationOptionsPtr options = usb::EnumerationOptions::New(); + options->filters = mojo::Array<usb::DeviceFilterPtr>(1); + options->filters[0] = usb::DeviceFilter::New(); + usb_device_manager()->GetDevices( + options.Pass(), base::Bind(&OnGetDevices, loop.QuitClosure())); + loop.Run(); +} + +} // namespace device diff --git a/device/devices_app/main.cc b/device/devices_app/main.cc new file mode 100644 index 0000000..e82edb3 --- /dev/null +++ b/device/devices_app/main.cc @@ -0,0 +1,14 @@ +// Copyright 2015 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 "base/sequenced_task_runner.h" +#include "device/devices_app/devices_app.h" +#include "mojo/application/public/cpp/application_runner.h" +#include "third_party/mojo/src/mojo/public/c/system/main.h" + +MojoResult MojoMain(MojoHandle shell_handle) { + mojo::ApplicationRunner runner( + device::DevicesApp::CreateDelegate(nullptr).release()); + return runner.Run(shell_handle); +} diff --git a/device/usb/BUILD.gn b/device/usb/BUILD.gn index ea0248a..71b593f 100644 --- a/device/usb/BUILD.gn +++ b/device/usb/BUILD.gn @@ -49,7 +49,6 @@ source_set("usb") { "//mojo/environment:chromium", "//net", "//third_party/libusb", - "//third_party/mojo/src/mojo/edk/system", ] public_deps = [ diff --git a/device/usb/device_manager_impl.cc b/device/usb/device_manager_impl.cc index bf444a4..166c8a0 100644 --- a/device/usb/device_manager_impl.cc +++ b/device/usb/device_manager_impl.cc @@ -5,11 +5,13 @@ #include "device/usb/device_manager_impl.h" #include "base/bind.h" +#include "base/location.h" #include "base/memory/scoped_ptr.h" +#include "base/sequenced_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "device/core/device_client.h" #include "device/usb/device_impl.h" #include "device/usb/public/cpp/device_manager_delegate.h" -#include "device/usb/public/cpp/device_manager_factory.h" #include "device/usb/public/interfaces/device.mojom.h" #include "device/usb/type_converters.h" #include "device/usb/usb_device.h" @@ -21,64 +23,123 @@ namespace device { namespace usb { -// static -void DeviceManagerFactory::Build(mojo::InterfaceRequest<DeviceManager> request, - scoped_ptr<DeviceManagerDelegate> delegate) { +namespace { + +void OnGetDevicesOnServiceThread( + const UsbService::GetDevicesCallback& callback, + scoped_refptr<base::TaskRunner> callback_task_runner, + const std::vector<scoped_refptr<UsbDevice>>& devices) { + callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); +} + +void GetDevicesOnServiceThread( + const UsbService::GetDevicesCallback& callback, + scoped_refptr<base::TaskRunner> callback_task_runner) { + DCHECK(DeviceClient::Get()); + UsbService* usb_service = DeviceClient::Get()->GetUsbService(); + if (!usb_service) { + std::vector<scoped_refptr<UsbDevice>> no_devices; + callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, no_devices)); + return; + } + usb_service->GetDevices( + base::Bind(&OnGetDevicesOnServiceThread, callback, callback_task_runner)); +} + +void RunOpenDeviceCallback(const DeviceManager::OpenDeviceCallback& callback, + OpenDeviceError error) { + callback.Run(error); +} + +void OnOpenDeviceOnServiceThread( + mojo::InterfaceRequest<Device> device_request, + const DeviceManager::OpenDeviceCallback& callback, + scoped_refptr<base::TaskRunner> callback_task_runner, + scoped_refptr<UsbDeviceHandle> device_handle) { + if (!device_handle) { + callback_task_runner->PostTask(FROM_HERE, + base::Bind(&RunOpenDeviceCallback, callback, + OPEN_DEVICE_ERROR_ACCESS_DENIED)); + return; + } + // Owned by its MessagePipe. - new DeviceManagerImpl(request.Pass(), delegate.Pass()); + new DeviceImpl(device_handle, device_request.Pass()); + + callback_task_runner->PostTask( + FROM_HERE, + base::Bind(&RunOpenDeviceCallback, callback, OPEN_DEVICE_ERROR_OK)); } +void OpenDeviceOnServiceThread( + const std::string& guid, + mojo::InterfaceRequest<Device> device_request, + const DeviceManager::OpenDeviceCallback& callback, + scoped_refptr<base::TaskRunner> callback_task_runner) { + DCHECK(DeviceClient::Get()); + UsbService* usb_service = DeviceClient::Get()->GetUsbService(); + if (!usb_service) { + callback_task_runner->PostTask(FROM_HERE, + base::Bind(&RunOpenDeviceCallback, callback, + OPEN_DEVICE_ERROR_NOT_FOUND)); + return; + } + scoped_refptr<UsbDevice> device = usb_service->GetDevice(guid); + if (!device) { + callback_task_runner->PostTask(FROM_HERE, + base::Bind(&RunOpenDeviceCallback, callback, + OPEN_DEVICE_ERROR_NOT_FOUND)); + return; + } + device->Open(base::Bind(&OnOpenDeviceOnServiceThread, + base::Passed(&device_request), callback, + callback_task_runner)); +} + +} // namespace + DeviceManagerImpl::DeviceManagerImpl( mojo::InterfaceRequest<DeviceManager> request, - scoped_ptr<DeviceManagerDelegate> delegate) + scoped_ptr<DeviceManagerDelegate> delegate, + scoped_refptr<base::SequencedTaskRunner> service_task_runner) : binding_(this, request.Pass()), delegate_(delegate.Pass()), + service_task_runner_(service_task_runner), weak_factory_(this) { } DeviceManagerImpl::~DeviceManagerImpl() { } +void DeviceManagerImpl::set_error_handler(mojo::ErrorHandler* error_handler) { + binding_.set_error_handler(error_handler); +} + void DeviceManagerImpl::GetDevices(EnumerationOptionsPtr options, const GetDevicesCallback& callback) { - DCHECK(DeviceClient::Get()); - UsbService* usb_service = DeviceClient::Get()->GetUsbService(); - if (!usb_service) { - mojo::Array<DeviceInfoPtr> results(0); - callback.Run(results.Pass()); - return; - } - std::vector<UsbDeviceFilter> filters = - options->filters.To<std::vector<UsbDeviceFilter>>(); - usb_service->GetDevices(base::Bind(&DeviceManagerImpl::OnGetDevices, - weak_factory_.GetWeakPtr(), callback, - filters)); + auto get_devices_callback = + base::Bind(&DeviceManagerImpl::OnGetDevices, weak_factory_.GetWeakPtr(), + base::Passed(&options), callback); + service_task_runner_->PostTask( + FROM_HERE, base::Bind(&GetDevicesOnServiceThread, get_devices_callback, + base::ThreadTaskRunnerHandle::Get())); } void DeviceManagerImpl::OpenDevice( const mojo::String& guid, mojo::InterfaceRequest<Device> device_request, const OpenDeviceCallback& callback) { - DCHECK(DeviceClient::Get()); - UsbService* usb_service = DeviceClient::Get()->GetUsbService(); - if (!usb_service) { - callback.Run(OPEN_DEVICE_ERROR_NOT_FOUND); - return; - } - scoped_refptr<UsbDevice> device = usb_service->GetDevice(guid); - if (!device) { - callback.Run(OPEN_DEVICE_ERROR_NOT_FOUND); - return; - } - device->Open(base::Bind(&DeviceManagerImpl::OnOpenDevice, - weak_factory_.GetWeakPtr(), callback, - base::Passed(&device_request))); + service_task_runner_->PostTask( + FROM_HERE, base::Bind(&OpenDeviceOnServiceThread, guid, + base::Passed(&device_request), callback, + base::ThreadTaskRunnerHandle::Get())); } void DeviceManagerImpl::OnGetDevices( + EnumerationOptionsPtr options, const GetDevicesCallback& callback, - const std::vector<UsbDeviceFilter>& filters, const std::vector<scoped_refptr<UsbDevice>>& devices) { + auto filters = options->filters.To<std::vector<UsbDeviceFilter>>(); mojo::Array<DeviceInfoPtr> device_infos(0); for (size_t i = 0; i < devices.size(); ++i) { DeviceInfoPtr device_info = DeviceInfo::From(*devices[i]); @@ -94,20 +155,5 @@ void DeviceManagerImpl::OnGetDevices( callback.Run(device_infos.Pass()); } -void DeviceManagerImpl::OnOpenDevice( - const OpenDeviceCallback& callback, - mojo::InterfaceRequest<Device> device_request, - scoped_refptr<UsbDeviceHandle> device_handle) { - if (!device_handle) { - callback.Run(OPEN_DEVICE_ERROR_ACCESS_DENIED); - return; - } - - // Owned by its MessagePipe. - new DeviceImpl(device_handle, device_request.Pass()); - - callback.Run(OPEN_DEVICE_ERROR_OK); -} - } // namespace usb } // namespace device diff --git a/device/usb/device_manager_impl.h b/device/usb/device_manager_impl.h index 5c77a65..7be09ff 100644 --- a/device/usb/device_manager_impl.h +++ b/device/usb/device_manager_impl.h @@ -15,6 +15,14 @@ #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h" +namespace base { +class SequencedTaskRunner; +} + +namespace mojo { +class ErrorHandler; +} + namespace device { class UsbDevice; @@ -25,14 +33,18 @@ namespace usb { class DeviceManagerDelegate; -// Implementation of the public DeviceManager interface. Clients in the browser -// can connect to this service via DeviceClient::ConnectToUSBDeviceManager. +// Implementation of the public DeviceManager interface. This interface can be +// requested from the devices app located at "system:devices", if available. class DeviceManagerImpl : public DeviceManager { public: - DeviceManagerImpl(mojo::InterfaceRequest<DeviceManager> request, - scoped_ptr<DeviceManagerDelegate> delegate); + DeviceManagerImpl( + mojo::InterfaceRequest<DeviceManager> request, + scoped_ptr<DeviceManagerDelegate> delegate, + scoped_refptr<base::SequencedTaskRunner> service_task_runner); ~DeviceManagerImpl() override; + void set_error_handler(mojo::ErrorHandler* error_handler); + private: // DeviceManager implementation: void GetDevices(EnumerationOptionsPtr options, @@ -42,18 +54,14 @@ class DeviceManagerImpl : public DeviceManager { const OpenDeviceCallback& callback) override; // Callback to handle the async response from the underlying UsbService. - void OnGetDevices(const GetDevicesCallback& callback, - const std::vector<UsbDeviceFilter>& filters, + void OnGetDevices(EnumerationOptionsPtr options, + const GetDevicesCallback& callback, const std::vector<scoped_refptr<UsbDevice>>& devices); - // Callback to handle the async Open response from a UsbDevice. - void OnOpenDevice(const OpenDeviceCallback& callback, - mojo::InterfaceRequest<Device> device_request, - scoped_refptr<UsbDeviceHandle> device_handle); - mojo::StrongBinding<DeviceManager> binding_; scoped_ptr<DeviceManagerDelegate> delegate_; + scoped_refptr<base::SequencedTaskRunner> service_task_runner_; base::WeakPtrFactory<DeviceManagerImpl> weak_factory_; diff --git a/device/usb/device_manager_impl_unittest.cc b/device/usb/device_manager_impl_unittest.cc index f0ce167..7854619 100644 --- a/device/usb/device_manager_impl_unittest.cc +++ b/device/usb/device_manager_impl_unittest.cc @@ -10,6 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/thread_task_runner_handle.h" #include "device/core/device_client.h" #include "device/usb/device_impl.h" #include "device/usb/device_manager_impl.h" @@ -17,7 +18,6 @@ #include "device/usb/mock_usb_device_handle.h" #include "device/usb/mock_usb_service.h" #include "device/usb/public/cpp/device_manager_delegate.h" -#include "device/usb/public/cpp/device_manager_factory.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" @@ -30,51 +30,27 @@ namespace usb { namespace { -bool DefaultDelegateFilter(const DeviceInfo& device_info) { - return true; -} - class TestDeviceManagerDelegate : public DeviceManagerDelegate { public: - using Filter = base::Callback<bool(const DeviceInfo&)>; - - TestDeviceManagerDelegate(const Filter& filter) : filter_(filter) {} + TestDeviceManagerDelegate() {} ~TestDeviceManagerDelegate() override {} - void set_filter(const Filter& filter) { filter_ = filter; } - private: // DeviceManagerDelegate implementation: - bool IsDeviceAllowed(const DeviceInfo& device_info) override { - return filter_.Run(device_info); - } - - Filter filter_; + bool IsDeviceAllowed(const DeviceInfo& device_info) override { return true; } }; class TestDeviceClient : public DeviceClient { public: - TestDeviceClient() : delegate_filter_(base::Bind(&DefaultDelegateFilter)) {} + TestDeviceClient() {} ~TestDeviceClient() override {} MockUsbService& mock_usb_service() { return mock_usb_service_; } - void SetDelegateFilter(const TestDeviceManagerDelegate::Filter& filter) { - delegate_filter_ = filter; - } - private: // DeviceClient implementation: UsbService* GetUsbService() override { return &mock_usb_service_; } - void ConnectToUSBDeviceManager( - mojo::InterfaceRequest<DeviceManager> request) override { - new DeviceManagerImpl(request.Pass(), - scoped_ptr<DeviceManagerDelegate>( - new TestDeviceManagerDelegate(delegate_filter_))); - } - - TestDeviceManagerDelegate::Filter delegate_filter_; MockUsbService mock_usb_service_; }; @@ -90,8 +66,13 @@ class USBDeviceManagerImplTest : public testing::Test { return device_client_->mock_usb_service(); } - void SetDelegateFilter(const TestDeviceManagerDelegate::Filter& filter) { - device_client_->SetDelegateFilter(filter); + DeviceManagerPtr ConnectToDeviceManager() { + DeviceManagerPtr device_manager; + new DeviceManagerImpl( + mojo::GetProxy(&device_manager), + scoped_ptr<DeviceManagerDelegate>(new TestDeviceManagerDelegate), + base::ThreadTaskRunnerHandle::Get()); + return device_manager.Pass(); } private: @@ -175,9 +156,7 @@ TEST_F(USBDeviceManagerImplTest, GetDevices) { mock_usb_service().AddDevice(device1); mock_usb_service().AddDevice(device2); - DeviceManagerPtr device_manager; - DeviceClient::Get()->ConnectToUSBDeviceManager( - mojo::GetProxy(&device_manager)); + DeviceManagerPtr device_manager = ConnectToDeviceManager(); EnumerationOptionsPtr options = EnumerationOptions::New(); options->filters = mojo::Array<DeviceFilterPtr>::New(1); @@ -209,9 +188,7 @@ TEST_F(USBDeviceManagerImplTest, OpenDevice) { mock_usb_service().AddDevice(mock_device); - DeviceManagerPtr device_manager; - DeviceClient::Get()->ConnectToUSBDeviceManager( - mojo::GetProxy(&device_manager)); + DeviceManagerPtr device_manager = ConnectToDeviceManager(); // Should be called on the mock as a result of OpenDevice() below. EXPECT_CALL(*mock_device.get(), Open(_)); diff --git a/device/usb/public/cpp/BUILD.gn b/device/usb/public/cpp/BUILD.gn index 43cea68..06480ea 100644 --- a/device/usb/public/cpp/BUILD.gn +++ b/device/usb/public/cpp/BUILD.gn @@ -5,7 +5,6 @@ source_set("cpp") { sources = [ "device_manager_delegate.h", - "device_manager_factory.h", ] public_deps = [ diff --git a/device/usb/public/cpp/device_manager_factory.h b/device/usb/public/cpp/device_manager_factory.h deleted file mode 100644 index 51f9727..0000000 --- a/device/usb/public/cpp/device_manager_factory.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015 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_USB_PUBLIC_CPP_DEVICE_MANAGER_FACTORY_H_ -#define DEVICE_USB_PUBLIC_CPP_DEVICE_MANAGER_FACTORY_H_ - -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "device/usb/public/interfaces/device_manager.mojom.h" -#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" - -namespace device { -namespace usb { - -class DeviceManagerDelegate; - -// Public interface to construct an implementation of the DeviceManager service. -class DeviceManagerFactory { - public: - // Builds a new DeviceManager instance to fulfill a request. The service is - // bound to the lifetime of |request|'s MessagePipe, and it takes ownership of - // |delegate|. - static void Build(mojo::InterfaceRequest<DeviceManager> request, - scoped_ptr<DeviceManagerDelegate> delegate); - - private: - DISALLOW_COPY_AND_ASSIGN(DeviceManagerFactory); -}; - -} // namespace usb -} // namespace device - -#endif // DEVICE_USB_PUBLIC_CPP_DEVICE_MANAGER_FACTORY_H_ diff --git a/device/usb/usb_context.cc b/device/usb/usb_context.cc index 7661469..99b76ab 100644 --- a/device/usb/usb_context.cc +++ b/device/usb/usb_context.cc @@ -63,6 +63,7 @@ void UsbContext::UsbEventHandler::ThreadMain() { void UsbContext::UsbEventHandler::Stop() { base::subtle::Release_Store(&running_, 0); libusb_interrupt_handle_event(context_); + base::PlatformThread::Join(thread_handle_); } UsbContext::UsbContext(PlatformUsbContext context) : context_(context) { |