OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "device/devices_app/devices_app.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/callback.h" |
| 9 #include "base/macros.h" |
| 10 #include "base/sequenced_task_runner.h" |
| 11 #include "base/thread_task_runner_handle.h" |
| 12 #include "base/threading/thread.h" |
| 13 #include "base/time/time.h" |
| 14 #include "device/core/device_client.h" |
| 15 #include "device/devices_app/usb/device_manager_impl.h" |
| 16 #include "device/devices_app/usb/public/cpp/device_manager_delegate.h" |
| 17 #include "device/usb/usb_service.h" |
| 18 #include "mojo/application/public/cpp/application_connection.h" |
| 19 #include "mojo/application/public/cpp/application_impl.h" |
| 20 #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h" |
| 21 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" |
| 22 #include "url/gurl.h" |
| 23 |
| 24 namespace device { |
| 25 |
| 26 const char kDevicesMojoAppUrl[] = "system:devices"; |
| 27 |
| 28 namespace { |
| 29 |
| 30 // The number of seconds to wait without any bound DeviceManagers before |
| 31 // exiting the app. |
| 32 const int64 kIdleTimeoutInSeconds = 10; |
| 33 |
| 34 // A usb::DeviceManagerDelegate implementation which provides origin-based |
| 35 // device access control. |
| 36 class USBDeviceManagerDelegate : public usb::DeviceManagerDelegate { |
| 37 public: |
| 38 explicit USBDeviceManagerDelegate(const GURL& remote_url) |
| 39 : remote_url_(remote_url) {} |
| 40 ~USBDeviceManagerDelegate() override {} |
| 41 |
| 42 private: |
| 43 // usb::DeviceManagerDelegate: |
| 44 bool IsDeviceAllowed(const usb::DeviceInfo& device) override { |
| 45 // Limited set of conditions to allow localhost connection for testing. This |
| 46 // does not presume to catch all common local host strings. |
| 47 if (remote_url_.host() == "127.0.0.1" || remote_url_.host() == "localhost") |
| 48 return true; |
| 49 |
| 50 // Also let browser apps and mojo apptests talk to all devices. |
| 51 if (remote_url_.SchemeIs("system") || |
| 52 remote_url_ == GURL("mojo://devices_apptests/")) |
| 53 return true; |
| 54 |
| 55 // TODO(rockot/reillyg): Implement origin-based device access control. |
| 56 return false; |
| 57 } |
| 58 |
| 59 GURL remote_url_; |
| 60 |
| 61 DISALLOW_COPY_AND_ASSIGN(USBDeviceManagerDelegate); |
| 62 }; |
| 63 |
| 64 // A DeviceClient implementation to be constructed iff the app is not running |
| 65 // in an embedder that provides a DeviceClient (i.e. running as a standalone |
| 66 // Mojo app, not in Chrome). |
| 67 class AppDeviceClient : public DeviceClient { |
| 68 public: |
| 69 explicit AppDeviceClient( |
| 70 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) |
| 71 : usb_service_(UsbService::GetInstance(blocking_task_runner)) {} |
| 72 ~AppDeviceClient() override {} |
| 73 |
| 74 private: |
| 75 // DeviceClient: |
| 76 UsbService* GetUsbService() override { return usb_service_; } |
| 77 |
| 78 UsbService* usb_service_; |
| 79 }; |
| 80 |
| 81 } // namespace |
| 82 |
| 83 // This class insures that a UsbService has been initialized and is accessible |
| 84 // via the DeviceClient interface. |
| 85 class DevicesApp::USBServiceInitializer { |
| 86 public: |
| 87 USBServiceInitializer() |
| 88 : blocking_thread_("USB service blocking I/O thread") { |
| 89 blocking_thread_.Start(); |
| 90 app_device_client_.reset( |
| 91 new AppDeviceClient(blocking_thread_.task_runner())); |
| 92 } |
| 93 |
| 94 ~USBServiceInitializer() {} |
| 95 |
| 96 private: |
| 97 scoped_ptr<AppDeviceClient> app_device_client_; |
| 98 base::Thread blocking_thread_; |
| 99 |
| 100 DISALLOW_COPY_AND_ASSIGN(USBServiceInitializer); |
| 101 }; |
| 102 |
| 103 DevicesApp::~DevicesApp() { |
| 104 } |
| 105 |
| 106 // static |
| 107 scoped_ptr<mojo::ApplicationDelegate> DevicesApp::CreateDelegate( |
| 108 scoped_refptr<base::SequencedTaskRunner> service_task_runner) { |
| 109 return scoped_ptr<mojo::ApplicationDelegate>( |
| 110 new DevicesApp(service_task_runner)); |
| 111 } |
| 112 |
| 113 DevicesApp::DevicesApp( |
| 114 scoped_refptr<base::SequencedTaskRunner> service_task_runner) |
| 115 : app_impl_(nullptr), |
| 116 service_task_runner_(service_task_runner), |
| 117 active_device_manager_count_(0) { |
| 118 } |
| 119 |
| 120 void DevicesApp::Initialize(mojo::ApplicationImpl* app) { |
| 121 app_impl_ = app; |
| 122 if (!service_task_runner_) { |
| 123 service_initializer_.reset(new USBServiceInitializer); |
| 124 service_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| 125 } |
| 126 StartIdleTimer(); |
| 127 } |
| 128 |
| 129 bool DevicesApp::ConfigureIncomingConnection( |
| 130 mojo::ApplicationConnection* connection) { |
| 131 connection->AddService<usb::DeviceManager>(this); |
| 132 return true; |
| 133 } |
| 134 |
| 135 void DevicesApp::Quit() { |
| 136 service_initializer_.reset(); |
| 137 app_impl_ = nullptr; |
| 138 } |
| 139 |
| 140 void DevicesApp::Create(mojo::ApplicationConnection* connection, |
| 141 mojo::InterfaceRequest<usb::DeviceManager> request) { |
| 142 scoped_ptr<usb::DeviceManagerDelegate> delegate(new USBDeviceManagerDelegate( |
| 143 GURL(connection->GetRemoteApplicationURL()))); |
| 144 |
| 145 // Owned by its message pipe. |
| 146 usb::DeviceManagerImpl* device_manager = new usb::DeviceManagerImpl( |
| 147 request.Pass(), delegate.Pass(), service_task_runner_); |
| 148 device_manager->set_error_handler(this); |
| 149 |
| 150 active_device_manager_count_++; |
| 151 idle_timeout_callback_.Cancel(); |
| 152 } |
| 153 |
| 154 void DevicesApp::OnConnectionError() { |
| 155 DCHECK_GE(active_device_manager_count_, 0u); |
| 156 active_device_manager_count_--; |
| 157 if (active_device_manager_count_ == 0) { |
| 158 // If the last DeviceManager connection has been dropped, kick off an idle |
| 159 // timeout to shut ourselves down. |
| 160 StartIdleTimer(); |
| 161 } |
| 162 } |
| 163 |
| 164 void DevicesApp::StartIdleTimer() { |
| 165 // Passing unretained |app_impl_| is safe here because |app_impl_| is |
| 166 // guaranteed to outlive |this|, and the callback is canceled if |this| is |
| 167 // destroyed. |
| 168 idle_timeout_callback_.Reset(base::Bind(&mojo::ApplicationImpl::Terminate, |
| 169 base::Unretained(app_impl_))); |
| 170 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 171 FROM_HERE, idle_timeout_callback_.callback(), |
| 172 base::TimeDelta::FromSeconds(kIdleTimeoutInSeconds)); |
| 173 } |
| 174 |
| 175 } // namespace device |
OLD | NEW |