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/i18n/icu_util.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/metrics/histogram.h"
14 #include "base/process/process.h"
15 #include "base/profiler/scoped_tracker.h"
16 #include "base/synchronization/lock.h"
17 #include "base/threading/thread.h"
18 #include "content/public/browser/content_browser_client.h"
19 #include "content/public/common/content_descriptors.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/common/result_codes.h"
22 #include "content/public/common/sandboxed_process_launcher_delegate.h"
25 #include "base/files/file_path.h"
26 #include "content/common/sandbox_win.h"
27 #include "content/public/common/sandbox_init.h"
28 #elif defined(OS_MACOSX)
29 #include "content/browser/bootstrap_sandbox_mac.h"
30 #include "content/browser/browser_io_surface_manager_mac.h"
31 #include "content/browser/mach_broker_mac.h"
32 #include "sandbox/mac/bootstrap_sandbox.h"
33 #elif defined(OS_ANDROID)
34 #include "base/android/jni_android.h"
35 #include "content/browser/android/child_process_launcher_android.h"
36 #elif defined(OS_POSIX)
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"
46 #include "gin/v8_initializer.h"
53 typedef base::Callback
<void(bool,
54 #if defined(OS_ANDROID)
57 base::Process
)> NotifyCallback
;
59 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time
) {
60 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER
);
61 // Log the launch time, separating out the first one (which will likely be
62 // slower due to the rest of the browser initializing at the same time).
63 static bool done_first_launch
= false;
64 if (done_first_launch
) {
65 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time
);
67 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time
);
68 done_first_launch
= true;
72 #if defined(OS_ANDROID)
73 // TODO(sievers): Remove this by defining better what happens on what
74 // thread in the corresponding Java code.
75 void OnChildProcessStartedAndroid(const NotifyCallback
& callback
,
76 BrowserThread::ID client_thread_id
,
77 const base::TimeTicks begin_launch_time
,
79 base::ProcessHandle handle
) {
80 // This can be called on the launcher thread or UI thread.
81 base::TimeDelta launch_time
= base::TimeTicks::Now() - begin_launch_time
;
82 BrowserThread::PostTask(
83 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
84 base::Bind(&RecordHistogramsOnLauncherThread
, launch_time
));
86 base::Closure
callback_on_client_thread(
87 base::Bind(callback
, false, base::Passed(&ipcfd
),
88 base::Passed(base::Process(handle
))));
89 if (BrowserThread::CurrentlyOn(client_thread_id
)) {
90 callback_on_client_thread
.Run();
92 BrowserThread::PostTask(
93 client_thread_id
, FROM_HERE
, callback_on_client_thread
);
98 void LaunchOnLauncherThread(const NotifyCallback
& callback
,
99 BrowserThread::ID client_thread_id
,
100 int child_process_id
,
101 SandboxedProcessLauncherDelegate
* delegate
,
102 #if defined(OS_ANDROID)
103 base::ScopedFD ipcfd
,
105 base::CommandLine
* cmd_line
) {
106 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER
);
107 scoped_ptr
<SandboxedProcessLauncherDelegate
> delegate_deleter(delegate
);
109 bool use_zygote
= false;
110 bool launch_elevated
= delegate
->ShouldLaunchElevated();
111 #elif defined(OS_MACOSX)
112 bool use_zygote
= false;
113 base::EnvironmentMap env
= delegate
->GetEnvironment();
114 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
115 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
116 bool use_zygote
= delegate
->ShouldUseZygote();
117 base::EnvironmentMap env
= delegate
->GetEnvironment();
118 base::ScopedFD ipcfd
= delegate
->TakeIpcFd();
120 scoped_ptr
<base::CommandLine
> cmd_line_deleter(cmd_line
);
121 base::TimeTicks begin_launch_time
= base::TimeTicks::Now();
123 base::Process process
;
125 if (launch_elevated
) {
126 base::LaunchOptions options
;
127 options
.start_hidden
= true;
128 process
= base::LaunchElevatedProcess(*cmd_line
, options
);
130 process
= StartSandboxedProcess(delegate
, cmd_line
);
132 #elif defined(OS_POSIX)
133 std::string process_type
=
134 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
135 scoped_ptr
<FileDescriptorInfo
> files_to_register(
136 FileDescriptorInfoImpl::Create());
138 #if defined(OS_ANDROID)
139 files_to_register
->Share(kPrimaryIPCChannel
, ipcfd
.get());
141 files_to_register
->Transfer(kPrimaryIPCChannel
, ipcfd
.Pass());
145 #if defined(OS_POSIX) && !defined(OS_MACOSX)
146 std::map
<int, base::MemoryMappedFile::Region
> regions
;
147 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
148 *cmd_line
, child_process_id
, files_to_register
.get()
149 #if defined(OS_ANDROID)
153 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
154 base::PlatformFile natives_pf
=
155 gin::V8Initializer::GetOpenNativesFileForChildProcesses(
156 ®ions
[kV8NativesDataDescriptor
]);
157 DCHECK_GE(natives_pf
, 0);
158 files_to_register
->Share(kV8NativesDataDescriptor
, natives_pf
);
160 base::MemoryMappedFile::Region snapshot_region
;
161 base::PlatformFile snapshot_pf
=
162 gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(
164 // Failure to load the V8 snapshot is not necessarily an error. V8 can start
165 // up (slower) without the snapshot.
166 if (snapshot_pf
!= -1) {
167 files_to_register
->Share(kV8SnapshotDataDescriptor
, snapshot_pf
);
168 regions
.insert(std::make_pair(kV8SnapshotDataDescriptor
, snapshot_region
));
171 if (process_type
!= switches::kZygoteProcess
) {
172 cmd_line
->AppendSwitch(::switches::kV8NativesPassedByFD
);
173 if (snapshot_pf
!= -1) {
174 cmd_line
->AppendSwitch(::switches::kV8SnapshotPassedByFD
);
177 #endif // defined(V8_USE_EXTERNAL_STARTUP_DATA)
178 #endif // defined(OS_POSIX) && !defined(OS_MACOSX)
180 #if defined(OS_ANDROID)
181 files_to_register
->Share(
182 kAndroidICUDataDescriptor
,
183 base::i18n::GetIcuDataFileHandle(®ions
[kAndroidICUDataDescriptor
]));
185 // Android WebView runs in single process, ensure that we never get here
186 // when running in single process mode.
187 CHECK(!cmd_line
->HasSwitch(switches::kSingleProcess
));
190 cmd_line
->argv(), child_process_id
, files_to_register
.Pass(), regions
,
191 base::Bind(&OnChildProcessStartedAndroid
, callback
, client_thread_id
,
192 begin_launch_time
, base::Passed(&ipcfd
)));
194 #elif defined(OS_POSIX)
195 // We need to close the client end of the IPC channel to reliably detect
196 // child termination.
198 #if !defined(OS_MACOSX)
200 base::ProcessHandle handle
= ZygoteHostImpl::GetInstance()->ForkRequest(
201 cmd_line
->argv(), files_to_register
.Pass(), process_type
);
202 process
= base::Process(handle
);
204 // Fall through to the normal posix case below when we're not zygoting.
205 #endif // !defined(OS_MACOSX)
207 // Convert FD mapping to FileHandleMappingVector
208 base::FileHandleMappingVector fds_to_map
=
209 files_to_register
->GetMappingWithIDAdjustment(
210 base::GlobalDescriptors::kBaseDescriptor
);
212 #if !defined(OS_MACOSX)
213 if (process_type
== switches::kRendererProcess
) {
214 const int sandbox_fd
=
215 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
216 fds_to_map
.push_back(std::make_pair(
220 #endif // defined(OS_MACOSX)
222 // Actually launch the app.
223 base::LaunchOptions options
;
224 options
.environ
= env
;
225 options
.fds_to_remap
= &fds_to_map
;
227 #if defined(OS_MACOSX)
228 // Hold the MachBroker lock for the duration of LaunchProcess. The child
229 // will send its task port to the parent almost immediately after startup.
230 // The Mach message will be delivered to the parent, but updating the
231 // record of the launch will wait until after the placeholder PID is
232 // inserted below. This ensures that while the child process may send its
233 // port to the parent prior to the parent leaving LaunchProcess, the
234 // order in which the record in MachBroker is updated is correct.
235 MachBroker
* broker
= MachBroker::GetInstance();
236 broker
->GetLock().Acquire();
238 // Make sure the MachBroker is running, and inform it to expect a
239 // check-in from the new process.
240 broker
->EnsureRunning();
242 // Make sure the IOSurfaceManager service is running.
243 BrowserIOSurfaceManager::GetInstance()->EnsureRunning();
245 const int bootstrap_sandbox_policy
= delegate
->GetSandboxType();
246 if (ShouldEnableBootstrapSandbox() &&
247 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
248 options
.replacement_bootstrap_name
=
249 GetBootstrapSandbox()->server_bootstrap_name();
250 GetBootstrapSandbox()->PrepareToForkWithPolicy(
251 bootstrap_sandbox_policy
);
253 #endif // defined(OS_MACOSX)
255 process
= base::LaunchProcess(*cmd_line
, options
);
257 #if defined(OS_MACOSX)
258 if (ShouldEnableBootstrapSandbox() &&
259 bootstrap_sandbox_policy
!= SANDBOX_TYPE_INVALID
) {
260 GetBootstrapSandbox()->FinishedFork(process
.Handle());
263 if (process
.IsValid())
264 broker
->AddPlaceholderForPid(process
.Pid(), child_process_id
);
266 // After updating the broker, release the lock and let the child's
267 // messasge be processed on the broker's thread.
268 broker
->GetLock().Release();
269 #endif // defined(OS_MACOSX)
271 #endif // else defined(OS_POSIX)
272 #if !defined(OS_ANDROID)
273 if (process
.IsValid()) {
274 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
277 BrowserThread::PostTask(client_thread_id
, FROM_HERE
,
280 base::Passed(&process
)));
281 #endif // !defined(OS_ANDROID)
284 void TerminateOnLauncherThread(bool zygote
, base::Process process
) {
285 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER
);
286 #if defined(OS_ANDROID)
287 VLOG(1) << "ChromeProcess: Stopping process with handle "
289 StopChildProcess(process
.Handle());
291 // Client has gone away, so just kill the process. Using exit code 0
292 // means that UMA won't treat this as a crash.
293 process
.Terminate(RESULT_CODE_NORMAL_EXIT
, false);
294 // On POSIX, we must additionally reap the child.
295 #if defined(OS_POSIX)
296 #if !defined(OS_MACOSX)
298 // If the renderer was created via a zygote, we have to proxy the reaping
299 // through the zygote process.
300 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process
.Handle());
303 base::EnsureProcessTerminated(process
.Pass());
305 #endif // defined(OS_ANDROID)
308 void SetProcessBackgroundedOnLauncherThread(base::Process process
,
310 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER
);
311 #if defined(OS_MACOSX)
312 MachBroker
* broker
= MachBroker::GetInstance();
313 mach_port_t task_port
= broker
->TaskForPid(process
.Pid());
314 if (task_port
!= TASK_NULL
) {
315 process
.SetProcessBackgrounded(task_port
, background
);
318 process
.SetProcessBackgrounded(background
);
319 #endif // defined(OS_MACOSX)
320 #if defined(OS_ANDROID)
321 SetChildProcessInForeground(process
.Handle(), !background
);
325 } // anonymous namespace
327 ChildProcessLauncher::ChildProcessLauncher(
328 SandboxedProcessLauncherDelegate
* delegate
,
329 base::CommandLine
* cmd_line
,
330 int child_process_id
,
332 bool terminate_on_shutdown
)
334 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION
),
335 exit_code_(RESULT_CODE_NORMAL_EXIT
),
338 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
339 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
340 defined(UNDEFINED_SANITIZER)
341 terminate_child_on_shutdown_(false),
343 terminate_child_on_shutdown_(terminate_on_shutdown
),
345 weak_factory_(this) {
346 DCHECK(CalledOnValidThread());
347 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_
));
348 Launch(delegate
, cmd_line
, child_process_id
);
351 ChildProcessLauncher::~ChildProcessLauncher() {
352 DCHECK(CalledOnValidThread());
353 if (process_
.IsValid() && terminate_child_on_shutdown_
) {
354 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
355 // don't this on the UI/IO threads.
356 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
357 base::Bind(&TerminateOnLauncherThread
, zygote_
,
358 base::Passed(&process_
)));
362 void ChildProcessLauncher::Launch(
363 SandboxedProcessLauncherDelegate
* delegate
,
364 base::CommandLine
* cmd_line
,
365 int child_process_id
) {
366 DCHECK(CalledOnValidThread());
368 #if defined(OS_ANDROID)
369 // Android only supports renderer, sandboxed utility and gpu.
370 std::string process_type
=
371 cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
372 CHECK(process_type
== switches::kGpuProcess
||
373 process_type
== switches::kRendererProcess
||
374 #if defined(ENABLE_PLUGINS)
375 process_type
== switches::kPpapiPluginProcess
||
377 process_type
== switches::kUtilityProcess
)
378 << "Unsupported process type: " << process_type
;
380 // Non-sandboxed utility or renderer process are currently not supported.
381 DCHECK(process_type
== switches::kGpuProcess
||
382 !cmd_line
->HasSwitch(switches::kNoSandbox
));
384 // We need to close the client end of the IPC channel to reliably detect
385 // child termination. We will close this fd after we create the child
386 // process which is asynchronous on Android.
387 base::ScopedFD
ipcfd(delegate
->TakeIpcFd().release());
389 NotifyCallback
reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch
,
390 weak_factory_
.GetWeakPtr(),
391 terminate_child_on_shutdown_
));
392 BrowserThread::PostTask(
393 BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
394 base::Bind(&LaunchOnLauncherThread
, reply_callback
, client_thread_id_
,
395 child_process_id
, delegate
,
396 #if defined(OS_ANDROID)
397 base::Passed(&ipcfd
),
402 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead
) {
403 DCHECK(CalledOnValidThread());
404 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
406 termination_status_
= ZygoteHostImpl::GetInstance()->
407 GetTerminationStatus(process_
.Handle(), known_dead
, &exit_code_
);
408 } else if (known_dead
) {
409 termination_status_
=
410 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
412 #elif defined(OS_MACOSX)
414 termination_status_
=
415 base::GetKnownDeadTerminationStatus(process_
.Handle(), &exit_code_
);
417 #elif defined(OS_ANDROID)
418 if (IsChildProcessOomProtected(process_
.Handle())) {
419 termination_status_
= base::TERMINATION_STATUS_OOM_PROTECTED
;
424 termination_status_
=
425 base::GetTerminationStatus(process_
.Handle(), &exit_code_
);
429 void ChildProcessLauncher::SetProcessBackgrounded(bool background
) {
430 DCHECK(CalledOnValidThread());
431 base::Process to_pass
= process_
.Duplicate();
432 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
433 base::Bind(&SetProcessBackgroundedOnLauncherThread
,
434 base::Passed(&to_pass
), background
));
437 void ChildProcessLauncher::DidLaunch(
438 base::WeakPtr
<ChildProcessLauncher
> instance
,
439 bool terminate_on_shutdown
,
441 #if defined(OS_ANDROID)
442 base::ScopedFD ipcfd
,
444 base::Process process
) {
445 if (!process
.IsValid())
446 LOG(ERROR
) << "Failed to launch child process";
448 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
450 tracked_objects::ScopedTracker
tracking_profile1(
451 FROM_HERE_WITH_EXPLICIT_FUNCTION(
452 "465841 ChildProcessLauncher::Context::Notify::Start"));
454 if (instance
.get()) {
455 instance
->Notify(zygote
,
456 #if defined(OS_ANDROID)
461 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
463 tracked_objects::ScopedTracker
tracking_profile4(
464 FROM_HERE_WITH_EXPLICIT_FUNCTION(
465 "465841 ChildProcessLauncher::Context::Notify::ProcessTerminate"));
466 if (process
.IsValid() && terminate_on_shutdown
) {
467 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
468 // don't this on the UI/IO threads.
469 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER
, FROM_HERE
,
470 base::Bind(&TerminateOnLauncherThread
, zygote
,
471 base::Passed(&process
)));
476 void ChildProcessLauncher::Notify(
478 #if defined(OS_ANDROID)
479 base::ScopedFD ipcfd
,
481 base::Process process
) {
482 DCHECK(CalledOnValidThread());
484 process_
= process
.Pass();
486 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
489 if (process_
.IsValid()) {
490 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
492 tracked_objects::ScopedTracker
tracking_profile2(
493 FROM_HERE_WITH_EXPLICIT_FUNCTION(
494 "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
495 client_
->OnProcessLaunched();
497 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
499 tracked_objects::ScopedTracker
tracking_profile3(
500 FROM_HERE_WITH_EXPLICIT_FUNCTION(
501 "465841 ChildProcessLauncher::Context::Notify::ProcessFailed"));
502 termination_status_
= base::TERMINATION_STATUS_LAUNCH_FAILED
;
503 client_
->OnProcessLaunchFailed();
507 bool ChildProcessLauncher::IsStarting() {
508 // TODO(crbug.com/469248): This fails in some tests.
509 // DCHECK(CalledOnValidThread());
513 const base::Process
& ChildProcessLauncher::GetProcess() const {
514 // TODO(crbug.com/469248): This fails in some tests.
515 // DCHECK(CalledOnValidThread());
519 base::TerminationStatus
ChildProcessLauncher::GetChildTerminationStatus(
522 DCHECK(CalledOnValidThread());
523 if (!process_
.IsValid()) {
524 // Process is already gone, so return the cached termination status.
526 *exit_code
= exit_code_
;
527 return termination_status_
;
530 UpdateTerminationStatus(known_dead
);
532 *exit_code
= exit_code_
;
534 // POSIX: If the process crashed, then the kernel closed the socket
535 // for it and so the child has already died by the time we get
536 // here. Since GetTerminationStatus called waitpid with WNOHANG,
537 // it'll reap the process. However, if GetTerminationStatus didn't
538 // reap the child (because it was still running), we'll need to
539 // Terminate via ProcessWatcher. So we can't close the handle here.
540 if (termination_status_
!= base::TERMINATION_STATUS_STILL_RUNNING
)
543 return termination_status_
;
546 ChildProcessLauncher::Client
* ChildProcessLauncher::ReplaceClientForTest(
548 Client
* ret
= client_
;
553 } // namespace content