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 15 matching lines...) Expand all Loading... |
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" | 27 #include "mojo/edk/embedder/embedder.h" |
28 #include "mojo/edk/embedder/scoped_platform_handle.h" | 28 #include "mojo/edk/embedder/scoped_platform_handle.h" |
29 | 29 |
30 #if defined(OS_WIN) | 30 #if defined(OS_WIN) |
31 #include "base/files/file_path.h" | 31 #include "base/files/file_path.h" |
32 #include "base/win/scoped_handle.h" | 32 #include "base/win/scoped_handle.h" |
33 #include "base/win/win_util.h" | 33 #include "base/win/win_util.h" |
34 #include "content/common/sandbox_win.h" | 34 #include "content/common/sandbox_win.h" |
35 #include "content/public/common/sandbox_init.h" | 35 #include "content/public/common/sandbox_init.h" |
| 36 #include "sandbox/win/src/sandbox_types.h" |
36 #elif defined(OS_MACOSX) | 37 #elif defined(OS_MACOSX) |
37 #include "content/browser/bootstrap_sandbox_manager_mac.h" | 38 #include "content/browser/bootstrap_sandbox_manager_mac.h" |
38 #include "content/browser/mach_broker_mac.h" | 39 #include "content/browser/mach_broker_mac.h" |
39 #include "sandbox/mac/bootstrap_sandbox.h" | 40 #include "sandbox/mac/bootstrap_sandbox.h" |
40 #include "sandbox/mac/pre_exec_delegate.h" | 41 #include "sandbox/mac/pre_exec_delegate.h" |
41 #elif defined(OS_ANDROID) | 42 #elif defined(OS_ANDROID) |
42 #include "base/android/jni_android.h" | 43 #include "base/android/jni_android.h" |
43 #include "content/browser/android/child_process_launcher_android.h" | 44 #include "content/browser/android/child_process_launcher_android.h" |
44 #elif defined(OS_POSIX) | 45 #elif defined(OS_POSIX) |
45 #include "base/memory/singleton.h" | 46 #include "base/memory/singleton.h" |
(...skipping 12 matching lines...) Expand all Loading... |
58 | 59 |
59 namespace content { | 60 namespace content { |
60 | 61 |
61 namespace { | 62 namespace { |
62 | 63 |
63 typedef base::Callback<void(ZygoteHandle, | 64 typedef base::Callback<void(ZygoteHandle, |
64 #if defined(OS_ANDROID) | 65 #if defined(OS_ANDROID) |
65 base::ScopedFD, | 66 base::ScopedFD, |
66 base::ScopedFD, | 67 base::ScopedFD, |
67 #endif | 68 #endif |
68 base::Process)> NotifyCallback; | 69 base::Process, |
| 70 int)> NotifyCallback; |
69 | 71 |
70 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { | 72 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { |
71 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 73 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
72 // Log the launch time, separating out the first one (which will likely be | 74 // 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). | 75 // slower due to the rest of the browser initializing at the same time). |
74 static bool done_first_launch = false; | 76 static bool done_first_launch = false; |
75 if (done_first_launch) { | 77 if (done_first_launch) { |
76 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); | 78 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); |
77 } else { | 79 } else { |
78 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); | 80 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); |
79 done_first_launch = true; | 81 done_first_launch = true; |
80 } | 82 } |
81 } | 83 } |
82 | 84 |
83 #if defined(OS_ANDROID) | 85 #if defined(OS_ANDROID) |
84 // TODO(sievers): Remove this by defining better what happens on what | 86 // TODO(sievers): Remove this by defining better what happens on what |
85 // thread in the corresponding Java code. | 87 // thread in the corresponding Java code. |
86 void OnChildProcessStartedAndroid(const NotifyCallback& callback, | 88 void OnChildProcessStartedAndroid(const NotifyCallback& callback, |
87 BrowserThread::ID client_thread_id, | 89 BrowserThread::ID client_thread_id, |
88 const base::TimeTicks begin_launch_time, | 90 const base::TimeTicks begin_launch_time, |
89 base::ScopedFD ipcfd, | 91 base::ScopedFD ipcfd, |
90 base::ScopedFD mojo_fd, | 92 base::ScopedFD mojo_fd, |
91 base::ProcessHandle handle) { | 93 base::ProcessHandle handle) { |
| 94 int launch_result = (handle == base::kNullProcessHandle) |
| 95 ? LAUNCH_RESULT_FAILURE |
| 96 : LAUNCH_RESULT_SUCCESS; |
92 // This can be called on the launcher thread or UI thread. | 97 // This can be called on the launcher thread or UI thread. |
93 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; | 98 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; |
94 BrowserThread::PostTask( | 99 BrowserThread::PostTask( |
95 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 100 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
96 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); | 101 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); |
97 | 102 |
98 base::Closure callback_on_client_thread( | 103 base::Closure callback_on_client_thread(base::Bind( |
99 base::Bind(callback, nullptr, base::Passed(&ipcfd), | 104 callback, nullptr, base::Passed(&ipcfd), base::Passed(&mojo_fd), |
100 base::Passed(&mojo_fd), base::Passed(base::Process(handle)))); | 105 base::Passed(base::Process(handle)), launch_result)); |
101 if (BrowserThread::CurrentlyOn(client_thread_id)) { | 106 if (BrowserThread::CurrentlyOn(client_thread_id)) { |
102 callback_on_client_thread.Run(); | 107 callback_on_client_thread.Run(); |
103 } else { | 108 } else { |
104 BrowserThread::PostTask( | 109 BrowserThread::PostTask( |
105 client_thread_id, FROM_HERE, callback_on_client_thread); | 110 client_thread_id, FROM_HERE, callback_on_client_thread); |
106 } | 111 } |
107 } | 112 } |
108 #endif | 113 #endif |
109 | 114 |
110 void LaunchOnLauncherThread(const NotifyCallback& callback, | 115 void LaunchOnLauncherThread(const NotifyCallback& callback, |
111 BrowserThread::ID client_thread_id, | 116 BrowserThread::ID client_thread_id, |
112 int child_process_id, | 117 int child_process_id, |
113 SandboxedProcessLauncherDelegate* delegate, | 118 SandboxedProcessLauncherDelegate* delegate, |
114 #if defined(OS_ANDROID) | 119 #if defined(OS_ANDROID) |
115 base::ScopedFD ipcfd, | 120 base::ScopedFD ipcfd, |
116 #endif | 121 #endif |
117 mojo::edk::ScopedPlatformHandle client_handle, | 122 mojo::edk::ScopedPlatformHandle client_handle, |
118 base::CommandLine* cmd_line) { | 123 base::CommandLine* cmd_line) { |
119 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 124 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
120 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); | 125 std::unique_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); |
121 #if !defined(OS_ANDROID) | 126 #if !defined(OS_ANDROID) |
122 ZygoteHandle zygote = nullptr; | 127 ZygoteHandle zygote = nullptr; |
| 128 int launch_result = LAUNCH_RESULT_FAILURE; |
123 #endif | 129 #endif |
124 #if defined(OS_WIN) | 130 #if defined(OS_WIN) |
125 bool launch_elevated = delegate->ShouldLaunchElevated(); | 131 bool launch_elevated = delegate->ShouldLaunchElevated(); |
126 #elif defined(OS_MACOSX) | 132 #elif defined(OS_MACOSX) |
127 base::EnvironmentMap env = delegate->GetEnvironment(); | 133 base::EnvironmentMap env = delegate->GetEnvironment(); |
128 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | 134 base::ScopedFD ipcfd = delegate->TakeIpcFd(); |
129 #elif defined(OS_POSIX) && !defined(OS_ANDROID) | 135 #elif defined(OS_POSIX) && !defined(OS_ANDROID) |
130 base::EnvironmentMap env = delegate->GetEnvironment(); | 136 base::EnvironmentMap env = delegate->GetEnvironment(); |
131 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | 137 base::ScopedFD ipcfd = delegate->TakeIpcFd(); |
132 #endif | 138 #endif |
133 std::unique_ptr<base::CommandLine> cmd_line_deleter(cmd_line); | 139 std::unique_ptr<base::CommandLine> cmd_line_deleter(cmd_line); |
134 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); | 140 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); |
135 | 141 |
136 base::Process process; | 142 base::Process process; |
137 #if defined(OS_WIN) | 143 #if defined(OS_WIN) |
138 if (launch_elevated) { | 144 if (launch_elevated) { |
139 // TODO(rockot): We may want to support Mojo IPC to elevated processes as | 145 // 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 | 146 // well, but this isn't currently feasible without sharing a pipe path on |
141 // the command line as elevated process launch goes through ShellExecuteEx. | 147 // the command line as elevated process launch goes through ShellExecuteEx. |
142 base::LaunchOptions options; | 148 base::LaunchOptions options; |
143 options.start_hidden = true; | 149 options.start_hidden = true; |
144 process = base::LaunchElevatedProcess(*cmd_line, options); | 150 process = base::LaunchElevatedProcess(*cmd_line, options); |
145 } else { | 151 } else { |
146 base::HandlesToInheritVector handles; | 152 base::HandlesToInheritVector handles; |
147 handles.push_back(client_handle.get().handle); | 153 handles.push_back(client_handle.get().handle); |
148 cmd_line->AppendSwitchASCII( | 154 cmd_line->AppendSwitchASCII( |
149 mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch, | 155 mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch, |
150 base::UintToString(base::win::HandleToUint32(handles[0]))); | 156 base::UintToString(base::win::HandleToUint32(handles[0]))); |
151 process = StartSandboxedProcess(delegate, cmd_line, handles); | 157 launch_result = |
| 158 StartSandboxedProcess(delegate, cmd_line, handles, &process); |
152 } | 159 } |
153 #elif defined(OS_POSIX) | 160 #elif defined(OS_POSIX) |
154 std::string process_type = | 161 std::string process_type = |
155 cmd_line->GetSwitchValueASCII(switches::kProcessType); | 162 cmd_line->GetSwitchValueASCII(switches::kProcessType); |
156 std::unique_ptr<FileDescriptorInfo> files_to_register( | 163 std::unique_ptr<FileDescriptorInfo> files_to_register( |
157 FileDescriptorInfoImpl::Create()); | 164 FileDescriptorInfoImpl::Create()); |
158 | 165 |
159 base::ScopedFD mojo_fd(client_handle.release().handle); | 166 base::ScopedFD mojo_fd(client_handle.release().handle); |
160 DCHECK(mojo_fd.is_valid()); | 167 DCHECK(mojo_fd.is_valid()); |
161 | 168 |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 } | 335 } |
329 | 336 |
330 // After updating the broker, release the lock and let the child's | 337 // After updating the broker, release the lock and let the child's |
331 // messasge be processed on the broker's thread. | 338 // messasge be processed on the broker's thread. |
332 broker->GetLock().Release(); | 339 broker->GetLock().Release(); |
333 #endif // defined(OS_MACOSX) | 340 #endif // defined(OS_MACOSX) |
334 } | 341 } |
335 #endif // else defined(OS_POSIX) | 342 #endif // else defined(OS_POSIX) |
336 #if !defined(OS_ANDROID) | 343 #if !defined(OS_ANDROID) |
337 if (process.IsValid()) { | 344 if (process.IsValid()) { |
| 345 launch_result = LAUNCH_RESULT_SUCCESS; |
338 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() - | 346 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() - |
339 begin_launch_time); | 347 begin_launch_time); |
340 } | 348 } |
341 BrowserThread::PostTask(client_thread_id, FROM_HERE, | 349 BrowserThread::PostTask(client_thread_id, FROM_HERE, |
342 base::Bind(callback, zygote, base::Passed(&process))); | 350 base::Bind(callback, zygote, base::Passed(&process), |
| 351 launch_result)); |
343 #endif // !defined(OS_ANDROID) | 352 #endif // !defined(OS_ANDROID) |
344 } | 353 } |
345 | 354 |
346 void TerminateOnLauncherThread(ZygoteHandle zygote, base::Process process) { | 355 void TerminateOnLauncherThread(ZygoteHandle zygote, base::Process process) { |
347 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 356 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
348 #if defined(OS_ANDROID) | 357 #if defined(OS_ANDROID) |
349 VLOG(1) << "ChromeProcess: Stopping process with handle " | 358 VLOG(1) << "ChromeProcess: Stopping process with handle " |
350 << process.Handle(); | 359 << process.Handle(); |
351 StopChildProcess(process.Handle()); | 360 StopChildProcess(process.Handle()); |
352 #else | 361 #else |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 } | 502 } |
494 | 503 |
495 void ChildProcessLauncher::DidLaunch( | 504 void ChildProcessLauncher::DidLaunch( |
496 base::WeakPtr<ChildProcessLauncher> instance, | 505 base::WeakPtr<ChildProcessLauncher> instance, |
497 bool terminate_on_shutdown, | 506 bool terminate_on_shutdown, |
498 ZygoteHandle zygote, | 507 ZygoteHandle zygote, |
499 #if defined(OS_ANDROID) | 508 #if defined(OS_ANDROID) |
500 base::ScopedFD ipcfd, | 509 base::ScopedFD ipcfd, |
501 base::ScopedFD mojo_fd, | 510 base::ScopedFD mojo_fd, |
502 #endif | 511 #endif |
503 base::Process process) { | 512 base::Process process, |
| 513 int error_code) { |
504 if (!process.IsValid()) | 514 if (!process.IsValid()) |
505 LOG(ERROR) << "Failed to launch child process"; | 515 LOG(ERROR) << "Failed to launch child process"; |
506 | 516 |
507 if (instance.get()) { | 517 if (instance.get()) { |
508 instance->Notify(zygote, | 518 instance->Notify(zygote, |
509 #if defined(OS_ANDROID) | 519 #if defined(OS_ANDROID) |
510 std::move(ipcfd), | 520 std::move(ipcfd), |
511 #endif | 521 #endif |
512 std::move(process)); | 522 std::move(process), |
| 523 error_code); |
513 } else { | 524 } else { |
514 if (process.IsValid() && terminate_on_shutdown) { | 525 if (process.IsValid() && terminate_on_shutdown) { |
515 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So | 526 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So |
516 // don't this on the UI/IO threads. | 527 // don't this on the UI/IO threads. |
517 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 528 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
518 base::Bind(&TerminateOnLauncherThread, zygote, | 529 base::Bind(&TerminateOnLauncherThread, zygote, |
519 base::Passed(&process))); | 530 base::Passed(&process))); |
520 } | 531 } |
521 } | 532 } |
522 } | 533 } |
523 | 534 |
524 void ChildProcessLauncher::Notify(ZygoteHandle zygote, | 535 void ChildProcessLauncher::Notify(ZygoteHandle zygote, |
525 #if defined(OS_ANDROID) | 536 #if defined(OS_ANDROID) |
526 base::ScopedFD ipcfd, | 537 base::ScopedFD ipcfd, |
527 #endif | 538 #endif |
528 base::Process process) { | 539 base::Process process, |
| 540 int error_code) { |
529 DCHECK(CalledOnValidThread()); | 541 DCHECK(CalledOnValidThread()); |
530 starting_ = false; | 542 starting_ = false; |
531 process_ = std::move(process); | 543 process_ = std::move(process); |
532 | 544 |
533 if (process_.IsValid()) { | 545 if (process_.IsValid()) { |
534 // Set up Mojo IPC to the new process. | 546 // Set up Mojo IPC to the new process. |
535 mojo::edk::ChildProcessLaunched(process_.Handle(), | 547 mojo::edk::ChildProcessLaunched(process_.Handle(), |
536 mojo_platform_channel_.PassServerHandle()); | 548 mojo_platform_channel_.PassServerHandle()); |
537 } | 549 } |
538 | 550 |
539 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 551 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
540 zygote_ = zygote; | 552 zygote_ = zygote; |
541 #endif | 553 #endif |
542 if (process_.IsValid()) { | 554 if (process_.IsValid()) { |
543 client_->OnProcessLaunched(); | 555 client_->OnProcessLaunched(); |
544 } else { | 556 } else { |
545 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED; | 557 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED; |
546 client_->OnProcessLaunchFailed(); | 558 client_->OnProcessLaunchFailed(error_code); |
547 } | 559 } |
548 } | 560 } |
549 | 561 |
550 bool ChildProcessLauncher::IsStarting() { | 562 bool ChildProcessLauncher::IsStarting() { |
551 // TODO(crbug.com/469248): This fails in some tests. | 563 // TODO(crbug.com/469248): This fails in some tests. |
552 // DCHECK(CalledOnValidThread()); | 564 // DCHECK(CalledOnValidThread()); |
553 return starting_; | 565 return starting_; |
554 } | 566 } |
555 | 567 |
556 const base::Process& ChildProcessLauncher::GetProcess() const { | 568 const base::Process& ChildProcessLauncher::GetProcess() const { |
(...skipping 30 matching lines...) Expand all Loading... |
587 } | 599 } |
588 | 600 |
589 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( | 601 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( |
590 Client* client) { | 602 Client* client) { |
591 Client* ret = client_; | 603 Client* ret = client_; |
592 client_ = client; | 604 client_ = client; |
593 return ret; | 605 return ret; |
594 } | 606 } |
595 | 607 |
596 } // namespace content | 608 } // namespace content |
OLD | NEW |