chrome/browser/extensions: Remove use of MessageLoopProxy and deprecated MessageLoop...
[chromium-blink-merge.git] / content / browser / child_process_launcher.cc
blob48c5e94285e1b4e8f4ccf870196537f4edeffbad
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"
7 #include "base/bind.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"
23 #if defined(OS_WIN)
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"
41 #endif
43 #if defined(OS_POSIX)
44 #include "base/posix/global_descriptors.h"
45 #include "content/browser/file_descriptor_info_impl.h"
46 #endif
48 namespace content {
50 namespace {
52 typedef base::Callback<void(bool,
53 #if defined(OS_ANDROID)
54 base::ScopedFD,
55 #endif
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);
65 } else {
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,
77 base::ScopedFD ipcfd,
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();
90 } else {
91 BrowserThread::PostTask(
92 client_thread_id, FROM_HERE, callback_on_client_thread);
95 #endif
97 void LaunchOnLauncherThread(const NotifyCallback& callback,
98 BrowserThread::ID client_thread_id,
99 int child_process_id,
100 SandboxedProcessLauncherDelegate* delegate,
101 #if defined(OS_ANDROID)
102 base::ScopedFD ipcfd,
103 #endif
104 base::CommandLine* cmd_line) {
105 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
106 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
107 #if defined(OS_WIN)
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();
118 #endif
119 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
120 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
122 base::Process process;
123 #if defined(OS_WIN)
124 if (launch_elevated) {
125 base::LaunchOptions options;
126 options.start_hidden = true;
127 process = base::LaunchElevatedProcess(*cmd_line, options);
128 } else {
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());
139 #else
140 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
141 #endif
142 #endif
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);
154 StartChildProcess(
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);
169 if (use_zygote) {
170 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
171 cmd_line->argv(), files_to_register.Pass(), process_type);
172 process = base::Process(handle);
173 } else
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(
187 sandbox_fd,
188 GetSandboxFD()));
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() -
245 begin_launch_time);
247 BrowserThread::PostTask(client_thread_id, FROM_HERE,
248 base::Bind(callback,
249 use_zygote,
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 "
258 << process.Handle();
259 StopChildProcess(process.Handle());
260 #else
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)
267 if (zygote) {
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());
271 } else
272 #endif // !OS_MACOSX
273 base::EnsureProcessTerminated(process.Pass());
274 #endif // OS_POSIX
275 #endif // defined(OS_ANDROID)
278 void SetProcessBackgroundedOnLauncherThread(base::Process process,
279 bool background) {
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);
287 #else
288 process.SetProcessBackgrounded(background);
289 #endif // defined(OS_MACOSX)
290 #if defined(OS_ANDROID)
291 SetChildProcessInForeground(process.Handle(), !background);
292 #endif
295 } // anonymous namespace
297 ChildProcessLauncher::ChildProcessLauncher(
298 SandboxedProcessLauncherDelegate* delegate,
299 base::CommandLine* cmd_line,
300 int child_process_id,
301 Client* client,
302 bool terminate_on_shutdown)
303 : client_(client),
304 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
305 exit_code_(RESULT_CODE_NORMAL_EXIT),
306 zygote_(false),
307 starting_(true),
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),
312 #else
313 terminate_child_on_shutdown_(terminate_on_shutdown),
314 #endif
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());
355 #endif
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),
365 #endif
366 cmd_line));
369 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
370 DCHECK(CalledOnValidThread());
371 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
372 if (zygote_) {
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_);
378 } else {
379 #elif defined(OS_MACOSX)
380 if (known_dead) {
381 termination_status_ =
382 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
383 } else {
384 #elif defined(OS_ANDROID)
385 if (IsChildProcessOomProtected(process_.Handle())) {
386 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
387 } else {
388 #else
390 #endif
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,
407 bool zygote,
408 #if defined(OS_ANDROID)
409 base::ScopedFD ipcfd,
410 #endif
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
416 // is fixed.
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)
424 ipcfd.Pass(),
425 #endif
426 process.Pass());
427 } else {
428 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
429 // is fixed.
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(
444 bool zygote,
445 #if defined(OS_ANDROID)
446 base::ScopedFD ipcfd,
447 #endif
448 base::Process process) {
449 DCHECK(CalledOnValidThread());
450 starting_ = false;
451 process_ = process.Pass();
453 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
454 zygote_ = zygote;
455 #endif
456 if (process_.IsValid()) {
457 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
458 // is fixed.
459 tracked_objects::ScopedTracker tracking_profile2(
460 FROM_HERE_WITH_EXPLICIT_FUNCTION(
461 "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
462 client_->OnProcessLaunched();
463 } else {
464 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
465 // is fixed.
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());
476 return starting_;
479 const base::Process& ChildProcessLauncher::GetProcess() const {
480 // TODO(crbug.com/469248): This fails in some tests.
481 // DCHECK(CalledOnValidThread());
482 return process_;
485 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
486 bool known_dead,
487 int* exit_code) {
488 DCHECK(CalledOnValidThread());
489 if (!process_.IsValid()) {
490 // Process is already gone, so return the cached termination status.
491 if (exit_code)
492 *exit_code = exit_code_;
493 return termination_status_;
496 UpdateTerminationStatus(known_dead);
497 if (exit_code)
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)
507 process_.Close();
509 return termination_status_;
512 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
513 Client* client) {
514 Client* ret = client_;
515 client_ = client;
516 return ret;
519 } // namespace content