| 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/usb/device_manager_impl.h" | |
| 16 #include "device/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 |