Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // This file implements the Windows service controlling Me2Me host processes | 5 // This file implements the Windows service controlling Me2Me host processes |
| 6 // running within user sessions. | 6 // running within user sessions. |
| 7 | 7 |
| 8 #include "remoting/host/wts_session_process_launcher_win.h" | 8 #include "remoting/host/wts_session_process_launcher_win.h" |
| 9 | 9 |
| 10 #include <windows.h> | 10 #include <windows.h> |
| 11 #include <sddl.h> | 11 #include <sddl.h> |
| 12 #include <limits> | 12 #include <limits> |
| 13 | 13 |
| 14 #include "base/bind.h" | |
| 15 #include "base/bind_helpers.h" | |
| 14 #include "base/command_line.h" | 16 #include "base/command_line.h" |
| 15 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/message_loop_proxy.h" | |
| 16 #include "base/process_util.h" | 19 #include "base/process_util.h" |
| 17 #include "base/rand_util.h" | 20 #include "base/rand_util.h" |
| 18 #include "base/string16.h" | 21 #include "base/string16.h" |
| 19 #include "base/stringprintf.h" | 22 #include "base/stringprintf.h" |
| 20 #include "base/threading/thread.h" | |
| 21 #include "base/utf_string_conversions.h" | 23 #include "base/utf_string_conversions.h" |
| 22 #include "base/win/scoped_handle.h" | 24 #include "base/win/scoped_handle.h" |
| 23 #include "base/win/scoped_process_information.h" | 25 #include "base/win/scoped_process_information.h" |
| 24 #include "ipc/ipc_channel_proxy.h" | 26 #include "ipc/ipc_channel_proxy.h" |
| 25 #include "ipc/ipc_message.h" | 27 #include "ipc/ipc_message.h" |
| 26 #include "ipc/ipc_message_macros.h" | 28 #include "ipc/ipc_message_macros.h" |
| 27 | 29 |
| 28 #include "remoting/host/chromoting_messages.h" | 30 #include "remoting/host/chromoting_messages.h" |
| 29 #include "remoting/host/sas_injector.h" | 31 #include "remoting/host/sas_injector.h" |
| 30 #include "remoting/host/wts_console_monitor_win.h" | 32 #include "remoting/host/wts_console_monitor_win.h" |
| 31 | 33 |
| 32 using base::win::ScopedHandle; | 34 using base::win::ScopedHandle; |
| 33 using base::TimeDelta; | 35 using base::TimeDelta; |
| 34 | 36 |
| 35 namespace { | 37 namespace { |
| 36 | 38 |
| 39 // The exit code returned by the host process when its configuration is not | |
| 40 // valid. | |
| 41 const int kInvalidHostConfigurationExitCode = 1; | |
| 42 | |
| 37 // The minimum and maximum delays between attempts to inject host process into | 43 // The minimum and maximum delays between attempts to inject host process into |
| 38 // a session. | 44 // a session. |
| 39 const int kMaxLaunchDelaySeconds = 60; | 45 const int kMaxLaunchDelaySeconds = 60; |
| 40 const int kMinLaunchDelaySeconds = 1; | 46 const int kMinLaunchDelaySeconds = 1; |
| 41 | 47 |
| 42 // Name of the default session desktop. | 48 // Name of the default session desktop. |
| 43 const char kDefaultDesktopName[] = "winsta0\\default"; | 49 const char kDefaultDesktopName[] = "winsta0\\default"; |
| 44 | 50 |
| 45 // Match the pipe name prefix used by Chrome IPC channels. | 51 // Match the pipe name prefix used by Chrome IPC channels. |
| 46 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome."; | 52 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome."; |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 return true; | 246 return true; |
| 241 } | 247 } |
| 242 | 248 |
| 243 } // namespace | 249 } // namespace |
| 244 | 250 |
| 245 namespace remoting { | 251 namespace remoting { |
| 246 | 252 |
| 247 WtsSessionProcessLauncher::WtsSessionProcessLauncher( | 253 WtsSessionProcessLauncher::WtsSessionProcessLauncher( |
| 248 WtsConsoleMonitor* monitor, | 254 WtsConsoleMonitor* monitor, |
| 249 const FilePath& host_binary, | 255 const FilePath& host_binary, |
| 250 base::Thread* io_thread) | 256 scoped_refptr<base::MessageLoopProxy> main_message_loop, |
| 257 scoped_refptr<base::MessageLoopProxy> ipc_message_loop) | |
| 251 : host_binary_(host_binary), | 258 : host_binary_(host_binary), |
| 252 io_thread_(io_thread), | 259 main_message_loop_(main_message_loop), |
| 260 ipc_message_loop_(ipc_message_loop), | |
| 253 monitor_(monitor), | 261 monitor_(monitor), |
| 254 state_(StateDetached) { | 262 state_(StateDetached) { |
| 255 monitor_->AddWtsConsoleObserver(this); | 263 monitor_->AddWtsConsoleObserver(this); |
| 256 } | 264 } |
| 257 | 265 |
| 258 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() { | 266 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() { |
| 259 DCHECK(state_ == StateDetached); | 267 DCHECK(state_ == StateDetached); |
| 260 DCHECK(!timer_.IsRunning()); | 268 DCHECK(!timer_.IsRunning()); |
| 261 DCHECK(process_.handle() == NULL); | 269 DCHECK(process_.handle() == NULL); |
| 262 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 270 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 263 DCHECK(chromoting_channel_.get() == NULL); | 271 DCHECK(chromoting_channel_.get() == NULL); |
| 264 | 272 |
| 265 monitor_->RemoveWtsConsoleObserver(this); | 273 monitor_->RemoveWtsConsoleObserver(this); |
| 266 } | 274 } |
| 267 | 275 |
| 268 void WtsSessionProcessLauncher::LaunchProcess() { | 276 void WtsSessionProcessLauncher::LaunchProcess() { |
| 277 DCHECK(main_message_loop_->BelongsToCurrentThread()); | |
| 269 DCHECK(state_ == StateStarting); | 278 DCHECK(state_ == StateStarting); |
| 270 DCHECK(!timer_.IsRunning()); | 279 DCHECK(!timer_.IsRunning()); |
| 271 DCHECK(process_.handle() == NULL); | 280 DCHECK(process_.handle() == NULL); |
| 272 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 281 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 273 DCHECK(chromoting_channel_.get() == NULL); | 282 DCHECK(chromoting_channel_.get() == NULL); |
| 274 | 283 |
| 275 launch_time_ = base::Time::Now(); | 284 launch_time_ = base::Time::Now(); |
| 276 | 285 |
| 277 string16 channel_name; | 286 string16 channel_name; |
| 278 ScopedHandle pipe; | 287 ScopedHandle pipe; |
| 279 if (CreatePipeForIpcChannel(this, &channel_name, &pipe)) { | 288 if (CreatePipeForIpcChannel(this, &channel_name, &pipe)) { |
| 280 // Wrap the pipe into an IPC channel. | 289 // Wrap the pipe into an IPC channel. |
| 281 chromoting_channel_.reset(new IPC::ChannelProxy( | 290 chromoting_channel_.reset(new IPC::ChannelProxy( |
| 282 IPC::ChannelHandle(pipe.Get()), | 291 IPC::ChannelHandle(pipe.Get()), |
| 283 IPC::Channel::MODE_SERVER, | 292 IPC::Channel::MODE_SERVER, |
| 284 this, | 293 this, |
| 285 io_thread_->message_loop_proxy().get())); | 294 ipc_message_loop_)); |
| 286 | 295 |
| 287 // Create the host process command line passing the name of the IPC channel | 296 // Create the host process command line passing the name of the IPC channel |
| 288 // to use and copying known switches from the service's command line. | 297 // to use and copying known switches from the service's command line. |
| 289 CommandLine command_line(host_binary_); | 298 CommandLine command_line(host_binary_); |
| 290 command_line.AppendSwitchNative(kChromotingIpcSwitchName, channel_name); | 299 command_line.AppendSwitchNative(kChromotingIpcSwitchName, channel_name); |
| 291 command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(), | 300 command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(), |
| 292 kCopiedSwitchNames, | 301 kCopiedSwitchNames, |
| 293 _countof(kCopiedSwitchNames)); | 302 _countof(kCopiedSwitchNames)); |
| 294 | 303 |
| 295 // Try to launch the process and attach an object watcher to the returned | 304 // Try to launch the process and attach an object watcher to the returned |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 313 // is limited by exponential backoff. | 322 // is limited by exponential backoff. |
| 314 launch_backoff_ = std::max(launch_backoff_ * 2, | 323 launch_backoff_ = std::max(launch_backoff_ * 2, |
| 315 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); | 324 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); |
| 316 launch_backoff_ = std::min(launch_backoff_, | 325 launch_backoff_ = std::min(launch_backoff_, |
| 317 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); | 326 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); |
| 318 timer_.Start(FROM_HERE, launch_backoff_, | 327 timer_.Start(FROM_HERE, launch_backoff_, |
| 319 this, &WtsSessionProcessLauncher::LaunchProcess); | 328 this, &WtsSessionProcessLauncher::LaunchProcess); |
| 320 } | 329 } |
| 321 | 330 |
| 322 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { | 331 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { |
| 332 if (!main_message_loop_->BelongsToCurrentThread()) { | |
| 333 main_message_loop_->PostTask( | |
| 334 FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnObjectSignaled, | |
| 335 base::Unretained(this), object)); | |
|
Wez
2012/04/10 21:26:20
How to do you ensure there are no tasks posted to
alexeypa (please no reviews)
2012/04/10 22:18:16
Good question. The shutdown sequence is indeed scr
| |
| 336 return; | |
| 337 } | |
| 338 | |
| 323 DCHECK(state_ == StateAttached); | 339 DCHECK(state_ == StateAttached); |
| 324 DCHECK(!timer_.IsRunning()); | 340 DCHECK(!timer_.IsRunning()); |
| 325 DCHECK(process_.handle() != NULL); | 341 DCHECK(process_.handle() != NULL); |
| 326 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 342 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 327 DCHECK(chromoting_channel_.get() != NULL); | 343 DCHECK(chromoting_channel_.get() != NULL); |
| 328 | 344 |
| 345 // Stop trying to restart the host process exited due misconfiguration. | |
|
Wez
2012/04/10 21:26:20
typo: missing "if it", I think.
alexeypa (please no reviews)
2012/04/10 22:18:16
Done.
| |
| 346 DWORD exit_code; | |
| 347 bool stop_trying = GetExitCodeProcess(process_.handle(), &exit_code) && | |
| 348 exit_code == kInvalidHostConfigurationExitCode; | |
| 349 | |
| 329 // The host process has been terminated for some reason. The handle can now be | 350 // The host process has been terminated for some reason. The handle can now be |
| 330 // closed. | 351 // closed. |
| 331 process_.Close(); | 352 process_.Close(); |
| 332 chromoting_channel_.reset(); | 353 chromoting_channel_.reset(); |
| 333 | 354 |
| 355 if (stop_trying) { | |
| 356 monitor_->RemoveWtsConsoleObserver(this); | |
|
Wez
2012/04/10 21:26:20
nit: Mention that once all observers are gone the
alexeypa (please no reviews)
2012/04/10 22:18:16
Done.
| |
| 357 return; | |
| 358 } | |
| 359 | |
| 334 // Expand the backoff interval if the process has died quickly or reset it if | 360 // Expand the backoff interval if the process has died quickly or reset it if |
| 335 // it was up longer than the maximum backoff delay. | 361 // it was up longer than the maximum backoff delay. |
| 336 base::TimeDelta delta = base::Time::Now() - launch_time_; | 362 base::TimeDelta delta = base::Time::Now() - launch_time_; |
| 337 if (delta < base::TimeDelta() || | 363 if (delta < base::TimeDelta() || |
| 338 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { | 364 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { |
| 339 launch_backoff_ = base::TimeDelta(); | 365 launch_backoff_ = base::TimeDelta(); |
| 340 } else { | 366 } else { |
| 341 launch_backoff_ = std::max(launch_backoff_ * 2, | 367 launch_backoff_ = std::max(launch_backoff_ * 2, |
| 342 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); | 368 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); |
| 343 launch_backoff_ = std::min(launch_backoff_, | 369 launch_backoff_ = std::min(launch_backoff_, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 354 bool handled = true; | 380 bool handled = true; |
| 355 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) | 381 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) |
| 356 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole, | 382 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole, |
| 357 OnSendSasToConsole) | 383 OnSendSasToConsole) |
| 358 IPC_MESSAGE_UNHANDLED(handled = false) | 384 IPC_MESSAGE_UNHANDLED(handled = false) |
| 359 IPC_END_MESSAGE_MAP() | 385 IPC_END_MESSAGE_MAP() |
| 360 return handled; | 386 return handled; |
| 361 } | 387 } |
| 362 | 388 |
| 363 void WtsSessionProcessLauncher::OnSendSasToConsole() { | 389 void WtsSessionProcessLauncher::OnSendSasToConsole() { |
| 390 if (!main_message_loop_->BelongsToCurrentThread()) { | |
| 391 main_message_loop_->PostTask( | |
| 392 FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnSendSasToConsole, | |
| 393 base::Unretained(this))); | |
| 394 return; | |
| 395 } | |
| 396 | |
| 364 if (state_ == StateAttached) { | 397 if (state_ == StateAttached) { |
| 365 if (sas_injector_.get() == NULL) { | 398 if (sas_injector_.get() == NULL) { |
| 366 sas_injector_ = SasInjector::Create(); | 399 sas_injector_ = SasInjector::Create(); |
| 367 } | 400 } |
| 368 | 401 |
| 369 if (sas_injector_.get() != NULL) { | 402 if (sas_injector_.get() != NULL) { |
| 370 sas_injector_->InjectSas(); | 403 sas_injector_->InjectSas(); |
| 371 } | 404 } |
| 372 } | 405 } |
| 373 } | 406 } |
| 374 | 407 |
| 375 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { | 408 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { |
| 409 DCHECK(main_message_loop_->BelongsToCurrentThread()); | |
| 376 DCHECK(state_ == StateDetached); | 410 DCHECK(state_ == StateDetached); |
| 377 DCHECK(!timer_.IsRunning()); | 411 DCHECK(!timer_.IsRunning()); |
| 378 DCHECK(process_.handle() == NULL); | 412 DCHECK(process_.handle() == NULL); |
| 379 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 413 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 380 DCHECK(chromoting_channel_.get() == NULL); | 414 DCHECK(chromoting_channel_.get() == NULL); |
| 381 | 415 |
| 382 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is | 416 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is |
| 383 // created as needed and kept for later reuse. | 417 // created as needed and kept for later reuse. |
| 384 if (privileged_token_.Get() == NULL) { | 418 if (privileged_token_.Get() == NULL) { |
| 385 if (!CreatePrivilegedToken(&privileged_token_)) { | 419 if (!CreatePrivilegedToken(&privileged_token_)) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 403 | 437 |
| 404 if (!result) | 438 if (!result) |
| 405 return; | 439 return; |
| 406 | 440 |
| 407 // Now try to launch the host. | 441 // Now try to launch the host. |
| 408 state_ = StateStarting; | 442 state_ = StateStarting; |
| 409 LaunchProcess(); | 443 LaunchProcess(); |
| 410 } | 444 } |
| 411 | 445 |
| 412 void WtsSessionProcessLauncher::OnSessionDetached() { | 446 void WtsSessionProcessLauncher::OnSessionDetached() { |
| 447 DCHECK(main_message_loop_->BelongsToCurrentThread()); | |
| 413 DCHECK(state_ == StateDetached || | 448 DCHECK(state_ == StateDetached || |
| 414 state_ == StateStarting || | 449 state_ == StateStarting || |
| 415 state_ == StateAttached); | 450 state_ == StateAttached); |
| 416 | 451 |
| 417 switch (state_) { | 452 switch (state_) { |
| 418 case StateDetached: | 453 case StateDetached: |
| 419 DCHECK(!timer_.IsRunning()); | 454 DCHECK(!timer_.IsRunning()); |
| 420 DCHECK(process_.handle() == NULL); | 455 DCHECK(process_.handle() == NULL); |
| 421 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 456 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 422 DCHECK(chromoting_channel_.get() == NULL); | 457 DCHECK(chromoting_channel_.get() == NULL); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 442 process_watcher_.StopWatching(); | 477 process_watcher_.StopWatching(); |
| 443 process_.Terminate(0); | 478 process_.Terminate(0); |
| 444 process_.Close(); | 479 process_.Close(); |
| 445 chromoting_channel_.reset(); | 480 chromoting_channel_.reset(); |
| 446 state_ = StateDetached; | 481 state_ = StateDetached; |
| 447 break; | 482 break; |
| 448 } | 483 } |
| 449 } | 484 } |
| 450 | 485 |
| 451 } // namespace remoting | 486 } // namespace remoting |
| OLD | NEW |