1 // Copyright (c) 2012 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 "remoting/host/ipc_desktop_environment.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/compiler_specific.h"
11 #include "base/logging.h"
12 #include "base/process/process_handle.h"
13 #include "base/single_thread_task_runner.h"
14 #include "build/build_config.h"
15 #include "ipc/ipc_channel_handle.h"
16 #include "ipc/ipc_sender.h"
17 #include "remoting/host/action_executor.h"
18 #include "remoting/host/audio_capturer.h"
19 #include "remoting/host/chromoting_messages.h"
20 #include "remoting/host/client_session_control.h"
21 #include "remoting/host/desktop_session.h"
22 #include "remoting/host/desktop_session_proxy.h"
23 #include "remoting/host/file_transfer/file_operations.h"
24 #include "remoting/host/input_injector.h"
25 #include "remoting/host/keyboard_layout_monitor.h"
26 #include "remoting/host/screen_controls.h"
27 #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
28 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
29 
30 namespace remoting {
31 
IpcDesktopEnvironment(scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,base::WeakPtr<ClientSessionControl> client_session_control,base::WeakPtr<DesktopSessionConnector> desktop_session_connector,const DesktopEnvironmentOptions & options)32 IpcDesktopEnvironment::IpcDesktopEnvironment(
33     scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
34     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
35     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
36     base::WeakPtr<ClientSessionControl> client_session_control,
37     base::WeakPtr<DesktopSessionConnector> desktop_session_connector,
38     const DesktopEnvironmentOptions& options)
39     : desktop_session_proxy_(
40           base::MakeRefCounted<DesktopSessionProxy>(audio_task_runner,
41                                                     caller_task_runner,
42                                                     io_task_runner,
43                                                     client_session_control,
44                                                     desktop_session_connector,
45                                                     options)) {
46   DCHECK(caller_task_runner->BelongsToCurrentThread());
47 }
48 
49 IpcDesktopEnvironment::~IpcDesktopEnvironment() = default;
50 
CreateActionExecutor()51 std::unique_ptr<ActionExecutor> IpcDesktopEnvironment::CreateActionExecutor() {
52   return desktop_session_proxy_->CreateActionExecutor();
53 }
54 
CreateAudioCapturer()55 std::unique_ptr<AudioCapturer> IpcDesktopEnvironment::CreateAudioCapturer() {
56   return desktop_session_proxy_->CreateAudioCapturer();
57 }
58 
CreateInputInjector()59 std::unique_ptr<InputInjector> IpcDesktopEnvironment::CreateInputInjector() {
60   return desktop_session_proxy_->CreateInputInjector();
61 }
62 
CreateScreenControls()63 std::unique_ptr<ScreenControls> IpcDesktopEnvironment::CreateScreenControls() {
64   return desktop_session_proxy_->CreateScreenControls();
65 }
66 
67 std::unique_ptr<webrtc::MouseCursorMonitor>
CreateMouseCursorMonitor()68 IpcDesktopEnvironment::CreateMouseCursorMonitor() {
69   return desktop_session_proxy_->CreateMouseCursorMonitor();
70 }
71 
72 std::unique_ptr<KeyboardLayoutMonitor>
CreateKeyboardLayoutMonitor(base::RepeatingCallback<void (const protocol::KeyboardLayout &)> callback)73 IpcDesktopEnvironment::CreateKeyboardLayoutMonitor(
74     base::RepeatingCallback<void(const protocol::KeyboardLayout&)> callback) {
75   return desktop_session_proxy_->CreateKeyboardLayoutMonitor(
76       std::move(callback));
77 }
78 
79 std::unique_ptr<webrtc::DesktopCapturer>
CreateVideoCapturer()80 IpcDesktopEnvironment::CreateVideoCapturer() {
81   return desktop_session_proxy_->CreateVideoCapturer();
82 }
83 
CreateFileOperations()84 std::unique_ptr<FileOperations> IpcDesktopEnvironment::CreateFileOperations() {
85   return desktop_session_proxy_->CreateFileOperations();
86 }
87 
GetCapabilities() const88 std::string IpcDesktopEnvironment::GetCapabilities() const {
89   return desktop_session_proxy_->GetCapabilities();
90 }
91 
SetCapabilities(const std::string & capabilities)92 void IpcDesktopEnvironment::SetCapabilities(const std::string& capabilities) {
93   return desktop_session_proxy_->SetCapabilities(capabilities);
94 }
95 
GetDesktopSessionId() const96 uint32_t IpcDesktopEnvironment::GetDesktopSessionId() const {
97   return desktop_session_proxy_->desktop_session_id();
98 }
99 
100 std::unique_ptr<DesktopAndCursorConditionalComposer>
CreateComposingVideoCapturer()101 IpcDesktopEnvironment::CreateComposingVideoCapturer() {
102   // Cursor compositing is done by the desktop process if necessary.
103   return nullptr;
104 }
105 
IpcDesktopEnvironmentFactory(scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,IPC::Sender * daemon_channel)106 IpcDesktopEnvironmentFactory::IpcDesktopEnvironmentFactory(
107     scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
108     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
109     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
110     IPC::Sender* daemon_channel)
111     : audio_task_runner_(audio_task_runner),
112       caller_task_runner_(caller_task_runner),
113       io_task_runner_(io_task_runner),
114       daemon_channel_(daemon_channel) {}
115 
116 IpcDesktopEnvironmentFactory::~IpcDesktopEnvironmentFactory() = default;
117 
Create(base::WeakPtr<ClientSessionControl> client_session_control,const DesktopEnvironmentOptions & options)118 std::unique_ptr<DesktopEnvironment> IpcDesktopEnvironmentFactory::Create(
119     base::WeakPtr<ClientSessionControl> client_session_control,
120     const DesktopEnvironmentOptions& options) {
121   DCHECK(caller_task_runner_->BelongsToCurrentThread());
122 
123   return std::make_unique<IpcDesktopEnvironment>(
124       audio_task_runner_, caller_task_runner_, io_task_runner_,
125       client_session_control, connector_factory_.GetWeakPtr(), options);
126 }
127 
SupportsAudioCapture() const128 bool IpcDesktopEnvironmentFactory::SupportsAudioCapture() const {
129   DCHECK(caller_task_runner_->BelongsToCurrentThread());
130 
131   return AudioCapturer::IsSupported();
132 }
133 
ConnectTerminal(DesktopSessionProxy * desktop_session_proxy,const ScreenResolution & resolution,bool virtual_terminal)134 void IpcDesktopEnvironmentFactory::ConnectTerminal(
135     DesktopSessionProxy* desktop_session_proxy,
136     const ScreenResolution& resolution,
137     bool virtual_terminal) {
138   DCHECK(caller_task_runner_->BelongsToCurrentThread());
139 
140   int id = next_id_++;
141   bool inserted = active_connections_.insert(
142       std::make_pair(id, desktop_session_proxy)).second;
143   CHECK(inserted);
144 
145   VLOG(1) << "Network: registered desktop environment " << id;
146 
147   daemon_channel_->Send(new ChromotingNetworkHostMsg_ConnectTerminal(
148       id, resolution, virtual_terminal));
149 }
150 
DisconnectTerminal(DesktopSessionProxy * desktop_session_proxy)151 void IpcDesktopEnvironmentFactory::DisconnectTerminal(
152     DesktopSessionProxy* desktop_session_proxy) {
153   DCHECK(caller_task_runner_->BelongsToCurrentThread());
154 
155   ActiveConnectionsList::iterator i;
156   for (i = active_connections_.begin(); i != active_connections_.end(); ++i) {
157     if (i->second == desktop_session_proxy)
158       break;
159   }
160 
161   if (i != active_connections_.end()) {
162     int id = i->first;
163     active_connections_.erase(i);
164 
165     VLOG(1) << "Network: unregistered desktop environment " << id;
166     daemon_channel_->Send(new ChromotingNetworkHostMsg_DisconnectTerminal(id));
167   }
168 }
169 
SetScreenResolution(DesktopSessionProxy * desktop_session_proxy,const ScreenResolution & resolution)170 void IpcDesktopEnvironmentFactory::SetScreenResolution(
171     DesktopSessionProxy* desktop_session_proxy,
172     const ScreenResolution& resolution) {
173   DCHECK(caller_task_runner_->BelongsToCurrentThread());
174 
175   ActiveConnectionsList::iterator i;
176   for (i = active_connections_.begin(); i != active_connections_.end(); ++i) {
177     if (i->second == desktop_session_proxy)
178       break;
179   }
180 
181   if (i != active_connections_.end()) {
182     daemon_channel_->Send(new ChromotingNetworkDaemonMsg_SetScreenResolution(
183         i->first, resolution));
184   }
185 }
186 
OnDesktopSessionAgentAttached(int terminal_id,int session_id,const IPC::ChannelHandle & desktop_pipe)187 void IpcDesktopEnvironmentFactory::OnDesktopSessionAgentAttached(
188     int terminal_id,
189     int session_id,
190     const IPC::ChannelHandle& desktop_pipe) {
191   if (!caller_task_runner_->BelongsToCurrentThread()) {
192     caller_task_runner_->PostTask(
193         FROM_HERE,
194         base::BindOnce(
195             &IpcDesktopEnvironmentFactory::OnDesktopSessionAgentAttached,
196             base::Unretained(this), terminal_id, session_id, desktop_pipe));
197     return;
198   }
199 
200   auto i = active_connections_.find(terminal_id);
201   if (i != active_connections_.end()) {
202     i->second->DetachFromDesktop();
203     i->second->AttachToDesktop(desktop_pipe, session_id);
204   } else {
205     mojo::ScopedMessagePipeHandle closer(desktop_pipe.mojo_handle);
206   }
207 }
208 
OnTerminalDisconnected(int terminal_id)209 void IpcDesktopEnvironmentFactory::OnTerminalDisconnected(int terminal_id) {
210   if (!caller_task_runner_->BelongsToCurrentThread()) {
211     caller_task_runner_->PostTask(
212         FROM_HERE,
213         base::BindOnce(&IpcDesktopEnvironmentFactory::OnTerminalDisconnected,
214                        base::Unretained(this), terminal_id));
215     return;
216   }
217 
218   auto i = active_connections_.find(terminal_id);
219   if (i != active_connections_.end()) {
220     DesktopSessionProxy* desktop_session_proxy = i->second;
221     active_connections_.erase(i);
222 
223     // Disconnect the client session.
224     desktop_session_proxy->DisconnectSession(protocol::OK);
225   }
226 }
227 
228 }  // namespace remoting
229