| 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 #include "gin/v8_initializer.h" | 60 #include "gin/v8_initializer.h" |
| 61 #endif | 61 #endif |
| 62 | 62 |
| 63 namespace content { | 63 namespace content { |
| 64 | 64 |
| 65 namespace { | 65 namespace { |
| 66 | 66 |
| 67 typedef base::Callback<void(ZygoteHandle, | 67 typedef base::Callback<void(ZygoteHandle, |
| 68 #if defined(OS_ANDROID) | 68 #if defined(OS_ANDROID) |
| 69 base::ScopedFD, | 69 base::ScopedFD, |
| 70 base::ScopedFD, | |
| 71 #endif | 70 #endif |
| 72 base::Process, | 71 base::Process, |
| 73 int)> NotifyCallback; | 72 int)> |
| 73 NotifyCallback; |
| 74 | 74 |
| 75 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { | 75 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { |
| 76 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 76 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| 77 // Log the launch time, separating out the first one (which will likely be | 77 // Log the launch time, separating out the first one (which will likely be |
| 78 // slower due to the rest of the browser initializing at the same time). | 78 // slower due to the rest of the browser initializing at the same time). |
| 79 static bool done_first_launch = false; | 79 static bool done_first_launch = false; |
| 80 if (done_first_launch) { | 80 if (done_first_launch) { |
| 81 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); | 81 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); |
| 82 } else { | 82 } else { |
| 83 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); | 83 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); |
| 84 done_first_launch = true; | 84 done_first_launch = true; |
| 85 } | 85 } |
| 86 } | 86 } |
| 87 | 87 |
| 88 #if defined(OS_ANDROID) | 88 #if defined(OS_ANDROID) |
| 89 // TODO(sievers): Remove this by defining better what happens on what | 89 // TODO(sievers): Remove this by defining better what happens on what |
| 90 // thread in the corresponding Java code. | 90 // thread in the corresponding Java code. |
| 91 void OnChildProcessStartedAndroid(const NotifyCallback& callback, | 91 void OnChildProcessStartedAndroid(const NotifyCallback& callback, |
| 92 BrowserThread::ID client_thread_id, | 92 BrowserThread::ID client_thread_id, |
| 93 const base::TimeTicks begin_launch_time, | 93 const base::TimeTicks begin_launch_time, |
| 94 base::ScopedFD ipcfd, | |
| 95 base::ScopedFD mojo_fd, | 94 base::ScopedFD mojo_fd, |
| 96 base::ProcessHandle handle) { | 95 base::ProcessHandle handle) { |
| 97 int launch_result = (handle == base::kNullProcessHandle) | 96 int launch_result = (handle == base::kNullProcessHandle) |
| 98 ? LAUNCH_RESULT_FAILURE | 97 ? LAUNCH_RESULT_FAILURE |
| 99 : LAUNCH_RESULT_SUCCESS; | 98 : LAUNCH_RESULT_SUCCESS; |
| 100 // This can be called on the launcher thread or UI thread. | 99 // This can be called on the launcher thread or UI thread. |
| 101 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; | 100 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; |
| 102 BrowserThread::PostTask( | 101 BrowserThread::PostTask( |
| 103 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 102 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| 104 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); | 103 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); |
| 105 | 104 |
| 106 base::Closure callback_on_client_thread(base::Bind( | 105 base::Closure callback_on_client_thread( |
| 107 callback, nullptr, base::Passed(&ipcfd), base::Passed(&mojo_fd), | 106 base::Bind(callback, nullptr, base::Passed(&mojo_fd), |
| 108 base::Passed(base::Process(handle)), launch_result)); | 107 base::Passed(base::Process(handle)), launch_result)); |
| 109 if (BrowserThread::CurrentlyOn(client_thread_id)) { | 108 if (BrowserThread::CurrentlyOn(client_thread_id)) { |
| 110 callback_on_client_thread.Run(); | 109 callback_on_client_thread.Run(); |
| 111 } else { | 110 } else { |
| 112 BrowserThread::PostTask( | 111 BrowserThread::PostTask( |
| 113 client_thread_id, FROM_HERE, callback_on_client_thread); | 112 client_thread_id, FROM_HERE, callback_on_client_thread); |
| 114 } | 113 } |
| 115 } | 114 } |
| 116 #endif | 115 #endif |
| 117 | 116 |
| 118 void LaunchOnLauncherThread(const NotifyCallback& callback, | 117 void LaunchOnLauncherThread(const NotifyCallback& callback, |
| 119 BrowserThread::ID client_thread_id, | 118 BrowserThread::ID client_thread_id, |
| 120 int child_process_id, | 119 int child_process_id, |
| 121 SandboxedProcessLauncherDelegate* delegate, | 120 SandboxedProcessLauncherDelegate* delegate, |
| 122 #if defined(OS_ANDROID) | |
| 123 base::ScopedFD ipcfd, | |
| 124 #endif | |
| 125 mojo::edk::ScopedPlatformHandle client_handle, | 121 mojo::edk::ScopedPlatformHandle client_handle, |
| 126 base::CommandLine* cmd_line) { | 122 base::CommandLine* cmd_line) { |
| 127 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 123 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| 128 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); | 124 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); |
| 129 #if !defined(OS_ANDROID) | 125 #if !defined(OS_ANDROID) |
| 130 ZygoteHandle zygote = nullptr; | 126 ZygoteHandle zygote = nullptr; |
| 131 int launch_result = LAUNCH_RESULT_FAILURE; | 127 int launch_result = LAUNCH_RESULT_FAILURE; |
| 132 #endif | 128 #endif |
| 133 #if defined(OS_WIN) | 129 #if defined(OS_WIN) |
| 134 bool launch_elevated = delegate->ShouldLaunchElevated(); | 130 bool launch_elevated = delegate->ShouldLaunchElevated(); |
| 135 #elif defined(OS_MACOSX) | 131 #elif defined(OS_MACOSX) |
| 136 base::EnvironmentMap env = delegate->GetEnvironment(); | 132 base::EnvironmentMap env = delegate->GetEnvironment(); |
| 137 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | |
| 138 #elif defined(OS_POSIX) && !defined(OS_ANDROID) | 133 #elif defined(OS_POSIX) && !defined(OS_ANDROID) |
| 139 base::EnvironmentMap env = delegate->GetEnvironment(); | 134 base::EnvironmentMap env = delegate->GetEnvironment(); |
| 140 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | |
| 141 #endif | 135 #endif |
| 142 std::unique_ptr<base::CommandLine> cmd_line_deleter(cmd_line); | 136 std::unique_ptr<base::CommandLine> cmd_line_deleter(cmd_line); |
| 143 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); | 137 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); |
| 144 | 138 |
| 145 base::Process process; | 139 base::Process process; |
| 146 #if defined(OS_WIN) | 140 #if defined(OS_WIN) |
| 147 if (launch_elevated) { | 141 if (launch_elevated) { |
| 148 // 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 |
| 149 // to the command line. | 143 // to the command line. |
| 150 base::LaunchOptions options; | 144 base::LaunchOptions options; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 163 #elif defined(OS_POSIX) | 157 #elif defined(OS_POSIX) |
| 164 std::string process_type = | 158 std::string process_type = |
| 165 cmd_line->GetSwitchValueASCII(switches::kProcessType); | 159 cmd_line->GetSwitchValueASCII(switches::kProcessType); |
| 166 std::unique_ptr<FileDescriptorInfo> files_to_register( | 160 std::unique_ptr<FileDescriptorInfo> files_to_register( |
| 167 FileDescriptorInfoImpl::Create()); | 161 FileDescriptorInfoImpl::Create()); |
| 168 | 162 |
| 169 base::ScopedFD mojo_fd(client_handle.release().handle); | 163 base::ScopedFD mojo_fd(client_handle.release().handle); |
| 170 DCHECK(mojo_fd.is_valid()); | 164 DCHECK(mojo_fd.is_valid()); |
| 171 | 165 |
| 172 #if defined(OS_ANDROID) | 166 #if defined(OS_ANDROID) |
| 173 if (ipcfd.get() != -1) | |
| 174 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get()); | |
| 175 files_to_register->Share(kMojoIPCChannel, mojo_fd.get()); | 167 files_to_register->Share(kMojoIPCChannel, mojo_fd.get()); |
| 176 #else | 168 #else |
| 177 if (ipcfd.get() != -1) | |
| 178 files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd)); | |
| 179 files_to_register->Transfer(kMojoIPCChannel, std::move(mojo_fd)); | 169 files_to_register->Transfer(kMojoIPCChannel, std::move(mojo_fd)); |
| 180 #endif | 170 #endif |
| 181 #endif | 171 #endif |
| 182 | 172 |
| 183 #if defined(OS_POSIX) && !defined(OS_MACOSX) | 173 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
| 184 std::map<int, base::MemoryMappedFile::Region> regions; | 174 std::map<int, base::MemoryMappedFile::Region> regions; |
| 185 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( | 175 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( |
| 186 *cmd_line, child_process_id, files_to_register.get() | 176 *cmd_line, child_process_id, files_to_register.get() |
| 187 #if defined(OS_ANDROID) | 177 #if defined(OS_ANDROID) |
| 188 , ®ions | 178 , ®ions |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 base::i18n::GetIcuDataFileHandle(®ions[kAndroidICUDataDescriptor])); | 236 base::i18n::GetIcuDataFileHandle(®ions[kAndroidICUDataDescriptor])); |
| 247 #endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE | 237 #endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE |
| 248 | 238 |
| 249 // Android WebView runs in single process, ensure that we never get here | 239 // Android WebView runs in single process, ensure that we never get here |
| 250 // when running in single process mode. | 240 // when running in single process mode. |
| 251 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); | 241 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); |
| 252 | 242 |
| 253 StartChildProcess( | 243 StartChildProcess( |
| 254 cmd_line->argv(), child_process_id, std::move(files_to_register), regions, | 244 cmd_line->argv(), child_process_id, std::move(files_to_register), regions, |
| 255 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, | 245 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, |
| 256 begin_launch_time, base::Passed(&ipcfd), | 246 begin_launch_time, base::Passed(&mojo_fd))); |
| 257 base::Passed(&mojo_fd))); | |
| 258 | 247 |
| 259 #elif defined(OS_POSIX) | 248 #elif defined(OS_POSIX) |
| 260 // We need to close the client end of the IPC channel to reliably detect | 249 // We need to close the client end of the IPC channel to reliably detect |
| 261 // child termination. | 250 // child termination. |
| 262 | 251 |
| 263 #if !defined(OS_MACOSX) | 252 #if !defined(OS_MACOSX) |
| 264 ZygoteHandle* zygote_handle = | 253 ZygoteHandle* zygote_handle = |
| 265 !base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoZygote) | 254 !base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoZygote) |
| 266 ? delegate->GetZygote() | 255 ? delegate->GetZygote() |
| 267 : nullptr; | 256 : nullptr; |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 #if defined(ENABLE_PLUGINS) | 436 #if defined(ENABLE_PLUGINS) |
| 448 process_type == switches::kPpapiPluginProcess || | 437 process_type == switches::kPpapiPluginProcess || |
| 449 #endif | 438 #endif |
| 450 process_type == switches::kUtilityProcess) | 439 process_type == switches::kUtilityProcess) |
| 451 << "Unsupported process type: " << process_type; | 440 << "Unsupported process type: " << process_type; |
| 452 | 441 |
| 453 // Non-sandboxed utility or renderer process are currently not supported. | 442 // Non-sandboxed utility or renderer process are currently not supported. |
| 454 DCHECK(process_type == switches::kGpuProcess || | 443 DCHECK(process_type == switches::kGpuProcess || |
| 455 !cmd_line->HasSwitch(switches::kNoSandbox)); | 444 !cmd_line->HasSwitch(switches::kNoSandbox)); |
| 456 | 445 |
| 457 // We need to close the client end of the IPC channel to reliably detect | |
| 458 // child termination. We will close this fd after we create the child | |
| 459 // process which is asynchronous on Android. | |
| 460 base::ScopedFD ipcfd(delegate->TakeIpcFd().release()); | |
| 461 #endif | 446 #endif |
| 462 mojo::edk::ScopedPlatformHandle server_handle; | 447 mojo::edk::ScopedPlatformHandle server_handle; |
| 463 mojo::edk::ScopedPlatformHandle client_handle; | 448 mojo::edk::ScopedPlatformHandle client_handle; |
| 464 #if defined(OS_WIN) | 449 #if defined(OS_WIN) |
| 465 if (delegate->ShouldLaunchElevated()) { | 450 if (delegate->ShouldLaunchElevated()) { |
| 466 mojo::edk::NamedPlatformChannelPair named_pair; | 451 mojo::edk::NamedPlatformChannelPair named_pair; |
| 467 server_handle = named_pair.PassServerHandle(); | 452 server_handle = named_pair.PassServerHandle(); |
| 468 named_pair.PrepareToPassClientHandleToChildProcess(cmd_line); | 453 named_pair.PrepareToPassClientHandleToChildProcess(cmd_line); |
| 469 } else | 454 } else |
| 470 #endif | 455 #endif |
| 471 { | 456 { |
| 472 mojo::edk::PlatformChannelPair channel_pair; | 457 mojo::edk::PlatformChannelPair channel_pair; |
| 473 server_handle = channel_pair.PassServerHandle(); | 458 server_handle = channel_pair.PassServerHandle(); |
| 474 client_handle = channel_pair.PassClientHandle(); | 459 client_handle = channel_pair.PassClientHandle(); |
| 475 } | 460 } |
| 476 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch, | 461 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch, |
| 477 weak_factory_.GetWeakPtr(), | 462 weak_factory_.GetWeakPtr(), |
| 478 terminate_child_on_shutdown_, | 463 terminate_child_on_shutdown_, |
| 479 base::Passed(&server_handle))); | 464 base::Passed(&server_handle))); |
| 480 BrowserThread::PostTask( | 465 BrowserThread::PostTask( |
| 481 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 466 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| 482 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_, | 467 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_, |
| 483 child_process_id, delegate, | 468 child_process_id, delegate, |
| 484 #if defined(OS_ANDROID) | |
| 485 base::Passed(&ipcfd), | |
| 486 #endif | |
| 487 base::Passed(&client_handle), cmd_line)); | 469 base::Passed(&client_handle), cmd_line)); |
| 488 } | 470 } |
| 489 | 471 |
| 490 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { | 472 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { |
| 491 DCHECK(CalledOnValidThread()); | 473 DCHECK(CalledOnValidThread()); |
| 492 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 474 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 493 if (zygote_) { | 475 if (zygote_) { |
| 494 termination_status_ = zygote_->GetTerminationStatus( | 476 termination_status_ = zygote_->GetTerminationStatus( |
| 495 process_.Handle(), known_dead, &exit_code_); | 477 process_.Handle(), known_dead, &exit_code_); |
| 496 } else if (known_dead) { | 478 } else if (known_dead) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 521 base::Bind(&SetProcessBackgroundedOnLauncherThread, | 503 base::Bind(&SetProcessBackgroundedOnLauncherThread, |
| 522 base::Passed(&to_pass), background)); | 504 base::Passed(&to_pass), background)); |
| 523 } | 505 } |
| 524 | 506 |
| 525 void ChildProcessLauncher::DidLaunch( | 507 void ChildProcessLauncher::DidLaunch( |
| 526 base::WeakPtr<ChildProcessLauncher> instance, | 508 base::WeakPtr<ChildProcessLauncher> instance, |
| 527 bool terminate_on_shutdown, | 509 bool terminate_on_shutdown, |
| 528 mojo::edk::ScopedPlatformHandle server_handle, | 510 mojo::edk::ScopedPlatformHandle server_handle, |
| 529 ZygoteHandle zygote, | 511 ZygoteHandle zygote, |
| 530 #if defined(OS_ANDROID) | 512 #if defined(OS_ANDROID) |
| 531 base::ScopedFD ipcfd, | |
| 532 base::ScopedFD mojo_fd, | 513 base::ScopedFD mojo_fd, |
| 533 #endif | 514 #endif |
| 534 base::Process process, | 515 base::Process process, |
| 535 int error_code) { | 516 int error_code) { |
| 536 if (!process.IsValid()) | 517 if (!process.IsValid()) |
| 537 LOG(ERROR) << "Failed to launch child process"; | 518 LOG(ERROR) << "Failed to launch child process"; |
| 538 | 519 |
| 539 if (instance.get()) { | 520 if (instance.get()) { |
| 540 instance->Notify(zygote, std::move(server_handle), | 521 instance->Notify(zygote, std::move(server_handle), |
| 541 #if defined(OS_ANDROID) | |
| 542 std::move(ipcfd), | |
| 543 #endif | |
| 544 std::move(process), error_code); | 522 std::move(process), error_code); |
| 545 } else { | 523 } else { |
| 546 if (process.IsValid() && terminate_on_shutdown) { | 524 if (process.IsValid() && terminate_on_shutdown) { |
| 547 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So | 525 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So |
| 548 // don't this on the UI/IO threads. | 526 // don't this on the UI/IO threads. |
| 549 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 527 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| 550 base::Bind(&TerminateOnLauncherThread, zygote, | 528 base::Bind(&TerminateOnLauncherThread, zygote, |
| 551 base::Passed(&process))); | 529 base::Passed(&process))); |
| 552 } | 530 } |
| 553 } | 531 } |
| 554 } | 532 } |
| 555 | 533 |
| 556 void ChildProcessLauncher::Notify(ZygoteHandle zygote, | 534 void ChildProcessLauncher::Notify(ZygoteHandle zygote, |
| 557 mojo::edk::ScopedPlatformHandle server_handle, | 535 mojo::edk::ScopedPlatformHandle server_handle, |
| 558 #if defined(OS_ANDROID) | |
| 559 base::ScopedFD ipcfd, | |
| 560 #endif | |
| 561 base::Process process, | 536 base::Process process, |
| 562 int error_code) { | 537 int error_code) { |
| 563 DCHECK(CalledOnValidThread()); | 538 DCHECK(CalledOnValidThread()); |
| 564 starting_ = false; | 539 starting_ = false; |
| 565 process_ = std::move(process); | 540 process_ = std::move(process); |
| 566 | 541 |
| 567 if (process_.IsValid()) { | 542 if (process_.IsValid()) { |
| 568 // Set up Mojo IPC to the new process. | 543 // Set up Mojo IPC to the new process. |
| 569 mojo::edk::ChildProcessLaunched(process_.Handle(), std::move(server_handle), | 544 mojo::edk::ChildProcessLaunched(process_.Handle(), std::move(server_handle), |
| 570 mojo_child_token_, process_error_callback_); | 545 mojo_child_token_, process_error_callback_); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 } | 597 } |
| 623 | 598 |
| 624 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( | 599 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( |
| 625 Client* client) { | 600 Client* client) { |
| 626 Client* ret = client_; | 601 Client* ret = client_; |
| 627 client_ = client; | 602 client_ = client; |
| 628 return ret; | 603 return ret; |
| 629 } | 604 } |
| 630 | 605 |
| 631 } // namespace content | 606 } // namespace content |
| OLD | NEW |