| 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 15 matching lines...) Expand all Loading... |
| 26 #include "content/public/common/sandboxed_process_launcher_delegate.h" | 26 #include "content/public/common/sandboxed_process_launcher_delegate.h" |
| 27 #include "mojo/edk/embedder/embedder.h" | 27 #include "mojo/edk/embedder/embedder.h" |
| 28 #include "mojo/edk/embedder/scoped_platform_handle.h" | 28 #include "mojo/edk/embedder/scoped_platform_handle.h" |
| 29 | 29 |
| 30 #if defined(OS_WIN) | 30 #if defined(OS_WIN) |
| 31 #include "base/files/file_path.h" | 31 #include "base/files/file_path.h" |
| 32 #include "base/win/scoped_handle.h" | 32 #include "base/win/scoped_handle.h" |
| 33 #include "base/win/win_util.h" | 33 #include "base/win/win_util.h" |
| 34 #include "content/common/sandbox_win.h" | 34 #include "content/common/sandbox_win.h" |
| 35 #include "content/public/common/sandbox_init.h" | 35 #include "content/public/common/sandbox_init.h" |
| 36 #include "sandbox/win/src/sandbox_types.h" |
| 36 #elif defined(OS_MACOSX) | 37 #elif defined(OS_MACOSX) |
| 37 #include "content/browser/bootstrap_sandbox_manager_mac.h" | 38 #include "content/browser/bootstrap_sandbox_manager_mac.h" |
| 38 #include "content/browser/mach_broker_mac.h" | 39 #include "content/browser/mach_broker_mac.h" |
| 39 #include "sandbox/mac/bootstrap_sandbox.h" | 40 #include "sandbox/mac/bootstrap_sandbox.h" |
| 40 #include "sandbox/mac/pre_exec_delegate.h" | 41 #include "sandbox/mac/pre_exec_delegate.h" |
| 41 #elif defined(OS_ANDROID) | 42 #elif defined(OS_ANDROID) |
| 42 #include "base/android/jni_android.h" | 43 #include "base/android/jni_android.h" |
| 43 #include "content/browser/android/child_process_launcher_android.h" | 44 #include "content/browser/android/child_process_launcher_android.h" |
| 44 #elif defined(OS_POSIX) | 45 #elif defined(OS_POSIX) |
| 45 #include "base/memory/singleton.h" | 46 #include "base/memory/singleton.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 58 | 59 |
| 59 namespace content { | 60 namespace content { |
| 60 | 61 |
| 61 namespace { | 62 namespace { |
| 62 | 63 |
| 63 typedef base::Callback<void(ZygoteHandle, | 64 typedef base::Callback<void(ZygoteHandle, |
| 64 #if defined(OS_ANDROID) | 65 #if defined(OS_ANDROID) |
| 65 base::ScopedFD, | 66 base::ScopedFD, |
| 66 base::ScopedFD, | 67 base::ScopedFD, |
| 67 #endif | 68 #endif |
| 68 base::Process)> NotifyCallback; | 69 base::Process, |
| 70 int)> NotifyCallback; |
| 69 | 71 |
| 70 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { | 72 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { |
| 71 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 73 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| 72 // Log the launch time, separating out the first one (which will likely be | 74 // Log the launch time, separating out the first one (which will likely be |
| 73 // slower due to the rest of the browser initializing at the same time). | 75 // slower due to the rest of the browser initializing at the same time). |
| 74 static bool done_first_launch = false; | 76 static bool done_first_launch = false; |
| 75 if (done_first_launch) { | 77 if (done_first_launch) { |
| 76 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); | 78 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); |
| 77 } else { | 79 } else { |
| 78 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); | 80 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); |
| 79 done_first_launch = true; | 81 done_first_launch = true; |
| 80 } | 82 } |
| 81 } | 83 } |
| 82 | 84 |
| 83 #if defined(OS_ANDROID) | 85 #if defined(OS_ANDROID) |
| 84 // TODO(sievers): Remove this by defining better what happens on what | 86 // TODO(sievers): Remove this by defining better what happens on what |
| 85 // thread in the corresponding Java code. | 87 // thread in the corresponding Java code. |
| 86 void OnChildProcessStartedAndroid(const NotifyCallback& callback, | 88 void OnChildProcessStartedAndroid(const NotifyCallback& callback, |
| 87 BrowserThread::ID client_thread_id, | 89 BrowserThread::ID client_thread_id, |
| 88 const base::TimeTicks begin_launch_time, | 90 const base::TimeTicks begin_launch_time, |
| 89 base::ScopedFD ipcfd, | 91 base::ScopedFD ipcfd, |
| 90 base::ScopedFD mojo_fd, | 92 base::ScopedFD mojo_fd, |
| 91 base::ProcessHandle handle) { | 93 base::ProcessHandle handle) { |
| 94 int launch_result = (handle == base::kNullProcessHandle) |
| 95 ? LAUNCH_RESULT_FAILURE |
| 96 : LAUNCH_RESULT_SUCCESS; |
| 92 // This can be called on the launcher thread or UI thread. | 97 // This can be called on the launcher thread or UI thread. |
| 93 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; | 98 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; |
| 94 BrowserThread::PostTask( | 99 BrowserThread::PostTask( |
| 95 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 100 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| 96 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); | 101 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); |
| 97 | 102 |
| 98 base::Closure callback_on_client_thread( | 103 base::Closure callback_on_client_thread(base::Bind( |
| 99 base::Bind(callback, nullptr, base::Passed(&ipcfd), | 104 callback, nullptr, base::Passed(&ipcfd), base::Passed(&mojo_fd), |
| 100 base::Passed(&mojo_fd), base::Passed(base::Process(handle)))); | 105 base::Passed(base::Process(handle)), launch_result)); |
| 101 if (BrowserThread::CurrentlyOn(client_thread_id)) { | 106 if (BrowserThread::CurrentlyOn(client_thread_id)) { |
| 102 callback_on_client_thread.Run(); | 107 callback_on_client_thread.Run(); |
| 103 } else { | 108 } else { |
| 104 BrowserThread::PostTask( | 109 BrowserThread::PostTask( |
| 105 client_thread_id, FROM_HERE, callback_on_client_thread); | 110 client_thread_id, FROM_HERE, callback_on_client_thread); |
| 106 } | 111 } |
| 107 } | 112 } |
| 108 #endif | 113 #endif |
| 109 | 114 |
| 110 void LaunchOnLauncherThread(const NotifyCallback& callback, | 115 void LaunchOnLauncherThread(const NotifyCallback& callback, |
| 111 BrowserThread::ID client_thread_id, | 116 BrowserThread::ID client_thread_id, |
| 112 int child_process_id, | 117 int child_process_id, |
| 113 SandboxedProcessLauncherDelegate* delegate, | 118 SandboxedProcessLauncherDelegate* delegate, |
| 114 #if defined(OS_ANDROID) | 119 #if defined(OS_ANDROID) |
| 115 base::ScopedFD ipcfd, | 120 base::ScopedFD ipcfd, |
| 116 #endif | 121 #endif |
| 117 mojo::edk::ScopedPlatformHandle client_handle, | 122 mojo::edk::ScopedPlatformHandle client_handle, |
| 118 base::CommandLine* cmd_line) { | 123 base::CommandLine* cmd_line) { |
| 119 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 124 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| 120 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); | 125 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); |
| 121 #if !defined(OS_ANDROID) | 126 #if !defined(OS_ANDROID) |
| 122 ZygoteHandle zygote = nullptr; | 127 ZygoteHandle zygote = nullptr; |
| 128 int launch_result = LAUNCH_RESULT_FAILURE; |
| 123 #endif | 129 #endif |
| 124 #if defined(OS_WIN) | 130 #if defined(OS_WIN) |
| 125 bool launch_elevated = delegate->ShouldLaunchElevated(); | 131 bool launch_elevated = delegate->ShouldLaunchElevated(); |
| 126 #elif defined(OS_MACOSX) | 132 #elif defined(OS_MACOSX) |
| 127 base::EnvironmentMap env = delegate->GetEnvironment(); | 133 base::EnvironmentMap env = delegate->GetEnvironment(); |
| 128 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | 134 base::ScopedFD ipcfd = delegate->TakeIpcFd(); |
| 129 #elif defined(OS_POSIX) && !defined(OS_ANDROID) | 135 #elif defined(OS_POSIX) && !defined(OS_ANDROID) |
| 130 base::EnvironmentMap env = delegate->GetEnvironment(); | 136 base::EnvironmentMap env = delegate->GetEnvironment(); |
| 131 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | 137 base::ScopedFD ipcfd = delegate->TakeIpcFd(); |
| 132 #endif | 138 #endif |
| 133 std::unique_ptr<base::CommandLine> cmd_line_deleter(cmd_line); | 139 std::unique_ptr<base::CommandLine> cmd_line_deleter(cmd_line); |
| 134 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); | 140 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); |
| 135 | 141 |
| 136 base::Process process; | 142 base::Process process; |
| 137 #if defined(OS_WIN) | 143 #if defined(OS_WIN) |
| 138 if (launch_elevated) { | 144 if (launch_elevated) { |
| 139 // TODO(rockot): We may want to support Mojo IPC to elevated processes as | 145 // TODO(rockot): We may want to support Mojo IPC to elevated processes as |
| 140 // well, but this isn't currently feasible without sharing a pipe path on | 146 // well, but this isn't currently feasible without sharing a pipe path on |
| 141 // the command line as elevated process launch goes through ShellExecuteEx. | 147 // the command line as elevated process launch goes through ShellExecuteEx. |
| 142 base::LaunchOptions options; | 148 base::LaunchOptions options; |
| 143 options.start_hidden = true; | 149 options.start_hidden = true; |
| 144 process = base::LaunchElevatedProcess(*cmd_line, options); | 150 process = base::LaunchElevatedProcess(*cmd_line, options); |
| 145 } else { | 151 } else { |
| 146 base::HandlesToInheritVector handles; | 152 base::HandlesToInheritVector handles; |
| 147 handles.push_back(client_handle.get().handle); | 153 handles.push_back(client_handle.get().handle); |
| 148 cmd_line->AppendSwitchASCII( | 154 cmd_line->AppendSwitchASCII( |
| 149 mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch, | 155 mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch, |
| 150 base::UintToString(base::win::HandleToUint32(handles[0]))); | 156 base::UintToString(base::win::HandleToUint32(handles[0]))); |
| 151 process = StartSandboxedProcess(delegate, cmd_line, handles); | 157 launch_result = |
| 158 StartSandboxedProcess(delegate, cmd_line, handles, &process); |
| 152 } | 159 } |
| 153 #elif defined(OS_POSIX) | 160 #elif defined(OS_POSIX) |
| 154 std::string process_type = | 161 std::string process_type = |
| 155 cmd_line->GetSwitchValueASCII(switches::kProcessType); | 162 cmd_line->GetSwitchValueASCII(switches::kProcessType); |
| 156 std::unique_ptr<FileDescriptorInfo> files_to_register( | 163 std::unique_ptr<FileDescriptorInfo> files_to_register( |
| 157 FileDescriptorInfoImpl::Create()); | 164 FileDescriptorInfoImpl::Create()); |
| 158 | 165 |
| 159 base::ScopedFD mojo_fd(client_handle.release().handle); | 166 base::ScopedFD mojo_fd(client_handle.release().handle); |
| 160 DCHECK(mojo_fd.is_valid()); | 167 DCHECK(mojo_fd.is_valid()); |
| 161 | 168 |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 } | 335 } |
| 329 | 336 |
| 330 // After updating the broker, release the lock and let the child's | 337 // After updating the broker, release the lock and let the child's |
| 331 // messasge be processed on the broker's thread. | 338 // messasge be processed on the broker's thread. |
| 332 broker->GetLock().Release(); | 339 broker->GetLock().Release(); |
| 333 #endif // defined(OS_MACOSX) | 340 #endif // defined(OS_MACOSX) |
| 334 } | 341 } |
| 335 #endif // else defined(OS_POSIX) | 342 #endif // else defined(OS_POSIX) |
| 336 #if !defined(OS_ANDROID) | 343 #if !defined(OS_ANDROID) |
| 337 if (process.IsValid()) { | 344 if (process.IsValid()) { |
| 345 launch_result = LAUNCH_RESULT_SUCCESS; |
| 338 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() - | 346 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() - |
| 339 begin_launch_time); | 347 begin_launch_time); |
| 340 } | 348 } |
| 341 BrowserThread::PostTask(client_thread_id, FROM_HERE, | 349 BrowserThread::PostTask(client_thread_id, FROM_HERE, |
| 342 base::Bind(callback, zygote, base::Passed(&process))); | 350 base::Bind(callback, zygote, base::Passed(&process), |
| 351 launch_result)); |
| 343 #endif // !defined(OS_ANDROID) | 352 #endif // !defined(OS_ANDROID) |
| 344 } | 353 } |
| 345 | 354 |
| 346 void TerminateOnLauncherThread(ZygoteHandle zygote, base::Process process) { | 355 void TerminateOnLauncherThread(ZygoteHandle zygote, base::Process process) { |
| 347 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 356 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| 348 #if defined(OS_ANDROID) | 357 #if defined(OS_ANDROID) |
| 349 VLOG(1) << "ChromeProcess: Stopping process with handle " | 358 VLOG(1) << "ChromeProcess: Stopping process with handle " |
| 350 << process.Handle(); | 359 << process.Handle(); |
| 351 StopChildProcess(process.Handle()); | 360 StopChildProcess(process.Handle()); |
| 352 #else | 361 #else |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 } | 502 } |
| 494 | 503 |
| 495 void ChildProcessLauncher::DidLaunch( | 504 void ChildProcessLauncher::DidLaunch( |
| 496 base::WeakPtr<ChildProcessLauncher> instance, | 505 base::WeakPtr<ChildProcessLauncher> instance, |
| 497 bool terminate_on_shutdown, | 506 bool terminate_on_shutdown, |
| 498 ZygoteHandle zygote, | 507 ZygoteHandle zygote, |
| 499 #if defined(OS_ANDROID) | 508 #if defined(OS_ANDROID) |
| 500 base::ScopedFD ipcfd, | 509 base::ScopedFD ipcfd, |
| 501 base::ScopedFD mojo_fd, | 510 base::ScopedFD mojo_fd, |
| 502 #endif | 511 #endif |
| 503 base::Process process) { | 512 base::Process process, |
| 513 int error_code) { |
| 504 if (!process.IsValid()) | 514 if (!process.IsValid()) |
| 505 LOG(ERROR) << "Failed to launch child process"; | 515 LOG(ERROR) << "Failed to launch child process"; |
| 506 | 516 |
| 507 if (instance.get()) { | 517 if (instance.get()) { |
| 508 instance->Notify(zygote, | 518 instance->Notify(zygote, |
| 509 #if defined(OS_ANDROID) | 519 #if defined(OS_ANDROID) |
| 510 std::move(ipcfd), | 520 std::move(ipcfd), |
| 511 #endif | 521 #endif |
| 512 std::move(process)); | 522 std::move(process), |
| 523 error_code); |
| 513 } else { | 524 } else { |
| 514 if (process.IsValid() && terminate_on_shutdown) { | 525 if (process.IsValid() && terminate_on_shutdown) { |
| 515 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So | 526 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So |
| 516 // don't this on the UI/IO threads. | 527 // don't this on the UI/IO threads. |
| 517 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 528 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| 518 base::Bind(&TerminateOnLauncherThread, zygote, | 529 base::Bind(&TerminateOnLauncherThread, zygote, |
| 519 base::Passed(&process))); | 530 base::Passed(&process))); |
| 520 } | 531 } |
| 521 } | 532 } |
| 522 } | 533 } |
| 523 | 534 |
| 524 void ChildProcessLauncher::Notify(ZygoteHandle zygote, | 535 void ChildProcessLauncher::Notify(ZygoteHandle zygote, |
| 525 #if defined(OS_ANDROID) | 536 #if defined(OS_ANDROID) |
| 526 base::ScopedFD ipcfd, | 537 base::ScopedFD ipcfd, |
| 527 #endif | 538 #endif |
| 528 base::Process process) { | 539 base::Process process, |
| 540 int error_code) { |
| 529 DCHECK(CalledOnValidThread()); | 541 DCHECK(CalledOnValidThread()); |
| 530 starting_ = false; | 542 starting_ = false; |
| 531 process_ = std::move(process); | 543 process_ = std::move(process); |
| 532 | 544 |
| 533 if (process_.IsValid()) { | 545 if (process_.IsValid()) { |
| 534 // Set up Mojo IPC to the new process. | 546 // Set up Mojo IPC to the new process. |
| 535 mojo::edk::ChildProcessLaunched(process_.Handle(), | 547 mojo::edk::ChildProcessLaunched(process_.Handle(), |
| 536 mojo_platform_channel_.PassServerHandle()); | 548 mojo_platform_channel_.PassServerHandle()); |
| 537 } | 549 } |
| 538 | 550 |
| 539 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 551 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 540 zygote_ = zygote; | 552 zygote_ = zygote; |
| 541 #endif | 553 #endif |
| 542 if (process_.IsValid()) { | 554 if (process_.IsValid()) { |
| 543 client_->OnProcessLaunched(); | 555 client_->OnProcessLaunched(); |
| 544 } else { | 556 } else { |
| 545 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED; | 557 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED; |
| 546 client_->OnProcessLaunchFailed(); | 558 client_->OnProcessLaunchFailed(error_code); |
| 547 } | 559 } |
| 548 } | 560 } |
| 549 | 561 |
| 550 bool ChildProcessLauncher::IsStarting() { | 562 bool ChildProcessLauncher::IsStarting() { |
| 551 // TODO(crbug.com/469248): This fails in some tests. | 563 // TODO(crbug.com/469248): This fails in some tests. |
| 552 // DCHECK(CalledOnValidThread()); | 564 // DCHECK(CalledOnValidThread()); |
| 553 return starting_; | 565 return starting_; |
| 554 } | 566 } |
| 555 | 567 |
| 556 const base::Process& ChildProcessLauncher::GetProcess() const { | 568 const base::Process& ChildProcessLauncher::GetProcess() const { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 587 } | 599 } |
| 588 | 600 |
| 589 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( | 601 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( |
| 590 Client* client) { | 602 Client* client) { |
| 591 Client* ret = client_; | 603 Client* ret = client_; |
| 592 client_ = client; | 604 client_ = client; |
| 593 return ret; | 605 return ret; |
| 594 } | 606 } |
| 595 | 607 |
| 596 } // namespace content | 608 } // namespace content |
| OLD | NEW |