Use PlaybackToMemory for BitmapRasterWorkerPool playback
[chromium-blink-merge.git] / content / browser / child_process_launcher.cc
blob8ca3c1d04fa7d2d22dd2353489c1d14146243c1e
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/metrics/stats_table.h"
47 #include "base/posix/global_descriptors.h"
48 #include "content/browser/file_descriptor_info_impl.h"
49 #endif
51 namespace content {
53 // Having the functionality of ChildProcessLauncher be in an internal
54 // ref counted object allows us to automatically terminate the process when the
55 // parent class destructs, while still holding on to state that we need.
56 class ChildProcessLauncher::Context
57 : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
58 public:
59 Context();
61 // Posts a task to a dedicated thread to do the actual work.
62 // Must be called on the UI thread.
63 void Launch(SandboxedProcessLauncherDelegate* delegate,
64 base::CommandLine* cmd_line,
65 int child_process_id,
66 Client* client);
68 #if defined(OS_ANDROID)
69 // Called on the UI thread with the operation result. Calls Notify().
70 static void OnChildProcessStarted(
71 // |this_object| is NOT thread safe. Only use it to post a task back.
72 scoped_refptr<Context> this_object,
73 BrowserThread::ID client_thread_id,
74 const base::TimeTicks begin_launch_time,
75 base::ProcessHandle handle);
76 #endif
78 // Resets the client (the client is going away).
79 void ResetClient();
81 bool starting() const { return starting_; }
83 const base::Process& process() const { return process_; }
85 int exit_code() const { return exit_code_; }
87 base::TerminationStatus termination_status() const {
88 return termination_status_;
91 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) {
92 terminate_child_on_shutdown_ = terminate_on_shutdown;
95 void UpdateTerminationStatus(bool known_dead);
97 void Close() { process_.Close(); }
99 void SetProcessBackgrounded(bool background);
101 private:
102 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
104 ~Context() {
105 Terminate();
108 static void RecordHistograms(base::TimeTicks begin_launch_time);
109 static void RecordLaunchHistograms(base::TimeDelta launch_time);
111 // Performs the actual work of launching the process.
112 // Runs on the PROCESS_LAUNCHER thread.
113 static void LaunchInternal(
114 // |this_object| is NOT thread safe. Only use it to post a task back.
115 scoped_refptr<Context> this_object,
116 BrowserThread::ID client_thread_id,
117 int child_process_id,
118 SandboxedProcessLauncherDelegate* delegate,
119 base::CommandLine* cmd_line);
121 // Notifies the client about the result of the operation.
122 // Runs on the UI thread.
123 void Notify(
124 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
125 bool zygote,
126 #endif
127 base::Process process);
129 void Terminate();
131 static void SetProcessBackgroundedInternal(base::Process process,
132 bool background);
134 static void TerminateInternal(
135 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
136 bool zygote,
137 #endif
138 base::Process process);
140 Client* client_;
141 BrowserThread::ID client_thread_id_;
142 base::Process process_;
143 base::TerminationStatus termination_status_;
144 int exit_code_;
145 #if defined(OS_ANDROID)
146 // The fd to close after creating the process.
147 base::ScopedFD ipcfd_;
148 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
149 bool zygote_;
150 #endif
151 bool starting_;
152 // Controls whether the child process should be terminated on browser
153 // shutdown. Default behavior is to terminate the child.
154 bool terminate_child_on_shutdown_;
157 ChildProcessLauncher::Context::Context()
158 : client_(NULL),
159 client_thread_id_(BrowserThread::UI),
160 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
161 exit_code_(RESULT_CODE_NORMAL_EXIT),
162 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
163 zygote_(false),
164 #endif
165 starting_(true),
166 // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622
167 #if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
168 defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS)
169 terminate_child_on_shutdown_(false) {
170 #else
171 terminate_child_on_shutdown_(true) {
172 #endif
175 void ChildProcessLauncher::Context::Launch(
176 SandboxedProcessLauncherDelegate* delegate,
177 base::CommandLine* cmd_line,
178 int child_process_id,
179 Client* client) {
180 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
181 client_ = client;
183 #if defined(OS_ANDROID)
184 // We need to close the client end of the IPC channel to reliably detect
185 // child termination. We will close this fd after we create the child
186 // process which is asynchronous on Android.
187 ipcfd_.reset(delegate->TakeIpcFd().release());
188 #endif
189 BrowserThread::PostTask(
190 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
191 base::Bind(&Context::LaunchInternal,
192 make_scoped_refptr(this),
193 client_thread_id_,
194 child_process_id,
195 delegate,
196 cmd_line));
199 #if defined(OS_ANDROID)
200 // static
201 void ChildProcessLauncher::Context::OnChildProcessStarted(
202 // |this_object| is NOT thread safe. Only use it to post a task back.
203 scoped_refptr<Context> this_object,
204 BrowserThread::ID client_thread_id,
205 const base::TimeTicks begin_launch_time,
206 base::ProcessHandle handle) {
207 RecordHistograms(begin_launch_time);
208 if (BrowserThread::CurrentlyOn(client_thread_id)) {
209 // This is always invoked on the UI thread which is commonly the
210 // |client_thread_id| so we can shortcut one PostTask.
211 this_object->Notify(base::Process(handle));
212 } else {
213 BrowserThread::PostTask(
214 client_thread_id, FROM_HERE,
215 base::Bind(&ChildProcessLauncher::Context::Notify,
216 this_object,
217 base::Passed(base::Process(handle))));
220 #endif
222 void ChildProcessLauncher::Context::ResetClient() {
223 // No need for locking as this function gets called on the same thread that
224 // client_ would be used.
225 CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
226 client_ = NULL;
229 void ChildProcessLauncher::Context::UpdateTerminationStatus(bool known_dead) {
230 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
231 if (zygote_) {
232 termination_status_ = ZygoteHostImpl::GetInstance()->
233 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
234 } else if (known_dead) {
235 termination_status_ =
236 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
237 } else {
238 #elif defined(OS_MACOSX)
239 if (known_dead) {
240 termination_status_ =
241 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
242 } else {
243 #elif defined(OS_ANDROID)
244 if (IsChildProcessOomProtected(process_.Handle())) {
245 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
246 } else {
247 #else
249 #endif
250 termination_status_ =
251 base::GetTerminationStatus(process_.Handle(), &exit_code_);
255 void ChildProcessLauncher::Context::SetProcessBackgrounded(bool background) {
256 base::Process to_pass = process_.Duplicate();
257 BrowserThread::PostTask(
258 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
259 base::Bind(&Context::SetProcessBackgroundedInternal,
260 base::Passed(&to_pass), background));
263 // static
264 void ChildProcessLauncher::Context::RecordHistograms(
265 base::TimeTicks begin_launch_time) {
266 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
267 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
268 RecordLaunchHistograms(launch_time);
269 } else {
270 BrowserThread::PostTask(
271 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
272 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms,
273 launch_time));
277 // static
278 void ChildProcessLauncher::Context::RecordLaunchHistograms(
279 base::TimeDelta launch_time) {
280 // Log the launch time, separating out the first one (which will likely be
281 // slower due to the rest of the browser initializing at the same time).
282 static bool done_first_launch = false;
283 if (done_first_launch) {
284 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
285 } else {
286 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
287 done_first_launch = true;
291 // static
292 void ChildProcessLauncher::Context::LaunchInternal(
293 // |this_object| is NOT thread safe. Only use it to post a task back.
294 scoped_refptr<Context> this_object,
295 BrowserThread::ID client_thread_id,
296 int child_process_id,
297 SandboxedProcessLauncherDelegate* delegate,
298 base::CommandLine* cmd_line) {
299 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
300 #if defined(OS_WIN)
301 bool launch_elevated = delegate->ShouldLaunchElevated();
302 #elif defined(OS_ANDROID)
303 // Uses |ipcfd_| instead of |ipcfd| on Android.
304 #elif defined(OS_MACOSX)
305 base::EnvironmentMap env = delegate->GetEnvironment();
306 base::ScopedFD ipcfd = delegate->TakeIpcFd();
307 #elif defined(OS_POSIX)
308 bool use_zygote = delegate->ShouldUseZygote();
309 base::EnvironmentMap env = delegate->GetEnvironment();
310 base::ScopedFD ipcfd = delegate->TakeIpcFd();
311 #endif
312 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
313 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
315 #if defined(OS_WIN)
316 base::ProcessHandle handle = base::kNullProcessHandle;
317 if (launch_elevated) {
318 base::LaunchOptions options;
319 options.start_hidden = true;
320 base::LaunchElevatedProcess(*cmd_line, options, &handle);
321 } else {
322 handle = StartSandboxedProcess(delegate, cmd_line);
324 #elif defined(OS_POSIX)
325 std::string process_type =
326 cmd_line->GetSwitchValueASCII(switches::kProcessType);
327 scoped_ptr<FileDescriptorInfo> files_to_register(
328 FileDescriptorInfoImpl::Create());
330 #if defined(OS_ANDROID)
331 files_to_register->Share(kPrimaryIPCChannel, this_object->ipcfd_.get());
332 #else
333 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
334 #endif
335 base::StatsTable* stats_table = base::StatsTable::current();
336 if (stats_table &&
337 base::SharedMemory::IsHandleValid(stats_table->GetSharedMemoryHandle())) {
338 base::FileDescriptor fd = stats_table->GetSharedMemoryHandle();
339 DCHECK(!fd.auto_close);
340 files_to_register->Share(kStatsTableSharedMemFd, fd.fd);
342 #endif
344 #if defined(OS_ANDROID)
345 // Android WebView runs in single process, ensure that we never get here
346 // when running in single process mode.
347 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
349 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
350 *cmd_line, child_process_id, files_to_register.get());
352 StartChildProcess(
353 cmd_line->argv(),
354 child_process_id,
355 files_to_register.Pass(),
356 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
357 this_object,
358 client_thread_id,
359 begin_launch_time));
361 #elif defined(OS_POSIX)
362 base::ProcessHandle handle = base::kNullProcessHandle;
363 // We need to close the client end of the IPC channel to reliably detect
364 // child termination.
366 #if !defined(OS_MACOSX)
367 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
368 *cmd_line, child_process_id, files_to_register.get());
369 if (use_zygote) {
370 handle = ZygoteHostImpl::GetInstance()->ForkRequest(
371 cmd_line->argv(), files_to_register.Pass(), process_type);
372 } else
373 // Fall through to the normal posix case below when we're not zygoting.
374 #endif // !defined(OS_MACOSX)
376 // Convert FD mapping to FileHandleMappingVector
377 base::FileHandleMappingVector fds_to_map =
378 files_to_register->GetMappingWithIDAdjustment(
379 base::GlobalDescriptors::kBaseDescriptor);
381 #if !defined(OS_MACOSX)
382 if (process_type == switches::kRendererProcess) {
383 const int sandbox_fd =
384 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
385 fds_to_map.push_back(std::make_pair(
386 sandbox_fd,
387 GetSandboxFD()));
389 #endif // defined(OS_MACOSX)
391 // Actually launch the app.
392 base::LaunchOptions options;
393 options.environ = env;
394 options.fds_to_remap = &fds_to_map;
396 #if defined(OS_MACOSX)
397 // Hold the MachBroker lock for the duration of LaunchProcess. The child
398 // will send its task port to the parent almost immediately after startup.
399 // The Mach message will be delivered to the parent, but updating the
400 // record of the launch will wait until after the placeholder PID is
401 // inserted below. This ensures that while the child process may send its
402 // port to the parent prior to the parent leaving LaunchProcess, the
403 // order in which the record in MachBroker is updated is correct.
404 MachBroker* broker = MachBroker::GetInstance();
405 broker->GetLock().Acquire();
407 // Make sure the MachBroker is running, and inform it to expect a
408 // check-in from the new process.
409 broker->EnsureRunning();
411 const int bootstrap_sandbox_policy = delegate->GetSandboxType();
412 if (ShouldEnableBootstrapSandbox() &&
413 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
414 options.replacement_bootstrap_name =
415 GetBootstrapSandbox()->server_bootstrap_name();
416 GetBootstrapSandbox()->PrepareToForkWithPolicy(
417 bootstrap_sandbox_policy);
419 #endif // defined(OS_MACOSX)
421 bool launched = base::LaunchProcess(*cmd_line, options, &handle);
422 if (!launched)
423 handle = base::kNullProcessHandle;
425 #if defined(OS_MACOSX)
426 if (ShouldEnableBootstrapSandbox() &&
427 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
428 GetBootstrapSandbox()->FinishedFork(handle);
431 if (launched)
432 broker->AddPlaceholderForPid(handle);
434 // After updating the broker, release the lock and let the child's
435 // messasge be processed on the broker's thread.
436 broker->GetLock().Release();
437 #endif // defined(OS_MACOSX)
439 #endif // else defined(OS_POSIX)
440 #if !defined(OS_ANDROID)
441 if (handle)
442 RecordHistograms(begin_launch_time);
443 BrowserThread::PostTask(
444 client_thread_id, FROM_HERE,
445 base::Bind(&Context::Notify,
446 this_object.get(),
447 #if defined(OS_POSIX) && !defined(OS_MACOSX)
448 use_zygote,
449 #endif
450 base::Passed(base::Process(handle))));
451 #endif // !defined(OS_ANDROID)
454 void ChildProcessLauncher::Context::Notify(
455 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
456 bool zygote,
457 #endif
458 base::Process process) {
459 #if defined(OS_ANDROID)
460 // Finally close the ipcfd
461 base::ScopedFD ipcfd_closer = ipcfd_.Pass();
462 #endif
463 starting_ = false;
464 process_ = process.Pass();
465 if (!process_.IsValid())
466 LOG(ERROR) << "Failed to launch child process";
468 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
469 zygote_ = zygote;
470 #endif
471 if (client_) {
472 if (process_.IsValid()) {
473 client_->OnProcessLaunched();
474 } else {
475 client_->OnProcessLaunchFailed();
477 } else {
478 Terminate();
482 void ChildProcessLauncher::Context::Terminate() {
483 if (!process_.IsValid())
484 return;
486 if (!terminate_child_on_shutdown_)
487 return;
489 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
490 // don't this on the UI/IO threads.
491 BrowserThread::PostTask(
492 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
493 base::Bind(&Context::TerminateInternal,
494 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
495 zygote_,
496 #endif
497 base::Passed(&process_)));
500 // static
501 void ChildProcessLauncher::Context::SetProcessBackgroundedInternal(
502 base::Process process,
503 bool background) {
504 process.SetProcessBackgrounded(background);
505 #if defined(OS_ANDROID)
506 SetChildProcessInForeground(process.Handle(), !background);
507 #endif
510 // static
511 void ChildProcessLauncher::Context::TerminateInternal(
512 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
513 bool zygote,
514 #endif
515 base::Process process) {
516 #if defined(OS_ANDROID)
517 VLOG(1) << "ChromeProcess: Stopping process with handle "
518 << process.Handle();
519 StopChildProcess(process.Handle());
520 #else
521 // Client has gone away, so just kill the process. Using exit code 0
522 // means that UMA won't treat this as a crash.
523 process.Terminate(RESULT_CODE_NORMAL_EXIT);
524 // On POSIX, we must additionally reap the child.
525 #if defined(OS_POSIX)
526 #if !defined(OS_MACOSX)
527 if (zygote) {
528 // If the renderer was created via a zygote, we have to proxy the reaping
529 // through the zygote process.
530 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
531 } else
532 #endif // !OS_MACOSX
533 base::EnsureProcessTerminated(process.Handle());
534 #endif // OS_POSIX
535 #endif // defined(OS_ANDROID)
538 // -----------------------------------------------------------------------------
540 ChildProcessLauncher::ChildProcessLauncher(
541 SandboxedProcessLauncherDelegate* delegate,
542 base::CommandLine* cmd_line,
543 int child_process_id,
544 Client* client) {
545 context_ = new Context();
546 context_->Launch(
547 delegate,
548 cmd_line,
549 child_process_id,
550 client);
553 ChildProcessLauncher::~ChildProcessLauncher() {
554 context_->ResetClient();
557 bool ChildProcessLauncher::IsStarting() {
558 return context_->starting();
561 const base::Process& ChildProcessLauncher::GetProcess() const {
562 DCHECK(!context_->starting());
563 return context_->process();
566 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
567 bool known_dead,
568 int* exit_code) {
569 if (!context_->process().IsValid()) {
570 // Process is already gone, so return the cached termination status.
571 if (exit_code)
572 *exit_code = context_->exit_code();
573 return context_->termination_status();
576 context_->UpdateTerminationStatus(known_dead);
577 if (exit_code)
578 *exit_code = context_->exit_code();
580 // POSIX: If the process crashed, then the kernel closed the socket
581 // for it and so the child has already died by the time we get
582 // here. Since GetTerminationStatus called waitpid with WNOHANG,
583 // it'll reap the process. However, if GetTerminationStatus didn't
584 // reap the child (because it was still running), we'll need to
585 // Terminate via ProcessWatcher. So we can't close the handle here.
586 if (context_->termination_status() != base::TERMINATION_STATUS_STILL_RUNNING)
587 context_->Close();
589 return context_->termination_status();
592 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
593 context_->SetProcessBackgrounded(background);
596 void ChildProcessLauncher::SetTerminateChildOnShutdown(
597 bool terminate_on_shutdown) {
598 if (context_.get())
599 context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
602 } // namespace content