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 presume not catch all common local host strings. | |
Reilly Grant (use Gerrit)
2015/06/10 20:02:47
does not presume to
Ken Rockot(use gerrit already)
2015/06/10 20:15:51
Done.
| |
47 if (remote_url_.host() == "127.0.0.1" || remote_url_.host() == "localhost") | |
Reilly Grant (use Gerrit)
2015/06/10 20:02:47
net::IsLocalHost() may be helpful here.
Ken Rockot(use gerrit already)
2015/06/10 20:15:51
I was going to use that, but (despite the fact tha
| |
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 |