Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / content / browser / child_process_launcher.cc
blob262e6a8ac90ea0c0e6b4097dd90b0f32382257b6
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/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"
24 #if defined(OS_WIN)
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/shared_memory.h"
38 #include "base/memory/singleton.h"
39 #include "content/browser/renderer_host/render_sandbox_host_linux.h"
40 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
41 #include "content/common/child_process_sandbox_support_impl_linux.h"
42 #endif
44 #if defined(OS_POSIX)
45 #include "base/posix/global_descriptors.h"
46 #include "content/browser/file_descriptor_info_impl.h"
47 #include "gin/v8_initializer.h"
48 #endif
50 namespace content {
52 namespace {
54 typedef base::Callback<void(bool,
55 #if defined(OS_ANDROID)
56 base::ScopedFD,
57 #endif
58 base::Process)> NotifyCallback;
60 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
61 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
62 // Log the launch time, separating out the first one (which will likely be
63 // slower due to the rest of the browser initializing at the same time).
64 static bool done_first_launch = false;
65 if (done_first_launch) {
66 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
67 } else {
68 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
69 done_first_launch = true;
73 #if defined(OS_ANDROID)
74 // TODO(sievers): Remove this by defining better what happens on what
75 // thread in the corresponding Java code.
76 void OnChildProcessStartedAndroid(const NotifyCallback& callback,
77 BrowserThread::ID client_thread_id,
78 const base::TimeTicks begin_launch_time,
79 base::ScopedFD ipcfd,
80 base::ProcessHandle handle) {
81 // This can be called on the launcher thread or UI thread.
82 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
83 BrowserThread::PostTask(
84 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
85 base::Bind(&RecordHistogramsOnLauncherThread, launch_time));
87 base::Closure callback_on_client_thread(
88 base::Bind(callback, false, base::Passed(&ipcfd),
89 base::Passed(base::Process(handle))));
90 if (BrowserThread::CurrentlyOn(client_thread_id)) {
91 callback_on_client_thread.Run();
92 } else {
93 BrowserThread::PostTask(
94 client_thread_id, FROM_HERE, callback_on_client_thread);
97 #endif
99 void LaunchOnLauncherThread(const NotifyCallback& callback,
100 BrowserThread::ID client_thread_id,
101 int child_process_id,
102 SandboxedProcessLauncherDelegate* delegate,
103 #if defined(OS_ANDROID)
104 base::ScopedFD ipcfd,
105 #endif
106 base::CommandLine* cmd_line) {
107 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
108 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
109 #if defined(OS_WIN)
110 bool use_zygote = false;
111 bool launch_elevated = delegate->ShouldLaunchElevated();
112 #elif defined(OS_MACOSX)
113 bool use_zygote = false;
114 base::EnvironmentMap env = delegate->GetEnvironment();
115 base::ScopedFD ipcfd = delegate->TakeIpcFd();
116 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
117 bool use_zygote = delegate->ShouldUseZygote();
118 base::EnvironmentMap env = delegate->GetEnvironment();
119 base::ScopedFD ipcfd = delegate->TakeIpcFd();
120 #endif
121 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
122 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
124 base::Process process;
125 #if defined(OS_WIN)
126 if (launch_elevated) {
127 base::LaunchOptions options;
128 options.start_hidden = true;
129 process = base::LaunchElevatedProcess(*cmd_line, options);
130 } else {
131 process = StartSandboxedProcess(delegate, cmd_line);
133 #elif defined(OS_POSIX)
134 std::string process_type =
135 cmd_line->GetSwitchValueASCII(switches::kProcessType);
136 scoped_ptr<FileDescriptorInfo> files_to_register(
137 FileDescriptorInfoImpl::Create());
139 #if defined(OS_ANDROID)
140 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get());
141 #else
142 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
143 #endif
144 #endif
146 #if defined(OS_POSIX) && !defined(OS_MACOSX)
147 std::map<int, base::MemoryMappedFile::Region> regions;
148 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
149 *cmd_line, child_process_id, files_to_register.get()
150 #if defined(OS_ANDROID)
151 , &regions
152 #endif
154 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
155 base::PlatformFile natives_pf =
156 gin::V8Initializer::GetOpenNativesFileForChildProcesses(
157 &regions[kV8NativesDataDescriptor]);
158 DCHECK_GE(natives_pf, 0);
159 files_to_register->Share(kV8NativesDataDescriptor, natives_pf);
161 base::MemoryMappedFile::Region snapshot_region;
162 base::PlatformFile snapshot_pf =
163 gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(
164 &snapshot_region);
165 // Failure to load the V8 snapshot is not necessarily an error. V8 can start
166 // up (slower) without the snapshot.
167 if (snapshot_pf != -1) {
168 files_to_register->Share(kV8SnapshotDataDescriptor, snapshot_pf);
169 regions.insert(std::make_pair(kV8SnapshotDataDescriptor, snapshot_region));
172 if (process_type != switches::kZygoteProcess) {
173 cmd_line->AppendSwitch(::switches::kV8NativesPassedByFD);
174 if (snapshot_pf != -1) {
175 cmd_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
178 #endif // defined(V8_USE_EXTERNAL_STARTUP_DATA)
179 #endif // defined(OS_POSIX) && !defined(OS_MACOSX)
181 #if defined(OS_ANDROID)
182 files_to_register->Share(
183 kAndroidICUDataDescriptor,
184 base::i18n::GetIcuDataFileHandle(&regions[kAndroidICUDataDescriptor]));
186 // Android WebView runs in single process, ensure that we never get here
187 // when running in single process mode.
188 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
190 StartChildProcess(
191 cmd_line->argv(), child_process_id, files_to_register.Pass(), regions,
192 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id,
193 begin_launch_time, base::Passed(&ipcfd)));
195 #elif defined(OS_POSIX)
196 // We need to close the client end of the IPC channel to reliably detect
197 // child termination.
199 #if !defined(OS_MACOSX)
200 if (use_zygote) {
201 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
202 cmd_line->argv(), files_to_register.Pass(), process_type);
203 process = base::Process(handle);
204 } else
205 // Fall through to the normal posix case below when we're not zygoting.
206 #endif // !defined(OS_MACOSX)
208 // Convert FD mapping to FileHandleMappingVector
209 base::FileHandleMappingVector fds_to_map =
210 files_to_register->GetMappingWithIDAdjustment(
211 base::GlobalDescriptors::kBaseDescriptor);
213 #if !defined(OS_MACOSX)
214 if (process_type == switches::kRendererProcess) {
215 const int sandbox_fd =
216 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
217 fds_to_map.push_back(std::make_pair(
218 sandbox_fd,
219 GetSandboxFD()));
221 #endif // defined(OS_MACOSX)
223 // Actually launch the app.
224 base::LaunchOptions options;
225 options.environ = env;
226 options.fds_to_remap = &fds_to_map;
228 #if defined(OS_MACOSX)
229 // Hold the MachBroker lock for the duration of LaunchProcess. The child
230 // will send its task port to the parent almost immediately after startup.
231 // The Mach message will be delivered to the parent, but updating the
232 // record of the launch will wait until after the placeholder PID is
233 // inserted below. This ensures that while the child process may send its
234 // port to the parent prior to the parent leaving LaunchProcess, the
235 // order in which the record in MachBroker is updated is correct.
236 MachBroker* broker = MachBroker::GetInstance();
237 broker->GetLock().Acquire();
239 // Make sure the MachBroker is running, and inform it to expect a
240 // check-in from the new process.
241 broker->EnsureRunning();
243 // Make sure the IOSurfaceManager service is running.
244 BrowserIOSurfaceManager::GetInstance()->EnsureRunning();
246 const int bootstrap_sandbox_policy = delegate->GetSandboxType();
247 if (ShouldEnableBootstrapSandbox() &&
248 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
249 options.replacement_bootstrap_name =
250 GetBootstrapSandbox()->server_bootstrap_name();
251 GetBootstrapSandbox()->PrepareToForkWithPolicy(
252 bootstrap_sandbox_policy);
254 #endif // defined(OS_MACOSX)
256 process = base::LaunchProcess(*cmd_line, options);
258 #if defined(OS_MACOSX)
259 if (ShouldEnableBootstrapSandbox() &&
260 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
261 GetBootstrapSandbox()->FinishedFork(process.Handle());
264 if (process.IsValid())
265 broker->AddPlaceholderForPid(process.Pid(), child_process_id);
267 // After updating the broker, release the lock and let the child's
268 // messasge be processed on the broker's thread.
269 broker->GetLock().Release();
270 #endif // defined(OS_MACOSX)
272 #endif // else defined(OS_POSIX)
273 #if !defined(OS_ANDROID)
274 if (process.IsValid()) {
275 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
276 begin_launch_time);
278 BrowserThread::PostTask(client_thread_id, FROM_HERE,
279 base::Bind(callback,
280 use_zygote,
281 base::Passed(&process)));
282 #endif // !defined(OS_ANDROID)
285 void TerminateOnLauncherThread(bool zygote, base::Process process) {
286 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
287 #if defined(OS_ANDROID)
288 VLOG(1) << "ChromeProcess: Stopping process with handle "
289 << process.Handle();
290 StopChildProcess(process.Handle());
291 #else
292 // Client has gone away, so just kill the process. Using exit code 0
293 // means that UMA won't treat this as a crash.
294 process.Terminate(RESULT_CODE_NORMAL_EXIT, false);
295 // On POSIX, we must additionally reap the child.
296 #if defined(OS_POSIX)
297 #if !defined(OS_MACOSX)
298 if (zygote) {
299 // If the renderer was created via a zygote, we have to proxy the reaping
300 // through the zygote process.
301 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
302 } else
303 #endif // !OS_MACOSX
304 base::EnsureProcessTerminated(process.Pass());
305 #endif // OS_POSIX
306 #endif // defined(OS_ANDROID)
309 void SetProcessBackgroundedOnLauncherThread(base::Process process,
310 bool background) {
311 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
312 #if defined(OS_MACOSX)
313 MachBroker* broker = MachBroker::GetInstance();
314 mach_port_t task_port = broker->TaskForPid(process.Pid());
315 if (task_port != TASK_NULL) {
316 process.SetProcessBackgrounded(task_port, background);
318 #else
319 process.SetProcessBackgrounded(background);
320 #endif // defined(OS_MACOSX)
321 #if defined(OS_ANDROID)
322 SetChildProcessInForeground(process.Handle(), !background);
323 #endif
326 } // anonymous namespace
328 ChildProcessLauncher::ChildProcessLauncher(
329 SandboxedProcessLauncherDelegate* delegate,
330 base::CommandLine* cmd_line,
331 int child_process_id,
332 Client* client,
333 bool terminate_on_shutdown)
334 : client_(client),
335 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
336 exit_code_(RESULT_CODE_NORMAL_EXIT),
337 zygote_(false),
338 starting_(true),
339 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
340 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
341 defined(UNDEFINED_SANITIZER)
342 terminate_child_on_shutdown_(false),
343 #else
344 terminate_child_on_shutdown_(terminate_on_shutdown),
345 #endif
346 weak_factory_(this) {
347 DCHECK(CalledOnValidThread());
348 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
349 Launch(delegate, cmd_line, child_process_id);
352 ChildProcessLauncher::~ChildProcessLauncher() {
353 DCHECK(CalledOnValidThread());
354 if (process_.IsValid() && terminate_child_on_shutdown_) {
355 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
356 // don't this on the UI/IO threads.
357 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
358 base::Bind(&TerminateOnLauncherThread, zygote_,
359 base::Passed(&process_)));
363 void ChildProcessLauncher::Launch(
364 SandboxedProcessLauncherDelegate* delegate,
365 base::CommandLine* cmd_line,
366 int child_process_id) {
367 DCHECK(CalledOnValidThread());
369 #if defined(OS_ANDROID)
370 // Android only supports renderer, sandboxed utility and gpu.
371 std::string process_type =
372 cmd_line->GetSwitchValueASCII(switches::kProcessType);
373 CHECK(process_type == switches::kGpuProcess ||
374 process_type == switches::kRendererProcess ||
375 #if defined(ENABLE_PLUGINS)
376 process_type == switches::kPpapiPluginProcess ||
377 #endif
378 process_type == switches::kUtilityProcess)
379 << "Unsupported process type: " << process_type;
381 // Non-sandboxed utility or renderer process are currently not supported.
382 DCHECK(process_type == switches::kGpuProcess ||
383 !cmd_line->HasSwitch(switches::kNoSandbox));
385 // We need to close the client end of the IPC channel to reliably detect
386 // child termination. We will close this fd after we create the child
387 // process which is asynchronous on Android.
388 base::ScopedFD ipcfd(delegate->TakeIpcFd().release());
389 #endif
390 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch,
391 weak_factory_.GetWeakPtr(),
392 terminate_child_on_shutdown_));
393 BrowserThread::PostTask(
394 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
395 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_,
396 child_process_id, delegate,
397 #if defined(OS_ANDROID)
398 base::Passed(&ipcfd),
399 #endif
400 cmd_line));
403 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
404 DCHECK(CalledOnValidThread());
405 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
406 if (zygote_) {
407 termination_status_ = ZygoteHostImpl::GetInstance()->
408 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
409 } else if (known_dead) {
410 termination_status_ =
411 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
412 } else {
413 #elif defined(OS_MACOSX)
414 if (known_dead) {
415 termination_status_ =
416 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
417 } else {
418 #elif defined(OS_ANDROID)
419 if (IsChildProcessOomProtected(process_.Handle())) {
420 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
421 } else {
422 #else
424 #endif
425 termination_status_ =
426 base::GetTerminationStatus(process_.Handle(), &exit_code_);
430 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
431 DCHECK(CalledOnValidThread());
432 base::Process to_pass = process_.Duplicate();
433 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
434 base::Bind(&SetProcessBackgroundedOnLauncherThread,
435 base::Passed(&to_pass), background));
438 void ChildProcessLauncher::DidLaunch(
439 base::WeakPtr<ChildProcessLauncher> instance,
440 bool terminate_on_shutdown,
441 bool zygote,
442 #if defined(OS_ANDROID)
443 base::ScopedFD ipcfd,
444 #endif
445 base::Process process) {
446 if (!process.IsValid())
447 LOG(ERROR) << "Failed to launch child process";
449 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
450 // is fixed.
451 tracked_objects::ScopedTracker tracking_profile1(
452 FROM_HERE_WITH_EXPLICIT_FUNCTION(
453 "465841 ChildProcessLauncher::Context::Notify::Start"));
455 if (instance.get()) {
456 instance->Notify(zygote,
457 #if defined(OS_ANDROID)
458 ipcfd.Pass(),
459 #endif
460 process.Pass());
461 } else {
462 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
463 // is fixed.
464 tracked_objects::ScopedTracker tracking_profile4(
465 FROM_HERE_WITH_EXPLICIT_FUNCTION(
466 "465841 ChildProcessLauncher::Context::Notify::ProcessTerminate"));
467 if (process.IsValid() && terminate_on_shutdown) {
468 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
469 // don't this on the UI/IO threads.
470 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
471 base::Bind(&TerminateOnLauncherThread, zygote,
472 base::Passed(&process)));
477 void ChildProcessLauncher::Notify(
478 bool zygote,
479 #if defined(OS_ANDROID)
480 base::ScopedFD ipcfd,
481 #endif
482 base::Process process) {
483 DCHECK(CalledOnValidThread());
484 starting_ = false;
485 process_ = process.Pass();
487 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
488 zygote_ = zygote;
489 #endif
490 if (process_.IsValid()) {
491 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
492 // is fixed.
493 tracked_objects::ScopedTracker tracking_profile2(
494 FROM_HERE_WITH_EXPLICIT_FUNCTION(
495 "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
496 client_->OnProcessLaunched();
497 } else {
498 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
499 // is fixed.
500 tracked_objects::ScopedTracker tracking_profile3(
501 FROM_HERE_WITH_EXPLICIT_FUNCTION(
502 "465841 ChildProcessLauncher::Context::Notify::ProcessFailed"));
503 termination_status_ = base::TERMINATION_STATUS_LAUNCH_FAILED;
504 client_->OnProcessLaunchFailed();
508 bool ChildProcessLauncher::IsStarting() {
509 // TODO(crbug.com/469248): This fails in some tests.
510 // DCHECK(CalledOnValidThread());
511 return starting_;
514 const base::Process& ChildProcessLauncher::GetProcess() const {
515 // TODO(crbug.com/469248): This fails in some tests.
516 // DCHECK(CalledOnValidThread());
517 return process_;
520 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
521 bool known_dead,
522 int* exit_code) {
523 DCHECK(CalledOnValidThread());
524 if (!process_.IsValid()) {
525 // Process is already gone, so return the cached termination status.
526 if (exit_code)
527 *exit_code = exit_code_;
528 return termination_status_;
531 UpdateTerminationStatus(known_dead);
532 if (exit_code)
533 *exit_code = exit_code_;
535 // POSIX: If the process crashed, then the kernel closed the socket
536 // for it and so the child has already died by the time we get
537 // here. Since GetTerminationStatus called waitpid with WNOHANG,
538 // it'll reap the process. However, if GetTerminationStatus didn't
539 // reap the child (because it was still running), we'll need to
540 // Terminate via ProcessWatcher. So we can't close the handle here.
541 if (termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
542 process_.Close();
544 return termination_status_;
547 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
548 Client* client) {
549 Client* ret = client_;
550 client_ = client;
551 return ret;
554 } // namespace content