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/process.h" | 16 #include "base/process/process.h" |
| 17 #include "base/rand_util.h" |
17 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 19 #include "base/strings/stringprintf.h" |
| 20 #include "base/strings/utf_string_conversions.h" |
18 #include "base/synchronization/lock.h" | 21 #include "base/synchronization/lock.h" |
19 #include "base/threading/thread.h" | 22 #include "base/threading/thread.h" |
20 #include "build/build_config.h" | 23 #include "build/build_config.h" |
21 #include "content/public/browser/content_browser_client.h" | 24 #include "content/public/browser/content_browser_client.h" |
22 #include "content/public/common/content_descriptors.h" | 25 #include "content/public/common/content_descriptors.h" |
23 #include "content/public/common/content_switches.h" | 26 #include "content/public/common/content_switches.h" |
24 #include "content/public/common/result_codes.h" | 27 #include "content/public/common/result_codes.h" |
25 #include "content/public/common/sandboxed_process_launcher_delegate.h" | 28 #include "content/public/common/sandboxed_process_launcher_delegate.h" |
| 29 #include "mojo/edk/embedder/embedder.h" |
| 30 #include "mojo/edk/embedder/platform_channel_pair.h" |
| 31 #include "mojo/edk/embedder/scoped_platform_handle.h" |
26 | 32 |
27 #if defined(OS_WIN) | 33 #if defined(OS_WIN) |
28 #include "base/files/file_path.h" | 34 #include "base/files/file_path.h" |
29 #include "content/common/sandbox_win.h" | 35 #include "content/common/sandbox_win.h" |
30 #include "content/public/common/sandbox_init.h" | 36 #include "content/public/common/sandbox_init.h" |
31 #elif defined(OS_MACOSX) | 37 #elif defined(OS_MACOSX) |
32 #include "content/browser/bootstrap_sandbox_manager_mac.h" | 38 #include "content/browser/bootstrap_sandbox_manager_mac.h" |
33 #include "content/browser/mach_broker_mac.h" | 39 #include "content/browser/mach_broker_mac.h" |
34 #include "sandbox/mac/bootstrap_sandbox.h" | 40 #include "sandbox/mac/bootstrap_sandbox.h" |
35 #include "sandbox/mac/pre_exec_delegate.h" | 41 #include "sandbox/mac/pre_exec_delegate.h" |
(...skipping 15 matching lines...) Expand all Loading... |
51 #include "gin/v8_initializer.h" | 57 #include "gin/v8_initializer.h" |
52 #endif | 58 #endif |
53 | 59 |
54 namespace content { | 60 namespace content { |
55 | 61 |
56 namespace { | 62 namespace { |
57 | 63 |
58 typedef base::Callback<void(ZygoteHandle, | 64 typedef base::Callback<void(ZygoteHandle, |
59 #if defined(OS_ANDROID) | 65 #if defined(OS_ANDROID) |
60 base::ScopedFD, | 66 base::ScopedFD, |
| 67 base::ScopedFD, |
61 #endif | 68 #endif |
62 base::Process)> NotifyCallback; | 69 base::Process)> NotifyCallback; |
63 | 70 |
64 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { | 71 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { |
65 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 72 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
66 // Log the launch time, separating out the first one (which will likely be | 73 // Log the launch time, separating out the first one (which will likely be |
67 // slower due to the rest of the browser initializing at the same time). | 74 // slower due to the rest of the browser initializing at the same time). |
68 static bool done_first_launch = false; | 75 static bool done_first_launch = false; |
69 if (done_first_launch) { | 76 if (done_first_launch) { |
70 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); | 77 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); |
71 } else { | 78 } else { |
72 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); | 79 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); |
73 done_first_launch = true; | 80 done_first_launch = true; |
74 } | 81 } |
75 } | 82 } |
76 | 83 |
| 84 #if defined(OS_WIN) |
| 85 // This generates a pipe name and secret to use for the Mojo IPC channel on |
| 86 // Windows. |
| 87 mojo::edk::ScopedPlatformHandle CreateMojoNamedPipe(base::CommandLine* cmd_line, |
| 88 std::string* secret) { |
| 89 std::string pipe_name = |
| 90 base::StringPrintf("\\\\.\\pipe\\chrome.%u.%u.%I64u", |
| 91 GetCurrentProcessId(), GetCurrentThreadId(), |
| 92 base::RandUint64()); |
| 93 std::string pipe_secret = mojo::edk::GenerateRandomToken(); |
| 94 |
| 95 const DWORD kOpenMode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | |
| 96 FILE_FLAG_FIRST_PIPE_INSTANCE; |
| 97 const DWORD kPipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE; |
| 98 mojo::edk::ScopedPlatformHandle pipe(mojo::edk::PlatformHandle( |
| 99 CreateNamedPipeW(base::UTF8ToWide(pipe_name).c_str(), kOpenMode, |
| 100 kPipeMode, |
| 101 1, // Max instances. |
| 102 4096, // Out buffer size. |
| 103 4096, // In buffer size. |
| 104 5000, // Timeout in milliseconds. |
| 105 nullptr))); // Default security descriptor. |
| 106 PCHECK(pipe.is_valid()); |
| 107 |
| 108 cmd_line->AppendSwitchASCII(switches::kMojoChannelName, pipe_name); |
| 109 cmd_line->AppendSwitchASCII(switches::kMojoChannelSecret, pipe_secret); |
| 110 |
| 111 *secret = pipe_secret; |
| 112 return pipe; |
| 113 } |
| 114 #endif |
| 115 |
77 #if defined(OS_ANDROID) | 116 #if defined(OS_ANDROID) |
78 // TODO(sievers): Remove this by defining better what happens on what | 117 // TODO(sievers): Remove this by defining better what happens on what |
79 // thread in the corresponding Java code. | 118 // thread in the corresponding Java code. |
80 void OnChildProcessStartedAndroid(const NotifyCallback& callback, | 119 void OnChildProcessStartedAndroid(const NotifyCallback& callback, |
81 BrowserThread::ID client_thread_id, | 120 BrowserThread::ID client_thread_id, |
82 const base::TimeTicks begin_launch_time, | 121 const base::TimeTicks begin_launch_time, |
83 base::ScopedFD ipcfd, | 122 base::ScopedFD ipcfd, |
| 123 base::ScopedFD mojo_fd, |
84 base::ProcessHandle handle) { | 124 base::ProcessHandle handle) { |
85 // This can be called on the launcher thread or UI thread. | 125 // This can be called on the launcher thread or UI thread. |
86 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; | 126 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; |
87 BrowserThread::PostTask( | 127 BrowserThread::PostTask( |
88 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 128 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
89 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); | 129 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); |
90 | 130 |
91 base::Closure callback_on_client_thread( | 131 base::Closure callback_on_client_thread( |
92 base::Bind(callback, nullptr, base::Passed(&ipcfd), | 132 base::Bind(callback, nullptr, base::Passed(&ipcfd), |
93 base::Passed(base::Process(handle)))); | 133 base::Passed(&mojo_fd), base::Passed(base::Process(handle)))); |
94 if (BrowserThread::CurrentlyOn(client_thread_id)) { | 134 if (BrowserThread::CurrentlyOn(client_thread_id)) { |
95 callback_on_client_thread.Run(); | 135 callback_on_client_thread.Run(); |
96 } else { | 136 } else { |
97 BrowserThread::PostTask( | 137 BrowserThread::PostTask( |
98 client_thread_id, FROM_HERE, callback_on_client_thread); | 138 client_thread_id, FROM_HERE, callback_on_client_thread); |
99 } | 139 } |
100 } | 140 } |
101 #endif | 141 #endif |
102 | 142 |
103 void LaunchOnLauncherThread(const NotifyCallback& callback, | 143 void LaunchOnLauncherThread(const NotifyCallback& callback, |
104 BrowserThread::ID client_thread_id, | 144 BrowserThread::ID client_thread_id, |
105 int child_process_id, | 145 int child_process_id, |
106 SandboxedProcessLauncherDelegate* delegate, | 146 SandboxedProcessLauncherDelegate* delegate, |
107 #if defined(OS_ANDROID) | 147 #if defined(OS_ANDROID) |
108 base::ScopedFD ipcfd, | 148 base::ScopedFD ipcfd, |
109 #endif | 149 #endif |
| 150 mojo::edk::ScopedPlatformHandle client_handle, |
110 base::CommandLine* cmd_line) { | 151 base::CommandLine* cmd_line) { |
111 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 152 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
112 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); | 153 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); |
113 #if !defined(OS_ANDROID) | 154 #if !defined(OS_ANDROID) |
114 ZygoteHandle zygote = nullptr; | 155 ZygoteHandle zygote = nullptr; |
115 #endif | 156 #endif |
116 #if defined(OS_WIN) | 157 #if defined(OS_WIN) |
117 bool launch_elevated = delegate->ShouldLaunchElevated(); | 158 bool launch_elevated = delegate->ShouldLaunchElevated(); |
118 #elif defined(OS_MACOSX) | 159 #elif defined(OS_MACOSX) |
119 base::EnvironmentMap env = delegate->GetEnvironment(); | 160 base::EnvironmentMap env = delegate->GetEnvironment(); |
(...skipping 13 matching lines...) Expand all Loading... |
133 process = base::LaunchElevatedProcess(*cmd_line, options); | 174 process = base::LaunchElevatedProcess(*cmd_line, options); |
134 } else { | 175 } else { |
135 process = StartSandboxedProcess(delegate, cmd_line); | 176 process = StartSandboxedProcess(delegate, cmd_line); |
136 } | 177 } |
137 #elif defined(OS_POSIX) | 178 #elif defined(OS_POSIX) |
138 std::string process_type = | 179 std::string process_type = |
139 cmd_line->GetSwitchValueASCII(switches::kProcessType); | 180 cmd_line->GetSwitchValueASCII(switches::kProcessType); |
140 scoped_ptr<FileDescriptorInfo> files_to_register( | 181 scoped_ptr<FileDescriptorInfo> files_to_register( |
141 FileDescriptorInfoImpl::Create()); | 182 FileDescriptorInfoImpl::Create()); |
142 | 183 |
| 184 base::ScopedFD mojo_fd(client_handle.release().handle); |
| 185 DCHECK(mojo_fd.is_valid()); |
| 186 |
143 #if defined(OS_ANDROID) | 187 #if defined(OS_ANDROID) |
144 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get()); | 188 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get()); |
| 189 files_to_register->Share(kMojoIPCChannel, mojo_fd.get()); |
145 #else | 190 #else |
146 files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd)); | 191 files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd)); |
| 192 files_to_register->Transfer(kMojoIPCChannel, std::move(mojo_fd)); |
147 #endif | 193 #endif |
148 #endif | 194 #endif |
149 | 195 |
150 #if defined(OS_POSIX) && !defined(OS_MACOSX) | 196 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
151 std::map<int, base::MemoryMappedFile::Region> regions; | 197 std::map<int, base::MemoryMappedFile::Region> regions; |
152 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( | 198 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( |
153 *cmd_line, child_process_id, files_to_register.get() | 199 *cmd_line, child_process_id, files_to_register.get() |
154 #if defined(OS_ANDROID) | 200 #if defined(OS_ANDROID) |
155 , ®ions | 201 , ®ions |
156 #endif | 202 #endif |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 kAndroidICUDataDescriptor, | 260 kAndroidICUDataDescriptor, |
215 base::i18n::GetIcuDataFileHandle(®ions[kAndroidICUDataDescriptor])); | 261 base::i18n::GetIcuDataFileHandle(®ions[kAndroidICUDataDescriptor])); |
216 | 262 |
217 // Android WebView runs in single process, ensure that we never get here | 263 // Android WebView runs in single process, ensure that we never get here |
218 // when running in single process mode. | 264 // when running in single process mode. |
219 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); | 265 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); |
220 | 266 |
221 StartChildProcess( | 267 StartChildProcess( |
222 cmd_line->argv(), child_process_id, std::move(files_to_register), regions, | 268 cmd_line->argv(), child_process_id, std::move(files_to_register), regions, |
223 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, | 269 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, |
224 begin_launch_time, base::Passed(&ipcfd))); | 270 begin_launch_time, base::Passed(&ipcfd), |
| 271 base::Passed(&mojo_fd))); |
225 | 272 |
226 #elif defined(OS_POSIX) | 273 #elif defined(OS_POSIX) |
227 // We need to close the client end of the IPC channel to reliably detect | 274 // We need to close the client end of the IPC channel to reliably detect |
228 // child termination. | 275 // child termination. |
229 | 276 |
230 #if !defined(OS_MACOSX) | 277 #if !defined(OS_MACOSX) |
231 ZygoteHandle* zygote_handle = delegate->GetZygote(); | 278 ZygoteHandle* zygote_handle = delegate->GetZygote(); |
232 // If |zygote_handle| is null, a zygote should not be used. | 279 // If |zygote_handle| is null, a zygote should not be used. |
233 if (zygote_handle) { | 280 if (zygote_handle) { |
234 // This code runs on the PROCESS_LAUNCHER thread so race conditions are not | 281 // 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... |
414 !cmd_line->HasSwitch(switches::kNoSandbox)); | 461 !cmd_line->HasSwitch(switches::kNoSandbox)); |
415 | 462 |
416 // We need to close the client end of the IPC channel to reliably detect | 463 // We need to close the client end of the IPC channel to reliably detect |
417 // child termination. We will close this fd after we create the child | 464 // child termination. We will close this fd after we create the child |
418 // process which is asynchronous on Android. | 465 // process which is asynchronous on Android. |
419 base::ScopedFD ipcfd(delegate->TakeIpcFd().release()); | 466 base::ScopedFD ipcfd(delegate->TakeIpcFd().release()); |
420 #endif | 467 #endif |
421 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch, | 468 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch, |
422 weak_factory_.GetWeakPtr(), | 469 weak_factory_.GetWeakPtr(), |
423 terminate_child_on_shutdown_)); | 470 terminate_child_on_shutdown_)); |
| 471 mojo::edk::ScopedPlatformHandle client_handle; |
| 472 #if defined(OS_WIN) |
| 473 mojo_server_handle_ = CreateMojoNamedPipe(cmd_line, &mojo_secret_); |
| 474 #else |
| 475 mojo::edk::PlatformChannelPair platform_channel; |
| 476 client_handle = platform_channel.PassClientHandle(); |
| 477 mojo_server_handle_ = platform_channel.PassServerHandle(); |
| 478 #endif |
424 BrowserThread::PostTask( | 479 BrowserThread::PostTask( |
425 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 480 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
426 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_, | 481 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_, |
427 child_process_id, delegate, | 482 child_process_id, delegate, |
428 #if defined(OS_ANDROID) | 483 #if defined(OS_ANDROID) |
429 base::Passed(&ipcfd), | 484 base::Passed(&ipcfd), |
430 #endif | 485 #endif |
431 cmd_line)); | 486 base::Passed(&client_handle), cmd_line)); |
432 } | 487 } |
433 | 488 |
434 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { | 489 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { |
435 DCHECK(CalledOnValidThread()); | 490 DCHECK(CalledOnValidThread()); |
436 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 491 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
437 if (zygote_) { | 492 if (zygote_) { |
438 termination_status_ = zygote_->GetTerminationStatus( | 493 termination_status_ = zygote_->GetTerminationStatus( |
439 process_.Handle(), known_dead, &exit_code_); | 494 process_.Handle(), known_dead, &exit_code_); |
440 } else if (known_dead) { | 495 } else if (known_dead) { |
441 termination_status_ = | 496 termination_status_ = |
(...skipping 23 matching lines...) Expand all Loading... |
465 base::Bind(&SetProcessBackgroundedOnLauncherThread, | 520 base::Bind(&SetProcessBackgroundedOnLauncherThread, |
466 base::Passed(&to_pass), background)); | 521 base::Passed(&to_pass), background)); |
467 } | 522 } |
468 | 523 |
469 void ChildProcessLauncher::DidLaunch( | 524 void ChildProcessLauncher::DidLaunch( |
470 base::WeakPtr<ChildProcessLauncher> instance, | 525 base::WeakPtr<ChildProcessLauncher> instance, |
471 bool terminate_on_shutdown, | 526 bool terminate_on_shutdown, |
472 ZygoteHandle zygote, | 527 ZygoteHandle zygote, |
473 #if defined(OS_ANDROID) | 528 #if defined(OS_ANDROID) |
474 base::ScopedFD ipcfd, | 529 base::ScopedFD ipcfd, |
| 530 base::ScopedFD mojo_fd, |
475 #endif | 531 #endif |
476 base::Process process) { | 532 base::Process process) { |
477 if (!process.IsValid()) | 533 if (!process.IsValid()) |
478 LOG(ERROR) << "Failed to launch child process"; | 534 LOG(ERROR) << "Failed to launch child process"; |
479 | 535 |
480 if (instance.get()) { | 536 if (instance.get()) { |
481 instance->Notify(zygote, | 537 instance->Notify(zygote, |
482 #if defined(OS_ANDROID) | 538 #if defined(OS_ANDROID) |
483 std::move(ipcfd), | 539 std::move(ipcfd), |
484 #endif | 540 #endif |
(...skipping 11 matching lines...) Expand all Loading... |
496 | 552 |
497 void ChildProcessLauncher::Notify(ZygoteHandle zygote, | 553 void ChildProcessLauncher::Notify(ZygoteHandle zygote, |
498 #if defined(OS_ANDROID) | 554 #if defined(OS_ANDROID) |
499 base::ScopedFD ipcfd, | 555 base::ScopedFD ipcfd, |
500 #endif | 556 #endif |
501 base::Process process) { | 557 base::Process process) { |
502 DCHECK(CalledOnValidThread()); | 558 DCHECK(CalledOnValidThread()); |
503 starting_ = false; | 559 starting_ = false; |
504 process_ = std::move(process); | 560 process_ = std::move(process); |
505 | 561 |
| 562 if (process_.IsValid()) { |
| 563 // Set up Mojo IPC to the new process. |
| 564 #if defined(OS_WIN) |
| 565 mojo::edk::ChildProcessLaunched(process_.Handle(), |
| 566 std::move(mojo_server_handle_), |
| 567 mojo_secret_); |
| 568 #else |
| 569 mojo::edk::ChildProcessLaunched(process_.Handle(), |
| 570 std::move(mojo_server_handle_)); |
| 571 #endif // defined(OS_WIN) |
| 572 } |
| 573 |
506 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 574 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
507 zygote_ = zygote; | 575 zygote_ = zygote; |
508 #endif | 576 #endif |
509 if (process_.IsValid()) { | 577 if (process_.IsValid()) { |
510 client_->OnProcessLaunched(); | 578 client_->OnProcessLaunched(); |
511 } else { | 579 } else { |
512 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED; | 580 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED; |
513 client_->OnProcessLaunchFailed(); | 581 client_->OnProcessLaunchFailed(); |
514 } | 582 } |
515 } | 583 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
554 } | 622 } |
555 | 623 |
556 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( | 624 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( |
557 Client* client) { | 625 Client* client) { |
558 Client* ret = client_; | 626 Client* ret = client_; |
559 client_ = client; | 627 client_ = client; |
560 return ret; | 628 return ret; |
561 } | 629 } |
562 | 630 |
563 } // namespace content | 631 } // namespace content |
OLD | NEW |