Service Worker: Release controllees upon activation failure.
[chromium-blink-merge.git] / content / browser / child_process_launcher.cc
blob28be72bb9c32eb853702adbdb0726379a3f9825c
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 "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/mach_broker_mac.h"
30 #include "sandbox/mac/bootstrap_sandbox.h"
31 #elif defined(OS_ANDROID)
32 #include "base/android/jni_android.h"
33 #include "content/browser/android/child_process_launcher_android.h"
34 #elif defined(OS_POSIX)
35 #include "base/memory/shared_memory.h"
36 #include "base/memory/singleton.h"
37 #include "content/browser/renderer_host/render_sandbox_host_linux.h"
38 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
39 #include "content/common/child_process_sandbox_support_impl_linux.h"
40 #endif
42 #if defined(OS_POSIX)
43 #include "base/posix/global_descriptors.h"
44 #include "content/browser/file_descriptor_info_impl.h"
45 #endif
47 namespace content {
49 namespace {
51 typedef base::Callback<void(bool,
52 #if defined(OS_ANDROID)
53 base::ScopedFD,
54 #endif
55 base::Process)> NotifyCallback;
57 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
58 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
59 // Log the launch time, separating out the first one (which will likely be
60 // slower due to the rest of the browser initializing at the same time).
61 static bool done_first_launch = false;
62 if (done_first_launch) {
63 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
64 } else {
65 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
66 done_first_launch = true;
70 #if defined(OS_ANDROID)
71 // TODO(sievers): Remove this by defining better what happens on what
72 // thread in the corresponding Java code.
73 void OnChildProcessStartedAndroid(const NotifyCallback& callback,
74 BrowserThread::ID client_thread_id,
75 const base::TimeTicks begin_launch_time,
76 base::ScopedFD ipcfd,
77 base::ProcessHandle handle) {
78 // This can be called on the launcher thread or UI thread.
79 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
80 BrowserThread::PostTask(
81 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
82 base::Bind(&RecordHistogramsOnLauncherThread, launch_time));
84 base::Closure callback_on_client_thread(
85 base::Bind(callback, false, base::Passed(&ipcfd),
86 base::Passed(base::Process(handle))));
87 if (BrowserThread::CurrentlyOn(client_thread_id)) {
88 callback_on_client_thread.Run();
89 } else {
90 BrowserThread::PostTask(
91 client_thread_id, FROM_HERE, callback_on_client_thread);
94 #endif
96 void LaunchOnLauncherThread(const NotifyCallback& callback,
97 BrowserThread::ID client_thread_id,
98 int child_process_id,
99 SandboxedProcessLauncherDelegate* delegate,
100 #if defined(OS_ANDROID)
101 base::ScopedFD ipcfd,
102 #endif
103 base::CommandLine* cmd_line) {
104 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
105 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
106 #if defined(OS_WIN)
107 bool use_zygote = false;
108 bool launch_elevated = delegate->ShouldLaunchElevated();
109 #elif defined(OS_MACOSX)
110 bool use_zygote = false;
111 base::EnvironmentMap env = delegate->GetEnvironment();
112 base::ScopedFD ipcfd = delegate->TakeIpcFd();
113 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
114 bool use_zygote = delegate->ShouldUseZygote();
115 base::EnvironmentMap env = delegate->GetEnvironment();
116 base::ScopedFD ipcfd = delegate->TakeIpcFd();
117 #endif
118 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
119 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
121 base::Process process;
122 #if defined(OS_WIN)
123 if (launch_elevated) {
124 base::LaunchOptions options;
125 options.start_hidden = true;
126 process = base::LaunchElevatedProcess(*cmd_line, options);
127 } else {
128 process = StartSandboxedProcess(delegate, cmd_line);
130 #elif defined(OS_POSIX)
131 std::string process_type =
132 cmd_line->GetSwitchValueASCII(switches::kProcessType);
133 scoped_ptr<FileDescriptorInfo> files_to_register(
134 FileDescriptorInfoImpl::Create());
136 #if defined(OS_ANDROID)
137 files_to_register->Share(kPrimaryIPCChannel, ipcfd.get());
138 #else
139 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
140 #endif
141 #endif
143 #if defined(OS_ANDROID)
144 // Android WebView runs in single process, ensure that we never get here
145 // when running in single process mode.
146 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
148 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
149 *cmd_line, child_process_id, files_to_register.get());
151 StartChildProcess(
152 cmd_line->argv(), child_process_id, files_to_register.Pass(),
153 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id,
154 begin_launch_time, base::Passed(&ipcfd)));
156 #elif defined(OS_POSIX)
157 // We need to close the client end of the IPC channel to reliably detect
158 // child termination.
160 #if !defined(OS_MACOSX)
161 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
162 *cmd_line, child_process_id, files_to_register.get());
163 if (use_zygote) {
164 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
165 cmd_line->argv(), files_to_register.Pass(), process_type);
166 process = base::Process(handle);
167 } else
168 // Fall through to the normal posix case below when we're not zygoting.
169 #endif // !defined(OS_MACOSX)
171 // Convert FD mapping to FileHandleMappingVector
172 base::FileHandleMappingVector fds_to_map =
173 files_to_register->GetMappingWithIDAdjustment(
174 base::GlobalDescriptors::kBaseDescriptor);
176 #if !defined(OS_MACOSX)
177 if (process_type == switches::kRendererProcess) {
178 const int sandbox_fd =
179 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
180 fds_to_map.push_back(std::make_pair(
181 sandbox_fd,
182 GetSandboxFD()));
184 #endif // defined(OS_MACOSX)
186 // Actually launch the app.
187 base::LaunchOptions options;
188 options.environ = env;
189 options.fds_to_remap = &fds_to_map;
191 #if defined(OS_MACOSX)
192 // Hold the MachBroker lock for the duration of LaunchProcess. The child
193 // will send its task port to the parent almost immediately after startup.
194 // The Mach message will be delivered to the parent, but updating the
195 // record of the launch will wait until after the placeholder PID is
196 // inserted below. This ensures that while the child process may send its
197 // port to the parent prior to the parent leaving LaunchProcess, the
198 // order in which the record in MachBroker is updated is correct.
199 MachBroker* broker = MachBroker::GetInstance();
200 broker->GetLock().Acquire();
202 // Make sure the MachBroker is running, and inform it to expect a
203 // check-in from the new process.
204 broker->EnsureRunning();
206 const int bootstrap_sandbox_policy = delegate->GetSandboxType();
207 if (ShouldEnableBootstrapSandbox() &&
208 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
209 options.replacement_bootstrap_name =
210 GetBootstrapSandbox()->server_bootstrap_name();
211 GetBootstrapSandbox()->PrepareToForkWithPolicy(
212 bootstrap_sandbox_policy);
214 #endif // defined(OS_MACOSX)
216 process = base::LaunchProcess(*cmd_line, options);
218 #if defined(OS_MACOSX)
219 if (ShouldEnableBootstrapSandbox() &&
220 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
221 GetBootstrapSandbox()->FinishedFork(process.Handle());
224 if (process.IsValid())
225 broker->AddPlaceholderForPid(process.Pid(), child_process_id);
227 // After updating the broker, release the lock and let the child's
228 // messasge be processed on the broker's thread.
229 broker->GetLock().Release();
230 #endif // defined(OS_MACOSX)
232 #endif // else defined(OS_POSIX)
233 #if !defined(OS_ANDROID)
234 if (process.IsValid()) {
235 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
236 begin_launch_time);
238 BrowserThread::PostTask(client_thread_id, FROM_HERE,
239 base::Bind(callback,
240 use_zygote,
241 base::Passed(&process)));
242 #endif // !defined(OS_ANDROID)
245 void TerminateOnLauncherThread(bool zygote, base::Process process) {
246 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
247 #if defined(OS_ANDROID)
248 VLOG(1) << "ChromeProcess: Stopping process with handle "
249 << process.Handle();
250 StopChildProcess(process.Handle());
251 #else
252 // Client has gone away, so just kill the process. Using exit code 0
253 // means that UMA won't treat this as a crash.
254 process.Terminate(RESULT_CODE_NORMAL_EXIT, false);
255 // On POSIX, we must additionally reap the child.
256 #if defined(OS_POSIX)
257 #if !defined(OS_MACOSX)
258 if (zygote) {
259 // If the renderer was created via a zygote, we have to proxy the reaping
260 // through the zygote process.
261 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
262 } else
263 #endif // !OS_MACOSX
264 base::EnsureProcessTerminated(process.Pass());
265 #endif // OS_POSIX
266 #endif // defined(OS_ANDROID)
269 void SetProcessBackgroundedOnLauncherThread(base::Process process,
270 bool background) {
271 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
272 process.SetProcessBackgrounded(background);
273 #if defined(OS_ANDROID)
274 SetChildProcessInForeground(process.Handle(), !background);
275 #endif
278 } // anonymous namespace
280 ChildProcessLauncher::ChildProcessLauncher(
281 SandboxedProcessLauncherDelegate* delegate,
282 base::CommandLine* cmd_line,
283 int child_process_id,
284 Client* client,
285 bool terminate_on_shutdown)
286 : client_(client),
287 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
288 exit_code_(RESULT_CODE_NORMAL_EXIT),
289 zygote_(false),
290 starting_(true),
291 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
292 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
293 defined(UNDEFINED_SANITIZER)
294 terminate_child_on_shutdown_(false),
295 #else
296 terminate_child_on_shutdown_(terminate_on_shutdown),
297 #endif
298 weak_factory_(this) {
299 DCHECK(CalledOnValidThread());
300 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
301 Launch(delegate, cmd_line, child_process_id);
304 ChildProcessLauncher::~ChildProcessLauncher() {
305 DCHECK(CalledOnValidThread());
306 if (process_.IsValid() && terminate_child_on_shutdown_) {
307 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
308 // don't this on the UI/IO threads.
309 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
310 base::Bind(&TerminateOnLauncherThread, zygote_,
311 base::Passed(&process_)));
315 void ChildProcessLauncher::Launch(
316 SandboxedProcessLauncherDelegate* delegate,
317 base::CommandLine* cmd_line,
318 int child_process_id) {
319 DCHECK(CalledOnValidThread());
321 #if defined(OS_ANDROID)
322 // Android only supports renderer, sandboxed utility and gpu.
323 std::string process_type =
324 cmd_line->GetSwitchValueASCII(switches::kProcessType);
325 CHECK(process_type == switches::kGpuProcess ||
326 process_type == switches::kRendererProcess ||
327 process_type == switches::kUtilityProcess)
328 << "Unsupported process type: " << process_type;
330 // Non-sandboxed utility or renderer process are currently not supported.
331 DCHECK(process_type == switches::kGpuProcess ||
332 !cmd_line->HasSwitch(switches::kNoSandbox));
334 // We need to close the client end of the IPC channel to reliably detect
335 // child termination. We will close this fd after we create the child
336 // process which is asynchronous on Android.
337 base::ScopedFD ipcfd(delegate->TakeIpcFd().release());
338 #endif
339 NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch,
340 weak_factory_.GetWeakPtr(),
341 terminate_child_on_shutdown_));
342 BrowserThread::PostTask(
343 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
344 base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_,
345 child_process_id, delegate,
346 #if defined(OS_ANDROID)
347 base::Passed(&ipcfd),
348 #endif
349 cmd_line));
352 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
353 DCHECK(CalledOnValidThread());
354 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
355 if (zygote_) {
356 termination_status_ = ZygoteHostImpl::GetInstance()->
357 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
358 } else if (known_dead) {
359 termination_status_ =
360 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
361 } else {
362 #elif defined(OS_MACOSX)
363 if (known_dead) {
364 termination_status_ =
365 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
366 } else {
367 #elif defined(OS_ANDROID)
368 if (IsChildProcessOomProtected(process_.Handle())) {
369 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
370 } else {
371 #else
373 #endif
374 termination_status_ =
375 base::GetTerminationStatus(process_.Handle(), &exit_code_);
379 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
380 DCHECK(CalledOnValidThread());
381 base::Process to_pass = process_.Duplicate();
382 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
383 base::Bind(&SetProcessBackgroundedOnLauncherThread,
384 base::Passed(&to_pass), background));
387 void ChildProcessLauncher::DidLaunch(
388 base::WeakPtr<ChildProcessLauncher> instance,
389 bool terminate_on_shutdown,
390 bool zygote,
391 #if defined(OS_ANDROID)
392 base::ScopedFD ipcfd,
393 #endif
394 base::Process process) {
395 if (!process.IsValid())
396 LOG(ERROR) << "Failed to launch child process";
398 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
399 // is fixed.
400 tracked_objects::ScopedTracker tracking_profile1(
401 FROM_HERE_WITH_EXPLICIT_FUNCTION(
402 "465841 ChildProcessLauncher::Context::Notify::Start"));
404 if (instance.get()) {
405 instance->Notify(zygote,
406 #if defined(OS_ANDROID)
407 ipcfd.Pass(),
408 #endif
409 process.Pass());
410 } else {
411 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
412 // is fixed.
413 tracked_objects::ScopedTracker tracking_profile4(
414 FROM_HERE_WITH_EXPLICIT_FUNCTION(
415 "465841 ChildProcessLauncher::Context::Notify::ProcessTerminate"));
416 if (process.IsValid() && terminate_on_shutdown) {
417 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
418 // don't this on the UI/IO threads.
419 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
420 base::Bind(&TerminateOnLauncherThread, zygote,
421 base::Passed(&process)));
426 void ChildProcessLauncher::Notify(
427 bool zygote,
428 #if defined(OS_ANDROID)
429 base::ScopedFD ipcfd,
430 #endif
431 base::Process process) {
432 DCHECK(CalledOnValidThread());
433 starting_ = false;
434 process_ = process.Pass();
436 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
437 zygote_ = zygote;
438 #endif
439 if (process_.IsValid()) {
440 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
441 // is fixed.
442 tracked_objects::ScopedTracker tracking_profile2(
443 FROM_HERE_WITH_EXPLICIT_FUNCTION(
444 "465841 ChildProcessLauncher::Context::Notify::ProcessLaunched"));
445 client_->OnProcessLaunched();
446 } else {
447 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/465841
448 // is fixed.
449 tracked_objects::ScopedTracker tracking_profile3(
450 FROM_HERE_WITH_EXPLICIT_FUNCTION(
451 "465841 ChildProcessLauncher::Context::Notify::ProcessFailed"));
452 client_->OnProcessLaunchFailed();
456 bool ChildProcessLauncher::IsStarting() {
457 // TODO(crbug.com/469248): This fails in some tests.
458 // DCHECK(CalledOnValidThread());
459 return starting_;
462 const base::Process& ChildProcessLauncher::GetProcess() const {
463 // TODO(crbug.com/469248): This fails in some tests.
464 // DCHECK(CalledOnValidThread());
465 return process_;
468 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
469 bool known_dead,
470 int* exit_code) {
471 DCHECK(CalledOnValidThread());
472 if (!process_.IsValid()) {
473 // Process is already gone, so return the cached termination status.
474 if (exit_code)
475 *exit_code = exit_code_;
476 return termination_status_;
479 UpdateTerminationStatus(known_dead);
480 if (exit_code)
481 *exit_code = exit_code_;
483 // POSIX: If the process crashed, then the kernel closed the socket
484 // for it and so the child has already died by the time we get
485 // here. Since GetTerminationStatus called waitpid with WNOHANG,
486 // it'll reap the process. However, if GetTerminationStatus didn't
487 // reap the child (because it was still running), we'll need to
488 // Terminate via ProcessWatcher. So we can't close the handle here.
489 if (termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
490 process_.Close();
492 return termination_status_;
495 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
496 Client* client) {
497 Client* ret = client_;
498 client_ = client;
499 return ret;
502 } // namespace content