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) { |
| 323 DCHECK(state_ == StateAttached); | 332 if (!main_message_loop_->BelongsToCurrentThread()) { |
| 333 main_message_loop_->PostTask( | |
| 334 FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnObjectSignaled, | |
| 335 base::Unretained(this), object)); | |
| 336 return; | |
| 337 } | |
| 338 | |
| 339 // It is possible that OnObjectSignaled() task will be queued by another | |
| 340 // thread right before |process_watcher_| was stopped. It such a case it is | |
| 341 // safe to ignore this notiifcation. | |
|
Wez
2012/04/11 01:01:23
typo: notiification
alexeypa (please no reviews)
2012/04/11 17:39:39
Done.
| |
| 342 if (state_ != StateAttached) { | |
| 343 return; | |
| 344 } | |
| 345 | |
| 324 DCHECK(!timer_.IsRunning()); | 346 DCHECK(!timer_.IsRunning()); |
| 325 DCHECK(process_.handle() != NULL); | 347 DCHECK(process_.handle() != NULL); |
| 326 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 348 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 327 DCHECK(chromoting_channel_.get() != NULL); | 349 DCHECK(chromoting_channel_.get() != NULL); |
| 328 | 350 |
| 351 // Stop trying to restart the host if its process exited due misconfiguration. | |
|
Wez
2012/04/11 01:01:23
typo: ... due to misconfiguration.
alexeypa (please no reviews)
2012/04/11 17:39:39
Done.
| |
| 352 DWORD exit_code; | |
| 353 bool stop_trying = GetExitCodeProcess(process_.handle(), &exit_code) && | |
| 354 exit_code == kInvalidHostConfigurationExitCode; | |
| 355 | |
| 329 // The host process has been terminated for some reason. The handle can now be | 356 // The host process has been terminated for some reason. The handle can now be |
| 330 // closed. | 357 // closed. |
| 331 process_.Close(); | 358 process_.Close(); |
| 332 chromoting_channel_.reset(); | 359 chromoting_channel_.reset(); |
| 333 | 360 |
| 361 if (stop_trying) { | |
| 362 // N.B. The service will stop once the last observer is removed from | |
| 363 // the list. | |
| 364 monitor_->RequestRemoveWtsConsoleObserver(this); | |
| 365 return; | |
| 366 } | |
| 367 | |
| 334 // Expand the backoff interval if the process has died quickly or reset it if | 368 // Expand the backoff interval if the process has died quickly or reset it if |
| 335 // it was up longer than the maximum backoff delay. | 369 // it was up longer than the maximum backoff delay. |
| 336 base::TimeDelta delta = base::Time::Now() - launch_time_; | 370 base::TimeDelta delta = base::Time::Now() - launch_time_; |
| 337 if (delta < base::TimeDelta() || | 371 if (delta < base::TimeDelta() || |
| 338 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { | 372 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { |
| 339 launch_backoff_ = base::TimeDelta(); | 373 launch_backoff_ = base::TimeDelta(); |
| 340 } else { | 374 } else { |
| 341 launch_backoff_ = std::max(launch_backoff_ * 2, | 375 launch_backoff_ = std::max(launch_backoff_ * 2, |
| 342 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); | 376 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); |
| 343 launch_backoff_ = std::min(launch_backoff_, | 377 launch_backoff_ = std::min(launch_backoff_, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 354 bool handled = true; | 388 bool handled = true; |
| 355 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) | 389 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) |
| 356 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole, | 390 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole, |
| 357 OnSendSasToConsole) | 391 OnSendSasToConsole) |
| 358 IPC_MESSAGE_UNHANDLED(handled = false) | 392 IPC_MESSAGE_UNHANDLED(handled = false) |
| 359 IPC_END_MESSAGE_MAP() | 393 IPC_END_MESSAGE_MAP() |
| 360 return handled; | 394 return handled; |
| 361 } | 395 } |
| 362 | 396 |
| 363 void WtsSessionProcessLauncher::OnSendSasToConsole() { | 397 void WtsSessionProcessLauncher::OnSendSasToConsole() { |
| 398 if (!main_message_loop_->BelongsToCurrentThread()) { | |
| 399 main_message_loop_->PostTask( | |
| 400 FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnSendSasToConsole, | |
| 401 base::Unretained(this))); | |
| 402 return; | |
| 403 } | |
| 404 | |
| 364 if (state_ == StateAttached) { | 405 if (state_ == StateAttached) { |
| 365 if (sas_injector_.get() == NULL) { | 406 if (sas_injector_.get() == NULL) { |
| 366 sas_injector_ = SasInjector::Create(); | 407 sas_injector_ = SasInjector::Create(); |
| 367 } | 408 } |
| 368 | 409 |
| 369 if (sas_injector_.get() != NULL) { | 410 if (sas_injector_.get() != NULL) { |
| 370 sas_injector_->InjectSas(); | 411 sas_injector_->InjectSas(); |
| 371 } | 412 } |
| 372 } | 413 } |
| 373 } | 414 } |
| 374 | 415 |
| 375 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { | 416 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { |
| 417 DCHECK(main_message_loop_->BelongsToCurrentThread()); | |
| 376 DCHECK(state_ == StateDetached); | 418 DCHECK(state_ == StateDetached); |
| 377 DCHECK(!timer_.IsRunning()); | 419 DCHECK(!timer_.IsRunning()); |
| 378 DCHECK(process_.handle() == NULL); | 420 DCHECK(process_.handle() == NULL); |
| 379 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 421 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 380 DCHECK(chromoting_channel_.get() == NULL); | 422 DCHECK(chromoting_channel_.get() == NULL); |
| 381 | 423 |
| 382 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is | 424 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is |
| 383 // created as needed and kept for later reuse. | 425 // created as needed and kept for later reuse. |
| 384 if (privileged_token_.Get() == NULL) { | 426 if (privileged_token_.Get() == NULL) { |
| 385 if (!CreatePrivilegedToken(&privileged_token_)) { | 427 if (!CreatePrivilegedToken(&privileged_token_)) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 403 | 445 |
| 404 if (!result) | 446 if (!result) |
| 405 return; | 447 return; |
| 406 | 448 |
| 407 // Now try to launch the host. | 449 // Now try to launch the host. |
| 408 state_ = StateStarting; | 450 state_ = StateStarting; |
| 409 LaunchProcess(); | 451 LaunchProcess(); |
| 410 } | 452 } |
| 411 | 453 |
| 412 void WtsSessionProcessLauncher::OnSessionDetached() { | 454 void WtsSessionProcessLauncher::OnSessionDetached() { |
| 455 DCHECK(main_message_loop_->BelongsToCurrentThread()); | |
| 413 DCHECK(state_ == StateDetached || | 456 DCHECK(state_ == StateDetached || |
| 414 state_ == StateStarting || | 457 state_ == StateStarting || |
| 415 state_ == StateAttached); | 458 state_ == StateAttached); |
| 416 | 459 |
| 417 switch (state_) { | 460 switch (state_) { |
| 418 case StateDetached: | 461 case StateDetached: |
| 419 DCHECK(!timer_.IsRunning()); | 462 DCHECK(!timer_.IsRunning()); |
| 420 DCHECK(process_.handle() == NULL); | 463 DCHECK(process_.handle() == NULL); |
| 421 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 464 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 422 DCHECK(chromoting_channel_.get() == NULL); | 465 DCHECK(chromoting_channel_.get() == NULL); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 442 process_watcher_.StopWatching(); | 485 process_watcher_.StopWatching(); |
| 443 process_.Terminate(0); | 486 process_.Terminate(0); |
| 444 process_.Close(); | 487 process_.Close(); |
| 445 chromoting_channel_.reset(); | 488 chromoting_channel_.reset(); |
| 446 state_ = StateDetached; | 489 state_ = StateDetached; |
| 447 break; | 490 break; |
| 448 } | 491 } |
| 449 } | 492 } |
| 450 | 493 |
| 451 } // namespace remoting | 494 } // namespace remoting |
| OLD | NEW |