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/file_util.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/metrics/histogram.h"
15 #include "base/process/process.h"
16 #include "base/synchronization/lock.h"
17 #include "base/threading/thread.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/content_browser_client.h"
20 #include "content/public/common/content_descriptors.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/public/common/result_codes.h"
25 #include "base/files/file_path.h"
26 #include "content/common/sandbox_win.h"
27 #include "content/public/common/sandbox_init.h"
28 #include "content/public/common/sandboxed_process_launcher_delegate.h"
29 #elif defined(OS_MACOSX)
30 #include "content/browser/mach_broker_mac.h"
31 #elif defined(OS_ANDROID)
32 #include "base/android/jni_android.h"
33 #include "content/browser/android/child_process_launcher_android.h"
34 #elif defined(OS_POSIX)
35 #include "base/memory/shared_memory.h"
36 #include "base/memory/singleton.h"
37 #include "content/browser/renderer_host/render_sandbox_host_linux.h"
38 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
39 #include "content/common/child_process_sandbox_support_impl_linux.h"
43 #include "base/metrics/stats_table.h"
44 #include "base/posix/global_descriptors.h"
49 // Having the functionality of ChildProcessLauncher be in an internal
50 // ref counted object allows us to automatically terminate the process when the
51 // parent class destructs, while still holding on to state that we need.
52 class ChildProcessLauncher::Context
53 : public base::RefCountedThreadSafe
<ChildProcessLauncher::Context
> {
57 client_thread_id_(BrowserThread::UI
),
58 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION
),
59 exit_code_(RESULT_CODE_NORMAL_EXIT
),
61 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
66 terminate_child_on_shutdown_
= !CommandLine::ForCurrentProcess()->
67 HasSwitch(switches::kChildCleanExit
);
69 terminate_child_on_shutdown_
= true;
75 SandboxedProcessLauncherDelegate
* delegate
,
76 #elif defined(OS_ANDROID)
78 #elif defined(OS_POSIX)
80 const base::EnvironmentMap
& environ
,
83 CommandLine
* cmd_line
,
88 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_
));
90 #if defined(OS_ANDROID)
91 // We need to close the client end of the IPC channel to reliably detect
92 // child termination. We will close this fd after we create the child
93 // process which is asynchronous on Android.
96 BrowserThread::PostTask(
97 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
99 &Context::LaunchInternal
,
100 make_scoped_refptr(this),
105 #elif defined(OS_ANDROID)
107 #elif defined(OS_POSIX)
115 #if defined(OS_ANDROID)
116 static void OnChildProcessStarted(
117 // |this_object| is NOT thread safe. Only use it to post a task back.
118 scoped_refptr
<Context
> this_object
,
119 BrowserThread::ID client_thread_id
,
120 const base::TimeTicks begin_launch_time
,
121 base::ProcessHandle handle
) {
122 RecordHistograms(begin_launch_time
);
123 if (BrowserThread::CurrentlyOn(client_thread_id
)) {
124 // This is always invoked on the UI thread which is commonly the
125 // |client_thread_id| so we can shortcut one PostTask.
126 this_object
->Notify(handle
);
128 BrowserThread::PostTask(
129 client_thread_id
, FROM_HERE
,
131 &ChildProcessLauncher::Context::Notify
,
139 // No need for locking as this function gets called on the same thread that
140 // client_ would be used.
141 CHECK(BrowserThread::CurrentlyOn(client_thread_id_
));
145 void set_terminate_child_on_shutdown(bool terminate_on_shutdown
) {
146 terminate_child_on_shutdown_
= terminate_on_shutdown
;
150 friend class base::RefCountedThreadSafe
<ChildProcessLauncher::Context
>;
151 friend class ChildProcessLauncher
;
157 static void RecordHistograms(const base::TimeTicks begin_launch_time
) {
158 base::TimeDelta launch_time
= base::TimeTicks::Now() - begin_launch_time
;
159 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER
)) {
160 RecordLaunchHistograms(launch_time
);
162 BrowserThread::PostTask(
163 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
164 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms
,
169 static void RecordLaunchHistograms(const base::TimeDelta launch_time
) {
170 // Log the launch time, separating out the first one (which will likely be
171 // slower due to the rest of the browser initializing at the same time).
172 static bool done_first_launch
= false;
173 if (done_first_launch
) {
174 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time
);
176 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time
);
177 done_first_launch
= true;
181 static void LaunchInternal(
182 // |this_object| is NOT thread safe. Only use it to post a task back.
183 scoped_refptr
<Context
> this_object
,
184 BrowserThread::ID client_thread_id
,
185 int child_process_id
,
187 SandboxedProcessLauncherDelegate
* delegate
,
188 #elif defined(OS_ANDROID)
190 #elif defined(OS_POSIX)
192 const base::EnvironmentMap
& env
,
195 CommandLine
* cmd_line
) {
196 scoped_ptr
<CommandLine
> cmd_line_deleter(cmd_line
);
197 base::TimeTicks begin_launch_time
= base::TimeTicks::Now();
200 scoped_ptr
<SandboxedProcessLauncherDelegate
> delegate_deleter(delegate
);
201 base::ProcessHandle handle
= StartSandboxedProcess(delegate
, cmd_line
);
202 #elif defined(OS_POSIX)
203 std::string process_type
=
204 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
205 std::vector
<FileDescriptorInfo
> files_to_register
;
206 files_to_register
.push_back(
207 FileDescriptorInfo(kPrimaryIPCChannel
,
208 base::FileDescriptor(ipcfd
, false)));
209 base::StatsTable
* stats_table
= base::StatsTable::current();
211 base::SharedMemory::IsHandleValid(
212 stats_table
->GetSharedMemoryHandle())) {
213 files_to_register
.push_back(
214 FileDescriptorInfo(kStatsTableSharedMemFd
,
215 stats_table
->GetSharedMemoryHandle()));
219 #if defined(OS_ANDROID)
220 // Android WebView runs in single process, ensure that we never get here
221 // when running in single process mode.
222 CHECK(!cmd_line
->HasSwitch(switches::kSingleProcess
));
224 GetContentClient()->browser()->
225 GetAdditionalMappedFilesForChildProcess(*cmd_line
, child_process_id
,
228 StartChildProcess(cmd_line
->argv(), files_to_register
,
229 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted
,
230 this_object
, client_thread_id
, begin_launch_time
));
232 #elif defined(OS_POSIX)
233 base::ProcessHandle handle
= base::kNullProcessHandle
;
234 // We need to close the client end of the IPC channel to reliably detect
235 // child termination.
236 file_util::ScopedFD
ipcfd_closer(&ipcfd
);
238 #if !defined(OS_MACOSX)
239 GetContentClient()->browser()->
240 GetAdditionalMappedFilesForChildProcess(*cmd_line
, child_process_id
,
243 handle
= ZygoteHostImpl::GetInstance()->ForkRequest(cmd_line
->argv(),
247 // Fall through to the normal posix case below when we're not zygoting.
248 #endif // !defined(OS_MACOSX)
250 // Convert FD mapping to FileHandleMappingVector
251 base::FileHandleMappingVector fds_to_map
;
252 for (size_t i
= 0; i
< files_to_register
.size(); ++i
) {
253 fds_to_map
.push_back(std::make_pair(
254 files_to_register
[i
].fd
.fd
,
255 files_to_register
[i
].id
+
256 base::GlobalDescriptors::kBaseDescriptor
));
259 #if !defined(OS_MACOSX)
260 if (process_type
== switches::kRendererProcess
) {
261 const int sandbox_fd
=
262 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
263 fds_to_map
.push_back(std::make_pair(
267 #endif // defined(OS_MACOSX)
269 // Actually launch the app.
270 base::LaunchOptions options
;
271 options
.environ
= env
;
272 options
.fds_to_remap
= &fds_to_map
;
274 #if defined(OS_MACOSX)
275 // Hold the MachBroker lock for the duration of LaunchProcess. The child
276 // will send its task port to the parent almost immediately after startup.
277 // The Mach message will be delivered to the parent, but updating the
278 // record of the launch will wait until after the placeholder PID is
279 // inserted below. This ensures that while the child process may send its
280 // port to the parent prior to the parent leaving LaunchProcess, the
281 // order in which the record in MachBroker is updated is correct.
282 MachBroker
* broker
= MachBroker::GetInstance();
283 broker
->GetLock().Acquire();
285 // Make sure the MachBroker is running, and inform it to expect a
286 // check-in from the new process.
287 broker
->EnsureRunning();
288 #endif // defined(OS_MACOSX)
290 bool launched
= base::LaunchProcess(*cmd_line
, options
, &handle
);
292 #if defined(OS_MACOSX)
294 broker
->AddPlaceholderForPid(handle
);
296 // After updating the broker, release the lock and let the child's
297 // messasge be processed on the broker's thread.
298 broker
->GetLock().Release();
299 #endif // defined(OS_MACOSX)
302 handle
= base::kNullProcessHandle
;
304 #endif // else defined(OS_POSIX)
305 #if !defined(OS_ANDROID)
307 RecordHistograms(begin_launch_time
);
308 BrowserThread::PostTask(
309 client_thread_id
, FROM_HERE
,
313 #if defined(OS_POSIX) && !defined(OS_MACOSX)
317 #endif // !defined(OS_ANDROID)
321 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
324 base::ProcessHandle handle
) {
325 #if defined(OS_ANDROID)
326 // Finally close the ipcfd
327 file_util::ScopedFD
ipcfd_closer(&ipcfd_
);
330 process_
.set_handle(handle
);
332 LOG(ERROR
) << "Failed to launch child process";
334 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
338 client_
->OnProcessLaunched();
345 if (!process_
.handle())
348 if (!terminate_child_on_shutdown_
)
351 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
352 // don't this on the UI/IO threads.
353 BrowserThread::PostTask(
354 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
356 &Context::TerminateInternal
,
357 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
361 process_
.set_handle(base::kNullProcessHandle
);
364 static void SetProcessBackgrounded(base::ProcessHandle handle
,
366 base::Process
process(handle
);
367 process
.SetProcessBackgrounded(background
);
370 static void TerminateInternal(
371 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
374 base::ProcessHandle handle
) {
375 #if defined(OS_ANDROID)
376 VLOG(0) << "ChromeProcess: Stopping process with handle " << handle
;
377 StopChildProcess(handle
);
379 base::Process
process(handle
);
380 // Client has gone away, so just kill the process. Using exit code 0
381 // means that UMA won't treat this as a crash.
382 process
.Terminate(RESULT_CODE_NORMAL_EXIT
);
383 // On POSIX, we must additionally reap the child.
384 #if defined(OS_POSIX)
385 #if !defined(OS_MACOSX)
387 // If the renderer was created via a zygote, we have to proxy the reaping
388 // through the zygote process.
389 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(handle
);
393 base::EnsureProcessTerminated(handle
);
397 #endif // defined(OS_ANDROID)
401 BrowserThread::ID client_thread_id_
;
402 base::Process process_
;
403 base::TerminationStatus termination_status_
;
406 // Controls whether the child process should be terminated on browser
407 // shutdown. Default behavior is to terminate the child.
408 bool terminate_child_on_shutdown_
;
409 #if defined(OS_ANDROID)
410 // The fd to close after creating the process.
412 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
418 ChildProcessLauncher::ChildProcessLauncher(
420 SandboxedProcessLauncherDelegate
* delegate
,
421 #elif defined(OS_POSIX)
423 const base::EnvironmentMap
& environ
,
426 CommandLine
* cmd_line
,
427 int child_process_id
,
429 context_
= new Context();
433 #elif defined(OS_ANDROID)
435 #elif defined(OS_POSIX)
445 ChildProcessLauncher::~ChildProcessLauncher() {
446 context_
->ResetClient();
449 bool ChildProcessLauncher::IsStarting() {
450 return context_
->starting_
;
453 base::ProcessHandle
ChildProcessLauncher::GetHandle() {
454 DCHECK(!context_
->starting_
);
455 return context_
->process_
.handle();
458 base::TerminationStatus
ChildProcessLauncher::GetChildTerminationStatus(
461 base::ProcessHandle handle
= context_
->process_
.handle();
462 if (handle
== base::kNullProcessHandle
) {
463 // Process is already gone, so return the cached termination status.
465 *exit_code
= context_
->exit_code_
;
466 return context_
->termination_status_
;
468 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
469 if (context_
->zygote_
) {
470 context_
->termination_status_
= ZygoteHostImpl::GetInstance()->
471 GetTerminationStatus(handle
, known_dead
, &context_
->exit_code_
);
472 } else if (known_dead
) {
473 context_
->termination_status_
=
474 base::GetKnownDeadTerminationStatus(handle
, &context_
->exit_code_
);
476 #elif defined(OS_MACOSX)
478 context_
->termination_status_
=
479 base::GetKnownDeadTerminationStatus(handle
, &context_
->exit_code_
);
481 #elif defined(OS_ANDROID)
482 if (IsChildProcessOomProtected(handle
)) {
483 context_
->termination_status_
= base::TERMINATION_STATUS_OOM_PROTECTED
;
488 context_
->termination_status_
=
489 base::GetTerminationStatus(handle
, &context_
->exit_code_
);
493 *exit_code
= context_
->exit_code_
;
495 // POSIX: If the process crashed, then the kernel closed the socket
496 // for it and so the child has already died by the time we get
497 // here. Since GetTerminationStatus called waitpid with WNOHANG,
498 // it'll reap the process. However, if GetTerminationStatus didn't
499 // reap the child (because it was still running), we'll need to
500 // Terminate via ProcessWatcher. So we can't close the handle here.
501 if (context_
->termination_status_
!= base::TERMINATION_STATUS_STILL_RUNNING
)
502 context_
->process_
.Close();
504 return context_
->termination_status_
;
507 void ChildProcessLauncher::SetProcessBackgrounded(bool background
) {
508 BrowserThread::PostTask(
509 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
511 &ChildProcessLauncher::Context::SetProcessBackgrounded
,
512 GetHandle(), background
));
515 void ChildProcessLauncher::SetTerminateChildOnShutdown(
516 bool terminate_on_shutdown
) {
518 context_
->set_terminate_child_on_shutdown(terminate_on_shutdown
);
521 } // namespace content