blob: 676a3d92d3a8673fc17ab7769b33de1b17a5183f [file] [log] [blame]
[email protected]60ccc242012-10-17 21:06:241// 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/desktop_session_win.h"
6
[email protected]5b731f3e2013-03-15 07:28:227#include <limits>
8#include <sddl.h>
9
[email protected]9410c0a2013-02-23 06:07:2110#include "base/base_switches.h"
11#include "base/command_line.h"
[email protected]5b731f3e2013-03-15 07:28:2212#include "base/files/file_path.h"
[email protected]a4eca0a2013-06-20 22:15:0513#include "base/guid.h"
[email protected]5b731f3e2013-03-15 07:28:2214#include "base/memory/ref_counted.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/memory/weak_ptr.h"
[email protected]60ccc242012-10-17 21:06:2417#include "base/path_service.h"
[email protected]eaf92532013-06-11 07:39:1918#include "base/strings/stringprintf.h"
[email protected]906265872013-06-07 22:40:4519#include "base/strings/utf_string_conversions.h"
[email protected]5b731f3e2013-03-15 07:28:2220#include "base/threading/thread_checker.h"
[email protected]5d7eb862013-06-28 15:21:2421#include "base/timer/timer.h"
[email protected]a4eca0a2013-06-20 22:15:0522#include "base/win/scoped_bstr.h"
[email protected]5b731f3e2013-03-15 07:28:2223#include "base/win/scoped_comptr.h"
24#include "base/win/scoped_handle.h"
[email protected]85c7fda22013-05-18 01:35:4725#include "base/win/windows_version.h"
[email protected]12066cb2012-10-25 03:25:4326#include "ipc/ipc_message_macros.h"
[email protected]5b731f3e2013-03-15 07:28:2227#include "ipc/ipc_platform_file.h"
[email protected]12066cb2012-10-25 03:25:4328#include "remoting/base/auto_thread_task_runner.h"
[email protected]5b731f3e2013-03-15 07:28:2229// MIDL-generated declarations and definitions.
30#include "remoting/host/chromoting_lib.h"
[email protected]12066cb2012-10-25 03:25:4331#include "remoting/host/chromoting_messages.h"
[email protected]60ccc242012-10-17 21:06:2432#include "remoting/host/daemon_process.h"
[email protected]5b731f3e2013-03-15 07:28:2233#include "remoting/host/desktop_session.h"
[email protected]9410c0a2013-02-23 06:07:2134#include "remoting/host/host_main.h"
35#include "remoting/host/ipc_constants.h"
[email protected]0dffd552012-12-07 01:08:0936#include "remoting/host/sas_injector.h"
[email protected]739e2802013-03-18 01:03:4837#include "remoting/host/screen_resolution.h"
[email protected]5b731f3e2013-03-15 07:28:2238#include "remoting/host/win/host_service.h"
[email protected]60ccc242012-10-17 21:06:2439#include "remoting/host/win/worker_process_launcher.h"
[email protected]60ccc242012-10-17 21:06:2440#include "remoting/host/win/wts_session_process_delegate.h"
[email protected]3fd005e22013-02-28 20:11:2941#include "remoting/host/win/wts_terminal_monitor.h"
[email protected]5b731f3e2013-03-15 07:28:2242#include "remoting/host/win/wts_terminal_observer.h"
43#include "remoting/host/worker_process_ipc_delegate.h"
[email protected]60ccc242012-10-17 21:06:2444
[email protected]12066cb2012-10-25 03:25:4345using base::win::ScopedHandle;
46
[email protected]5b731f3e2013-03-15 07:28:2247namespace remoting {
48
[email protected]60ccc242012-10-17 21:06:2449namespace {
50
[email protected]60ccc242012-10-17 21:06:2451// The security descriptor of the daemon IPC endpoint. It gives full access
[email protected]6d65223d2013-03-05 20:32:4652// to SYSTEM and denies access by anyone else.
[email protected]5b731f3e2013-03-15 07:28:2253const wchar_t kDaemonIpcSecurityDescriptor[] =
54 SDDL_OWNER L":" SDDL_LOCAL_SYSTEM
55 SDDL_GROUP L":" SDDL_LOCAL_SYSTEM
56 SDDL_DACL L":("
57 SDDL_ACCESS_ALLOWED L";;" SDDL_GENERIC_ALL L";;;" SDDL_LOCAL_SYSTEM
58 L")";
[email protected]60ccc242012-10-17 21:06:2459
[email protected]9410c0a2013-02-23 06:07:2160// The command line parameters that should be copied from the service's command
[email protected]f0ce8fbb2014-06-16 18:36:1761// line to the desktop process.
[email protected]9410c0a2013-02-23 06:07:2162const char* kCopiedSwitchNames[] = { switches::kV, switches::kVModule };
63
[email protected]3c6ae172013-03-18 08:50:5864// The default screen dimensions for an RDP session.
[email protected]792c4f42013-04-06 16:05:2165const int kDefaultRdpScreenWidth = 1280;
[email protected]3c6ae172013-03-18 08:50:5866const int kDefaultRdpScreenHeight = 768;
67
[email protected]5b731f3e2013-03-15 07:28:2268// RDC 6.1 (W2K8) supports dimensions of up to 4096x2048.
69const int kMaxRdpScreenWidth = 4096;
70const int kMaxRdpScreenHeight = 2048;
[email protected]60ccc242012-10-17 21:06:2471
[email protected]5b731f3e2013-03-15 07:28:2272// The minimum effective screen dimensions supported by Windows are 800x600.
73const int kMinRdpScreenWidth = 800;
74const int kMinRdpScreenHeight = 600;
[email protected]60ccc242012-10-17 21:06:2475
[email protected]739e2802013-03-18 01:03:4876// Default dots per inch used by RDP is 96 DPI.
77const int kDefaultRdpDpi = 96;
[email protected]5b731f3e2013-03-15 07:28:2278
79// The session attach notification should arrive within 30 seconds.
80const int kSessionAttachTimeoutSeconds = 30;
81
82// DesktopSession implementation which attaches to the host's physical console.
83// Receives IPC messages from the desktop process, running in the console
84// session, via |WorkerProcessIpcDelegate|, and monitors console session
85// attach/detach events via |WtsConsoleObserer|.
86class ConsoleSession : public DesktopSessionWin {
87 public:
88 // Same as DesktopSessionWin().
89 ConsoleSession(
90 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
[email protected]12066cb2012-10-25 03:25:4391 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
[email protected]60ccc242012-10-17 21:06:2492 DaemonProcess* daemon_process,
93 int id,
[email protected]5b731f3e2013-03-15 07:28:2294 WtsTerminalMonitor* monitor);
95 virtual ~ConsoleSession();
96
97 protected:
[email protected]6f526ce2013-03-18 04:38:5698 // DesktopSession overrides.
99 virtual void SetScreenResolution(const ScreenResolution& resolution) OVERRIDE;
100
[email protected]5b731f3e2013-03-15 07:28:22101 // DesktopSessionWin overrides.
102 virtual void InjectSas() OVERRIDE;
103
104 private:
105 scoped_ptr<SasInjector> sas_injector_;
106
107 DISALLOW_COPY_AND_ASSIGN(ConsoleSession);
108};
109
110// DesktopSession implementation which attaches to virtual RDP console.
111// Receives IPC messages from the desktop process, running in the console
112// session, via |WorkerProcessIpcDelegate|, and monitors console session
113// attach/detach events via |WtsConsoleObserer|.
114class RdpSession : public DesktopSessionWin {
115 public:
116 // Same as DesktopSessionWin().
117 RdpSession(
118 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
119 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
120 DaemonProcess* daemon_process,
121 int id,
122 WtsTerminalMonitor* monitor);
123 virtual ~RdpSession();
124
125 // Performs the part of initialization that can fail.
[email protected]739e2802013-03-18 01:03:48126 bool Initialize(const ScreenResolution& resolution);
[email protected]5b731f3e2013-03-15 07:28:22127
128 // Mirrors IRdpDesktopSessionEventHandler.
[email protected]a4eca0a2013-06-20 22:15:05129 void OnRdpConnected();
[email protected]5b731f3e2013-03-15 07:28:22130 void OnRdpClosed();
131
132 protected:
[email protected]6f526ce2013-03-18 04:38:56133 // DesktopSession overrides.
134 virtual void SetScreenResolution(const ScreenResolution& resolution) OVERRIDE;
135
[email protected]5b731f3e2013-03-15 07:28:22136 // DesktopSessionWin overrides.
137 virtual void InjectSas() OVERRIDE;
138
139 private:
140 // An implementation of IRdpDesktopSessionEventHandler interface that forwards
141 // notifications to the owning desktop session.
142 class EventHandler : public IRdpDesktopSessionEventHandler {
143 public:
144 explicit EventHandler(base::WeakPtr<RdpSession> desktop_session);
145 virtual ~EventHandler();
146
147 // IUnknown interface.
148 STDMETHOD_(ULONG, AddRef)() OVERRIDE;
149 STDMETHOD_(ULONG, Release)() OVERRIDE;
150 STDMETHOD(QueryInterface)(REFIID riid, void** ppv) OVERRIDE;
151
152 // IRdpDesktopSessionEventHandler interface.
[email protected]a4eca0a2013-06-20 22:15:05153 STDMETHOD(OnRdpConnected)() OVERRIDE;
[email protected]5b731f3e2013-03-15 07:28:22154 STDMETHOD(OnRdpClosed)() OVERRIDE;
155
156 private:
157 ULONG ref_count_;
158
159 // Points to the desktop session object receiving OnRdpXxx() notifications.
160 base::WeakPtr<RdpSession> desktop_session_;
161
162 // This class must be used on a single thread.
163 base::ThreadChecker thread_checker_;
164
165 DISALLOW_COPY_AND_ASSIGN(EventHandler);
166 };
167
168 // Used to create an RDP desktop session.
169 base::win::ScopedComPtr<IRdpDesktopSession> rdp_desktop_session_;
170
[email protected]a4eca0a2013-06-20 22:15:05171 // Used to match |rdp_desktop_session_| with the session it is attached to.
172 std::string terminal_id_;
173
[email protected]5b731f3e2013-03-15 07:28:22174 base::WeakPtrFactory<RdpSession> weak_factory_;
175
176 DISALLOW_COPY_AND_ASSIGN(RdpSession);
177};
178
179ConsoleSession::ConsoleSession(
180 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
181 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
182 DaemonProcess* daemon_process,
183 int id,
184 WtsTerminalMonitor* monitor)
185 : DesktopSessionWin(caller_task_runner, io_task_runner, daemon_process, id,
186 monitor) {
[email protected]a4eca0a2013-06-20 22:15:05187 StartMonitoring(WtsTerminalMonitor::kConsole);
[email protected]5b731f3e2013-03-15 07:28:22188}
189
190ConsoleSession::~ConsoleSession() {
191}
192
[email protected]6f526ce2013-03-18 04:38:56193void ConsoleSession::SetScreenResolution(const ScreenResolution& resolution) {
194 // Do nothing. The screen resolution of the console session is controlled by
195 // the DesktopSessionAgent instance running in that session.
196 DCHECK(caller_task_runner()->BelongsToCurrentThread());
197}
198
[email protected]5b731f3e2013-03-15 07:28:22199void ConsoleSession::InjectSas() {
[email protected]dd81166082013-03-18 20:33:33200 DCHECK(caller_task_runner()->BelongsToCurrentThread());
201
[email protected]5b731f3e2013-03-15 07:28:22202 if (!sas_injector_)
203 sas_injector_ = SasInjector::Create();
204 if (!sas_injector_->InjectSas())
205 LOG(ERROR) << "Failed to inject Secure Attention Sequence.";
206}
207
208RdpSession::RdpSession(
209 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
210 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
211 DaemonProcess* daemon_process,
212 int id,
213 WtsTerminalMonitor* monitor)
214 : DesktopSessionWin(caller_task_runner, io_task_runner, daemon_process, id,
215 monitor),
[email protected]aa46ba52013-04-27 00:00:44216 weak_factory_(this) {
[email protected]5b731f3e2013-03-15 07:28:22217}
218
219RdpSession::~RdpSession() {
220}
221
[email protected]739e2802013-03-18 01:03:48222bool RdpSession::Initialize(const ScreenResolution& resolution) {
[email protected]5b731f3e2013-03-15 07:28:22223 DCHECK(caller_task_runner()->BelongsToCurrentThread());
224
225 // Create the RDP wrapper object.
226 HRESULT result = rdp_desktop_session_.CreateInstance(
227 __uuidof(RdpDesktopSession));
228 if (FAILED(result)) {
229 LOG(ERROR) << "Failed to create RdpSession object, 0x"
230 << std::hex << result << std::dec << ".";
231 return false;
232 }
233
[email protected]3c6ae172013-03-18 08:50:58234 ScreenResolution local_resolution = resolution;
235
236 // If the screen resolution is not specified, use the default screen
237 // resolution.
238 if (local_resolution.IsEmpty()) {
[email protected]b9ed58f2013-05-16 10:45:24239 local_resolution = ScreenResolution(
240 webrtc::DesktopSize(kDefaultRdpScreenWidth, kDefaultRdpScreenHeight),
241 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
[email protected]3c6ae172013-03-18 08:50:58242 }
243
[email protected]739e2802013-03-18 01:03:48244 // Get the screen dimensions assuming the default DPI.
[email protected]b9ed58f2013-05-16 10:45:24245 webrtc::DesktopSize host_size = local_resolution.ScaleDimensionsToDpi(
246 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
[email protected]5b731f3e2013-03-15 07:28:22247
248 // Make sure that the host resolution is within the limits supported by RDP.
[email protected]b9ed58f2013-05-16 10:45:24249 host_size = webrtc::DesktopSize(
[email protected]5b731f3e2013-03-15 07:28:22250 std::min(kMaxRdpScreenWidth,
251 std::max(kMinRdpScreenWidth, host_size.width())),
252 std::min(kMaxRdpScreenHeight,
253 std::max(kMinRdpScreenHeight, host_size.height())));
254
255 // Create an RDP session.
256 base::win::ScopedComPtr<IRdpDesktopSessionEventHandler> event_handler(
257 new EventHandler(weak_factory_.GetWeakPtr()));
[email protected]a4eca0a2013-06-20 22:15:05258 terminal_id_ = base::GenerateGUID();
[email protected]6c3bf032013-12-25 19:37:03259 base::win::ScopedBstr terminal_id(base::UTF8ToUTF16(terminal_id_).c_str());
[email protected]5b731f3e2013-03-15 07:28:22260 result = rdp_desktop_session_->Connect(host_size.width(),
261 host_size.height(),
[email protected]a4eca0a2013-06-20 22:15:05262 terminal_id,
[email protected]5b731f3e2013-03-15 07:28:22263 event_handler);
264 if (FAILED(result)) {
265 LOG(ERROR) << "RdpSession::Create() failed, 0x"
266 << std::hex << result << std::dec << ".";
267 return false;
268 }
269
270 return true;
271}
272
[email protected]a4eca0a2013-06-20 22:15:05273void RdpSession::OnRdpConnected() {
[email protected]5b731f3e2013-03-15 07:28:22274 DCHECK(caller_task_runner()->BelongsToCurrentThread());
275
276 StopMonitoring();
[email protected]a4eca0a2013-06-20 22:15:05277 StartMonitoring(terminal_id_);
[email protected]5b731f3e2013-03-15 07:28:22278}
279
280void RdpSession::OnRdpClosed() {
281 DCHECK(caller_task_runner()->BelongsToCurrentThread());
282
[email protected]a4b39952013-06-21 03:57:08283 TerminateSession();
[email protected]5b731f3e2013-03-15 07:28:22284}
285
[email protected]6f526ce2013-03-18 04:38:56286void RdpSession::SetScreenResolution(const ScreenResolution& resolution) {
287 DCHECK(caller_task_runner()->BelongsToCurrentThread());
288
289 // TODO(alexeypa): implement resize-to-client for RDP sessions here.
290 // See http://crbug.com/137696.
291 NOTIMPLEMENTED();
292}
293
[email protected]5b731f3e2013-03-15 07:28:22294void RdpSession::InjectSas() {
295 DCHECK(caller_task_runner()->BelongsToCurrentThread());
296
[email protected]97328ee2013-06-04 06:46:59297 rdp_desktop_session_->InjectSas();
[email protected]5b731f3e2013-03-15 07:28:22298}
299
300RdpSession::EventHandler::EventHandler(
301 base::WeakPtr<RdpSession> desktop_session)
302 : ref_count_(0),
303 desktop_session_(desktop_session) {
304}
305
306RdpSession::EventHandler::~EventHandler() {
307 DCHECK(thread_checker_.CalledOnValidThread());
308
[email protected]1bf06232013-06-07 13:50:24309 if (desktop_session_)
[email protected]5b731f3e2013-03-15 07:28:22310 desktop_session_->OnRdpClosed();
311}
312
313ULONG STDMETHODCALLTYPE RdpSession::EventHandler::AddRef() {
314 DCHECK(thread_checker_.CalledOnValidThread());
315
316 return ++ref_count_;
317}
318
319ULONG STDMETHODCALLTYPE RdpSession::EventHandler::Release() {
320 DCHECK(thread_checker_.CalledOnValidThread());
321
322 if (--ref_count_ == 0) {
323 delete this;
324 return 0;
325 }
326
327 return ref_count_;
328}
329
330STDMETHODIMP RdpSession::EventHandler::QueryInterface(REFIID riid, void** ppv) {
331 DCHECK(thread_checker_.CalledOnValidThread());
332
333 if (riid == IID_IUnknown ||
334 riid == IID_IRdpDesktopSessionEventHandler) {
335 *ppv = static_cast<IRdpDesktopSessionEventHandler*>(this);
336 AddRef();
337 return S_OK;
338 }
339
340 *ppv = NULL;
341 return E_NOINTERFACE;
342}
343
[email protected]a4eca0a2013-06-20 22:15:05344STDMETHODIMP RdpSession::EventHandler::OnRdpConnected() {
[email protected]5b731f3e2013-03-15 07:28:22345 DCHECK(thread_checker_.CalledOnValidThread());
346
[email protected]a4eca0a2013-06-20 22:15:05347 if (desktop_session_)
348 desktop_session_->OnRdpConnected();
[email protected]5b731f3e2013-03-15 07:28:22349
[email protected]5b731f3e2013-03-15 07:28:22350 return S_OK;
351}
352
353STDMETHODIMP RdpSession::EventHandler::OnRdpClosed() {
354 DCHECK(thread_checker_.CalledOnValidThread());
355
[email protected]1bf06232013-06-07 13:50:24356 if (!desktop_session_)
[email protected]5b731f3e2013-03-15 07:28:22357 return S_OK;
358
359 base::WeakPtr<RdpSession> desktop_session = desktop_session_;
360 desktop_session_.reset();
361 desktop_session->OnRdpClosed();
362 return S_OK;
363}
364
365} // namespace
366
367// static
368scoped_ptr<DesktopSession> DesktopSessionWin::CreateForConsole(
369 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
370 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
371 DaemonProcess* daemon_process,
372 int id,
[email protected]739e2802013-03-18 01:03:48373 const ScreenResolution& resolution) {
[email protected]5b731f3e2013-03-15 07:28:22374 scoped_ptr<ConsoleSession> session(new ConsoleSession(
375 caller_task_runner, io_task_runner, daemon_process, id,
376 HostService::GetInstance()));
377
378 return session.PassAs<DesktopSession>();
379}
380
381// static
382scoped_ptr<DesktopSession> DesktopSessionWin::CreateForVirtualTerminal(
383 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
384 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
385 DaemonProcess* daemon_process,
386 int id,
[email protected]739e2802013-03-18 01:03:48387 const ScreenResolution& resolution) {
[email protected]5b731f3e2013-03-15 07:28:22388 scoped_ptr<RdpSession> session(new RdpSession(
389 caller_task_runner, io_task_runner, daemon_process, id,
390 HostService::GetInstance()));
[email protected]739e2802013-03-18 01:03:48391 if (!session->Initialize(resolution))
[email protected]5b731f3e2013-03-15 07:28:22392 return scoped_ptr<DesktopSession>();
393
394 return session.PassAs<DesktopSession>();
395}
396
397DesktopSessionWin::DesktopSessionWin(
398 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
399 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
400 DaemonProcess* daemon_process,
401 int id,
[email protected]3fd005e22013-02-28 20:11:29402 WtsTerminalMonitor* monitor)
[email protected]60ccc242012-10-17 21:06:24403 : DesktopSession(daemon_process, id),
[email protected]5b731f3e2013-03-15 07:28:22404 caller_task_runner_(caller_task_runner),
[email protected]60ccc242012-10-17 21:06:24405 io_task_runner_(io_task_runner),
[email protected]5b731f3e2013-03-15 07:28:22406 monitor_(monitor),
407 monitoring_notifications_(false) {
408 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]94618e72013-05-14 00:13:08409
410 ReportElapsedTime("created");
[email protected]60ccc242012-10-17 21:06:24411}
412
413DesktopSessionWin::~DesktopSessionWin() {
[email protected]5b731f3e2013-03-15 07:28:22414 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24415
[email protected]5b731f3e2013-03-15 07:28:22416 StopMonitoring();
417}
418
419void DesktopSessionWin::OnSessionAttachTimeout() {
420 DCHECK(caller_task_runner_->BelongsToCurrentThread());
421
422 LOG(ERROR) << "Session attach notification didn't arrived within "
423 << kSessionAttachTimeoutSeconds << " seconds.";
[email protected]a4b39952013-06-21 03:57:08424 TerminateSession();
[email protected]5b731f3e2013-03-15 07:28:22425}
426
[email protected]a4eca0a2013-06-20 22:15:05427void DesktopSessionWin::StartMonitoring(const std::string& terminal_id) {
[email protected]5b731f3e2013-03-15 07:28:22428 DCHECK(caller_task_runner_->BelongsToCurrentThread());
429 DCHECK(!monitoring_notifications_);
430 DCHECK(!session_attach_timer_.IsRunning());
431
[email protected]94618e72013-05-14 00:13:08432 ReportElapsedTime("started monitoring");
433
[email protected]5b731f3e2013-03-15 07:28:22434 session_attach_timer_.Start(
435 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds),
436 this, &DesktopSessionWin::OnSessionAttachTimeout);
437
438 monitoring_notifications_ = true;
[email protected]a4eca0a2013-06-20 22:15:05439 monitor_->AddWtsTerminalObserver(terminal_id, this);
[email protected]5b731f3e2013-03-15 07:28:22440}
441
442void DesktopSessionWin::StopMonitoring() {
443 DCHECK(caller_task_runner_->BelongsToCurrentThread());
444
445 if (monitoring_notifications_) {
[email protected]94618e72013-05-14 00:13:08446 ReportElapsedTime("stopped monitoring");
447
[email protected]5b731f3e2013-03-15 07:28:22448 monitoring_notifications_ = false;
449 monitor_->RemoveWtsTerminalObserver(this);
450 }
451
452 session_attach_timer_.Stop();
453 OnSessionDetached();
[email protected]60ccc242012-10-17 21:06:24454}
455
[email protected]a4b39952013-06-21 03:57:08456void DesktopSessionWin::TerminateSession() {
457 DCHECK(caller_task_runner_->BelongsToCurrentThread());
458
459 StopMonitoring();
460
461 // This call will delete |this| so it should be at the very end of the method.
462 daemon_process()->CloseDesktopSession(id());
463}
464
[email protected]b15c8702012-10-18 20:34:21465void DesktopSessionWin::OnChannelConnected(int32 peer_pid) {
[email protected]5b731f3e2013-03-15 07:28:22466 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]12066cb2012-10-25 03:25:43467
[email protected]94618e72013-05-14 00:13:08468 ReportElapsedTime("channel connected");
469
[email protected]12066cb2012-10-25 03:25:43470 // Obtain the handle of the desktop process. It will be passed to the network
[email protected]5b731f3e2013-03-15 07:28:22471 // process to use to duplicate handles of shared memory objects from
472 // the desktop process.
[email protected]12066cb2012-10-25 03:25:43473 desktop_process_.Set(OpenProcess(PROCESS_DUP_HANDLE, false, peer_pid));
474 if (!desktop_process_.IsValid()) {
[email protected]e9057a6f2013-03-08 22:37:55475 CrashDesktopProcess(FROM_HERE);
[email protected]12066cb2012-10-25 03:25:43476 return;
477 }
478
479 VLOG(1) << "IPC: daemon <- desktop (" << peer_pid << ")";
[email protected]60ccc242012-10-17 21:06:24480}
481
482bool DesktopSessionWin::OnMessageReceived(const IPC::Message& message) {
[email protected]5b731f3e2013-03-15 07:28:22483 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24484
[email protected]12066cb2012-10-25 03:25:43485 bool handled = true;
486 IPC_BEGIN_MESSAGE_MAP(DesktopSessionWin, message)
487 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached,
488 OnDesktopSessionAgentAttached)
[email protected]0dffd552012-12-07 01:08:09489 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_InjectSas,
[email protected]5b731f3e2013-03-15 07:28:22490 InjectSas)
[email protected]12066cb2012-10-25 03:25:43491 IPC_MESSAGE_UNHANDLED(handled = false)
492 IPC_END_MESSAGE_MAP()
[email protected]f5f0f402013-03-05 22:46:38493
494 if (!handled) {
495 LOG(ERROR) << "Received unexpected IPC type: " << message.type();
[email protected]e9057a6f2013-03-08 22:37:55496 CrashDesktopProcess(FROM_HERE);
[email protected]f5f0f402013-03-05 22:46:38497 }
498
[email protected]12066cb2012-10-25 03:25:43499 return handled;
[email protected]60ccc242012-10-17 21:06:24500}
501
[email protected]a4b39952013-06-21 03:57:08502void DesktopSessionWin::OnPermanentError(int exit_code) {
[email protected]5b731f3e2013-03-15 07:28:22503 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24504
[email protected]a4b39952013-06-21 03:57:08505 TerminateSession();
[email protected]60ccc242012-10-17 21:06:24506}
507
508void DesktopSessionWin::OnSessionAttached(uint32 session_id) {
[email protected]5b731f3e2013-03-15 07:28:22509 DCHECK(caller_task_runner_->BelongsToCurrentThread());
510 DCHECK(!launcher_);
511 DCHECK(monitoring_notifications_);
[email protected]60ccc242012-10-17 21:06:24512
[email protected]94618e72013-05-14 00:13:08513 ReportElapsedTime("attached");
514
[email protected]85c7fda22013-05-18 01:35:47515 // Launch elevated on Win8 to be able to inject Alt+Tab.
516 bool launch_elevated = base::win::GetVersion() >= base::win::VERSION_WIN8;
517
518 // Get the name of the executable to run. |kDesktopBinaryName| specifies
519 // uiAccess="true" in it's manifest.
[email protected]9410c0a2013-02-23 06:07:21520 base::FilePath desktop_binary;
[email protected]85c7fda22013-05-18 01:35:47521 bool result;
522 if (launch_elevated) {
523 result = GetInstalledBinaryPath(kDesktopBinaryName, &desktop_binary);
524 } else {
525 result = GetInstalledBinaryPath(kHostBinaryName, &desktop_binary);
526 }
527
528 if (!result) {
[email protected]a4b39952013-06-21 03:57:08529 TerminateSession();
[email protected]9410c0a2013-02-23 06:07:21530 return;
[email protected]60ccc242012-10-17 21:06:24531 }
532
[email protected]5b731f3e2013-03-15 07:28:22533 session_attach_timer_.Stop();
534
[email protected]9410c0a2013-02-23 06:07:21535 scoped_ptr<CommandLine> target(new CommandLine(desktop_binary));
536 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeDesktop);
[email protected]5b731f3e2013-03-15 07:28:22537 // Copy the command line switches enabling verbose logging.
[email protected]9410c0a2013-02-23 06:07:21538 target->CopySwitchesFrom(*CommandLine::ForCurrentProcess(),
539 kCopiedSwitchNames,
540 arraysize(kCopiedSwitchNames));
541
[email protected]5b731f3e2013-03-15 07:28:22542 // Create a delegate capable of launching a process in a different session.
[email protected]60ccc242012-10-17 21:06:24543 scoped_ptr<WtsSessionProcessDelegate> delegate(
[email protected]85c7fda22013-05-18 01:35:47544 new WtsSessionProcessDelegate(io_task_runner_,
545 target.Pass(),
546 launch_elevated,
[email protected]6c3bf032013-12-25 19:37:03547 base::WideToUTF8(
548 kDaemonIpcSecurityDescriptor)));
[email protected]85c7fda22013-05-18 01:35:47549 if (!delegate->Initialize(session_id)) {
[email protected]a4b39952013-06-21 03:57:08550 TerminateSession();
[email protected]85c7fda22013-05-18 01:35:47551 return;
552 }
[email protected]60ccc242012-10-17 21:06:24553
554 // Create a launcher for the desktop process, using the per-session delegate.
[email protected]85c7fda22013-05-18 01:35:47555 launcher_.reset(new WorkerProcessLauncher(delegate.Pass(), this));
[email protected]60ccc242012-10-17 21:06:24556}
557
558void DesktopSessionWin::OnSessionDetached() {
[email protected]5b731f3e2013-03-15 07:28:22559 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24560
561 launcher_.reset();
[email protected]5b731f3e2013-03-15 07:28:22562
563 if (monitoring_notifications_) {
[email protected]94618e72013-05-14 00:13:08564 ReportElapsedTime("detached");
565
[email protected]5b731f3e2013-03-15 07:28:22566 session_attach_timer_.Start(
567 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds),
568 this, &DesktopSessionWin::OnSessionAttachTimeout);
569 }
[email protected]60ccc242012-10-17 21:06:24570}
571
[email protected]12066cb2012-10-25 03:25:43572void DesktopSessionWin::OnDesktopSessionAgentAttached(
573 IPC::PlatformFileForTransit desktop_pipe) {
574 if (!daemon_process()->OnDesktopSessionAgentAttached(id(),
575 desktop_process_,
576 desktop_pipe)) {
[email protected]e9057a6f2013-03-08 22:37:55577 CrashDesktopProcess(FROM_HERE);
[email protected]12066cb2012-10-25 03:25:43578 }
579}
580
[email protected]e9057a6f2013-03-08 22:37:55581void DesktopSessionWin::CrashDesktopProcess(
[email protected]12066cb2012-10-25 03:25:43582 const tracked_objects::Location& location) {
[email protected]5b731f3e2013-03-15 07:28:22583 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]12066cb2012-10-25 03:25:43584
[email protected]e9057a6f2013-03-08 22:37:55585 launcher_->Crash(location);
[email protected]12066cb2012-10-25 03:25:43586}
587
[email protected]94618e72013-05-14 00:13:08588void DesktopSessionWin::ReportElapsedTime(const std::string& event) {
589 base::Time now = base::Time::Now();
590
591 std::string passed;
592 if (!last_timestamp_.is_null()) {
593 passed = base::StringPrintf(", %.2fs passed",
594 (now - last_timestamp_).InSecondsF());
595 }
596
597 base::Time::Exploded exploded;
598 now.LocalExplode(&exploded);
599 VLOG(1) << base::StringPrintf("session(%d): %s at %02d:%02d:%02d.%03d%s",
600 id(),
601 event.c_str(),
602 exploded.hour,
603 exploded.minute,
604 exploded.second,
605 exploded.millisecond,
606 passed.c_str());
607
608 last_timestamp_ = now;
609}
610
[email protected]60ccc242012-10-17 21:06:24611} // namespace remoting