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 |