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(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
169 defined(UNDEFINED_SANITIZER)) && !defined(OS_CHROMEOS)
170 terminate_child_on_shutdown_(false) {
172 terminate_child_on_shutdown_(true) {
176 void ChildProcessLauncher::Context::Launch(
177 SandboxedProcessLauncherDelegate
* delegate
,
178 base::CommandLine
* cmd_line
,
179 int child_process_id
,
181 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_
));
184 #if defined(OS_ANDROID)
185 // Android only supports renderer, sandboxed utility and gpu.
186 std::string process_type
=
187 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
188 CHECK(process_type
== switches::kGpuProcess
||
189 process_type
== switches::kRendererProcess
||
190 process_type
== switches::kUtilityProcess
)
191 << "Unsupported process type: " << process_type
;
193 // Non-sandboxed utility or renderer process are currently not supported.
194 DCHECK(process_type
== switches::kGpuProcess
||
195 !cmd_line
->HasSwitch(switches::kNoSandbox
));
197 // We need to close the client end of the IPC channel to reliably detect
198 // child termination. We will close this fd after we create the child
199 // process which is asynchronous on Android.
200 ipcfd_
.reset(delegate
->TakeIpcFd().release());
202 BrowserThread::PostTask(
203 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
204 base::Bind(&Context::LaunchInternal
,
205 make_scoped_refptr(this),
212 #if defined(OS_ANDROID)
214 void ChildProcessLauncher::Context::OnChildProcessStarted(
215 // |this_object| is NOT thread safe. Only use it to post a task back.
216 scoped_refptr
<Context
> this_object
,
217 BrowserThread::ID client_thread_id
,
218 const base::TimeTicks begin_launch_time
,
219 base::ProcessHandle handle
) {
220 RecordHistograms(begin_launch_time
);
221 if (BrowserThread::CurrentlyOn(client_thread_id
)) {
222 // This is always invoked on the UI thread which is commonly the
223 // |client_thread_id| so we can shortcut one PostTask.
224 this_object
->Notify(base::Process(handle
));
226 BrowserThread::PostTask(
227 client_thread_id
, FROM_HERE
,
228 base::Bind(&ChildProcessLauncher::Context::Notify
,
230 base::Passed(base::Process(handle
))));
235 void ChildProcessLauncher::Context::ResetClient() {
236 // No need for locking as this function gets called on the same thread that
237 // client_ would be used.
238 CHECK(BrowserThread::CurrentlyOn(client_thread_id_
));
242 void ChildProcessLauncher::Context::UpdateTerminationStatus(bool known_dead
) {
243 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
245 termination_status_
= ZygoteHostImpl::GetInstance()->
246 GetTerminationStatus(process_
.Handle(), known_dead
, &exit_code_
);
247 } else if (known_dead
) {
248 termination_status_
=
249 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
251 #elif defined(OS_MACOSX)
253 termination_status_
=
254 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
256 #elif defined(OS_ANDROID)
257 if (IsChildProcessOomProtected(process_
.Handle())) {
258 termination_status_
= base::TERMINATION_STATUS_OOM_PROTECTED
;
263 termination_status_
=
264 base::GetTerminationStatus(process_
.Handle(), &exit_code_
);
268 void ChildProcessLauncher::Context::SetProcessBackgrounded(bool background
) {
269 base::Process to_pass
= process_
.Duplicate();
270 BrowserThread::PostTask(
271 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
272 base::Bind(&Context::SetProcessBackgroundedInternal
,
273 base::Passed(&to_pass
), background
));
277 void ChildProcessLauncher::Context::RecordHistograms(
278 base::TimeTicks begin_launch_time
) {
279 base::TimeDelta launch_time
= base::TimeTicks::Now() - begin_launch_time
;
280 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER
)) {
281 RecordLaunchHistograms(launch_time
);
283 BrowserThread::PostTask(
284 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
285 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms
,
291 void ChildProcessLauncher::Context::RecordLaunchHistograms(
292 base::TimeDelta launch_time
) {
293 // Log the launch time, separating out the first one (which will likely be
294 // slower due to the rest of the browser initializing at the same time).
295 static bool done_first_launch
= false;
296 if (done_first_launch
) {
297 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time
);
299 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time
);
300 done_first_launch
= true;
305 void ChildProcessLauncher::Context::LaunchInternal(
306 // |this_object| is NOT thread safe. Only use it to post a task back.
307 scoped_refptr
<Context
> this_object
,
308 BrowserThread::ID client_thread_id
,
309 int child_process_id
,
310 SandboxedProcessLauncherDelegate
* delegate
,
311 base::CommandLine
* cmd_line
) {
312 scoped_ptr
<SandboxedProcessLauncherDelegate
> delegate_deleter(delegate
);
314 bool launch_elevated
= delegate
->ShouldLaunchElevated();
315 #elif defined(OS_ANDROID)
316 // Uses |ipcfd_| instead of |ipcfd| on Android.
317 #elif defined(OS_MACOSX)
318 base::EnvironmentMap env
= delegate
->GetEnvironment();
319 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
320 #elif defined(OS_POSIX)
321 bool use_zygote
= delegate
->ShouldUseZygote();
322 base::EnvironmentMap env
= delegate
->GetEnvironment();
323 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
325 scoped_ptr
<base::CommandLine
> cmd_line_deleter(cmd_line
);
326 base::TimeTicks begin_launch_time
= base::TimeTicks::Now();
328 base::Process process
;
330 if (launch_elevated
) {
331 base::LaunchOptions options
;
332 options
.start_hidden
= true;
333 process
= base::LaunchElevatedProcess(*cmd_line
, options
);
335 process
= StartSandboxedProcess(delegate
, cmd_line
);
337 #elif defined(OS_POSIX)
338 std::string process_type
=
339 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
340 scoped_ptr
<FileDescriptorInfo
> files_to_register(
341 FileDescriptorInfoImpl::Create());
343 #if defined(OS_ANDROID)
344 files_to_register
->Share(kPrimaryIPCChannel
, this_object
->ipcfd_
.get());
346 files_to_register
->Transfer(kPrimaryIPCChannel
, ipcfd
.Pass());
348 base::StatsTable
* stats_table
= base::StatsTable::current();
350 base::SharedMemory::IsHandleValid(stats_table
->GetSharedMemoryHandle())) {
351 base::FileDescriptor fd
= stats_table
->GetSharedMemoryHandle();
352 DCHECK(!fd
.auto_close
);
353 files_to_register
->Share(kStatsTableSharedMemFd
, fd
.fd
);
357 #if defined(OS_ANDROID)
358 // Android WebView runs in single process, ensure that we never get here
359 // when running in single process mode.
360 CHECK(!cmd_line
->HasSwitch(switches::kSingleProcess
));
362 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
363 *cmd_line
, child_process_id
, files_to_register
.get());
368 files_to_register
.Pass(),
369 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted
,
374 #elif defined(OS_POSIX)
375 // We need to close the client end of the IPC channel to reliably detect
376 // child termination.
378 #if !defined(OS_MACOSX)
379 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
380 *cmd_line
, child_process_id
, files_to_register
.get());
382 base::ProcessHandle handle
= ZygoteHostImpl::GetInstance()->ForkRequest(
383 cmd_line
->argv(), files_to_register
.Pass(), process_type
);
384 process
= base::Process(handle
);
386 // Fall through to the normal posix case below when we're not zygoting.
387 #endif // !defined(OS_MACOSX)
389 // Convert FD mapping to FileHandleMappingVector
390 base::FileHandleMappingVector fds_to_map
=
391 files_to_register
->GetMappingWithIDAdjustment(
392 base::GlobalDescriptors::kBaseDescriptor
);
394 #if !defined(OS_MACOSX)
395 if (process_type
== switches::kRendererProcess
) {
396 const int sandbox_fd
=
397 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
398 fds_to_map
.push_back(std::make_pair(
402 #endif // defined(OS_MACOSX)
404 // Actually launch the app.
405 base::LaunchOptions options
;
406 options
.environ
= env
;
407 options
.fds_to_remap
= &fds_to_map
;
409 #if defined(OS_MACOSX)
410 // Hold the MachBroker lock for the duration of LaunchProcess. The child
411 // will send its task port to the parent almost immediately after startup.
412 // The Mach message will be delivered to the parent, but updating the
413 // record of the launch will wait until after the placeholder PID is
414 // inserted below. This ensures that while the child process may send its
415 // port to the parent prior to the parent leaving LaunchProcess, the
416 // order in which the record in MachBroker is updated is correct.
417 MachBroker
* broker
= MachBroker::GetInstance();
418 broker
->GetLock().Acquire();
420 // Make sure the MachBroker is running, and inform it to expect a
421 // check-in from the new process.
422 broker
->EnsureRunning();
424 const int bootstrap_sandbox_policy
= delegate
->GetSandboxType();
425 if (ShouldEnableBootstrapSandbox() &&
426 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
427 options
.replacement_bootstrap_name
=
428 GetBootstrapSandbox()->server_bootstrap_name();
429 GetBootstrapSandbox()->PrepareToForkWithPolicy(
430 bootstrap_sandbox_policy
);
432 #endif // defined(OS_MACOSX)
434 process
= base::LaunchProcess(*cmd_line
, options
);
436 #if defined(OS_MACOSX)
437 if (ShouldEnableBootstrapSandbox() &&
438 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
439 GetBootstrapSandbox()->FinishedFork(process
.Handle());
442 if (process
.IsValid())
443 broker
->AddPlaceholderForPid(process
.pid(), child_process_id
);
445 // After updating the broker, release the lock and let the child's
446 // messasge be processed on the broker's thread.
447 broker
->GetLock().Release();
448 #endif // defined(OS_MACOSX)
450 #endif // else defined(OS_POSIX)
451 #if !defined(OS_ANDROID)
452 if (process
.IsValid())
453 RecordHistograms(begin_launch_time
);
454 BrowserThread::PostTask(
455 client_thread_id
, FROM_HERE
,
456 base::Bind(&Context::Notify
,
458 #if defined(OS_POSIX) && !defined(OS_MACOSX)
461 base::Passed(&process
)));
462 #endif // !defined(OS_ANDROID)
465 void ChildProcessLauncher::Context::Notify(
466 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
469 base::Process process
) {
470 #if defined(OS_ANDROID)
471 // Finally close the ipcfd
472 base::ScopedFD ipcfd_closer
= ipcfd_
.Pass();
475 process_
= process
.Pass();
476 if (!process_
.IsValid())
477 LOG(ERROR
) << "Failed to launch child process";
479 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
483 if (process_
.IsValid()) {
484 client_
->OnProcessLaunched();
486 client_
->OnProcessLaunchFailed();
493 void ChildProcessLauncher::Context::Terminate() {
494 if (!process_
.IsValid())
497 if (!terminate_child_on_shutdown_
)
500 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
501 // don't this on the UI/IO threads.
502 BrowserThread::PostTask(
503 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
504 base::Bind(&Context::TerminateInternal
,
505 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
508 base::Passed(&process_
)));
512 void ChildProcessLauncher::Context::SetProcessBackgroundedInternal(
513 base::Process process
,
515 process
.SetProcessBackgrounded(background
);
516 #if defined(OS_ANDROID)
517 SetChildProcessInForeground(process
.Handle(), !background
);
522 void ChildProcessLauncher::Context::TerminateInternal(
523 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
526 base::Process process
) {
527 #if defined(OS_ANDROID)
528 VLOG(1) << "ChromeProcess: Stopping process with handle "
530 StopChildProcess(process
.Handle());
532 // Client has gone away, so just kill the process. Using exit code 0
533 // means that UMA won't treat this as a crash.
534 process
.Terminate(RESULT_CODE_NORMAL_EXIT
);
535 // On POSIX, we must additionally reap the child.
536 #if defined(OS_POSIX)
537 #if !defined(OS_MACOSX)
539 // If the renderer was created via a zygote, we have to proxy the reaping
540 // through the zygote process.
541 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process
.Handle());
544 base::EnsureProcessTerminated(process
.Pass());
546 #endif // defined(OS_ANDROID)
549 // -----------------------------------------------------------------------------
551 ChildProcessLauncher::ChildProcessLauncher(
552 SandboxedProcessLauncherDelegate
* delegate
,
553 base::CommandLine
* cmd_line
,
554 int child_process_id
,
556 context_
= new Context();
564 ChildProcessLauncher::~ChildProcessLauncher() {
565 context_
->ResetClient();
568 bool ChildProcessLauncher::IsStarting() {
569 return context_
->starting();
572 const base::Process
& ChildProcessLauncher::GetProcess() const {
573 DCHECK(!context_
->starting());
574 return context_
->process();
577 base::TerminationStatus
ChildProcessLauncher::GetChildTerminationStatus(
580 if (!context_
->process().IsValid()) {
581 // Process is already gone, so return the cached termination status.
583 *exit_code
= context_
->exit_code();
584 return context_
->termination_status();
587 context_
->UpdateTerminationStatus(known_dead
);
589 *exit_code
= context_
->exit_code();
591 // POSIX: If the process crashed, then the kernel closed the socket
592 // for it and so the child has already died by the time we get
593 // here. Since GetTerminationStatus called waitpid with WNOHANG,
594 // it'll reap the process. However, if GetTerminationStatus didn't
595 // reap the child (because it was still running), we'll need to
596 // Terminate via ProcessWatcher. So we can't close the handle here.
597 if (context_
->termination_status() != base::TERMINATION_STATUS_STILL_RUNNING
)
600 return context_
->termination_status();
603 void ChildProcessLauncher::SetProcessBackgrounded(bool background
) {
604 context_
->SetProcessBackgrounded(background
);
607 void ChildProcessLauncher::SetTerminateChildOnShutdown(
608 bool terminate_on_shutdown
) {
610 context_
->set_terminate_child_on_shutdown(terminate_on_shutdown
);
613 } // namespace content