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 |