| 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/win/wts_session_process_delegate.h" | 8 #include "remoting/host/win/wts_session_process_delegate.h" |
| 9 | 9 |
| 10 #include <utility> |
| 11 |
| 10 #include "base/bind.h" | 12 #include "base/bind.h" |
| 11 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 12 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
| 13 #include "base/logging.h" | 15 #include "base/logging.h" |
| 14 #include "base/macros.h" | 16 #include "base/macros.h" |
| 15 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 16 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
| 17 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
| 18 #include "base/thread_task_runner_handle.h" | 20 #include "base/thread_task_runner_handle.h" |
| 19 #include "base/win/scoped_handle.h" | 21 #include "base/win/scoped_handle.h" |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 | 84 |
| 83 // Drains the completion port queue to make sure that all job object | 85 // Drains the completion port queue to make sure that all job object |
| 84 // notifications have been received. | 86 // notifications have been received. |
| 85 void DrainJobNotifications(); | 87 void DrainJobNotifications(); |
| 86 | 88 |
| 87 // Notified that the completion port queue has been drained. | 89 // Notified that the completion port queue has been drained. |
| 88 void DrainJobNotificationsCompleted(); | 90 void DrainJobNotificationsCompleted(); |
| 89 | 91 |
| 90 // Creates and initializes the job object that will sandbox the launched child | 92 // Creates and initializes the job object that will sandbox the launched child |
| 91 // processes. | 93 // processes. |
| 92 void InitializeJob(scoped_ptr<base::win::ScopedHandle> job); | 94 void InitializeJob(ScopedHandle job); |
| 93 | 95 |
| 94 // Notified that the job object initialization is complete. | 96 // Notified that the job object initialization is complete. |
| 95 void InitializeJobCompleted(scoped_ptr<base::win::ScopedHandle> job); | 97 void InitializeJobCompleted(ScopedHandle job); |
| 96 | 98 |
| 97 // Called when the number of processes running in the job reaches zero. | 99 // Called when the number of processes running in the job reaches zero. |
| 98 void OnActiveProcessZero(); | 100 void OnActiveProcessZero(); |
| 99 | 101 |
| 100 void ReportFatalError(); | 102 void ReportFatalError(); |
| 101 void ReportProcessLaunched(base::win::ScopedHandle worker_process); | 103 void ReportProcessLaunched(base::win::ScopedHandle worker_process); |
| 102 | 104 |
| 103 // The task runner all public methods of this class should be called on. | 105 // The task runner all public methods of this class should be called on. |
| 104 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; | 106 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; |
| 105 | 107 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 scoped_ptr<base::CommandLine> target_command, | 150 scoped_ptr<base::CommandLine> target_command, |
| 149 bool launch_elevated, | 151 bool launch_elevated, |
| 150 const std::string& channel_security) | 152 const std::string& channel_security) |
| 151 : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 153 : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 152 io_task_runner_(io_task_runner), | 154 io_task_runner_(io_task_runner), |
| 153 channel_security_(channel_security), | 155 channel_security_(channel_security), |
| 154 event_handler_(nullptr), | 156 event_handler_(nullptr), |
| 155 get_named_pipe_client_pid_(nullptr), | 157 get_named_pipe_client_pid_(nullptr), |
| 156 launch_elevated_(launch_elevated), | 158 launch_elevated_(launch_elevated), |
| 157 launch_pending_(false), | 159 launch_pending_(false), |
| 158 target_command_(target_command.Pass()) { | 160 target_command_(std::move(target_command)) {} |
| 159 } | |
| 160 | 161 |
| 161 bool WtsSessionProcessDelegate::Core::Initialize(uint32_t session_id) { | 162 bool WtsSessionProcessDelegate::Core::Initialize(uint32_t session_id) { |
| 162 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 163 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 163 | 164 |
| 164 // Windows XP does not support elevation. | 165 // Windows XP does not support elevation. |
| 165 if (base::win::GetVersion() < base::win::VERSION_VISTA) | 166 if (base::win::GetVersion() < base::win::VERSION_VISTA) |
| 166 launch_elevated_ = false; | 167 launch_elevated_ = false; |
| 167 | 168 |
| 168 if (launch_elevated_) { | 169 if (launch_elevated_) { |
| 169 // GetNamedPipeClientProcessId() is available starting from Vista. | 170 // GetNamedPipeClientProcessId() is available starting from Vista. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 191 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; | 192 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; |
| 192 info.BasicLimitInformation.ActiveProcessLimit = 2; | 193 info.BasicLimitInformation.ActiveProcessLimit = 2; |
| 193 if (!SetInformationJobObject(job.Get(), | 194 if (!SetInformationJobObject(job.Get(), |
| 194 JobObjectExtendedLimitInformation, | 195 JobObjectExtendedLimitInformation, |
| 195 &info, | 196 &info, |
| 196 sizeof(info))) { | 197 sizeof(info))) { |
| 197 PLOG(ERROR) << "Failed to set limits on the job object"; | 198 PLOG(ERROR) << "Failed to set limits on the job object"; |
| 198 return false; | 199 return false; |
| 199 } | 200 } |
| 200 | 201 |
| 201 // ScopedHandle is not compatible with base::Passed, so we wrap it to | |
| 202 // a scoped pointer. | |
| 203 scoped_ptr<ScopedHandle> job_wrapper(new ScopedHandle()); | |
| 204 *job_wrapper = job.Pass(); | |
| 205 | |
| 206 // To receive job object notifications the job object is registered with | 202 // To receive job object notifications the job object is registered with |
| 207 // the completion port represented by |io_task_runner|. The registration has | 203 // the completion port represented by |io_task_runner|. The registration has |
| 208 // to be done on the I/O thread because | 204 // to be done on the I/O thread because |
| 209 // MessageLoopForIO::RegisterJobObject() can only be called via | 205 // MessageLoopForIO::RegisterJobObject() can only be called via |
| 210 // MessageLoopForIO::current(). | 206 // MessageLoopForIO::current(). |
| 211 io_task_runner_->PostTask( | 207 io_task_runner_->PostTask( |
| 212 FROM_HERE, | 208 FROM_HERE, base::Bind(&Core::InitializeJob, this, base::Passed(&job))); |
| 213 base::Bind(&Core::InitializeJob, this, base::Passed(&job_wrapper))); | |
| 214 } | 209 } |
| 215 | 210 |
| 216 // Create a session token for the launched process. | 211 // Create a session token for the launched process. |
| 217 return CreateSessionToken(session_id, &session_token_); | 212 return CreateSessionToken(session_id, &session_token_); |
| 218 } | 213 } |
| 219 | 214 |
| 220 void WtsSessionProcessDelegate::Core::Stop() { | 215 void WtsSessionProcessDelegate::Core::Stop() { |
| 221 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 216 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 222 | 217 |
| 223 KillProcess(); | 218 KillProcess(); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 | 319 |
| 325 DWORD desired_access = | 320 DWORD desired_access = |
| 326 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | 321 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; |
| 327 ScopedHandle worker_process(OpenProcess(desired_access, false, pid)); | 322 ScopedHandle worker_process(OpenProcess(desired_access, false, pid)); |
| 328 if (!worker_process.IsValid()) { | 323 if (!worker_process.IsValid()) { |
| 329 PLOG(ERROR) << "Failed to open process " << pid; | 324 PLOG(ERROR) << "Failed to open process " << pid; |
| 330 ReportFatalError(); | 325 ReportFatalError(); |
| 331 return; | 326 return; |
| 332 } | 327 } |
| 333 | 328 |
| 334 ReportProcessLaunched(worker_process.Pass()); | 329 ReportProcessLaunched(std::move(worker_process)); |
| 335 } | 330 } |
| 336 | 331 |
| 337 if (event_handler_) | 332 if (event_handler_) |
| 338 event_handler_->OnChannelConnected(peer_pid); | 333 event_handler_->OnChannelConnected(peer_pid); |
| 339 } | 334 } |
| 340 | 335 |
| 341 void WtsSessionProcessDelegate::Core::OnChannelError() { | 336 void WtsSessionProcessDelegate::Core::OnChannelError() { |
| 342 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 337 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 343 | 338 |
| 344 event_handler_->OnChannelError(); | 339 event_handler_->OnChannelError(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 return; | 410 return; |
| 416 } | 411 } |
| 417 } | 412 } |
| 418 | 413 |
| 419 if (!ResumeThread(worker_thread.Get())) { | 414 if (!ResumeThread(worker_thread.Get())) { |
| 420 PLOG(ERROR) << "Failed to resume the worker thread"; | 415 PLOG(ERROR) << "Failed to resume the worker thread"; |
| 421 ReportFatalError(); | 416 ReportFatalError(); |
| 422 return; | 417 return; |
| 423 } | 418 } |
| 424 | 419 |
| 425 channel_ = channel.Pass(); | 420 channel_ = std::move(channel); |
| 426 pipe_ = pipe.Pass(); | 421 pipe_ = std::move(pipe); |
| 427 | 422 |
| 428 // Report success if the worker process is lauched directly. Otherwise, PID of | 423 // Report success if the worker process is lauched directly. Otherwise, PID of |
| 429 // the client connected to the pipe will be used later. See | 424 // the client connected to the pipe will be used later. See |
| 430 // OnChannelConnected(). | 425 // OnChannelConnected(). |
| 431 if (!launch_elevated_) | 426 if (!launch_elevated_) |
| 432 ReportProcessLaunched(worker_process.Pass()); | 427 ReportProcessLaunched(std::move(worker_process)); |
| 433 } | 428 } |
| 434 | 429 |
| 435 void WtsSessionProcessDelegate::Core::DrainJobNotifications() { | 430 void WtsSessionProcessDelegate::Core::DrainJobNotifications() { |
| 436 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 431 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 437 | 432 |
| 438 // DrainJobNotifications() is posted after the job object is destroyed, so | 433 // DrainJobNotifications() is posted after the job object is destroyed, so |
| 439 // by this time all notifications from the job object have been processed | 434 // by this time all notifications from the job object have been processed |
| 440 // already. Let the main thread know that the queue has been drained. | 435 // already. Let the main thread know that the queue has been drained. |
| 441 caller_task_runner_->PostTask(FROM_HERE, base::Bind( | 436 caller_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 442 &Core::DrainJobNotificationsCompleted, this)); | 437 &Core::DrainJobNotificationsCompleted, this)); |
| 443 } | 438 } |
| 444 | 439 |
| 445 void WtsSessionProcessDelegate::Core::DrainJobNotificationsCompleted() { | 440 void WtsSessionProcessDelegate::Core::DrainJobNotificationsCompleted() { |
| 446 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 441 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 447 | 442 |
| 448 if (job_.IsValid()) { | 443 if (job_.IsValid()) { |
| 449 job_.Close(); | 444 job_.Close(); |
| 450 | 445 |
| 451 // Drain the completion queue to make sure all job object notification have | 446 // Drain the completion queue to make sure all job object notification have |
| 452 // been received. | 447 // been received. |
| 453 io_task_runner_->PostTask(FROM_HERE, base::Bind( | 448 io_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 454 &Core::DrainJobNotifications, this)); | 449 &Core::DrainJobNotifications, this)); |
| 455 } | 450 } |
| 456 } | 451 } |
| 457 | 452 |
| 458 void WtsSessionProcessDelegate::Core::InitializeJob( | 453 void WtsSessionProcessDelegate::Core::InitializeJob(ScopedHandle job) { |
| 459 scoped_ptr<base::win::ScopedHandle> job) { | |
| 460 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 454 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 461 | 455 |
| 462 // Register to receive job notifications via the I/O thread's completion port. | 456 // Register to receive job notifications via the I/O thread's completion port. |
| 463 if (!base::MessageLoopForIO::current()->RegisterJobObject(job->Get(), this)) { | 457 if (!base::MessageLoopForIO::current()->RegisterJobObject(job.Get(), this)) { |
| 464 PLOG(ERROR) << "Failed to associate the job object with a completion port"; | 458 PLOG(ERROR) << "Failed to associate the job object with a completion port"; |
| 465 return; | 459 return; |
| 466 } | 460 } |
| 467 | 461 |
| 468 // Let the main thread know that initialization is complete. | 462 // Let the main thread know that initialization is complete. |
| 469 caller_task_runner_->PostTask(FROM_HERE, base::Bind( | 463 caller_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 470 &Core::InitializeJobCompleted, this, base::Passed(&job))); | 464 &Core::InitializeJobCompleted, this, base::Passed(&job))); |
| 471 } | 465 } |
| 472 | 466 |
| 473 void WtsSessionProcessDelegate::Core::InitializeJobCompleted( | 467 void WtsSessionProcessDelegate::Core::InitializeJobCompleted(ScopedHandle job) { |
| 474 scoped_ptr<ScopedHandle> job) { | |
| 475 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 468 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 476 DCHECK(!job_.IsValid()); | 469 DCHECK(!job_.IsValid()); |
| 477 | 470 |
| 478 job_ = job->Pass(); | 471 job_ = std::move(job); |
| 479 | 472 |
| 480 if (launch_pending_) | 473 if (launch_pending_) |
| 481 DoLaunchProcess(); | 474 DoLaunchProcess(); |
| 482 } | 475 } |
| 483 | 476 |
| 484 void WtsSessionProcessDelegate::Core::OnActiveProcessZero() { | 477 void WtsSessionProcessDelegate::Core::OnActiveProcessZero() { |
| 485 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 478 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 486 | 479 |
| 487 if (launch_pending_) { | 480 if (launch_pending_) { |
| 488 LOG(ERROR) << "The worker process exited before connecting via IPC."; | 481 LOG(ERROR) << "The worker process exited before connecting via IPC."; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 500 WorkerProcessLauncher* event_handler = event_handler_; | 493 WorkerProcessLauncher* event_handler = event_handler_; |
| 501 event_handler_ = nullptr; | 494 event_handler_ = nullptr; |
| 502 event_handler->OnFatalError(); | 495 event_handler->OnFatalError(); |
| 503 } | 496 } |
| 504 | 497 |
| 505 void WtsSessionProcessDelegate::Core::ReportProcessLaunched( | 498 void WtsSessionProcessDelegate::Core::ReportProcessLaunched( |
| 506 base::win::ScopedHandle worker_process) { | 499 base::win::ScopedHandle worker_process) { |
| 507 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 500 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 508 DCHECK(!worker_process_.IsValid()); | 501 DCHECK(!worker_process_.IsValid()); |
| 509 | 502 |
| 510 worker_process_ = worker_process.Pass(); | 503 worker_process_ = std::move(worker_process); |
| 511 | 504 |
| 512 // Report a handle that can be used to wait for the worker process completion, | 505 // Report a handle that can be used to wait for the worker process completion, |
| 513 // query information about the process and duplicate handles. | 506 // query information about the process and duplicate handles. |
| 514 DWORD desired_access = | 507 DWORD desired_access = |
| 515 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | 508 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; |
| 516 HANDLE temp_handle; | 509 HANDLE temp_handle; |
| 517 if (!DuplicateHandle(GetCurrentProcess(), | 510 if (!DuplicateHandle(GetCurrentProcess(), worker_process_.Get(), |
| 518 worker_process_.Get(), | 511 GetCurrentProcess(), &temp_handle, desired_access, FALSE, |
| 519 GetCurrentProcess(), | |
| 520 &temp_handle, | |
| 521 desired_access, | |
| 522 FALSE, | |
| 523 0)) { | 512 0)) { |
| 524 PLOG(ERROR) << "Failed to duplicate a handle"; | 513 PLOG(ERROR) << "Failed to duplicate a handle"; |
| 525 ReportFatalError(); | 514 ReportFatalError(); |
| 526 return; | 515 return; |
| 527 } | 516 } |
| 528 ScopedHandle limited_handle(temp_handle); | 517 ScopedHandle limited_handle(temp_handle); |
| 529 | 518 |
| 530 event_handler_->OnProcessLaunched(limited_handle.Pass()); | 519 event_handler_->OnProcessLaunched(std::move(limited_handle)); |
| 531 } | 520 } |
| 532 | 521 |
| 533 WtsSessionProcessDelegate::WtsSessionProcessDelegate( | 522 WtsSessionProcessDelegate::WtsSessionProcessDelegate( |
| 534 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, | 523 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
| 535 scoped_ptr<base::CommandLine> target_command, | 524 scoped_ptr<base::CommandLine> target_command, |
| 536 bool launch_elevated, | 525 bool launch_elevated, |
| 537 const std::string& channel_security) { | 526 const std::string& channel_security) { |
| 538 core_ = new Core(io_task_runner, | 527 core_ = new Core(io_task_runner, std::move(target_command), launch_elevated, |
| 539 target_command.Pass(), | |
| 540 launch_elevated, | |
| 541 channel_security); | 528 channel_security); |
| 542 } | 529 } |
| 543 | 530 |
| 544 WtsSessionProcessDelegate::~WtsSessionProcessDelegate() { | 531 WtsSessionProcessDelegate::~WtsSessionProcessDelegate() { |
| 545 core_->Stop(); | 532 core_->Stop(); |
| 546 } | 533 } |
| 547 | 534 |
| 548 bool WtsSessionProcessDelegate::Initialize(uint32_t session_id) { | 535 bool WtsSessionProcessDelegate::Initialize(uint32_t session_id) { |
| 549 return core_->Initialize(session_id); | 536 return core_->Initialize(session_id); |
| 550 } | 537 } |
| 551 | 538 |
| 552 void WtsSessionProcessDelegate::LaunchProcess( | 539 void WtsSessionProcessDelegate::LaunchProcess( |
| 553 WorkerProcessLauncher* event_handler) { | 540 WorkerProcessLauncher* event_handler) { |
| 554 core_->LaunchProcess(event_handler); | 541 core_->LaunchProcess(event_handler); |
| 555 } | 542 } |
| 556 | 543 |
| 557 void WtsSessionProcessDelegate::Send(IPC::Message* message) { | 544 void WtsSessionProcessDelegate::Send(IPC::Message* message) { |
| 558 core_->Send(message); | 545 core_->Send(message); |
| 559 } | 546 } |
| 560 | 547 |
| 561 void WtsSessionProcessDelegate::CloseChannel() { | 548 void WtsSessionProcessDelegate::CloseChannel() { |
| 562 core_->CloseChannel(); | 549 core_->CloseChannel(); |
| 563 } | 550 } |
| 564 | 551 |
| 565 void WtsSessionProcessDelegate::KillProcess() { | 552 void WtsSessionProcessDelegate::KillProcess() { |
| 566 core_->KillProcess(); | 553 core_->KillProcess(); |
| 567 } | 554 } |
| 568 | 555 |
| 569 } // namespace remoting | 556 } // namespace remoting |
| OLD | NEW |