[Mac] Implement Ambient Light API
[chromium-blink-merge.git] / content / browser / child_process_launcher.cc
blob0599ffef133989ccc28481f13b813ac50019b9f9
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(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
169 defined(UNDEFINED_SANITIZER)) && !defined(OS_CHROMEOS)
170 terminate_child_on_shutdown_(false) {
171 #else
172 terminate_child_on_shutdown_(true) {
173 #endif
176 void ChildProcessLauncher::Context::Launch(
177 SandboxedProcessLauncherDelegate* delegate,
178 base::CommandLine* cmd_line,
179 int child_process_id,
180 Client* client) {
181 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
182 client_ = client;
184 #if defined(OS_ANDROID)
185 // Android only supports renderer, sandboxed utility and gpu.
186 std::string process_type =
187 cmd_line->GetSwitchValueASCII(switches::kProcessType);
188 CHECK(process_type == switches::kGpuProcess ||
189 process_type == switches::kRendererProcess ||
190 process_type == switches::kUtilityProcess)
191 << "Unsupported process type: " << process_type;
193 // Non-sandboxed utility or renderer process are currently not supported.
194 DCHECK(process_type == switches::kGpuProcess ||
195 !cmd_line->HasSwitch(switches::kNoSandbox));
197 // We need to close the client end of the IPC channel to reliably detect
198 // child termination. We will close this fd after we create the child
199 // process which is asynchronous on Android.
200 ipcfd_.reset(delegate->TakeIpcFd().release());
201 #endif
202 BrowserThread::PostTask(
203 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
204 base::Bind(&Context::LaunchInternal,
205 make_scoped_refptr(this),
206 client_thread_id_,
207 child_process_id,
208 delegate,
209 cmd_line));
212 #if defined(OS_ANDROID)
213 // static
214 void ChildProcessLauncher::Context::OnChildProcessStarted(
215 // |this_object| is NOT thread safe. Only use it to post a task back.
216 scoped_refptr<Context> this_object,
217 BrowserThread::ID client_thread_id,
218 const base::TimeTicks begin_launch_time,
219 base::ProcessHandle handle) {
220 RecordHistograms(begin_launch_time);
221 if (BrowserThread::CurrentlyOn(client_thread_id)) {
222 // This is always invoked on the UI thread which is commonly the
223 // |client_thread_id| so we can shortcut one PostTask.
224 this_object->Notify(base::Process(handle));
225 } else {
226 BrowserThread::PostTask(
227 client_thread_id, FROM_HERE,
228 base::Bind(&ChildProcessLauncher::Context::Notify,
229 this_object,
230 base::Passed(base::Process(handle))));
233 #endif
235 void ChildProcessLauncher::Context::ResetClient() {
236 // No need for locking as this function gets called on the same thread that
237 // client_ would be used.
238 CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
239 client_ = NULL;
242 void ChildProcessLauncher::Context::UpdateTerminationStatus(bool known_dead) {
243 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
244 if (zygote_) {
245 termination_status_ = ZygoteHostImpl::GetInstance()->
246 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
247 } else if (known_dead) {
248 termination_status_ =
249 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
250 } else {
251 #elif defined(OS_MACOSX)
252 if (known_dead) {
253 termination_status_ =
254 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
255 } else {
256 #elif defined(OS_ANDROID)
257 if (IsChildProcessOomProtected(process_.Handle())) {
258 termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
259 } else {
260 #else
262 #endif
263 termination_status_ =
264 base::GetTerminationStatus(process_.Handle(), &exit_code_);
268 void ChildProcessLauncher::Context::SetProcessBackgrounded(bool background) {
269 base::Process to_pass = process_.Duplicate();
270 BrowserThread::PostTask(
271 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
272 base::Bind(&Context::SetProcessBackgroundedInternal,
273 base::Passed(&to_pass), background));
276 // static
277 void ChildProcessLauncher::Context::RecordHistograms(
278 base::TimeTicks begin_launch_time) {
279 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
280 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
281 RecordLaunchHistograms(launch_time);
282 } else {
283 BrowserThread::PostTask(
284 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
285 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms,
286 launch_time));
290 // static
291 void ChildProcessLauncher::Context::RecordLaunchHistograms(
292 base::TimeDelta launch_time) {
293 // Log the launch time, separating out the first one (which will likely be
294 // slower due to the rest of the browser initializing at the same time).
295 static bool done_first_launch = false;
296 if (done_first_launch) {
297 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
298 } else {
299 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
300 done_first_launch = true;
304 // static
305 void ChildProcessLauncher::Context::LaunchInternal(
306 // |this_object| is NOT thread safe. Only use it to post a task back.
307 scoped_refptr<Context> this_object,
308 BrowserThread::ID client_thread_id,
309 int child_process_id,
310 SandboxedProcessLauncherDelegate* delegate,
311 base::CommandLine* cmd_line) {
312 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
313 #if defined(OS_WIN)
314 bool launch_elevated = delegate->ShouldLaunchElevated();
315 #elif defined(OS_ANDROID)
316 // Uses |ipcfd_| instead of |ipcfd| on Android.
317 #elif defined(OS_MACOSX)
318 base::EnvironmentMap env = delegate->GetEnvironment();
319 base::ScopedFD ipcfd = delegate->TakeIpcFd();
320 #elif defined(OS_POSIX)
321 bool use_zygote = delegate->ShouldUseZygote();
322 base::EnvironmentMap env = delegate->GetEnvironment();
323 base::ScopedFD ipcfd = delegate->TakeIpcFd();
324 #endif
325 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
326 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
328 base::Process process;
329 #if defined(OS_WIN)
330 if (launch_elevated) {
331 base::LaunchOptions options;
332 options.start_hidden = true;
333 process = base::LaunchElevatedProcess(*cmd_line, options);
334 } else {
335 process = StartSandboxedProcess(delegate, cmd_line);
337 #elif defined(OS_POSIX)
338 std::string process_type =
339 cmd_line->GetSwitchValueASCII(switches::kProcessType);
340 scoped_ptr<FileDescriptorInfo> files_to_register(
341 FileDescriptorInfoImpl::Create());
343 #if defined(OS_ANDROID)
344 files_to_register->Share(kPrimaryIPCChannel, this_object->ipcfd_.get());
345 #else
346 files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
347 #endif
348 base::StatsTable* stats_table = base::StatsTable::current();
349 if (stats_table &&
350 base::SharedMemory::IsHandleValid(stats_table->GetSharedMemoryHandle())) {
351 base::FileDescriptor fd = stats_table->GetSharedMemoryHandle();
352 DCHECK(!fd.auto_close);
353 files_to_register->Share(kStatsTableSharedMemFd, fd.fd);
355 #endif
357 #if defined(OS_ANDROID)
358 // Android WebView runs in single process, ensure that we never get here
359 // when running in single process mode.
360 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
362 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
363 *cmd_line, child_process_id, files_to_register.get());
365 StartChildProcess(
366 cmd_line->argv(),
367 child_process_id,
368 files_to_register.Pass(),
369 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
370 this_object,
371 client_thread_id,
372 begin_launch_time));
374 #elif defined(OS_POSIX)
375 // We need to close the client end of the IPC channel to reliably detect
376 // child termination.
378 #if !defined(OS_MACOSX)
379 GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
380 *cmd_line, child_process_id, files_to_register.get());
381 if (use_zygote) {
382 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
383 cmd_line->argv(), files_to_register.Pass(), process_type);
384 process = base::Process(handle);
385 } else
386 // Fall through to the normal posix case below when we're not zygoting.
387 #endif // !defined(OS_MACOSX)
389 // Convert FD mapping to FileHandleMappingVector
390 base::FileHandleMappingVector fds_to_map =
391 files_to_register->GetMappingWithIDAdjustment(
392 base::GlobalDescriptors::kBaseDescriptor);
394 #if !defined(OS_MACOSX)
395 if (process_type == switches::kRendererProcess) {
396 const int sandbox_fd =
397 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
398 fds_to_map.push_back(std::make_pair(
399 sandbox_fd,
400 GetSandboxFD()));
402 #endif // defined(OS_MACOSX)
404 // Actually launch the app.
405 base::LaunchOptions options;
406 options.environ = env;
407 options.fds_to_remap = &fds_to_map;
409 #if defined(OS_MACOSX)
410 // Hold the MachBroker lock for the duration of LaunchProcess. The child
411 // will send its task port to the parent almost immediately after startup.
412 // The Mach message will be delivered to the parent, but updating the
413 // record of the launch will wait until after the placeholder PID is
414 // inserted below. This ensures that while the child process may send its
415 // port to the parent prior to the parent leaving LaunchProcess, the
416 // order in which the record in MachBroker is updated is correct.
417 MachBroker* broker = MachBroker::GetInstance();
418 broker->GetLock().Acquire();
420 // Make sure the MachBroker is running, and inform it to expect a
421 // check-in from the new process.
422 broker->EnsureRunning();
424 const int bootstrap_sandbox_policy = delegate->GetSandboxType();
425 if (ShouldEnableBootstrapSandbox() &&
426 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
427 options.replacement_bootstrap_name =
428 GetBootstrapSandbox()->server_bootstrap_name();
429 GetBootstrapSandbox()->PrepareToForkWithPolicy(
430 bootstrap_sandbox_policy);
432 #endif // defined(OS_MACOSX)
434 process = base::LaunchProcess(*cmd_line, options);
436 #if defined(OS_MACOSX)
437 if (ShouldEnableBootstrapSandbox() &&
438 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
439 GetBootstrapSandbox()->FinishedFork(process.Handle());
442 if (process.IsValid())
443 broker->AddPlaceholderForPid(process.pid(), child_process_id);
445 // After updating the broker, release the lock and let the child's
446 // messasge be processed on the broker's thread.
447 broker->GetLock().Release();
448 #endif // defined(OS_MACOSX)
450 #endif // else defined(OS_POSIX)
451 #if !defined(OS_ANDROID)
452 if (process.IsValid())
453 RecordHistograms(begin_launch_time);
454 BrowserThread::PostTask(
455 client_thread_id, FROM_HERE,
456 base::Bind(&Context::Notify,
457 this_object.get(),
458 #if defined(OS_POSIX) && !defined(OS_MACOSX)
459 use_zygote,
460 #endif
461 base::Passed(&process)));
462 #endif // !defined(OS_ANDROID)
465 void ChildProcessLauncher::Context::Notify(
466 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
467 bool zygote,
468 #endif
469 base::Process process) {
470 #if defined(OS_ANDROID)
471 // Finally close the ipcfd
472 base::ScopedFD ipcfd_closer = ipcfd_.Pass();
473 #endif
474 starting_ = false;
475 process_ = process.Pass();
476 if (!process_.IsValid())
477 LOG(ERROR) << "Failed to launch child process";
479 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
480 zygote_ = zygote;
481 #endif
482 if (client_) {
483 if (process_.IsValid()) {
484 client_->OnProcessLaunched();
485 } else {
486 client_->OnProcessLaunchFailed();
488 } else {
489 Terminate();
493 void ChildProcessLauncher::Context::Terminate() {
494 if (!process_.IsValid())
495 return;
497 if (!terminate_child_on_shutdown_)
498 return;
500 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
501 // don't this on the UI/IO threads.
502 BrowserThread::PostTask(
503 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
504 base::Bind(&Context::TerminateInternal,
505 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
506 zygote_,
507 #endif
508 base::Passed(&process_)));
511 // static
512 void ChildProcessLauncher::Context::SetProcessBackgroundedInternal(
513 base::Process process,
514 bool background) {
515 process.SetProcessBackgrounded(background);
516 #if defined(OS_ANDROID)
517 SetChildProcessInForeground(process.Handle(), !background);
518 #endif
521 // static
522 void ChildProcessLauncher::Context::TerminateInternal(
523 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
524 bool zygote,
525 #endif
526 base::Process process) {
527 #if defined(OS_ANDROID)
528 VLOG(1) << "ChromeProcess: Stopping process with handle "
529 << process.Handle();
530 StopChildProcess(process.Handle());
531 #else
532 // Client has gone away, so just kill the process. Using exit code 0
533 // means that UMA won't treat this as a crash.
534 process.Terminate(RESULT_CODE_NORMAL_EXIT);
535 // On POSIX, we must additionally reap the child.
536 #if defined(OS_POSIX)
537 #if !defined(OS_MACOSX)
538 if (zygote) {
539 // If the renderer was created via a zygote, we have to proxy the reaping
540 // through the zygote process.
541 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
542 } else
543 #endif // !OS_MACOSX
544 base::EnsureProcessTerminated(process.Pass());
545 #endif // OS_POSIX
546 #endif // defined(OS_ANDROID)
549 // -----------------------------------------------------------------------------
551 ChildProcessLauncher::ChildProcessLauncher(
552 SandboxedProcessLauncherDelegate* delegate,
553 base::CommandLine* cmd_line,
554 int child_process_id,
555 Client* client) {
556 context_ = new Context();
557 context_->Launch(
558 delegate,
559 cmd_line,
560 child_process_id,
561 client);
564 ChildProcessLauncher::~ChildProcessLauncher() {
565 context_->ResetClient();
568 bool ChildProcessLauncher::IsStarting() {
569 return context_->starting();
572 const base::Process& ChildProcessLauncher::GetProcess() const {
573 DCHECK(!context_->starting());
574 return context_->process();
577 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
578 bool known_dead,
579 int* exit_code) {
580 if (!context_->process().IsValid()) {
581 // Process is already gone, so return the cached termination status.
582 if (exit_code)
583 *exit_code = context_->exit_code();
584 return context_->termination_status();
587 context_->UpdateTerminationStatus(known_dead);
588 if (exit_code)
589 *exit_code = context_->exit_code();
591 // POSIX: If the process crashed, then the kernel closed the socket
592 // for it and so the child has already died by the time we get
593 // here. Since GetTerminationStatus called waitpid with WNOHANG,
594 // it'll reap the process. However, if GetTerminationStatus didn't
595 // reap the child (because it was still running), we'll need to
596 // Terminate via ProcessWatcher. So we can't close the handle here.
597 if (context_->termination_status() != base::TERMINATION_STATUS_STILL_RUNNING)
598 context_->Close();
600 return context_->termination_status();
603 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
604 context_->SetProcessBackgrounded(background);
607 void ChildProcessLauncher::SetTerminateChildOnShutdown(
608 bool terminate_on_shutdown) {
609 if (context_.get())
610 context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
613 } // namespace content