Remove the 'gyp_config' concept from MB.
[chromium-blink-merge.git] / content / browser / child_process_launcher.cc
blob55037881bb67a00ecf80440d802d4e93bdbb1631
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/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 #include "gin/v8_initializer.h"
47 #endif
49 namespace content {
51 namespace {
53 typedef base::Callback<void(bool,
54 #if defined(OS_ANDROID)
55 base::ScopedFD,
56 #endif
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);
66 } else {
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,
78 base::ScopedFD ipcfd,
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();
91 } else {
92 BrowserThread::PostTask(
93 client_thread_id, FROM_HERE, callback_on_client_thread);
96 #endif
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,
104 #endif
105 base::CommandLine* cmd_line) {
106 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
107 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
108 #if defined(OS_WIN)
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();
119 #endif
120 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
121 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
123 base::Process process;
124 #if defined(OS_WIN)
125 if (launch_elevated) {
126 base::LaunchOptions options;
127 options.start_hidden = true;
128 process = base::LaunchElevatedProcess(*cmd_line, options);
129 } else {
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());
140 #else
141 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
142 #endif
143 #endif
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)
150 , &regions
151 #endif
153 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
154 base::PlatformFile natives_pf =
155 gin::V8Initializer::GetOpenNativesFileForChildProcesses(
156 &regions[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(
163 &snapshot_region);
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(&regions[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));
189 StartChildProcess(
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)
199 if (use_zygote) {
200 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
201 cmd_line->argv(), files_to_register.Pass(), process_type);
202 process = base::Process(handle);
203 } else
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(
217 sandbox_fd,
218 GetSandboxFD()));
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() -
275 begin_launch_time);
277 BrowserThread::PostTask(client_thread_id, FROM_HERE,
278 base::Bind(callback,
279 use_zygote,
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 "
288 << process.Handle();
289 StopChildProcess(process.Handle());
290 #else
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)
297 if (zygote) {
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());
301 } else
302 #endif // !OS_MACOSX
303 base::EnsureProcessTerminated(process.Pass());
304 #endif // OS_POSIX
305 #endif // defined(OS_ANDROID)
308 void SetProcessBackgroundedOnLauncherThread(base::Process process,
309 bool background) {
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);
317 #else
318 process.SetProcessBackgrounded(background);
319 #endif // defined(OS_MACOSX)
320 #if defined(OS_ANDROID)
321 SetChildProcessInForeground(process.Handle(), !background);
322 #endif
325 } // anonymous namespace
327 ChildProcessLauncher::ChildProcessLauncher(
328 SandboxedProcessLauncherDelegate* delegate,
329 base::CommandLine* cmd_line,
330 int child_process_id,
331 Client* client,
332 bool terminate_on_shutdown)
333 : client_(client),
334 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
335 exit_code_(RESULT_CODE_NORMAL_EXIT),
336 zygote_(false),
337 starting_(true),
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),
342 #else
343 terminate_child_on_shutdown_(terminate_on_shutdown),
344 #endif
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 ||
376 #endif
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());
388 #endif
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),
398 #endif
399 cmd_line));
402 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
403 DCHECK(CalledOnValidThread());
404 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
405 if (zygote_) {
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_);
411 } else {
412 #elif defined(OS_MACOSX)
413 if (known_dead) {
414 termination_status_ =
415 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
416 } else {
417 #elif defined(OS_ANDROID)
418 if (IsChildProcessOomProtected(process_.Handle())) {
419 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
420 } else {
421 #else
423 #endif
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,
440 bool zygote,
441 #if defined(OS_ANDROID)
442 base::ScopedFD ipcfd,
443 #endif
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
449 // is fixed.
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)
457 ipcfd.Pass(),
458 #endif
459 process.Pass());
460 } else {
461 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
462 // is fixed.
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(
477 bool zygote,
478 #if defined(OS_ANDROID)
479 base::ScopedFD ipcfd,
480 #endif
481 base::Process process) {
482 DCHECK(CalledOnValidThread());
483 starting_ = false;
484 process_ = process.Pass();
486 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
487 zygote_ = zygote;
488 #endif
489 if (process_.IsValid()) {
490 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
491 // is fixed.
492 tracked_objects::ScopedTracker tracking_profile2(
493 FROM_HERE_WITH_EXPLICIT_FUNCTION(
494 "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
495 client_->OnProcessLaunched();
496 } else {
497 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
498 // is fixed.
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());
510 return starting_;
513 const base::Process& ChildProcessLauncher::GetProcess() const {
514 // TODO(crbug.com/469248): This fails in some tests.
515 // DCHECK(CalledOnValidThread());
516 return process_;
519 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
520 bool known_dead,
521 int* exit_code) {
522 DCHECK(CalledOnValidThread());
523 if (!process_.IsValid()) {
524 // Process is already gone, so return the cached termination status.
525 if (exit_code)
526 *exit_code = exit_code_;
527 return termination_status_;
530 UpdateTerminationStatus(known_dead);
531 if (exit_code)
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)
541 process_.Close();
543 return termination_status_;
546 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
547 Client* client) {
548 Client* ret = client_;
549 client_ = client;
550 return ret;
553 } // namespace content