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/posix/global_descriptors.h"
47 #include "content/browser/file_descriptor_info_impl.h"
52 // Having the functionality of ChildProcessLauncher be in an internal
53 // ref counted object allows us to automatically terminate the process when the
54 // parent class destructs, while still holding on to state that we need.
55 class ChildProcessLauncher::Context
56 : public base::RefCountedThreadSafe
<ChildProcessLauncher::Context
> {
60 // Posts a task to a dedicated thread to do the actual work.
61 // Must be called on the UI thread.
62 void Launch(SandboxedProcessLauncherDelegate
* delegate
,
63 base::CommandLine
* cmd_line
,
67 #if defined(OS_ANDROID)
68 // Called on the UI thread with the operation result. Calls Notify().
69 static void OnChildProcessStarted(
70 // |this_object| is NOT thread safe. Only use it to post a task back.
71 scoped_refptr
<Context
> this_object
,
72 BrowserThread::ID client_thread_id
,
73 const base::TimeTicks begin_launch_time
,
74 base::ProcessHandle handle
);
77 // Resets the client (the client is going away).
80 bool starting() const { return starting_
; }
82 const base::Process
& process() const { return process_
; }
84 int exit_code() const { return exit_code_
; }
86 base::TerminationStatus
termination_status() const {
87 return termination_status_
;
90 void set_terminate_child_on_shutdown(bool terminate_on_shutdown
) {
91 terminate_child_on_shutdown_
= terminate_on_shutdown
;
94 void UpdateTerminationStatus(bool known_dead
);
96 void Close() { process_
.Close(); }
98 void SetProcessBackgrounded(bool background
);
101 friend class base::RefCountedThreadSafe
<ChildProcessLauncher::Context
>;
107 static void RecordHistograms(base::TimeTicks begin_launch_time
);
108 static void RecordLaunchHistograms(base::TimeDelta launch_time
);
110 // Performs the actual work of launching the process.
111 // Runs on the PROCESS_LAUNCHER thread.
112 static void LaunchInternal(
113 // |this_object| is NOT thread safe. Only use it to post a task back.
114 scoped_refptr
<Context
> this_object
,
115 BrowserThread::ID client_thread_id
,
116 int child_process_id
,
117 SandboxedProcessLauncherDelegate
* delegate
,
118 base::CommandLine
* cmd_line
);
120 // Notifies the client about the result of the operation.
121 // Runs on the UI thread.
123 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
126 base::Process process
);
130 static void SetProcessBackgroundedInternal(base::Process process
,
133 static void TerminateInternal(
134 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
137 base::Process process
);
140 BrowserThread::ID client_thread_id_
;
141 base::Process process_
;
142 base::TerminationStatus termination_status_
;
144 #if defined(OS_ANDROID)
145 // The fd to close after creating the process.
146 base::ScopedFD ipcfd_
;
147 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
151 // Controls whether the child process should be terminated on browser
152 // shutdown. Default behavior is to terminate the child.
153 bool terminate_child_on_shutdown_
;
156 ChildProcessLauncher::Context::Context()
158 client_thread_id_(BrowserThread::UI
),
159 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION
),
160 exit_code_(RESULT_CODE_NORMAL_EXIT
),
161 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
165 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
166 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
167 defined(UNDEFINED_SANITIZER)
168 terminate_child_on_shutdown_(false) {
170 terminate_child_on_shutdown_(true) {
174 void ChildProcessLauncher::Context::Launch(
175 SandboxedProcessLauncherDelegate
* delegate
,
176 base::CommandLine
* cmd_line
,
177 int child_process_id
,
179 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_
));
182 #if defined(OS_ANDROID)
183 // Android only supports renderer, sandboxed utility and gpu.
184 std::string process_type
=
185 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
186 CHECK(process_type
== switches::kGpuProcess
||
187 process_type
== switches::kRendererProcess
||
188 process_type
== switches::kUtilityProcess
)
189 << "Unsupported process type: " << process_type
;
191 // Non-sandboxed utility or renderer process are currently not supported.
192 DCHECK(process_type
== switches::kGpuProcess
||
193 !cmd_line
->HasSwitch(switches::kNoSandbox
));
195 // We need to close the client end of the IPC channel to reliably detect
196 // child termination. We will close this fd after we create the child
197 // process which is asynchronous on Android.
198 ipcfd_
.reset(delegate
->TakeIpcFd().release());
200 BrowserThread::PostTask(
201 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
202 base::Bind(&Context::LaunchInternal
,
203 make_scoped_refptr(this),
210 #if defined(OS_ANDROID)
212 void ChildProcessLauncher::Context::OnChildProcessStarted(
213 // |this_object| is NOT thread safe. Only use it to post a task back.
214 scoped_refptr
<Context
> this_object
,
215 BrowserThread::ID client_thread_id
,
216 const base::TimeTicks begin_launch_time
,
217 base::ProcessHandle handle
) {
218 RecordHistograms(begin_launch_time
);
219 if (BrowserThread::CurrentlyOn(client_thread_id
)) {
220 // This is always invoked on the UI thread which is commonly the
221 // |client_thread_id| so we can shortcut one PostTask.
222 this_object
->Notify(base::Process(handle
));
224 BrowserThread::PostTask(
225 client_thread_id
, FROM_HERE
,
226 base::Bind(&ChildProcessLauncher::Context::Notify
,
228 base::Passed(base::Process(handle
))));
233 void ChildProcessLauncher::Context::ResetClient() {
234 // No need for locking as this function gets called on the same thread that
235 // client_ would be used.
236 CHECK(BrowserThread::CurrentlyOn(client_thread_id_
));
240 void ChildProcessLauncher::Context::UpdateTerminationStatus(bool known_dead
) {
241 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
243 termination_status_
= ZygoteHostImpl::GetInstance()->
244 GetTerminationStatus(process_
.Handle(), known_dead
, &exit_code_
);
245 } else if (known_dead
) {
246 termination_status_
=
247 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
249 #elif defined(OS_MACOSX)
251 termination_status_
=
252 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
254 #elif defined(OS_ANDROID)
255 if (IsChildProcessOomProtected(process_
.Handle())) {
256 termination_status_
= base::TERMINATION_STATUS_OOM_PROTECTED
;
261 termination_status_
=
262 base::GetTerminationStatus(process_
.Handle(), &exit_code_
);
266 void ChildProcessLauncher::Context::SetProcessBackgrounded(bool background
) {
267 base::Process to_pass
= process_
.Duplicate();
268 BrowserThread::PostTask(
269 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
270 base::Bind(&Context::SetProcessBackgroundedInternal
,
271 base::Passed(&to_pass
), background
));
275 void ChildProcessLauncher::Context::RecordHistograms(
276 base::TimeTicks begin_launch_time
) {
277 base::TimeDelta launch_time
= base::TimeTicks::Now() - begin_launch_time
;
278 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER
)) {
279 RecordLaunchHistograms(launch_time
);
281 BrowserThread::PostTask(
282 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
283 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms
,
289 void ChildProcessLauncher::Context::RecordLaunchHistograms(
290 base::TimeDelta launch_time
) {
291 // Log the launch time, separating out the first one (which will likely be
292 // slower due to the rest of the browser initializing at the same time).
293 static bool done_first_launch
= false;
294 if (done_first_launch
) {
295 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time
);
297 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time
);
298 done_first_launch
= true;
303 void ChildProcessLauncher::Context::LaunchInternal(
304 // |this_object| is NOT thread safe. Only use it to post a task back.
305 scoped_refptr
<Context
> this_object
,
306 BrowserThread::ID client_thread_id
,
307 int child_process_id
,
308 SandboxedProcessLauncherDelegate
* delegate
,
309 base::CommandLine
* cmd_line
) {
310 scoped_ptr
<SandboxedProcessLauncherDelegate
> delegate_deleter(delegate
);
312 bool launch_elevated
= delegate
->ShouldLaunchElevated();
313 #elif defined(OS_ANDROID)
314 // Uses |ipcfd_| instead of |ipcfd| on Android.
315 #elif defined(OS_MACOSX)
316 base::EnvironmentMap env
= delegate
->GetEnvironment();
317 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
318 #elif defined(OS_POSIX)
319 bool use_zygote
= delegate
->ShouldUseZygote();
320 base::EnvironmentMap env
= delegate
->GetEnvironment();
321 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
323 scoped_ptr
<base::CommandLine
> cmd_line_deleter(cmd_line
);
324 base::TimeTicks begin_launch_time
= base::TimeTicks::Now();
326 base::Process process
;
328 if (launch_elevated
) {
329 base::LaunchOptions options
;
330 options
.start_hidden
= true;
331 process
= base::LaunchElevatedProcess(*cmd_line
, options
);
333 process
= StartSandboxedProcess(delegate
, cmd_line
);
335 #elif defined(OS_POSIX)
336 std::string process_type
=
337 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
338 scoped_ptr
<FileDescriptorInfo
> files_to_register(
339 FileDescriptorInfoImpl::Create());
341 #if defined(OS_ANDROID)
342 files_to_register
->Share(kPrimaryIPCChannel
, this_object
->ipcfd_
.get());
344 files_to_register
->Transfer(kPrimaryIPCChannel
, ipcfd
.Pass());
348 #if defined(OS_ANDROID)
349 // Android WebView runs in single process, ensure that we never get here
350 // when running in single process mode.
351 CHECK(!cmd_line
->HasSwitch(switches::kSingleProcess
));
353 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
354 *cmd_line
, child_process_id
, files_to_register
.get());
359 files_to_register
.Pass(),
360 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted
,
365 #elif defined(OS_POSIX)
366 // We need to close the client end of the IPC channel to reliably detect
367 // child termination.
369 #if !defined(OS_MACOSX)
370 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
371 *cmd_line
, child_process_id
, files_to_register
.get());
373 base::ProcessHandle handle
= ZygoteHostImpl::GetInstance()->ForkRequest(
374 cmd_line
->argv(), files_to_register
.Pass(), process_type
);
375 process
= base::Process(handle
);
377 // Fall through to the normal posix case below when we're not zygoting.
378 #endif // !defined(OS_MACOSX)
380 // Convert FD mapping to FileHandleMappingVector
381 base::FileHandleMappingVector fds_to_map
=
382 files_to_register
->GetMappingWithIDAdjustment(
383 base::GlobalDescriptors::kBaseDescriptor
);
385 #if !defined(OS_MACOSX)
386 if (process_type
== switches::kRendererProcess
) {
387 const int sandbox_fd
=
388 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
389 fds_to_map
.push_back(std::make_pair(
393 #endif // defined(OS_MACOSX)
395 // Actually launch the app.
396 base::LaunchOptions options
;
397 options
.environ
= env
;
398 options
.fds_to_remap
= &fds_to_map
;
400 #if defined(OS_MACOSX)
401 // Hold the MachBroker lock for the duration of LaunchProcess. The child
402 // will send its task port to the parent almost immediately after startup.
403 // The Mach message will be delivered to the parent, but updating the
404 // record of the launch will wait until after the placeholder PID is
405 // inserted below. This ensures that while the child process may send its
406 // port to the parent prior to the parent leaving LaunchProcess, the
407 // order in which the record in MachBroker is updated is correct.
408 MachBroker
* broker
= MachBroker::GetInstance();
409 broker
->GetLock().Acquire();
411 // Make sure the MachBroker is running, and inform it to expect a
412 // check-in from the new process.
413 broker
->EnsureRunning();
415 const int bootstrap_sandbox_policy
= delegate
->GetSandboxType();
416 if (ShouldEnableBootstrapSandbox() &&
417 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
418 options
.replacement_bootstrap_name
=
419 GetBootstrapSandbox()->server_bootstrap_name();
420 GetBootstrapSandbox()->PrepareToForkWithPolicy(
421 bootstrap_sandbox_policy
);
423 #endif // defined(OS_MACOSX)
425 process
= base::LaunchProcess(*cmd_line
, options
);
427 #if defined(OS_MACOSX)
428 if (ShouldEnableBootstrapSandbox() &&
429 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
430 GetBootstrapSandbox()->FinishedFork(process
.Handle());
433 if (process
.IsValid())
434 broker
->AddPlaceholderForPid(process
.Pid(), child_process_id
);
436 // After updating the broker, release the lock and let the child's
437 // messasge be processed on the broker's thread.
438 broker
->GetLock().Release();
439 #endif // defined(OS_MACOSX)
441 #endif // else defined(OS_POSIX)
442 #if !defined(OS_ANDROID)
443 if (process
.IsValid())
444 RecordHistograms(begin_launch_time
);
445 BrowserThread::PostTask(
446 client_thread_id
, FROM_HERE
,
447 base::Bind(&Context::Notify
,
449 #if defined(OS_POSIX) && !defined(OS_MACOSX)
452 base::Passed(&process
)));
453 #endif // !defined(OS_ANDROID)
456 void ChildProcessLauncher::Context::Notify(
457 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
460 base::Process process
) {
461 #if defined(OS_ANDROID)
462 // Finally close the ipcfd
463 base::ScopedFD ipcfd_closer
= ipcfd_
.Pass();
466 process_
= process
.Pass();
467 if (!process_
.IsValid())
468 LOG(ERROR
) << "Failed to launch child process";
470 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
474 if (process_
.IsValid()) {
475 client_
->OnProcessLaunched();
477 client_
->OnProcessLaunchFailed();
484 void ChildProcessLauncher::Context::Terminate() {
485 if (!process_
.IsValid())
488 if (!terminate_child_on_shutdown_
)
491 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
492 // don't this on the UI/IO threads.
493 BrowserThread::PostTask(
494 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
495 base::Bind(&Context::TerminateInternal
,
496 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
499 base::Passed(&process_
)));
503 void ChildProcessLauncher::Context::SetProcessBackgroundedInternal(
504 base::Process process
,
506 process
.SetProcessBackgrounded(background
);
507 #if defined(OS_ANDROID)
508 SetChildProcessInForeground(process
.Handle(), !background
);
513 void ChildProcessLauncher::Context::TerminateInternal(
514 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
517 base::Process process
) {
518 #if defined(OS_ANDROID)
519 VLOG(1) << "ChromeProcess: Stopping process with handle "
521 StopChildProcess(process
.Handle());
523 // Client has gone away, so just kill the process. Using exit code 0
524 // means that UMA won't treat this as a crash.
525 process
.Terminate(RESULT_CODE_NORMAL_EXIT
);
526 // On POSIX, we must additionally reap the child.
527 #if defined(OS_POSIX)
528 #if !defined(OS_MACOSX)
530 // If the renderer was created via a zygote, we have to proxy the reaping
531 // through the zygote process.
532 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process
.Handle());
535 base::EnsureProcessTerminated(process
.Pass());
537 #endif // defined(OS_ANDROID)
540 // -----------------------------------------------------------------------------
542 ChildProcessLauncher::ChildProcessLauncher(
543 SandboxedProcessLauncherDelegate
* delegate
,
544 base::CommandLine
* cmd_line
,
545 int child_process_id
,
547 context_
= new Context();
555 ChildProcessLauncher::~ChildProcessLauncher() {
556 context_
->ResetClient();
559 bool ChildProcessLauncher::IsStarting() {
560 return context_
->starting();
563 const base::Process
& ChildProcessLauncher::GetProcess() const {
564 DCHECK(!context_
->starting());
565 return context_
->process();
568 base::TerminationStatus
ChildProcessLauncher::GetChildTerminationStatus(
571 if (!context_
->process().IsValid()) {
572 // Process is already gone, so return the cached termination status.
574 *exit_code
= context_
->exit_code();
575 return context_
->termination_status();
578 context_
->UpdateTerminationStatus(known_dead
);
580 *exit_code
= context_
->exit_code();
582 // POSIX: If the process crashed, then the kernel closed the socket
583 // for it and so the child has already died by the time we get
584 // here. Since GetTerminationStatus called waitpid with WNOHANG,
585 // it'll reap the process. However, if GetTerminationStatus didn't
586 // reap the child (because it was still running), we'll need to
587 // Terminate via ProcessWatcher. So we can't close the handle here.
588 if (context_
->termination_status() != base::TERMINATION_STATUS_STILL_RUNNING
)
591 return context_
->termination_status();
594 void ChildProcessLauncher::SetProcessBackgrounded(bool background
) {
595 context_
->SetProcessBackgrounded(background
);
598 void ChildProcessLauncher::SetTerminateChildOnShutdown(
599 bool terminate_on_shutdown
) {
601 context_
->set_terminate_child_on_shutdown(terminate_on_shutdown
);
604 } // namespace content