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 |