Roll src/third_party/WebKit 3a0ba1e:fcd7003 (svn 191141:191149)
[chromium-blink-merge.git] / content / browser / child_process_launcher.cc
blobe5c93ee3562bbecd378d96c671d77c4fe219c39e
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.
9 #include "base/bind.h"
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"
26 #if defined(OS_WIN)
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"
43 #endif
45 #if defined(OS_POSIX)
46 #include "base/posix/global_descriptors.h"
47 #include "content/browser/file_descriptor_info_impl.h"
48 #endif
50 namespace content {
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> {
57 public:
58 Context();
60 // Posts a task to a dedicated thread to do the actual work.
61 // Must be called on the UI thread.
62 void Launch(SandboxedProcessLauncherDelegate* delegate,
63 base::CommandLine* cmd_line,
64 int child_process_id,
65 Client* client);
67 #if defined(OS_ANDROID)
68 // Called on the UI thread with the operation result. Calls Notify().
69 static void OnChildProcessStarted(
70 // |this_object| is NOT thread safe. Only use it to post a task back.
71 scoped_refptr<Context> this_object,
72 BrowserThread::ID client_thread_id,
73 const base::TimeTicks begin_launch_time,
74 base::ProcessHandle handle);
75 #endif
77 // Resets the client (the client is going away).
78 void ResetClient();
80 bool starting() const { return starting_; }
82 const base::Process& process() const { return process_; }
84 int exit_code() const { return exit_code_; }
86 base::TerminationStatus termination_status() const {
87 return termination_status_;
90 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) {
91 terminate_child_on_shutdown_ = terminate_on_shutdown;
94 void UpdateTerminationStatus(bool known_dead);
96 void Close() { process_.Close(); }
98 void SetProcessBackgrounded(bool background);
100 private:
101 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
103 ~Context() {
104 Terminate();
107 static void RecordHistograms(base::TimeTicks begin_launch_time);
108 static void RecordLaunchHistograms(base::TimeDelta launch_time);
110 // Performs the actual work of launching the process.
111 // Runs on the PROCESS_LAUNCHER thread.
112 static void LaunchInternal(
113 // |this_object| is NOT thread safe. Only use it to post a task back.
114 scoped_refptr<Context> this_object,
115 BrowserThread::ID client_thread_id,
116 int child_process_id,
117 SandboxedProcessLauncherDelegate* delegate,
118 base::CommandLine* cmd_line);
120 // Notifies the client about the result of the operation.
121 // Runs on the UI thread.
122 void Notify(
123 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
124 bool zygote,
125 #endif
126 base::Process process);
128 void Terminate();
130 static void SetProcessBackgroundedInternal(base::Process process,
131 bool background);
133 static void TerminateInternal(
134 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
135 bool zygote,
136 #endif
137 base::Process process);
139 Client* client_;
140 BrowserThread::ID client_thread_id_;
141 base::Process process_;
142 base::TerminationStatus termination_status_;
143 int exit_code_;
144 #if defined(OS_ANDROID)
145 // The fd to close after creating the process.
146 base::ScopedFD ipcfd_;
147 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
148 bool zygote_;
149 #endif
150 bool starting_;
151 // Controls whether the child process should be terminated on browser
152 // shutdown. Default behavior is to terminate the child.
153 bool terminate_child_on_shutdown_;
156 ChildProcessLauncher::Context::Context()
157 : client_(NULL),
158 client_thread_id_(BrowserThread::UI),
159 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
160 exit_code_(RESULT_CODE_NORMAL_EXIT),
161 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
162 zygote_(false),
163 #endif
164 starting_(true),
165 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
166 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
167 defined(UNDEFINED_SANITIZER)
168 terminate_child_on_shutdown_(false) {
169 #else
170 terminate_child_on_shutdown_(true) {
171 #endif
174 void ChildProcessLauncher::Context::Launch(
175 SandboxedProcessLauncherDelegate* delegate,
176 base::CommandLine* cmd_line,
177 int child_process_id,
178 Client* client) {
179 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
180 client_ = client;
182 #if defined(OS_ANDROID)
183 // Android only supports renderer, sandboxed utility and gpu.
184 std::string process_type =
185 cmd_line->GetSwitchValueASCII(switches::kProcessType);
186 CHECK(process_type == switches::kGpuProcess ||
187 process_type == switches::kRendererProcess ||
188 process_type == switches::kUtilityProcess)
189 << "Unsupported process type: " << process_type;
191 // Non-sandboxed utility or renderer process are currently not supported.
192 DCHECK(process_type == switches::kGpuProcess ||
193 !cmd_line->HasSwitch(switches::kNoSandbox));
195 // We need to close the client end of the IPC channel to reliably detect
196 // child termination. We will close this fd after we create the child
197 // process which is asynchronous on Android.
198 ipcfd_.reset(delegate->TakeIpcFd().release());
199 #endif
200 BrowserThread::PostTask(
201 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
202 base::Bind(&Context::LaunchInternal,
203 make_scoped_refptr(this),
204 client_thread_id_,
205 child_process_id,
206 delegate,
207 cmd_line));
210 #if defined(OS_ANDROID)
211 // static
212 void ChildProcessLauncher::Context::OnChildProcessStarted(
213 // |this_object| is NOT thread safe. Only use it to post a task back.
214 scoped_refptr<Context> this_object,
215 BrowserThread::ID client_thread_id,
216 const base::TimeTicks begin_launch_time,
217 base::ProcessHandle handle) {
218 RecordHistograms(begin_launch_time);
219 if (BrowserThread::CurrentlyOn(client_thread_id)) {
220 // This is always invoked on the UI thread which is commonly the
221 // |client_thread_id| so we can shortcut one PostTask.
222 this_object->Notify(base::Process(handle));
223 } else {
224 BrowserThread::PostTask(
225 client_thread_id, FROM_HERE,
226 base::Bind(&ChildProcessLauncher::Context::Notify,
227 this_object,
228 base::Passed(base::Process(handle))));
231 #endif
233 void ChildProcessLauncher::Context::ResetClient() {
234 // No need for locking as this function gets called on the same thread that
235 // client_ would be used.
236 CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
237 client_ = NULL;
240 void ChildProcessLauncher::Context::UpdateTerminationStatus(bool known_dead) {
241 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
242 if (zygote_) {
243 termination_status_ = ZygoteHostImpl::GetInstance()->
244 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
245 } else if (known_dead) {
246 termination_status_ =
247 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
248 } else {
249 #elif defined(OS_MACOSX)
250 if (known_dead) {
251 termination_status_ =
252 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
253 } else {
254 #elif defined(OS_ANDROID)
255 if (IsChildProcessOomProtected(process_.Handle())) {
256 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
257 } else {
258 #else
260 #endif
261 termination_status_ =
262 base::GetTerminationStatus(process_.Handle(), &exit_code_);
266 void ChildProcessLauncher::Context::SetProcessBackgrounded(bool background) {
267 base::Process to_pass = process_.Duplicate();
268 BrowserThread::PostTask(
269 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
270 base::Bind(&Context::SetProcessBackgroundedInternal,
271 base::Passed(&to_pass), background));
274 // static
275 void ChildProcessLauncher::Context::RecordHistograms(
276 base::TimeTicks begin_launch_time) {
277 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
278 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
279 RecordLaunchHistograms(launch_time);
280 } else {
281 BrowserThread::PostTask(
282 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
283 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms,
284 launch_time));
288 // static
289 void ChildProcessLauncher::Context::RecordLaunchHistograms(
290 base::TimeDelta launch_time) {
291 // Log the launch time, separating out the first one (which will likely be
292 // slower due to the rest of the browser initializing at the same time).
293 static bool done_first_launch = false;
294 if (done_first_launch) {
295 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
296 } else {
297 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
298 done_first_launch = true;
302 // static
303 void ChildProcessLauncher::Context::LaunchInternal(
304 // |this_object| is NOT thread safe. Only use it to post a task back.
305 scoped_refptr<Context> this_object,
306 BrowserThread::ID client_thread_id,
307 int child_process_id,
308 SandboxedProcessLauncherDelegate* delegate,
309 base::CommandLine* cmd_line) {
310 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
311 #if defined(OS_WIN)
312 bool launch_elevated = delegate->ShouldLaunchElevated();
313 #elif defined(OS_ANDROID)
314 // Uses |ipcfd_| instead of |ipcfd| on Android.
315 #elif defined(OS_MACOSX)
316 base::EnvironmentMap env = delegate->GetEnvironment();
317 base::ScopedFD ipcfd = delegate->TakeIpcFd();
318 #elif defined(OS_POSIX)
319 bool use_zygote = delegate->ShouldUseZygote();
320 base::EnvironmentMap env = delegate->GetEnvironment();
321 base::ScopedFD ipcfd = delegate->TakeIpcFd();
322 #endif
323 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
324 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
326 base::Process process;
327 #if defined(OS_WIN)
328 if (launch_elevated) {
329 base::LaunchOptions options;
330 options.start_hidden = true;
331 process = base::LaunchElevatedProcess(*cmd_line, options);
332 } else {
333 process = StartSandboxedProcess(delegate, cmd_line);
335 #elif defined(OS_POSIX)
336 std::string process_type =
337 cmd_line->GetSwitchValueASCII(switches::kProcessType);
338 scoped_ptr<FileDescriptorInfo> files_to_register(
339 FileDescriptorInfoImpl::Create());
341 #if defined(OS_ANDROID)
342 files_to_register->Share(kPrimaryIPCChannel, this_object->ipcfd_.get());
343 #else
344 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
345 #endif
346 #endif
348 #if defined(OS_ANDROID)
349 // Android WebView runs in single process, ensure that we never get here
350 // when running in single process mode.
351 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
353 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
354 *cmd_line, child_process_id, files_to_register.get());
356 StartChildProcess(
357 cmd_line->argv(),
358 child_process_id,
359 files_to_register.Pass(),
360 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
361 this_object,
362 client_thread_id,
363 begin_launch_time));
365 #elif defined(OS_POSIX)
366 // We need to close the client end of the IPC channel to reliably detect
367 // child termination.
369 #if !defined(OS_MACOSX)
370 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
371 *cmd_line, child_process_id, files_to_register.get());
372 if (use_zygote) {
373 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
374 cmd_line->argv(), files_to_register.Pass(), process_type);
375 process = base::Process(handle);
376 } else
377 // Fall through to the normal posix case below when we're not zygoting.
378 #endif // !defined(OS_MACOSX)
380 // Convert FD mapping to FileHandleMappingVector
381 base::FileHandleMappingVector fds_to_map =
382 files_to_register->GetMappingWithIDAdjustment(
383 base::GlobalDescriptors::kBaseDescriptor);
385 #if !defined(OS_MACOSX)
386 if (process_type == switches::kRendererProcess) {
387 const int sandbox_fd =
388 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
389 fds_to_map.push_back(std::make_pair(
390 sandbox_fd,
391 GetSandboxFD()));
393 #endif // defined(OS_MACOSX)
395 // Actually launch the app.
396 base::LaunchOptions options;
397 options.environ = env;
398 options.fds_to_remap = &fds_to_map;
400 #if defined(OS_MACOSX)
401 // Hold the MachBroker lock for the duration of LaunchProcess. The child
402 // will send its task port to the parent almost immediately after startup.
403 // The Mach message will be delivered to the parent, but updating the
404 // record of the launch will wait until after the placeholder PID is
405 // inserted below. This ensures that while the child process may send its
406 // port to the parent prior to the parent leaving LaunchProcess, the
407 // order in which the record in MachBroker is updated is correct.
408 MachBroker* broker = MachBroker::GetInstance();
409 broker->GetLock().Acquire();
411 // Make sure the MachBroker is running, and inform it to expect a
412 // check-in from the new process.
413 broker->EnsureRunning();
415 const int bootstrap_sandbox_policy = delegate->GetSandboxType();
416 if (ShouldEnableBootstrapSandbox() &&
417 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
418 options.replacement_bootstrap_name =
419 GetBootstrapSandbox()->server_bootstrap_name();
420 GetBootstrapSandbox()->PrepareToForkWithPolicy(
421 bootstrap_sandbox_policy);
423 #endif // defined(OS_MACOSX)
425 process = base::LaunchProcess(*cmd_line, options);
427 #if defined(OS_MACOSX)
428 if (ShouldEnableBootstrapSandbox() &&
429 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
430 GetBootstrapSandbox()->FinishedFork(process.Handle());
433 if (process.IsValid())
434 broker->AddPlaceholderForPid(process.Pid(), child_process_id);
436 // After updating the broker, release the lock and let the child's
437 // messasge be processed on the broker's thread.
438 broker->GetLock().Release();
439 #endif // defined(OS_MACOSX)
441 #endif // else defined(OS_POSIX)
442 #if !defined(OS_ANDROID)
443 if (process.IsValid())
444 RecordHistograms(begin_launch_time);
445 BrowserThread::PostTask(
446 client_thread_id, FROM_HERE,
447 base::Bind(&Context::Notify,
448 this_object.get(),
449 #if defined(OS_POSIX) && !defined(OS_MACOSX)
450 use_zygote,
451 #endif
452 base::Passed(&process)));
453 #endif // !defined(OS_ANDROID)
456 void ChildProcessLauncher::Context::Notify(
457 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
458 bool zygote,
459 #endif
460 base::Process process) {
461 #if defined(OS_ANDROID)
462 // Finally close the ipcfd
463 base::ScopedFD ipcfd_closer = ipcfd_.Pass();
464 #endif
465 starting_ = false;
466 process_ = process.Pass();
467 if (!process_.IsValid())
468 LOG(ERROR) << "Failed to launch child process";
470 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
471 zygote_ = zygote;
472 #endif
473 if (client_) {
474 if (process_.IsValid()) {
475 client_->OnProcessLaunched();
476 } else {
477 client_->OnProcessLaunchFailed();
479 } else {
480 Terminate();
484 void ChildProcessLauncher::Context::Terminate() {
485 if (!process_.IsValid())
486 return;
488 if (!terminate_child_on_shutdown_)
489 return;
491 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
492 // don't this on the UI/IO threads.
493 BrowserThread::PostTask(
494 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
495 base::Bind(&Context::TerminateInternal,
496 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
497 zygote_,
498 #endif
499 base::Passed(&process_)));
502 // static
503 void ChildProcessLauncher::Context::SetProcessBackgroundedInternal(
504 base::Process process,
505 bool background) {
506 process.SetProcessBackgrounded(background);
507 #if defined(OS_ANDROID)
508 SetChildProcessInForeground(process.Handle(), !background);
509 #endif
512 // static
513 void ChildProcessLauncher::Context::TerminateInternal(
514 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
515 bool zygote,
516 #endif
517 base::Process process) {
518 #if defined(OS_ANDROID)
519 VLOG(1) << "ChromeProcess: Stopping process with handle "
520 << process.Handle();
521 StopChildProcess(process.Handle());
522 #else
523 // Client has gone away, so just kill the process. Using exit code 0
524 // means that UMA won't treat this as a crash.
525 process.Terminate(RESULT_CODE_NORMAL_EXIT);
526 // On POSIX, we must additionally reap the child.
527 #if defined(OS_POSIX)
528 #if !defined(OS_MACOSX)
529 if (zygote) {
530 // If the renderer was created via a zygote, we have to proxy the reaping
531 // through the zygote process.
532 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
533 } else
534 #endif // !OS_MACOSX
535 base::EnsureProcessTerminated(process.Pass());
536 #endif // OS_POSIX
537 #endif // defined(OS_ANDROID)
540 // -----------------------------------------------------------------------------
542 ChildProcessLauncher::ChildProcessLauncher(
543 SandboxedProcessLauncherDelegate* delegate,
544 base::CommandLine* cmd_line,
545 int child_process_id,
546 Client* client) {
547 context_ = new Context();
548 context_->Launch(
549 delegate,
550 cmd_line,
551 child_process_id,
552 client);
555 ChildProcessLauncher::~ChildProcessLauncher() {
556 context_->ResetClient();
559 bool ChildProcessLauncher::IsStarting() {
560 return context_->starting();
563 const base::Process& ChildProcessLauncher::GetProcess() const {
564 DCHECK(!context_->starting());
565 return context_->process();
568 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
569 bool known_dead,
570 int* exit_code) {
571 if (!context_->process().IsValid()) {
572 // Process is already gone, so return the cached termination status.
573 if (exit_code)
574 *exit_code = context_->exit_code();
575 return context_->termination_status();
578 context_->UpdateTerminationStatus(known_dead);
579 if (exit_code)
580 *exit_code = context_->exit_code();
582 // POSIX: If the process crashed, then the kernel closed the socket
583 // for it and so the child has already died by the time we get
584 // here. Since GetTerminationStatus called waitpid with WNOHANG,
585 // it'll reap the process. However, if GetTerminationStatus didn't
586 // reap the child (because it was still running), we'll need to
587 // Terminate via ProcessWatcher. So we can't close the handle here.
588 if (context_->termination_status() != base::TERMINATION_STATUS_STILL_RUNNING)
589 context_->Close();
591 return context_->termination_status();
594 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
595 context_->SetProcessBackgrounded(background);
598 void ChildProcessLauncher::SetTerminateChildOnShutdown(
599 bool terminate_on_shutdown) {
600 if (context_.get())
601 context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
604 } // namespace content