| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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 #include "content/browser/child_process_launcher.h" | 5 #include "content/browser/child_process_launcher.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 base::Passed(base::Process(handle)), launch_result)); | 108 base::Passed(base::Process(handle)), launch_result)); |
| 109 if (BrowserThread::CurrentlyOn(client_thread_id)) { | 109 if (BrowserThread::CurrentlyOn(client_thread_id)) { |
| 110 callback_on_client_thread.Run(); | 110 callback_on_client_thread.Run(); |
| 111 } else { | 111 } else { |
| 112 BrowserThread::PostTask( | 112 BrowserThread::PostTask( |
| 113 client_thread_id, FROM_HERE, callback_on_client_thread); | 113 client_thread_id, FROM_HERE, callback_on_client_thread); |
| 114 } | 114 } |
| 115 } | 115 } |
| 116 #endif | 116 #endif |
| 117 | 117 |
| 118 void LaunchOnLauncherThread(const NotifyCallback& callback, | 118 void LaunchOnLauncherThread( |
| 119 BrowserThread::ID client_thread_id, | 119 const NotifyCallback& callback, |
| 120 int child_process_id, | 120 BrowserThread::ID client_thread_id, |
| 121 SandboxedProcessLauncherDelegate* delegate, | 121 int child_process_id, |
| 122 mojo::edk::ScopedPlatformHandle client_handle, | 122 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate, |
| 123 base::CommandLine* cmd_line) { | 123 mojo::edk::ScopedPlatformHandle client_handle, |
| 124 std::unique_ptr<base::CommandLine> cmd_line) { |
| 124 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 125 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| 125 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); | |
| 126 #if !defined(OS_ANDROID) | 126 #if !defined(OS_ANDROID) |
| 127 ZygoteHandle zygote = nullptr; | 127 ZygoteHandle zygote = nullptr; |
| 128 int launch_result = LAUNCH_RESULT_FAILURE; | 128 int launch_result = LAUNCH_RESULT_FAILURE; |
| 129 #endif | 129 #endif |
| 130 #if defined(OS_WIN) | 130 #if defined(OS_WIN) |
| 131 bool launch_elevated = delegate->ShouldLaunchElevated(); | 131 bool launch_elevated = delegate->ShouldLaunchElevated(); |
| 132 #elif defined(OS_MACOSX) | 132 #elif defined(OS_MACOSX) |
| 133 base::EnvironmentMap env = delegate->GetEnvironment(); | 133 base::EnvironmentMap env = delegate->GetEnvironment(); |
| 134 #elif defined(OS_POSIX) && !defined(OS_ANDROID) | 134 #elif defined(OS_POSIX) && !defined(OS_ANDROID) |
| 135 base::EnvironmentMap env = delegate->GetEnvironment(); | 135 base::EnvironmentMap env = delegate->GetEnvironment(); |
| 136 #endif | 136 #endif |
| 137 std::unique_ptr<base::CommandLine> cmd_line_deleter(cmd_line); | |
| 138 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); | 137 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); |
| 139 | 138 |
| 140 base::Process process; | 139 base::Process process; |
| 141 #if defined(OS_WIN) | 140 #if defined(OS_WIN) |
| 142 if (launch_elevated) { | 141 if (launch_elevated) { |
| 143 // When establishing a Mojo connection, the pipe path has already been added | 142 // When establishing a Mojo connection, the pipe path has already been added |
| 144 // to the command line. | 143 // to the command line. |
| 145 base::LaunchOptions options; | 144 base::LaunchOptions options; |
| 146 options.start_hidden = true; | 145 options.start_hidden = true; |
| 147 process = base::LaunchElevatedProcess(*cmd_line, options); | 146 process = base::LaunchElevatedProcess(*cmd_line, options); |
| 148 } else { | 147 } else { |
| 149 base::HandlesToInheritVector handles; | 148 base::HandlesToInheritVector handles; |
| 150 handles.push_back(client_handle.get().handle); | 149 handles.push_back(client_handle.get().handle); |
| 151 base::FieldTrialList::AppendFieldTrialHandleIfNeeded(&handles); | 150 base::FieldTrialList::AppendFieldTrialHandleIfNeeded(&handles); |
| 152 cmd_line->AppendSwitchASCII( | 151 cmd_line->AppendSwitchASCII( |
| 153 mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch, | 152 mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch, |
| 154 base::UintToString(base::win::HandleToUint32(handles[0]))); | 153 base::UintToString(base::win::HandleToUint32(handles[0]))); |
| 155 launch_result = | 154 launch_result = StartSandboxedProcess( |
| 156 StartSandboxedProcess(delegate, cmd_line, handles, &process); | 155 delegate.get(), cmd_line.get(), handles, &process); |
| 157 } | 156 } |
| 158 #elif defined(OS_POSIX) | 157 #elif defined(OS_POSIX) |
| 159 std::string process_type = | 158 std::string process_type = |
| 160 cmd_line->GetSwitchValueASCII(switches::kProcessType); | 159 cmd_line->GetSwitchValueASCII(switches::kProcessType); |
| 161 std::unique_ptr<FileDescriptorInfo> files_to_register( | 160 std::unique_ptr<FileDescriptorInfo> files_to_register( |
| 162 FileDescriptorInfoImpl::Create()); | 161 FileDescriptorInfoImpl::Create()); |
| 163 | 162 |
| 164 base::ScopedFD mojo_fd(client_handle.release().handle); | 163 base::ScopedFD mojo_fd(client_handle.release().handle); |
| 165 DCHECK(mojo_fd.is_valid()); | 164 DCHECK(mojo_fd.is_valid()); |
| 166 | 165 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 if (process.IsValid()) { | 325 if (process.IsValid()) { |
| 327 broker->AddPlaceholderForPid(process.Pid(), child_process_id); | 326 broker->AddPlaceholderForPid(process.Pid(), child_process_id); |
| 328 } else { | 327 } else { |
| 329 if (pre_exec_delegate) { | 328 if (pre_exec_delegate) { |
| 330 BootstrapSandboxManager::GetInstance()->sandbox()->RevokeToken( | 329 BootstrapSandboxManager::GetInstance()->sandbox()->RevokeToken( |
| 331 pre_exec_delegate->sandbox_token()); | 330 pre_exec_delegate->sandbox_token()); |
| 332 } | 331 } |
| 333 } | 332 } |
| 334 | 333 |
| 335 // After updating the broker, release the lock and let the child's | 334 // After updating the broker, release the lock and let the child's |
| 336 // messasge be processed on the broker's thread. | 335 // message be processed on the broker's thread. |
| 337 broker->GetLock().Release(); | 336 broker->GetLock().Release(); |
| 338 #endif // defined(OS_MACOSX) | 337 #endif // defined(OS_MACOSX) |
| 339 } | 338 } |
| 340 #endif // else defined(OS_POSIX) | 339 #endif // else defined(OS_POSIX) |
| 341 #if !defined(OS_ANDROID) | 340 #if !defined(OS_ANDROID) |
| 342 if (process.IsValid()) { | 341 if (process.IsValid()) { |
| 343 launch_result = LAUNCH_RESULT_SUCCESS; | 342 launch_result = LAUNCH_RESULT_SUCCESS; |
| 344 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() - | 343 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() - |
| 345 begin_launch_time); | 344 begin_launch_time); |
| 346 } | 345 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 #endif // defined(OS_MACOSX) | 384 #endif // defined(OS_MACOSX) |
| 386 } | 385 } |
| 387 #if defined(OS_ANDROID) | 386 #if defined(OS_ANDROID) |
| 388 SetChildProcessInForeground(process.Handle(), !background); | 387 SetChildProcessInForeground(process.Handle(), !background); |
| 389 #endif | 388 #endif |
| 390 } | 389 } |
| 391 | 390 |
| 392 } // namespace | 391 } // namespace |
| 393 | 392 |
| 394 ChildProcessLauncher::ChildProcessLauncher( | 393 ChildProcessLauncher::ChildProcessLauncher( |
| 395 SandboxedProcessLauncherDelegate* delegate, | 394 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate, |
| 396 base::CommandLine* cmd_line, | 395 std::unique_ptr<base::CommandLine> cmd_line, |
| 397 int child_process_id, | 396 int child_process_id, |
| 398 Client* client, | 397 Client* client, |
| 399 const std::string& mojo_child_token, | 398 const std::string& mojo_child_token, |
| 400 const mojo::edk::ProcessErrorCallback& process_error_callback, | 399 const mojo::edk::ProcessErrorCallback& process_error_callback, |
| 401 bool terminate_on_shutdown) | 400 bool terminate_on_shutdown) |
| 402 : client_(client), | 401 : client_(client), |
| 403 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION), | 402 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION), |
| 404 exit_code_(RESULT_CODE_NORMAL_EXIT), | 403 exit_code_(RESULT_CODE_NORMAL_EXIT), |
| 405 zygote_(nullptr), | 404 zygote_(nullptr), |
| 406 starting_(true), | 405 starting_(true), |
| 407 process_error_callback_(process_error_callback), | 406 process_error_callback_(process_error_callback), |
| 408 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ | 407 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ |
| 409 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ | 408 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ |
| 410 defined(UNDEFINED_SANITIZER) | 409 defined(UNDEFINED_SANITIZER) |
| 411 terminate_child_on_shutdown_(false), | 410 terminate_child_on_shutdown_(false), |
| 412 #else | 411 #else |
| 413 terminate_child_on_shutdown_(terminate_on_shutdown), | 412 terminate_child_on_shutdown_(terminate_on_shutdown), |
| 414 #endif | 413 #endif |
| 415 mojo_child_token_(mojo_child_token), | 414 mojo_child_token_(mojo_child_token), |
| 416 weak_factory_(this) { | 415 weak_factory_(this) { |
| 417 DCHECK(CalledOnValidThread()); | 416 DCHECK(CalledOnValidThread()); |
| 418 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_)); | 417 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_)); |
| 419 Launch(delegate, cmd_line, child_process_id); | 418 Launch(std::move(delegate), std::move(cmd_line), child_process_id); |
| 420 } | 419 } |
| 421 | 420 |
| 422 ChildProcessLauncher::~ChildProcessLauncher() { | 421 ChildProcessLauncher::~ChildProcessLauncher() { |
| 423 DCHECK(CalledOnValidThread()); | 422 DCHECK(CalledOnValidThread()); |
| 424 if (process_.IsValid() && terminate_child_on_shutdown_) { | 423 if (process_.IsValid() && terminate_child_on_shutdown_) { |
| 425 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So | 424 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So |
| 426 // don't this on the UI/IO threads. | 425 // don't this on the UI/IO threads. |
| 427 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 426 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| 428 base::Bind(&TerminateOnLauncherThread, zygote_, | 427 base::Bind(&TerminateOnLauncherThread, zygote_, |
| 429 base::Passed(&process_))); | 428 base::Passed(&process_))); |
| 430 } | 429 } |
| 431 } | 430 } |
| 432 | 431 |
| 433 void ChildProcessLauncher::Launch(SandboxedProcessLauncherDelegate* delegate, | 432 void ChildProcessLauncher::Launch( |
| 434 base::CommandLine* cmd_line, | 433 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate, |
| 435 int child_process_id) { | 434 std::unique_ptr<base::CommandLine> cmd_line, |
| 435 int child_process_id) { |
| 436 DCHECK(CalledOnValidThread()); | 436 DCHECK(CalledOnValidThread()); |
| 437 | 437 |
| 438 #if defined(OS_ANDROID) | 438 #if defined(OS_ANDROID) |
| 439 // Android only supports renderer, sandboxed utility and gpu. | 439 // Android only supports renderer, sandboxed utility and gpu. |
| 440 std::string process_type = | 440 std::string process_type = |
| 441 cmd_line->GetSwitchValueASCII(switches::kProcessType); | 441 cmd_line->GetSwitchValueASCII(switches::kProcessType); |
| 442 CHECK(process_type == switches::kGpuProcess || | 442 CHECK(process_type == switches::kGpuProcess || |
| 443 process_type == switches::kRendererProcess || | 443 process_type == switches::kRendererProcess || |
| 444 #if BUILDFLAG(ENABLE_PLUGINS) | 444 #if BUILDFLAG(ENABLE_PLUGINS) |
| 445 process_type == switches::kPpapiPluginProcess || | 445 process_type == switches::kPpapiPluginProcess || |
| 446 #endif | 446 #endif |
| 447 process_type == switches::kUtilityProcess) | 447 process_type == switches::kUtilityProcess) |
| 448 << "Unsupported process type: " << process_type; | 448 << "Unsupported process type: " << process_type; |
| 449 | 449 |
| 450 // Non-sandboxed utility or renderer process are currently not supported. | 450 // Non-sandboxed utility or renderer process are currently not supported. |
| 451 DCHECK(process_type == switches::kGpuProcess || | 451 DCHECK(process_type == switches::kGpuProcess || |
| 452 !cmd_line->HasSwitch(switches::kNoSandbox)); | 452 !cmd_line->HasSwitch(switches::kNoSandbox)); |
| 453 | 453 |
| 454 #endif | 454 #endif |
| 455 mojo::edk::ScopedPlatformHandle server_handle; | 455 mojo::edk::ScopedPlatformHandle server_handle; |
| 456 mojo::edk::ScopedPlatformHandle client_handle; | 456 mojo::edk::ScopedPlatformHandle client_handle; |
| 457 #if defined(OS_WIN) | 457 #if defined(OS_WIN) |
| 458 if (delegate->ShouldLaunchElevated()) { | 458 if (delegate->ShouldLaunchElevated()) { |
| 459 mojo::edk::NamedPlatformChannelPair named_pair; | 459 mojo::edk::NamedPlatformChannelPair named_pair; |
| 460 server_handle = named_pair.PassServerHandle(); | 460 server_handle = named_pair.PassServerHandle(); |
| 461 named_pair.PrepareToPassClientHandleToChildProcess(cmd_line); | 461 named_pair.PrepareToPassClientHandleToChildProcess(cmd_line.get()); |
| 462 } else | 462 } else |
| 463 #endif | 463 #endif |
| 464 { | 464 { |
| 465 mojo::edk::PlatformChannelPair channel_pair; | 465 mojo::edk::PlatformChannelPair channel_pair; |
| 466 server_handle = channel_pair.PassServerHandle(); | 466 server_handle = channel_pair.PassServerHandle(); |
| 467 client_handle = channel_pair.PassClientHandle(); | 467 client_handle = channel_pair.PassClientHandle(); |
| 468 } | 468 } |
| 469 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch, | 469 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch, |
| 470 weak_factory_.GetWeakPtr(), | 470 weak_factory_.GetWeakPtr(), |
| 471 terminate_child_on_shutdown_, | 471 terminate_child_on_shutdown_, |
| 472 base::Passed(&server_handle))); | 472 base::Passed(&server_handle))); |
| 473 BrowserThread::PostTask( | 473 BrowserThread::PostTask( |
| 474 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 474 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| 475 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_, | 475 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_, |
| 476 child_process_id, delegate, | 476 child_process_id, base::Passed(&delegate), |
| 477 base::Passed(&client_handle), cmd_line)); | 477 base::Passed(&client_handle), base::Passed(&cmd_line))); |
| 478 } | 478 } |
| 479 | 479 |
| 480 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { | 480 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { |
| 481 DCHECK(CalledOnValidThread()); | 481 DCHECK(CalledOnValidThread()); |
| 482 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 482 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 483 if (zygote_) { | 483 if (zygote_) { |
| 484 termination_status_ = zygote_->GetTerminationStatus( | 484 termination_status_ = zygote_->GetTerminationStatus( |
| 485 process_.Handle(), known_dead, &exit_code_); | 485 process_.Handle(), known_dead, &exit_code_); |
| 486 } else if (known_dead) { | 486 } else if (known_dead) { |
| 487 termination_status_ = | 487 termination_status_ = |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 } | 605 } |
| 606 | 606 |
| 607 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( | 607 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( |
| 608 Client* client) { | 608 Client* client) { |
| 609 Client* ret = client_; | 609 Client* ret = client_; |
| 610 client_ = client; | 610 client_ = client; |
| 611 return ret; | 611 return ret; |
| 612 } | 612 } |
| 613 | 613 |
| 614 } // namespace content | 614 } // namespace content |
| OLD | NEW |