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 <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
12 #include "base/i18n/icu_util.h" | 12 #include "base/i18n/icu_util.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
15 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
16 #include "base/process/launch.h" | 16 #include "base/process/launch.h" |
17 #include "base/process/process.h" | 17 #include "base/process/process.h" |
18 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
19 #include "base/synchronization/lock.h" | 19 #include "base/synchronization/lock.h" |
20 #include "base/threading/thread.h" | 20 #include "base/threading/thread.h" |
21 #include "build/build_config.h" | 21 #include "build/build_config.h" |
22 #include "content/public/browser/content_browser_client.h" | 22 #include "content/public/browser/content_browser_client.h" |
23 #include "content/public/common/content_descriptors.h" | 23 #include "content/public/common/content_descriptors.h" |
24 #include "content/public/common/content_switches.h" | 24 #include "content/public/common/content_switches.h" |
25 #include "content/public/common/result_codes.h" | 25 #include "content/public/common/result_codes.h" |
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" | |
28 #include "mojo/edk/embedder/scoped_platform_handle.h" | |
29 | 27 |
30 #if defined(OS_WIN) | 28 #if defined(OS_WIN) |
31 #include "base/files/file_path.h" | 29 #include "base/files/file_path.h" |
32 #include "base/win/scoped_handle.h" | |
33 #include "base/win/win_util.h" | |
34 #include "content/common/sandbox_win.h" | 30 #include "content/common/sandbox_win.h" |
35 #include "content/public/common/sandbox_init.h" | 31 #include "content/public/common/sandbox_init.h" |
36 #elif defined(OS_MACOSX) | 32 #elif defined(OS_MACOSX) |
37 #include "content/browser/bootstrap_sandbox_manager_mac.h" | 33 #include "content/browser/bootstrap_sandbox_manager_mac.h" |
38 #include "content/browser/mach_broker_mac.h" | 34 #include "content/browser/mach_broker_mac.h" |
39 #include "sandbox/mac/bootstrap_sandbox.h" | 35 #include "sandbox/mac/bootstrap_sandbox.h" |
40 #include "sandbox/mac/pre_exec_delegate.h" | 36 #include "sandbox/mac/pre_exec_delegate.h" |
41 #elif defined(OS_ANDROID) | 37 #elif defined(OS_ANDROID) |
42 #include "base/android/jni_android.h" | 38 #include "base/android/jni_android.h" |
43 #include "content/browser/android/child_process_launcher_android.h" | 39 #include "content/browser/android/child_process_launcher_android.h" |
(...skipping 12 matching lines...) Expand all Loading... |
56 #include "gin/v8_initializer.h" | 52 #include "gin/v8_initializer.h" |
57 #endif | 53 #endif |
58 | 54 |
59 namespace content { | 55 namespace content { |
60 | 56 |
61 namespace { | 57 namespace { |
62 | 58 |
63 typedef base::Callback<void(ZygoteHandle, | 59 typedef base::Callback<void(ZygoteHandle, |
64 #if defined(OS_ANDROID) | 60 #if defined(OS_ANDROID) |
65 base::ScopedFD, | 61 base::ScopedFD, |
66 base::ScopedFD, | |
67 #endif | 62 #endif |
68 base::Process)> NotifyCallback; | 63 base::Process)> NotifyCallback; |
69 | 64 |
70 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { | 65 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { |
71 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 66 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
72 // Log the launch time, separating out the first one (which will likely be | 67 // 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). | 68 // slower due to the rest of the browser initializing at the same time). |
74 static bool done_first_launch = false; | 69 static bool done_first_launch = false; |
75 if (done_first_launch) { | 70 if (done_first_launch) { |
76 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); | 71 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); |
77 } else { | 72 } else { |
78 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); | 73 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); |
79 done_first_launch = true; | 74 done_first_launch = true; |
80 } | 75 } |
81 } | 76 } |
82 | 77 |
83 #if defined(OS_ANDROID) | 78 #if defined(OS_ANDROID) |
84 // TODO(sievers): Remove this by defining better what happens on what | 79 // TODO(sievers): Remove this by defining better what happens on what |
85 // thread in the corresponding Java code. | 80 // thread in the corresponding Java code. |
86 void OnChildProcessStartedAndroid(const NotifyCallback& callback, | 81 void OnChildProcessStartedAndroid(const NotifyCallback& callback, |
87 BrowserThread::ID client_thread_id, | 82 BrowserThread::ID client_thread_id, |
88 const base::TimeTicks begin_launch_time, | 83 const base::TimeTicks begin_launch_time, |
89 base::ScopedFD ipcfd, | 84 base::ScopedFD ipcfd, |
90 base::ScopedFD mojo_fd, | |
91 base::ProcessHandle handle) { | 85 base::ProcessHandle handle) { |
92 // This can be called on the launcher thread or UI thread. | 86 // This can be called on the launcher thread or UI thread. |
93 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; | 87 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; |
94 BrowserThread::PostTask( | 88 BrowserThread::PostTask( |
95 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 89 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
96 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); | 90 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); |
97 | 91 |
98 base::Closure callback_on_client_thread( | 92 base::Closure callback_on_client_thread( |
99 base::Bind(callback, nullptr, base::Passed(&ipcfd), | 93 base::Bind(callback, nullptr, base::Passed(&ipcfd), |
100 base::Passed(&mojo_fd), base::Passed(base::Process(handle)))); | 94 base::Passed(base::Process(handle)))); |
101 if (BrowserThread::CurrentlyOn(client_thread_id)) { | 95 if (BrowserThread::CurrentlyOn(client_thread_id)) { |
102 callback_on_client_thread.Run(); | 96 callback_on_client_thread.Run(); |
103 } else { | 97 } else { |
104 BrowserThread::PostTask( | 98 BrowserThread::PostTask( |
105 client_thread_id, FROM_HERE, callback_on_client_thread); | 99 client_thread_id, FROM_HERE, callback_on_client_thread); |
106 } | 100 } |
107 } | 101 } |
108 #endif | 102 #endif |
109 | 103 |
110 void LaunchOnLauncherThread(const NotifyCallback& callback, | 104 void LaunchOnLauncherThread(const NotifyCallback& callback, |
111 BrowserThread::ID client_thread_id, | 105 BrowserThread::ID client_thread_id, |
112 int child_process_id, | 106 int child_process_id, |
113 SandboxedProcessLauncherDelegate* delegate, | 107 SandboxedProcessLauncherDelegate* delegate, |
114 #if defined(OS_ANDROID) | 108 #if defined(OS_ANDROID) |
115 base::ScopedFD ipcfd, | 109 base::ScopedFD ipcfd, |
116 #endif | 110 #endif |
117 mojo::edk::ScopedPlatformHandle client_handle, | |
118 base::CommandLine* cmd_line) { | 111 base::CommandLine* cmd_line) { |
119 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 112 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
120 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); | 113 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); |
121 #if !defined(OS_ANDROID) | 114 #if !defined(OS_ANDROID) |
122 ZygoteHandle zygote = nullptr; | 115 ZygoteHandle zygote = nullptr; |
123 #endif | 116 #endif |
124 #if defined(OS_WIN) | 117 #if defined(OS_WIN) |
125 bool launch_elevated = delegate->ShouldLaunchElevated(); | 118 bool launch_elevated = delegate->ShouldLaunchElevated(); |
126 #elif defined(OS_MACOSX) | 119 #elif defined(OS_MACOSX) |
127 base::EnvironmentMap env = delegate->GetEnvironment(); | 120 base::EnvironmentMap env = delegate->GetEnvironment(); |
128 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | 121 base::ScopedFD ipcfd = delegate->TakeIpcFd(); |
129 #elif defined(OS_POSIX) && !defined(OS_ANDROID) | 122 #elif defined(OS_POSIX) && !defined(OS_ANDROID) |
130 base::EnvironmentMap env = delegate->GetEnvironment(); | 123 base::EnvironmentMap env = delegate->GetEnvironment(); |
131 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | 124 base::ScopedFD ipcfd = delegate->TakeIpcFd(); |
132 #endif | 125 #endif |
133 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line); | 126 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line); |
134 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); | 127 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); |
135 | 128 |
136 base::Process process; | 129 base::Process process; |
137 #if defined(OS_WIN) | 130 #if defined(OS_WIN) |
138 if (launch_elevated) { | 131 if (launch_elevated) { |
139 // 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 | |
141 // the command line as elevated process launch goes through ShellExecuteEx. | |
142 base::LaunchOptions options; | 132 base::LaunchOptions options; |
143 options.start_hidden = true; | 133 options.start_hidden = true; |
144 process = base::LaunchElevatedProcess(*cmd_line, options); | 134 process = base::LaunchElevatedProcess(*cmd_line, options); |
145 } else { | 135 } else { |
146 base::HandlesToInheritVector handles; | 136 process = StartSandboxedProcess( |
147 handles.push_back(client_handle.get().handle); | 137 delegate, cmd_line, base::HandlesToInheritVector()); |
148 cmd_line->AppendSwitchASCII( | |
149 mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch, | |
150 base::UintToString(base::win::HandleToUint32(handles[0]))); | |
151 process = StartSandboxedProcess(delegate, cmd_line, handles); | |
152 } | 138 } |
153 #elif defined(OS_POSIX) | 139 #elif defined(OS_POSIX) |
154 std::string process_type = | 140 std::string process_type = |
155 cmd_line->GetSwitchValueASCII(switches::kProcessType); | 141 cmd_line->GetSwitchValueASCII(switches::kProcessType); |
156 scoped_ptr<FileDescriptorInfo> files_to_register( | 142 scoped_ptr<FileDescriptorInfo> files_to_register( |
157 FileDescriptorInfoImpl::Create()); | 143 FileDescriptorInfoImpl::Create()); |
158 | 144 |
159 base::ScopedFD mojo_fd(client_handle.release().handle); | |
160 DCHECK(mojo_fd.is_valid()); | |
161 | |
162 #if defined(OS_ANDROID) | 145 #if defined(OS_ANDROID) |
163 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get()); | 146 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get()); |
164 files_to_register->Share(kMojoIPCChannel, mojo_fd.get()); | |
165 #else | 147 #else |
166 files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd)); | 148 files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd)); |
167 files_to_register->Transfer(kMojoIPCChannel, std::move(mojo_fd)); | |
168 #endif | 149 #endif |
169 #endif | 150 #endif |
170 | 151 |
171 #if defined(OS_POSIX) && !defined(OS_MACOSX) | 152 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
172 std::map<int, base::MemoryMappedFile::Region> regions; | 153 std::map<int, base::MemoryMappedFile::Region> regions; |
173 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( | 154 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( |
174 *cmd_line, child_process_id, files_to_register.get() | 155 *cmd_line, child_process_id, files_to_register.get() |
175 #if defined(OS_ANDROID) | 156 #if defined(OS_ANDROID) |
176 , ®ions | 157 , ®ions |
177 #endif | 158 #endif |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 kAndroidICUDataDescriptor, | 216 kAndroidICUDataDescriptor, |
236 base::i18n::GetIcuDataFileHandle(®ions[kAndroidICUDataDescriptor])); | 217 base::i18n::GetIcuDataFileHandle(®ions[kAndroidICUDataDescriptor])); |
237 | 218 |
238 // Android WebView runs in single process, ensure that we never get here | 219 // Android WebView runs in single process, ensure that we never get here |
239 // when running in single process mode. | 220 // when running in single process mode. |
240 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); | 221 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); |
241 | 222 |
242 StartChildProcess( | 223 StartChildProcess( |
243 cmd_line->argv(), child_process_id, std::move(files_to_register), regions, | 224 cmd_line->argv(), child_process_id, std::move(files_to_register), regions, |
244 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, | 225 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, |
245 begin_launch_time, base::Passed(&ipcfd), | 226 begin_launch_time, base::Passed(&ipcfd))); |
246 base::Passed(&mojo_fd))); | |
247 | 227 |
248 #elif defined(OS_POSIX) | 228 #elif defined(OS_POSIX) |
249 // We need to close the client end of the IPC channel to reliably detect | 229 // We need to close the client end of the IPC channel to reliably detect |
250 // child termination. | 230 // child termination. |
251 | 231 |
252 #if !defined(OS_MACOSX) | 232 #if !defined(OS_MACOSX) |
253 ZygoteHandle* zygote_handle = delegate->GetZygote(); | 233 ZygoteHandle* zygote_handle = delegate->GetZygote(); |
254 // If |zygote_handle| is null, a zygote should not be used. | 234 // If |zygote_handle| is null, a zygote should not be used. |
255 if (zygote_handle) { | 235 if (zygote_handle) { |
256 // This code runs on the PROCESS_LAUNCHER thread so race conditions are not | 236 // This code runs on the PROCESS_LAUNCHER thread so race conditions are not |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 !cmd_line->HasSwitch(switches::kNoSandbox)); | 416 !cmd_line->HasSwitch(switches::kNoSandbox)); |
437 | 417 |
438 // We need to close the client end of the IPC channel to reliably detect | 418 // We need to close the client end of the IPC channel to reliably detect |
439 // child termination. We will close this fd after we create the child | 419 // child termination. We will close this fd after we create the child |
440 // process which is asynchronous on Android. | 420 // process which is asynchronous on Android. |
441 base::ScopedFD ipcfd(delegate->TakeIpcFd().release()); | 421 base::ScopedFD ipcfd(delegate->TakeIpcFd().release()); |
442 #endif | 422 #endif |
443 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch, | 423 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch, |
444 weak_factory_.GetWeakPtr(), | 424 weak_factory_.GetWeakPtr(), |
445 terminate_child_on_shutdown_)); | 425 terminate_child_on_shutdown_)); |
446 mojo::edk::ScopedPlatformHandle client_handle = | |
447 mojo_platform_channel_.PassClientHandle(); | |
448 BrowserThread::PostTask( | 426 BrowserThread::PostTask( |
449 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 427 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
450 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_, | 428 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_, |
451 child_process_id, delegate, | 429 child_process_id, delegate, |
452 #if defined(OS_ANDROID) | 430 #if defined(OS_ANDROID) |
453 base::Passed(&ipcfd), | 431 base::Passed(&ipcfd), |
454 #endif | 432 #endif |
455 base::Passed(&client_handle), cmd_line)); | 433 cmd_line)); |
456 } | 434 } |
457 | 435 |
458 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { | 436 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { |
459 DCHECK(CalledOnValidThread()); | 437 DCHECK(CalledOnValidThread()); |
460 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 438 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
461 if (zygote_) { | 439 if (zygote_) { |
462 termination_status_ = zygote_->GetTerminationStatus( | 440 termination_status_ = zygote_->GetTerminationStatus( |
463 process_.Handle(), known_dead, &exit_code_); | 441 process_.Handle(), known_dead, &exit_code_); |
464 } else if (known_dead) { | 442 } else if (known_dead) { |
465 termination_status_ = | 443 termination_status_ = |
(...skipping 23 matching lines...) Expand all Loading... |
489 base::Bind(&SetProcessBackgroundedOnLauncherThread, | 467 base::Bind(&SetProcessBackgroundedOnLauncherThread, |
490 base::Passed(&to_pass), background)); | 468 base::Passed(&to_pass), background)); |
491 } | 469 } |
492 | 470 |
493 void ChildProcessLauncher::DidLaunch( | 471 void ChildProcessLauncher::DidLaunch( |
494 base::WeakPtr<ChildProcessLauncher> instance, | 472 base::WeakPtr<ChildProcessLauncher> instance, |
495 bool terminate_on_shutdown, | 473 bool terminate_on_shutdown, |
496 ZygoteHandle zygote, | 474 ZygoteHandle zygote, |
497 #if defined(OS_ANDROID) | 475 #if defined(OS_ANDROID) |
498 base::ScopedFD ipcfd, | 476 base::ScopedFD ipcfd, |
499 base::ScopedFD mojo_fd, | |
500 #endif | 477 #endif |
501 base::Process process) { | 478 base::Process process) { |
502 if (!process.IsValid()) | 479 if (!process.IsValid()) |
503 LOG(ERROR) << "Failed to launch child process"; | 480 LOG(ERROR) << "Failed to launch child process"; |
504 | 481 |
505 if (instance.get()) { | 482 if (instance.get()) { |
506 instance->Notify(zygote, | 483 instance->Notify(zygote, |
507 #if defined(OS_ANDROID) | 484 #if defined(OS_ANDROID) |
508 std::move(ipcfd), | 485 std::move(ipcfd), |
509 #endif | 486 #endif |
(...skipping 11 matching lines...) Expand all Loading... |
521 | 498 |
522 void ChildProcessLauncher::Notify(ZygoteHandle zygote, | 499 void ChildProcessLauncher::Notify(ZygoteHandle zygote, |
523 #if defined(OS_ANDROID) | 500 #if defined(OS_ANDROID) |
524 base::ScopedFD ipcfd, | 501 base::ScopedFD ipcfd, |
525 #endif | 502 #endif |
526 base::Process process) { | 503 base::Process process) { |
527 DCHECK(CalledOnValidThread()); | 504 DCHECK(CalledOnValidThread()); |
528 starting_ = false; | 505 starting_ = false; |
529 process_ = std::move(process); | 506 process_ = std::move(process); |
530 | 507 |
531 if (process_.IsValid()) { | |
532 // Set up Mojo IPC to the new process. | |
533 mojo::edk::ChildProcessLaunched(process_.Handle(), | |
534 mojo_platform_channel_.PassServerHandle()); | |
535 } | |
536 | |
537 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 508 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
538 zygote_ = zygote; | 509 zygote_ = zygote; |
539 #endif | 510 #endif |
540 if (process_.IsValid()) { | 511 if (process_.IsValid()) { |
541 client_->OnProcessLaunched(); | 512 client_->OnProcessLaunched(); |
542 } else { | 513 } else { |
543 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED; | 514 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED; |
544 client_->OnProcessLaunchFailed(); | 515 client_->OnProcessLaunchFailed(); |
545 } | 516 } |
546 } | 517 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 } | 556 } |
586 | 557 |
587 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( | 558 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( |
588 Client* client) { | 559 Client* client) { |
589 Client* ret = client_; | 560 Client* ret = client_; |
590 client_ = client; | 561 client_ = client; |
591 return ret; | 562 return ret; |
592 } | 563 } |
593 | 564 |
594 } // namespace content | 565 } // namespace content |
OLD | NEW |