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