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/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"
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 client_thread_id_(BrowserThread::UI
),
61 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION
),
62 exit_code_(RESULT_CODE_NORMAL_EXIT
),
64 // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622
65 #if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
66 defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS)
67 terminate_child_on_shutdown_(false)
69 terminate_child_on_shutdown_(true)
71 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
78 SandboxedProcessLauncherDelegate
* delegate
,
79 base::CommandLine
* cmd_line
,
84 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_
));
86 #if defined(OS_ANDROID)
87 // We need to close the client end of the IPC channel to reliably detect
88 // child termination. We will close this fd after we create the child
89 // process which is asynchronous on Android.
90 ipcfd_
= delegate
->GetIpcFd();
92 BrowserThread::PostTask(
93 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
95 &Context::LaunchInternal
,
96 make_scoped_refptr(this),
103 #if defined(OS_ANDROID)
104 static void OnChildProcessStarted(
105 // |this_object| is NOT thread safe. Only use it to post a task back.
106 scoped_refptr
<Context
> this_object
,
107 BrowserThread::ID client_thread_id
,
108 const base::TimeTicks begin_launch_time
,
109 base::ProcessHandle handle
) {
110 RecordHistograms(begin_launch_time
);
111 if (BrowserThread::CurrentlyOn(client_thread_id
)) {
112 // This is always invoked on the UI thread which is commonly the
113 // |client_thread_id| so we can shortcut one PostTask.
114 this_object
->Notify(handle
);
116 BrowserThread::PostTask(
117 client_thread_id
, FROM_HERE
,
119 &ChildProcessLauncher::Context::Notify
,
127 // No need for locking as this function gets called on the same thread that
128 // client_ would be used.
129 CHECK(BrowserThread::CurrentlyOn(client_thread_id_
));
133 void set_terminate_child_on_shutdown(bool terminate_on_shutdown
) {
134 terminate_child_on_shutdown_
= terminate_on_shutdown
;
138 friend class base::RefCountedThreadSafe
<ChildProcessLauncher::Context
>;
139 friend class ChildProcessLauncher
;
145 static void RecordHistograms(const base::TimeTicks begin_launch_time
) {
146 base::TimeDelta launch_time
= base::TimeTicks::Now() - begin_launch_time
;
147 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER
)) {
148 RecordLaunchHistograms(launch_time
);
150 BrowserThread::PostTask(
151 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
152 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms
,
157 static void RecordLaunchHistograms(const base::TimeDelta launch_time
) {
158 // Log the launch time, separating out the first one (which will likely be
159 // slower due to the rest of the browser initializing at the same time).
160 static bool done_first_launch
= false;
161 if (done_first_launch
) {
162 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time
);
164 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time
);
165 done_first_launch
= true;
169 static void LaunchInternal(
170 // |this_object| is NOT thread safe. Only use it to post a task back.
171 scoped_refptr
<Context
> this_object
,
172 BrowserThread::ID client_thread_id
,
173 int child_process_id
,
174 SandboxedProcessLauncherDelegate
* delegate
,
175 base::CommandLine
* cmd_line
) {
176 scoped_ptr
<SandboxedProcessLauncherDelegate
> delegate_deleter(delegate
);
178 bool launch_elevated
= delegate
->ShouldLaunchElevated();
179 #elif defined(OS_ANDROID)
180 int ipcfd
= delegate
->GetIpcFd();
181 #elif defined(OS_MACOSX)
182 base::EnvironmentMap env
= delegate
->GetEnvironment();
183 int ipcfd
= delegate
->GetIpcFd();
184 #elif defined(OS_POSIX)
185 bool use_zygote
= delegate
->ShouldUseZygote();
186 base::EnvironmentMap env
= delegate
->GetEnvironment();
187 int ipcfd
= delegate
->GetIpcFd();
189 scoped_ptr
<base::CommandLine
> cmd_line_deleter(cmd_line
);
190 base::TimeTicks begin_launch_time
= base::TimeTicks::Now();
193 base::ProcessHandle handle
= base::kNullProcessHandle
;
194 if (launch_elevated
) {
195 base::LaunchOptions options
;
196 options
.start_hidden
= true;
197 base::LaunchElevatedProcess(*cmd_line
, options
, &handle
);
199 handle
= StartSandboxedProcess(delegate
, cmd_line
);
201 #elif defined(OS_POSIX)
202 std::string process_type
=
203 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
204 std::vector
<FileDescriptorInfo
> files_to_register
;
205 files_to_register
.push_back(
206 FileDescriptorInfo(kPrimaryIPCChannel
,
207 base::FileDescriptor(ipcfd
, false)));
208 base::StatsTable
* stats_table
= base::StatsTable::current();
210 base::SharedMemory::IsHandleValid(
211 stats_table
->GetSharedMemoryHandle())) {
212 files_to_register
.push_back(
213 FileDescriptorInfo(kStatsTableSharedMemFd
,
214 stats_table
->GetSharedMemoryHandle()));
218 #if defined(OS_ANDROID)
219 // Android WebView runs in single process, ensure that we never get here
220 // when running in single process mode.
221 CHECK(!cmd_line
->HasSwitch(switches::kSingleProcess
));
223 GetContentClient()->browser()->
224 GetAdditionalMappedFilesForChildProcess(*cmd_line
, child_process_id
,
227 StartChildProcess(cmd_line
->argv(), child_process_id
, files_to_register
,
228 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted
,
229 this_object
, client_thread_id
, begin_launch_time
));
231 #elif defined(OS_POSIX)
232 base::ProcessHandle handle
= base::kNullProcessHandle
;
233 // We need to close the client end of the IPC channel to reliably detect
234 // child termination.
235 base::ScopedFD
ipcfd_closer(ipcfd
);
237 #if !defined(OS_MACOSX)
238 GetContentClient()->browser()->
239 GetAdditionalMappedFilesForChildProcess(*cmd_line
, child_process_id
,
242 handle
= ZygoteHostImpl::GetInstance()->ForkRequest(cmd_line
->argv(),
246 // Fall through to the normal posix case below when we're not zygoting.
247 #endif // !defined(OS_MACOSX)
249 // Convert FD mapping to FileHandleMappingVector
250 base::FileHandleMappingVector fds_to_map
;
251 for (size_t i
= 0; i
< files_to_register
.size(); ++i
) {
252 fds_to_map
.push_back(std::make_pair(
253 files_to_register
[i
].fd
.fd
,
254 files_to_register
[i
].id
+
255 base::GlobalDescriptors::kBaseDescriptor
));
258 #if !defined(OS_MACOSX)
259 if (process_type
== switches::kRendererProcess
) {
260 const int sandbox_fd
=
261 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
262 fds_to_map
.push_back(std::make_pair(
266 #endif // defined(OS_MACOSX)
268 // Actually launch the app.
269 base::LaunchOptions options
;
270 options
.environ
= env
;
271 options
.fds_to_remap
= &fds_to_map
;
273 #if defined(OS_MACOSX)
274 // Hold the MachBroker lock for the duration of LaunchProcess. The child
275 // will send its task port to the parent almost immediately after startup.
276 // The Mach message will be delivered to the parent, but updating the
277 // record of the launch will wait until after the placeholder PID is
278 // inserted below. This ensures that while the child process may send its
279 // port to the parent prior to the parent leaving LaunchProcess, the
280 // order in which the record in MachBroker is updated is correct.
281 MachBroker
* broker
= MachBroker::GetInstance();
282 broker
->GetLock().Acquire();
284 // Make sure the MachBroker is running, and inform it to expect a
285 // check-in from the new process.
286 broker
->EnsureRunning();
288 const int bootstrap_sandbox_policy
= delegate
->GetSandboxType();
289 if (ShouldEnableBootstrapSandbox() &&
290 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
291 options
.replacement_bootstrap_name
=
292 GetBootstrapSandbox()->server_bootstrap_name();
293 GetBootstrapSandbox()->PrepareToForkWithPolicy(
294 bootstrap_sandbox_policy
);
296 #endif // defined(OS_MACOSX)
298 bool launched
= base::LaunchProcess(*cmd_line
, options
, &handle
);
300 handle
= base::kNullProcessHandle
;
302 #if defined(OS_MACOSX)
303 if (ShouldEnableBootstrapSandbox() &&
304 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
305 GetBootstrapSandbox()->FinishedFork(handle
);
309 broker
->AddPlaceholderForPid(handle
);
311 // After updating the broker, release the lock and let the child's
312 // messasge be processed on the broker's thread.
313 broker
->GetLock().Release();
314 #endif // defined(OS_MACOSX)
316 #endif // else defined(OS_POSIX)
317 #if !defined(OS_ANDROID)
319 RecordHistograms(begin_launch_time
);
320 BrowserThread::PostTask(
321 client_thread_id
, FROM_HERE
,
325 #if defined(OS_POSIX) && !defined(OS_MACOSX)
329 #endif // !defined(OS_ANDROID)
333 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
336 base::ProcessHandle handle
) {
337 #if defined(OS_ANDROID)
338 // Finally close the ipcfd
339 base::ScopedFD
ipcfd_closer(ipcfd_
);
342 process_
.set_handle(handle
);
344 LOG(ERROR
) << "Failed to launch child process";
346 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
351 client_
->OnProcessLaunched();
353 client_
->OnProcessLaunchFailed();
361 if (!process_
.handle())
364 if (!terminate_child_on_shutdown_
)
367 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
368 // don't this on the UI/IO threads.
369 BrowserThread::PostTask(
370 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
372 &Context::TerminateInternal
,
373 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
377 process_
.set_handle(base::kNullProcessHandle
);
380 static void SetProcessBackgrounded(base::ProcessHandle handle
,
382 base::Process
process(handle
);
383 process
.SetProcessBackgrounded(background
);
384 #if defined(OS_ANDROID)
385 SetChildProcessInForeground(handle
, !background
);
389 static void TerminateInternal(
390 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
393 base::ProcessHandle handle
) {
394 #if defined(OS_ANDROID)
395 VLOG(0) << "ChromeProcess: Stopping process with handle " << handle
;
396 StopChildProcess(handle
);
398 base::Process
process(handle
);
399 // Client has gone away, so just kill the process. Using exit code 0
400 // means that UMA won't treat this as a crash.
401 process
.Terminate(RESULT_CODE_NORMAL_EXIT
);
402 // On POSIX, we must additionally reap the child.
403 #if defined(OS_POSIX)
404 #if !defined(OS_MACOSX)
406 // If the renderer was created via a zygote, we have to proxy the reaping
407 // through the zygote process.
408 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(handle
);
412 base::EnsureProcessTerminated(handle
);
416 #endif // defined(OS_ANDROID)
420 BrowserThread::ID client_thread_id_
;
421 base::Process process_
;
422 base::TerminationStatus termination_status_
;
425 // Controls whether the child process should be terminated on browser
426 // shutdown. Default behavior is to terminate the child.
427 bool terminate_child_on_shutdown_
;
428 #if defined(OS_ANDROID)
429 // The fd to close after creating the process.
431 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
437 ChildProcessLauncher::ChildProcessLauncher(
438 SandboxedProcessLauncherDelegate
* delegate
,
439 base::CommandLine
* cmd_line
,
440 int child_process_id
,
442 context_
= new Context();
450 ChildProcessLauncher::~ChildProcessLauncher() {
451 context_
->ResetClient();
454 bool ChildProcessLauncher::IsStarting() {
455 return context_
->starting_
;
458 base::ProcessHandle
ChildProcessLauncher::GetHandle() {
459 DCHECK(!context_
->starting_
);
460 return context_
->process_
.handle();
463 base::TerminationStatus
ChildProcessLauncher::GetChildTerminationStatus(
466 base::ProcessHandle handle
= context_
->process_
.handle();
467 if (handle
== base::kNullProcessHandle
) {
468 // Process is already gone, so return the cached termination status.
470 *exit_code
= context_
->exit_code_
;
471 return context_
->termination_status_
;
473 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
474 if (context_
->zygote_
) {
475 context_
->termination_status_
= ZygoteHostImpl::GetInstance()->
476 GetTerminationStatus(handle
, known_dead
, &context_
->exit_code_
);
477 } else if (known_dead
) {
478 context_
->termination_status_
=
479 base::GetKnownDeadTerminationStatus(handle
, &context_
->exit_code_
);
481 #elif defined(OS_MACOSX)
483 context_
->termination_status_
=
484 base::GetKnownDeadTerminationStatus(handle
, &context_
->exit_code_
);
486 #elif defined(OS_ANDROID)
487 if (IsChildProcessOomProtected(handle
)) {
488 context_
->termination_status_
= base::TERMINATION_STATUS_OOM_PROTECTED
;
493 context_
->termination_status_
=
494 base::GetTerminationStatus(handle
, &context_
->exit_code_
);
498 *exit_code
= context_
->exit_code_
;
500 // POSIX: If the process crashed, then the kernel closed the socket
501 // for it and so the child has already died by the time we get
502 // here. Since GetTerminationStatus called waitpid with WNOHANG,
503 // it'll reap the process. However, if GetTerminationStatus didn't
504 // reap the child (because it was still running), we'll need to
505 // Terminate via ProcessWatcher. So we can't close the handle here.
506 if (context_
->termination_status_
!= base::TERMINATION_STATUS_STILL_RUNNING
)
507 context_
->process_
.Close();
509 return context_
->termination_status_
;
512 void ChildProcessLauncher::SetProcessBackgrounded(bool background
) {
513 BrowserThread::PostTask(
514 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
516 &ChildProcessLauncher::Context::SetProcessBackgrounded
,
517 GetHandle(), background
));
520 void ChildProcessLauncher::SetTerminateChildOnShutdown(
521 bool terminate_on_shutdown
) {
523 context_
->set_terminate_child_on_shutdown(terminate_on_shutdown
);
526 } // namespace content