1 // Copyright 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"
8 #include "base/command_line.h"
9 #include "base/files/file_util.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/metrics/histogram.h"
13 #include "base/process/process.h"
14 #include "base/profiler/scoped_tracker.h"
15 #include "base/synchronization/lock.h"
16 #include "base/threading/thread.h"
17 #include "content/public/browser/content_browser_client.h"
18 #include "content/public/common/content_descriptors.h"
19 #include "content/public/common/content_switches.h"
20 #include "content/public/common/result_codes.h"
21 #include "content/public/common/sandboxed_process_launcher_delegate.h"
24 #include "base/files/file_path.h"
25 #include "content/common/sandbox_win.h"
26 #include "content/public/common/sandbox_init.h"
27 #elif defined(OS_MACOSX)
28 #include "content/browser/bootstrap_sandbox_mac.h"
29 #include "content/browser/browser_io_surface_manager_mac.h"
30 #include "content/browser/mach_broker_mac.h"
31 #include "sandbox/mac/bootstrap_sandbox.h"
32 #elif defined(OS_ANDROID)
33 #include "base/android/jni_android.h"
34 #include "content/browser/android/child_process_launcher_android.h"
35 #elif defined(OS_POSIX)
36 #include "base/memory/shared_memory.h"
37 #include "base/memory/singleton.h"
38 #include "content/browser/renderer_host/render_sandbox_host_linux.h"
39 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
40 #include "content/common/child_process_sandbox_support_impl_linux.h"
44 #include "base/posix/global_descriptors.h"
45 #include "content/browser/file_descriptor_info_impl.h"
52 typedef base::Callback
<void(bool,
53 #if defined(OS_ANDROID)
56 base::Process
)> NotifyCallback
;
58 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time
) {
59 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER
);
60 // Log the launch time, separating out the first one (which will likely be
61 // slower due to the rest of the browser initializing at the same time).
62 static bool done_first_launch
= false;
63 if (done_first_launch
) {
64 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time
);
66 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time
);
67 done_first_launch
= true;
71 #if defined(OS_ANDROID)
72 // TODO(sievers): Remove this by defining better what happens on what
73 // thread in the corresponding Java code.
74 void OnChildProcessStartedAndroid(const NotifyCallback
& callback
,
75 BrowserThread::ID client_thread_id
,
76 const base::TimeTicks begin_launch_time
,
78 base::ProcessHandle handle
) {
79 // This can be called on the launcher thread or UI thread.
80 base::TimeDelta launch_time
= base::TimeTicks::Now() - begin_launch_time
;
81 BrowserThread::PostTask(
82 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
83 base::Bind(&RecordHistogramsOnLauncherThread
, launch_time
));
85 base::Closure
callback_on_client_thread(
86 base::Bind(callback
, false, base::Passed(&ipcfd
),
87 base::Passed(base::Process(handle
))));
88 if (BrowserThread::CurrentlyOn(client_thread_id
)) {
89 callback_on_client_thread
.Run();
91 BrowserThread::PostTask(
92 client_thread_id
, FROM_HERE
, callback_on_client_thread
);
97 void LaunchOnLauncherThread(const NotifyCallback
& callback
,
98 BrowserThread::ID client_thread_id
,
100 SandboxedProcessLauncherDelegate
* delegate
,
101 #if defined(OS_ANDROID)
102 base::ScopedFD ipcfd
,
104 base::CommandLine
* cmd_line
) {
105 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER
);
106 scoped_ptr
<SandboxedProcessLauncherDelegate
> delegate_deleter(delegate
);
108 bool use_zygote
= false;
109 bool launch_elevated
= delegate
->ShouldLaunchElevated();
110 #elif defined(OS_MACOSX)
111 bool use_zygote
= false;
112 base::EnvironmentMap env
= delegate
->GetEnvironment();
113 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
114 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
115 bool use_zygote
= delegate
->ShouldUseZygote();
116 base::EnvironmentMap env
= delegate
->GetEnvironment();
117 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
119 scoped_ptr
<base::CommandLine
> cmd_line_deleter(cmd_line
);
120 base::TimeTicks begin_launch_time
= base::TimeTicks::Now();
122 base::Process process
;
124 if (launch_elevated
) {
125 base::LaunchOptions options
;
126 options
.start_hidden
= true;
127 process
= base::LaunchElevatedProcess(*cmd_line
, options
);
129 process
= StartSandboxedProcess(delegate
, cmd_line
);
131 #elif defined(OS_POSIX)
132 std::string process_type
=
133 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
134 scoped_ptr
<FileDescriptorInfo
> files_to_register(
135 FileDescriptorInfoImpl::Create());
137 #if defined(OS_ANDROID)
138 files_to_register
->Share(kPrimaryIPCChannel
, ipcfd
.get());
140 files_to_register
->Transfer(kPrimaryIPCChannel
, ipcfd
.Pass());
144 #if defined(OS_ANDROID)
145 // Android WebView runs in single process, ensure that we never get here
146 // when running in single process mode.
147 CHECK(!cmd_line
->HasSwitch(switches::kSingleProcess
));
148 std::map
<int, base::MemoryMappedFile::Region
> regions
;
149 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
150 *cmd_line
, child_process_id
, files_to_register
.get());
152 GetContentClient()->browser()->AppendMappedFileCommandLineSwitches(cmd_line
);
155 cmd_line
->argv(), child_process_id
, files_to_register
.Pass(), regions
,
156 base::Bind(&OnChildProcessStartedAndroid
, callback
, client_thread_id
,
157 begin_launch_time
, base::Passed(&ipcfd
)));
159 #elif defined(OS_POSIX)
160 // We need to close the client end of the IPC channel to reliably detect
161 // child termination.
163 #if !defined(OS_MACOSX)
164 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
165 *cmd_line
, child_process_id
, files_to_register
.get());
167 GetContentClient()->browser()->AppendMappedFileCommandLineSwitches(cmd_line
);
170 base::ProcessHandle handle
= ZygoteHostImpl::GetInstance()->ForkRequest(
171 cmd_line
->argv(), files_to_register
.Pass(), process_type
);
172 process
= base::Process(handle
);
174 // Fall through to the normal posix case below when we're not zygoting.
175 #endif // !defined(OS_MACOSX)
177 // Convert FD mapping to FileHandleMappingVector
178 base::FileHandleMappingVector fds_to_map
=
179 files_to_register
->GetMappingWithIDAdjustment(
180 base::GlobalDescriptors::kBaseDescriptor
);
182 #if !defined(OS_MACOSX)
183 if (process_type
== switches::kRendererProcess
) {
184 const int sandbox_fd
=
185 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
186 fds_to_map
.push_back(std::make_pair(
190 #endif // defined(OS_MACOSX)
192 // Actually launch the app.
193 base::LaunchOptions options
;
194 options
.environ
= env
;
195 options
.fds_to_remap
= &fds_to_map
;
197 #if defined(OS_MACOSX)
198 // Hold the MachBroker lock for the duration of LaunchProcess. The child
199 // will send its task port to the parent almost immediately after startup.
200 // The Mach message will be delivered to the parent, but updating the
201 // record of the launch will wait until after the placeholder PID is
202 // inserted below. This ensures that while the child process may send its
203 // port to the parent prior to the parent leaving LaunchProcess, the
204 // order in which the record in MachBroker is updated is correct.
205 MachBroker
* broker
= MachBroker::GetInstance();
206 broker
->GetLock().Acquire();
208 // Make sure the MachBroker is running, and inform it to expect a
209 // check-in from the new process.
210 broker
->EnsureRunning();
212 // Make sure the IOSurfaceManager service is running.
213 BrowserIOSurfaceManager::GetInstance()->EnsureRunning();
215 const int bootstrap_sandbox_policy
= delegate
->GetSandboxType();
216 if (ShouldEnableBootstrapSandbox() &&
217 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
218 options
.replacement_bootstrap_name
=
219 GetBootstrapSandbox()->server_bootstrap_name();
220 GetBootstrapSandbox()->PrepareToForkWithPolicy(
221 bootstrap_sandbox_policy
);
223 #endif // defined(OS_MACOSX)
225 process
= base::LaunchProcess(*cmd_line
, options
);
227 #if defined(OS_MACOSX)
228 if (ShouldEnableBootstrapSandbox() &&
229 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
230 GetBootstrapSandbox()->FinishedFork(process
.Handle());
233 if (process
.IsValid())
234 broker
->AddPlaceholderForPid(process
.Pid(), child_process_id
);
236 // After updating the broker, release the lock and let the child's
237 // messasge be processed on the broker's thread.
238 broker
->GetLock().Release();
239 #endif // defined(OS_MACOSX)
241 #endif // else defined(OS_POSIX)
242 #if !defined(OS_ANDROID)
243 if (process
.IsValid()) {
244 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
247 BrowserThread::PostTask(client_thread_id
, FROM_HERE
,
250 base::Passed(&process
)));
251 #endif // !defined(OS_ANDROID)
254 void TerminateOnLauncherThread(bool zygote
, base::Process process
) {
255 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER
);
256 #if defined(OS_ANDROID)
257 VLOG(1) << "ChromeProcess: Stopping process with handle "
259 StopChildProcess(process
.Handle());
261 // Client has gone away, so just kill the process. Using exit code 0
262 // means that UMA won't treat this as a crash.
263 process
.Terminate(RESULT_CODE_NORMAL_EXIT
, false);
264 // On POSIX, we must additionally reap the child.
265 #if defined(OS_POSIX)
266 #if !defined(OS_MACOSX)
268 // If the renderer was created via a zygote, we have to proxy the reaping
269 // through the zygote process.
270 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process
.Handle());
273 base::EnsureProcessTerminated(process
.Pass());
275 #endif // defined(OS_ANDROID)
278 void SetProcessBackgroundedOnLauncherThread(base::Process process
,
280 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER
);
281 #if defined(OS_MACOSX)
282 MachBroker
* broker
= MachBroker::GetInstance();
283 mach_port_t task_port
= broker
->TaskForPid(process
.Pid());
284 if (task_port
!= TASK_NULL
) {
285 process
.SetProcessBackgrounded(task_port
, background
);
288 process
.SetProcessBackgrounded(background
);
289 #endif // defined(OS_MACOSX)
290 #if defined(OS_ANDROID)
291 SetChildProcessInForeground(process
.Handle(), !background
);
295 } // anonymous namespace
297 ChildProcessLauncher::ChildProcessLauncher(
298 SandboxedProcessLauncherDelegate
* delegate
,
299 base::CommandLine
* cmd_line
,
300 int child_process_id
,
302 bool terminate_on_shutdown
)
304 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION
),
305 exit_code_(RESULT_CODE_NORMAL_EXIT
),
308 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
309 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
310 defined(UNDEFINED_SANITIZER)
311 terminate_child_on_shutdown_(false),
313 terminate_child_on_shutdown_(terminate_on_shutdown
),
315 weak_factory_(this) {
316 DCHECK(CalledOnValidThread());
317 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_
));
318 Launch(delegate
, cmd_line
, child_process_id
);
321 ChildProcessLauncher::~ChildProcessLauncher() {
322 DCHECK(CalledOnValidThread());
323 if (process_
.IsValid() && terminate_child_on_shutdown_
) {
324 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
325 // don't this on the UI/IO threads.
326 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
327 base::Bind(&TerminateOnLauncherThread
, zygote_
,
328 base::Passed(&process_
)));
332 void ChildProcessLauncher::Launch(
333 SandboxedProcessLauncherDelegate
* delegate
,
334 base::CommandLine
* cmd_line
,
335 int child_process_id
) {
336 DCHECK(CalledOnValidThread());
338 #if defined(OS_ANDROID)
339 // Android only supports renderer, sandboxed utility and gpu.
340 std::string process_type
=
341 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
342 CHECK(process_type
== switches::kGpuProcess
||
343 process_type
== switches::kRendererProcess
||
344 process_type
== switches::kUtilityProcess
)
345 << "Unsupported process type: " << process_type
;
347 // Non-sandboxed utility or renderer process are currently not supported.
348 DCHECK(process_type
== switches::kGpuProcess
||
349 !cmd_line
->HasSwitch(switches::kNoSandbox
));
351 // We need to close the client end of the IPC channel to reliably detect
352 // child termination. We will close this fd after we create the child
353 // process which is asynchronous on Android.
354 base::ScopedFD
ipcfd(delegate
->TakeIpcFd().release());
356 NotifyCallback
reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch
,
357 weak_factory_
.GetWeakPtr(),
358 terminate_child_on_shutdown_
));
359 BrowserThread::PostTask(
360 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
361 base::Bind(&LaunchOnLauncherThread
, reply_callback
, client_thread_id_
,
362 child_process_id
, delegate
,
363 #if defined(OS_ANDROID)
364 base::Passed(&ipcfd
),
369 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead
) {
370 DCHECK(CalledOnValidThread());
371 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
373 termination_status_
= ZygoteHostImpl::GetInstance()->
374 GetTerminationStatus(process_
.Handle(), known_dead
, &exit_code_
);
375 } else if (known_dead
) {
376 termination_status_
=
377 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
379 #elif defined(OS_MACOSX)
381 termination_status_
=
382 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
384 #elif defined(OS_ANDROID)
385 if (IsChildProcessOomProtected(process_
.Handle())) {
386 termination_status_
= base::TERMINATION_STATUS_OOM_PROTECTED
;
391 termination_status_
=
392 base::GetTerminationStatus(process_
.Handle(), &exit_code_
);
396 void ChildProcessLauncher::SetProcessBackgrounded(bool background
) {
397 DCHECK(CalledOnValidThread());
398 base::Process to_pass
= process_
.Duplicate();
399 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
400 base::Bind(&SetProcessBackgroundedOnLauncherThread
,
401 base::Passed(&to_pass
), background
));
404 void ChildProcessLauncher::DidLaunch(
405 base::WeakPtr
<ChildProcessLauncher
> instance
,
406 bool terminate_on_shutdown
,
408 #if defined(OS_ANDROID)
409 base::ScopedFD ipcfd
,
411 base::Process process
) {
412 if (!process
.IsValid())
413 LOG(ERROR
) << "Failed to launch child process";
415 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
417 tracked_objects::ScopedTracker
tracking_profile1(
418 FROM_HERE_WITH_EXPLICIT_FUNCTION(
419 "465841 ChildProcessLauncher::Context::Notify::Start"));
421 if (instance
.get()) {
422 instance
->Notify(zygote
,
423 #if defined(OS_ANDROID)
428 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
430 tracked_objects::ScopedTracker
tracking_profile4(
431 FROM_HERE_WITH_EXPLICIT_FUNCTION(
432 "465841 ChildProcessLauncher::Context::Notify::ProcessTerminate"));
433 if (process
.IsValid() && terminate_on_shutdown
) {
434 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
435 // don't this on the UI/IO threads.
436 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
437 base::Bind(&TerminateOnLauncherThread
, zygote
,
438 base::Passed(&process
)));
443 void ChildProcessLauncher::Notify(
445 #if defined(OS_ANDROID)
446 base::ScopedFD ipcfd
,
448 base::Process process
) {
449 DCHECK(CalledOnValidThread());
451 process_
= process
.Pass();
453 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
456 if (process_
.IsValid()) {
457 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
459 tracked_objects::ScopedTracker
tracking_profile2(
460 FROM_HERE_WITH_EXPLICIT_FUNCTION(
461 "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
462 client_
->OnProcessLaunched();
464 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
466 tracked_objects::ScopedTracker
tracking_profile3(
467 FROM_HERE_WITH_EXPLICIT_FUNCTION(
468 "465841 ChildProcessLauncher::Context::Notify::ProcessFailed"));
469 client_
->OnProcessLaunchFailed();
473 bool ChildProcessLauncher::IsStarting() {
474 // TODO(crbug.com/469248): This fails in some tests.
475 // DCHECK(CalledOnValidThread());
479 const base::Process
& ChildProcessLauncher::GetProcess() const {
480 // TODO(crbug.com/469248): This fails in some tests.
481 // DCHECK(CalledOnValidThread());
485 base::TerminationStatus
ChildProcessLauncher::GetChildTerminationStatus(
488 DCHECK(CalledOnValidThread());
489 if (!process_
.IsValid()) {
490 // Process is already gone, so return the cached termination status.
492 *exit_code
= exit_code_
;
493 return termination_status_
;
496 UpdateTerminationStatus(known_dead
);
498 *exit_code
= 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 (termination_status_
!= base::TERMINATION_STATUS_STILL_RUNNING
)
509 return termination_status_
;
512 ChildProcessLauncher::Client
* ChildProcessLauncher::ReplaceClientForTest(
514 Client
* ret
= client_
;
519 } // namespace content