1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/child_process_launcher.h"
7 #include <utility> // For std::pair.
10 #include "base/command_line.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_file.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/metrics/histogram.h"
16 #include "base/process/process.h"
17 #include "base/synchronization/lock.h"
18 #include "base/threading/thread.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/content_browser_client.h"
21 #include "content/public/common/content_descriptors.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/result_codes.h"
24 #include "content/public/common/sandboxed_process_launcher_delegate.h"
27 #include "base/files/file_path.h"
28 #include "content/common/sandbox_win.h"
29 #include "content/public/common/sandbox_init.h"
30 #elif defined(OS_MACOSX)
31 #include "content/browser/bootstrap_sandbox_mac.h"
32 #include "content/browser/mach_broker_mac.h"
33 #include "sandbox/mac/bootstrap_sandbox.h"
34 #elif defined(OS_ANDROID)
35 #include "base/android/jni_android.h"
36 #include "content/browser/android/child_process_launcher_android.h"
37 #elif defined(OS_POSIX)
38 #include "base/memory/shared_memory.h"
39 #include "base/memory/singleton.h"
40 #include "content/browser/renderer_host/render_sandbox_host_linux.h"
41 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
42 #include "content/common/child_process_sandbox_support_impl_linux.h"
46 #include "base/metrics/stats_table.h"
47 #include "base/posix/global_descriptors.h"
48 #include "content/browser/file_descriptor_info_impl.h"
53 // Having the functionality of ChildProcessLauncher be in an internal
54 // ref counted object allows us to automatically terminate the process when the
55 // parent class destructs, while still holding on to state that we need.
56 class ChildProcessLauncher::Context
57 : public base::RefCountedThreadSafe
<ChildProcessLauncher::Context
> {
61 // Posts a task to a dedicated thread to do the actual work.
62 // Must be called on the UI thread.
63 void Launch(SandboxedProcessLauncherDelegate
* delegate
,
64 base::CommandLine
* cmd_line
,
68 #if defined(OS_ANDROID)
69 // Called on the UI thread with the operation result. Calls Notify().
70 static void OnChildProcessStarted(
71 // |this_object| is NOT thread safe. Only use it to post a task back.
72 scoped_refptr
<Context
> this_object
,
73 BrowserThread::ID client_thread_id
,
74 const base::TimeTicks begin_launch_time
,
75 base::ProcessHandle handle
);
78 // Resets the client (the client is going away).
81 bool starting() const { return starting_
; }
83 const base::Process
& process() const { return process_
; }
85 int exit_code() const { return exit_code_
; }
87 base::TerminationStatus
termination_status() const {
88 return termination_status_
;
91 void set_terminate_child_on_shutdown(bool terminate_on_shutdown
) {
92 terminate_child_on_shutdown_
= terminate_on_shutdown
;
95 void UpdateTerminationStatus(bool known_dead
);
97 void Close() { process_
.Close(); }
99 void SetProcessBackgrounded(bool background
);
102 friend class base::RefCountedThreadSafe
<ChildProcessLauncher::Context
>;
108 static void RecordHistograms(base::TimeTicks begin_launch_time
);
109 static void RecordLaunchHistograms(base::TimeDelta launch_time
);
111 // Performs the actual work of launching the process.
112 // Runs on the PROCESS_LAUNCHER thread.
113 static void LaunchInternal(
114 // |this_object| is NOT thread safe. Only use it to post a task back.
115 scoped_refptr
<Context
> this_object
,
116 BrowserThread::ID client_thread_id
,
117 int child_process_id
,
118 SandboxedProcessLauncherDelegate
* delegate
,
119 base::CommandLine
* cmd_line
);
121 // Notifies the client about the result of the operation.
122 // Runs on the UI thread.
124 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
127 base::Process process
);
131 static void SetProcessBackgroundedInternal(base::Process process
,
134 static void TerminateInternal(
135 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
138 base::Process process
);
141 BrowserThread::ID client_thread_id_
;
142 base::Process process_
;
143 base::TerminationStatus termination_status_
;
145 #if defined(OS_ANDROID)
146 // The fd to close after creating the process.
147 base::ScopedFD ipcfd_
;
148 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
152 // Controls whether the child process should be terminated on browser
153 // shutdown. Default behavior is to terminate the child.
154 bool terminate_child_on_shutdown_
;
157 ChildProcessLauncher::Context::Context()
159 client_thread_id_(BrowserThread::UI
),
160 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION
),
161 exit_code_(RESULT_CODE_NORMAL_EXIT
),
162 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
166 // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622
167 #if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
168 defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS)
169 terminate_child_on_shutdown_(false) {
171 terminate_child_on_shutdown_(true) {
175 void ChildProcessLauncher::Context::Launch(
176 SandboxedProcessLauncherDelegate
* delegate
,
177 base::CommandLine
* cmd_line
,
178 int child_process_id
,
180 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_
));
183 #if defined(OS_ANDROID)
184 // We need to close the client end of the IPC channel to reliably detect
185 // child termination. We will close this fd after we create the child
186 // process which is asynchronous on Android.
187 ipcfd_
.reset(delegate
->TakeIpcFd().release());
189 BrowserThread::PostTask(
190 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
191 base::Bind(&Context::LaunchInternal
,
192 make_scoped_refptr(this),
199 #if defined(OS_ANDROID)
201 void ChildProcessLauncher::Context::OnChildProcessStarted(
202 // |this_object| is NOT thread safe. Only use it to post a task back.
203 scoped_refptr
<Context
> this_object
,
204 BrowserThread::ID client_thread_id
,
205 const base::TimeTicks begin_launch_time
,
206 base::ProcessHandle handle
) {
207 RecordHistograms(begin_launch_time
);
208 if (BrowserThread::CurrentlyOn(client_thread_id
)) {
209 // This is always invoked on the UI thread which is commonly the
210 // |client_thread_id| so we can shortcut one PostTask.
211 this_object
->Notify(base::Process(handle
));
213 BrowserThread::PostTask(
214 client_thread_id
, FROM_HERE
,
215 base::Bind(&ChildProcessLauncher::Context::Notify
,
217 base::Passed(base::Process(handle
))));
222 void ChildProcessLauncher::Context::ResetClient() {
223 // No need for locking as this function gets called on the same thread that
224 // client_ would be used.
225 CHECK(BrowserThread::CurrentlyOn(client_thread_id_
));
229 void ChildProcessLauncher::Context::UpdateTerminationStatus(bool known_dead
) {
230 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
232 termination_status_
= ZygoteHostImpl::GetInstance()->
233 GetTerminationStatus(process_
.Handle(), known_dead
, &exit_code_
);
234 } else if (known_dead
) {
235 termination_status_
=
236 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
238 #elif defined(OS_MACOSX)
240 termination_status_
=
241 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
243 #elif defined(OS_ANDROID)
244 if (IsChildProcessOomProtected(process_
.Handle())) {
245 termination_status_
= base::TERMINATION_STATUS_OOM_PROTECTED
;
250 termination_status_
=
251 base::GetTerminationStatus(process_
.Handle(), &exit_code_
);
255 void ChildProcessLauncher::Context::SetProcessBackgrounded(bool background
) {
256 base::Process to_pass
= process_
.Duplicate();
257 BrowserThread::PostTask(
258 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
259 base::Bind(&Context::SetProcessBackgroundedInternal
,
260 base::Passed(&to_pass
), background
));
264 void ChildProcessLauncher::Context::RecordHistograms(
265 base::TimeTicks begin_launch_time
) {
266 base::TimeDelta launch_time
= base::TimeTicks::Now() - begin_launch_time
;
267 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER
)) {
268 RecordLaunchHistograms(launch_time
);
270 BrowserThread::PostTask(
271 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
272 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms
,
278 void ChildProcessLauncher::Context::RecordLaunchHistograms(
279 base::TimeDelta launch_time
) {
280 // Log the launch time, separating out the first one (which will likely be
281 // slower due to the rest of the browser initializing at the same time).
282 static bool done_first_launch
= false;
283 if (done_first_launch
) {
284 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time
);
286 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time
);
287 done_first_launch
= true;
292 void ChildProcessLauncher::Context::LaunchInternal(
293 // |this_object| is NOT thread safe. Only use it to post a task back.
294 scoped_refptr
<Context
> this_object
,
295 BrowserThread::ID client_thread_id
,
296 int child_process_id
,
297 SandboxedProcessLauncherDelegate
* delegate
,
298 base::CommandLine
* cmd_line
) {
299 scoped_ptr
<SandboxedProcessLauncherDelegate
> delegate_deleter(delegate
);
301 bool launch_elevated
= delegate
->ShouldLaunchElevated();
302 #elif defined(OS_ANDROID)
303 // Uses |ipcfd_| instead of |ipcfd| on Android.
304 #elif defined(OS_MACOSX)
305 base::EnvironmentMap env
= delegate
->GetEnvironment();
306 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
307 #elif defined(OS_POSIX)
308 bool use_zygote
= delegate
->ShouldUseZygote();
309 base::EnvironmentMap env
= delegate
->GetEnvironment();
310 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
312 scoped_ptr
<base::CommandLine
> cmd_line_deleter(cmd_line
);
313 base::TimeTicks begin_launch_time
= base::TimeTicks::Now();
316 base::ProcessHandle handle
= base::kNullProcessHandle
;
317 if (launch_elevated
) {
318 base::LaunchOptions options
;
319 options
.start_hidden
= true;
320 base::LaunchElevatedProcess(*cmd_line
, options
, &handle
);
322 handle
= StartSandboxedProcess(delegate
, cmd_line
);
324 #elif defined(OS_POSIX)
325 std::string process_type
=
326 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
327 scoped_ptr
<FileDescriptorInfo
> files_to_register(
328 FileDescriptorInfoImpl::Create());
330 #if defined(OS_ANDROID)
331 files_to_register
->Share(kPrimaryIPCChannel
, this_object
->ipcfd_
.get());
333 files_to_register
->Transfer(kPrimaryIPCChannel
, ipcfd
.Pass());
335 base::StatsTable
* stats_table
= base::StatsTable::current();
337 base::SharedMemory::IsHandleValid(stats_table
->GetSharedMemoryHandle())) {
338 base::FileDescriptor fd
= stats_table
->GetSharedMemoryHandle();
339 DCHECK(!fd
.auto_close
);
340 files_to_register
->Share(kStatsTableSharedMemFd
, fd
.fd
);
344 #if defined(OS_ANDROID)
345 // Android WebView runs in single process, ensure that we never get here
346 // when running in single process mode.
347 CHECK(!cmd_line
->HasSwitch(switches::kSingleProcess
));
349 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
350 *cmd_line
, child_process_id
, files_to_register
.get());
355 files_to_register
.Pass(),
356 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted
,
361 #elif defined(OS_POSIX)
362 base::ProcessHandle handle
= base::kNullProcessHandle
;
363 // We need to close the client end of the IPC channel to reliably detect
364 // child termination.
366 #if !defined(OS_MACOSX)
367 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
368 *cmd_line
, child_process_id
, files_to_register
.get());
370 handle
= ZygoteHostImpl::GetInstance()->ForkRequest(
371 cmd_line
->argv(), files_to_register
.Pass(), process_type
);
373 // Fall through to the normal posix case below when we're not zygoting.
374 #endif // !defined(OS_MACOSX)
376 // Convert FD mapping to FileHandleMappingVector
377 base::FileHandleMappingVector fds_to_map
=
378 files_to_register
->GetMappingWithIDAdjustment(
379 base::GlobalDescriptors::kBaseDescriptor
);
381 #if !defined(OS_MACOSX)
382 if (process_type
== switches::kRendererProcess
) {
383 const int sandbox_fd
=
384 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
385 fds_to_map
.push_back(std::make_pair(
389 #endif // defined(OS_MACOSX)
391 // Actually launch the app.
392 base::LaunchOptions options
;
393 options
.environ
= env
;
394 options
.fds_to_remap
= &fds_to_map
;
396 #if defined(OS_MACOSX)
397 // Hold the MachBroker lock for the duration of LaunchProcess. The child
398 // will send its task port to the parent almost immediately after startup.
399 // The Mach message will be delivered to the parent, but updating the
400 // record of the launch will wait until after the placeholder PID is
401 // inserted below. This ensures that while the child process may send its
402 // port to the parent prior to the parent leaving LaunchProcess, the
403 // order in which the record in MachBroker is updated is correct.
404 MachBroker
* broker
= MachBroker::GetInstance();
405 broker
->GetLock().Acquire();
407 // Make sure the MachBroker is running, and inform it to expect a
408 // check-in from the new process.
409 broker
->EnsureRunning();
411 const int bootstrap_sandbox_policy
= delegate
->GetSandboxType();
412 if (ShouldEnableBootstrapSandbox() &&
413 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
414 options
.replacement_bootstrap_name
=
415 GetBootstrapSandbox()->server_bootstrap_name();
416 GetBootstrapSandbox()->PrepareToForkWithPolicy(
417 bootstrap_sandbox_policy
);
419 #endif // defined(OS_MACOSX)
421 bool launched
= base::LaunchProcess(*cmd_line
, options
, &handle
);
423 handle
= base::kNullProcessHandle
;
425 #if defined(OS_MACOSX)
426 if (ShouldEnableBootstrapSandbox() &&
427 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
428 GetBootstrapSandbox()->FinishedFork(handle
);
432 broker
->AddPlaceholderForPid(handle
);
434 // After updating the broker, release the lock and let the child's
435 // messasge be processed on the broker's thread.
436 broker
->GetLock().Release();
437 #endif // defined(OS_MACOSX)
439 #endif // else defined(OS_POSIX)
440 #if !defined(OS_ANDROID)
442 RecordHistograms(begin_launch_time
);
443 BrowserThread::PostTask(
444 client_thread_id
, FROM_HERE
,
445 base::Bind(&Context::Notify
,
447 #if defined(OS_POSIX) && !defined(OS_MACOSX)
450 base::Passed(base::Process(handle
))));
451 #endif // !defined(OS_ANDROID)
454 void ChildProcessLauncher::Context::Notify(
455 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
458 base::Process process
) {
459 #if defined(OS_ANDROID)
460 // Finally close the ipcfd
461 base::ScopedFD ipcfd_closer
= ipcfd_
.Pass();
464 process_
= process
.Pass();
465 if (!process_
.IsValid())
466 LOG(ERROR
) << "Failed to launch child process";
468 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
472 if (process_
.IsValid()) {
473 client_
->OnProcessLaunched();
475 client_
->OnProcessLaunchFailed();
482 void ChildProcessLauncher::Context::Terminate() {
483 if (!process_
.IsValid())
486 if (!terminate_child_on_shutdown_
)
489 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
490 // don't this on the UI/IO threads.
491 BrowserThread::PostTask(
492 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
493 base::Bind(&Context::TerminateInternal
,
494 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
497 base::Passed(&process_
)));
501 void ChildProcessLauncher::Context::SetProcessBackgroundedInternal(
502 base::Process process
,
504 process
.SetProcessBackgrounded(background
);
505 #if defined(OS_ANDROID)
506 SetChildProcessInForeground(process
.Handle(), !background
);
511 void ChildProcessLauncher::Context::TerminateInternal(
512 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
515 base::Process process
) {
516 #if defined(OS_ANDROID)
517 VLOG(1) << "ChromeProcess: Stopping process with handle "
519 StopChildProcess(process
.Handle());
521 // Client has gone away, so just kill the process. Using exit code 0
522 // means that UMA won't treat this as a crash.
523 process
.Terminate(RESULT_CODE_NORMAL_EXIT
);
524 // On POSIX, we must additionally reap the child.
525 #if defined(OS_POSIX)
526 #if !defined(OS_MACOSX)
528 // If the renderer was created via a zygote, we have to proxy the reaping
529 // through the zygote process.
530 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process
.Handle());
533 base::EnsureProcessTerminated(process
.Handle());
535 #endif // defined(OS_ANDROID)
538 // -----------------------------------------------------------------------------
540 ChildProcessLauncher::ChildProcessLauncher(
541 SandboxedProcessLauncherDelegate
* delegate
,
542 base::CommandLine
* cmd_line
,
543 int child_process_id
,
545 context_
= new Context();
553 ChildProcessLauncher::~ChildProcessLauncher() {
554 context_
->ResetClient();
557 bool ChildProcessLauncher::IsStarting() {
558 return context_
->starting();
561 const base::Process
& ChildProcessLauncher::GetProcess() const {
562 DCHECK(!context_
->starting());
563 return context_
->process();
566 base::TerminationStatus
ChildProcessLauncher::GetChildTerminationStatus(
569 if (!context_
->process().IsValid()) {
570 // Process is already gone, so return the cached termination status.
572 *exit_code
= context_
->exit_code();
573 return context_
->termination_status();
576 context_
->UpdateTerminationStatus(known_dead
);
578 *exit_code
= context_
->exit_code();
580 // POSIX: If the process crashed, then the kernel closed the socket
581 // for it and so the child has already died by the time we get
582 // here. Since GetTerminationStatus called waitpid with WNOHANG,
583 // it'll reap the process. However, if GetTerminationStatus didn't
584 // reap the child (because it was still running), we'll need to
585 // Terminate via ProcessWatcher. So we can't close the handle here.
586 if (context_
->termination_status() != base::TERMINATION_STATUS_STILL_RUNNING
)
589 return context_
->termination_status();
592 void ChildProcessLauncher::SetProcessBackgrounded(bool background
) {
593 context_
->SetProcessBackgrounded(background
);
596 void ChildProcessLauncher::SetTerminateChildOnShutdown(
597 bool terminate_on_shutdown
) {
599 context_
->set_terminate_child_on_shutdown(terminate_on_shutdown
);
602 } // namespace content