Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / child_process_launcher.cc
blob152cd5c8aee6e25000e4483623fe46c739f33f51
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/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 #endif
50 namespace content {
52 // Having the functionality of ChildProcessLauncher be in an internal
53 // ref counted object allows us to automatically terminate the process when the
54 // parent class destructs, while still holding on to state that we need.
55 class ChildProcessLauncher::Context
56 : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
57 public:
58 Context()
59 : client_(NULL),
60 client_thread_id_(BrowserThread::UI),
61 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
62 exit_code_(RESULT_CODE_NORMAL_EXIT),
63 starting_(true),
64 // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622
65 #if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
66 defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS)
67 terminate_child_on_shutdown_(false)
68 #else
69 terminate_child_on_shutdown_(true)
70 #endif
71 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
72 , zygote_(false)
73 #endif
77 void Launch(
78 SandboxedProcessLauncherDelegate* delegate,
79 base::CommandLine* cmd_line,
80 int child_process_id,
81 Client* client) {
82 client_ = client;
84 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
86 #if defined(OS_ANDROID)
87 // We need to close the client end of the IPC channel to reliably detect
88 // child termination. We will close this fd after we create the child
89 // process which is asynchronous on Android.
90 ipcfd_ = delegate->GetIpcFd();
91 #endif
92 BrowserThread::PostTask(
93 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
94 base::Bind(
95 &Context::LaunchInternal,
96 make_scoped_refptr(this),
97 client_thread_id_,
98 child_process_id,
99 delegate,
100 cmd_line));
103 #if defined(OS_ANDROID)
104 static void OnChildProcessStarted(
105 // |this_object| is NOT thread safe. Only use it to post a task back.
106 scoped_refptr<Context> this_object,
107 BrowserThread::ID client_thread_id,
108 const base::TimeTicks begin_launch_time,
109 base::ProcessHandle handle) {
110 RecordHistograms(begin_launch_time);
111 if (BrowserThread::CurrentlyOn(client_thread_id)) {
112 // This is always invoked on the UI thread which is commonly the
113 // |client_thread_id| so we can shortcut one PostTask.
114 this_object->Notify(handle);
115 } else {
116 BrowserThread::PostTask(
117 client_thread_id, FROM_HERE,
118 base::Bind(
119 &ChildProcessLauncher::Context::Notify,
120 this_object,
121 handle));
124 #endif
126 void ResetClient() {
127 // No need for locking as this function gets called on the same thread that
128 // client_ would be used.
129 CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
130 client_ = NULL;
133 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) {
134 terminate_child_on_shutdown_ = terminate_on_shutdown;
137 private:
138 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
139 friend class ChildProcessLauncher;
141 ~Context() {
142 Terminate();
145 static void RecordHistograms(const base::TimeTicks begin_launch_time) {
146 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
147 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
148 RecordLaunchHistograms(launch_time);
149 } else {
150 BrowserThread::PostTask(
151 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
152 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms,
153 launch_time));
157 static void RecordLaunchHistograms(const base::TimeDelta launch_time) {
158 // Log the launch time, separating out the first one (which will likely be
159 // slower due to the rest of the browser initializing at the same time).
160 static bool done_first_launch = false;
161 if (done_first_launch) {
162 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
163 } else {
164 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
165 done_first_launch = true;
169 static void LaunchInternal(
170 // |this_object| is NOT thread safe. Only use it to post a task back.
171 scoped_refptr<Context> this_object,
172 BrowserThread::ID client_thread_id,
173 int child_process_id,
174 SandboxedProcessLauncherDelegate* delegate,
175 base::CommandLine* cmd_line) {
176 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
177 #if defined(OS_WIN)
178 bool launch_elevated = delegate->ShouldLaunchElevated();
179 #elif defined(OS_ANDROID)
180 int ipcfd = delegate->GetIpcFd();
181 #elif defined(OS_MACOSX)
182 base::EnvironmentMap env = delegate->GetEnvironment();
183 int ipcfd = delegate->GetIpcFd();
184 #elif defined(OS_POSIX)
185 bool use_zygote = delegate->ShouldUseZygote();
186 base::EnvironmentMap env = delegate->GetEnvironment();
187 int ipcfd = delegate->GetIpcFd();
188 #endif
189 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
190 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
192 #if defined(OS_WIN)
193 base::ProcessHandle handle = base::kNullProcessHandle;
194 if (launch_elevated) {
195 base::LaunchOptions options;
196 options.start_hidden = true;
197 base::LaunchElevatedProcess(*cmd_line, options, &handle);
198 } else {
199 handle = StartSandboxedProcess(delegate, cmd_line);
201 #elif defined(OS_POSIX)
202 std::string process_type =
203 cmd_line->GetSwitchValueASCII(switches::kProcessType);
204 std::vector<FileDescriptorInfo> files_to_register;
205 files_to_register.push_back(
206 FileDescriptorInfo(kPrimaryIPCChannel,
207 base::FileDescriptor(ipcfd, false)));
208 base::StatsTable* stats_table = base::StatsTable::current();
209 if (stats_table &&
210 base::SharedMemory::IsHandleValid(
211 stats_table->GetSharedMemoryHandle())) {
212 files_to_register.push_back(
213 FileDescriptorInfo(kStatsTableSharedMemFd,
214 stats_table->GetSharedMemoryHandle()));
216 #endif
218 #if defined(OS_ANDROID)
219 // Android WebView runs in single process, ensure that we never get here
220 // when running in single process mode.
221 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
223 GetContentClient()->browser()->
224 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
225 &files_to_register);
227 StartChildProcess(cmd_line->argv(), child_process_id, files_to_register,
228 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
229 this_object, client_thread_id, begin_launch_time));
231 #elif defined(OS_POSIX)
232 base::ProcessHandle handle = base::kNullProcessHandle;
233 // We need to close the client end of the IPC channel to reliably detect
234 // child termination.
235 base::ScopedFD ipcfd_closer(ipcfd);
237 #if !defined(OS_MACOSX)
238 GetContentClient()->browser()->
239 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
240 &files_to_register);
241 if (use_zygote) {
242 handle = ZygoteHostImpl::GetInstance()->ForkRequest(cmd_line->argv(),
243 files_to_register,
244 process_type);
245 } else
246 // Fall through to the normal posix case below when we're not zygoting.
247 #endif // !defined(OS_MACOSX)
249 // Convert FD mapping to FileHandleMappingVector
250 base::FileHandleMappingVector fds_to_map;
251 for (size_t i = 0; i < files_to_register.size(); ++i) {
252 fds_to_map.push_back(std::make_pair(
253 files_to_register[i].fd.fd,
254 files_to_register[i].id +
255 base::GlobalDescriptors::kBaseDescriptor));
258 #if !defined(OS_MACOSX)
259 if (process_type == switches::kRendererProcess) {
260 const int sandbox_fd =
261 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
262 fds_to_map.push_back(std::make_pair(
263 sandbox_fd,
264 GetSandboxFD()));
266 #endif // defined(OS_MACOSX)
268 // Actually launch the app.
269 base::LaunchOptions options;
270 options.environ = env;
271 options.fds_to_remap = &fds_to_map;
273 #if defined(OS_MACOSX)
274 // Hold the MachBroker lock for the duration of LaunchProcess. The child
275 // will send its task port to the parent almost immediately after startup.
276 // The Mach message will be delivered to the parent, but updating the
277 // record of the launch will wait until after the placeholder PID is
278 // inserted below. This ensures that while the child process may send its
279 // port to the parent prior to the parent leaving LaunchProcess, the
280 // order in which the record in MachBroker is updated is correct.
281 MachBroker* broker = MachBroker::GetInstance();
282 broker->GetLock().Acquire();
284 // Make sure the MachBroker is running, and inform it to expect a
285 // check-in from the new process.
286 broker->EnsureRunning();
288 const int bootstrap_sandbox_policy = delegate->GetSandboxType();
289 if (ShouldEnableBootstrapSandbox() &&
290 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
291 options.replacement_bootstrap_name =
292 GetBootstrapSandbox()->server_bootstrap_name();
293 GetBootstrapSandbox()->PrepareToForkWithPolicy(
294 bootstrap_sandbox_policy);
296 #endif // defined(OS_MACOSX)
298 bool launched = base::LaunchProcess(*cmd_line, options, &handle);
299 if (!launched)
300 handle = base::kNullProcessHandle;
302 #if defined(OS_MACOSX)
303 if (ShouldEnableBootstrapSandbox() &&
304 bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
305 GetBootstrapSandbox()->FinishedFork(handle);
308 if (launched)
309 broker->AddPlaceholderForPid(handle);
311 // After updating the broker, release the lock and let the child's
312 // messasge be processed on the broker's thread.
313 broker->GetLock().Release();
314 #endif // defined(OS_MACOSX)
316 #endif // else defined(OS_POSIX)
317 #if !defined(OS_ANDROID)
318 if (handle)
319 RecordHistograms(begin_launch_time);
320 BrowserThread::PostTask(
321 client_thread_id, FROM_HERE,
322 base::Bind(
323 &Context::Notify,
324 this_object.get(),
325 #if defined(OS_POSIX) && !defined(OS_MACOSX)
326 use_zygote,
327 #endif
328 handle));
329 #endif // !defined(OS_ANDROID)
332 void Notify(
333 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
334 bool zygote,
335 #endif
336 base::ProcessHandle handle) {
337 #if defined(OS_ANDROID)
338 // Finally close the ipcfd
339 base::ScopedFD ipcfd_closer(ipcfd_);
340 #endif
341 starting_ = false;
342 process_.set_handle(handle);
343 if (!handle)
344 LOG(ERROR) << "Failed to launch child process";
346 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
347 zygote_ = zygote;
348 #endif
349 if (client_) {
350 if (handle) {
351 client_->OnProcessLaunched();
352 } else {
353 client_->OnProcessLaunchFailed();
355 } else {
356 Terminate();
360 void Terminate() {
361 if (!process_.handle())
362 return;
364 if (!terminate_child_on_shutdown_)
365 return;
367 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
368 // don't this on the UI/IO threads.
369 BrowserThread::PostTask(
370 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
371 base::Bind(
372 &Context::TerminateInternal,
373 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
374 zygote_,
375 #endif
376 process_.handle()));
377 process_.set_handle(base::kNullProcessHandle);
380 static void SetProcessBackgrounded(base::ProcessHandle handle,
381 bool background) {
382 base::Process process(handle);
383 process.SetProcessBackgrounded(background);
384 #if defined(OS_ANDROID)
385 SetChildProcessInForeground(handle, !background);
386 #endif
389 static void TerminateInternal(
390 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
391 bool zygote,
392 #endif
393 base::ProcessHandle handle) {
394 #if defined(OS_ANDROID)
395 VLOG(0) << "ChromeProcess: Stopping process with handle " << handle;
396 StopChildProcess(handle);
397 #else
398 base::Process process(handle);
399 // Client has gone away, so just kill the process. Using exit code 0
400 // means that UMA won't treat this as a crash.
401 process.Terminate(RESULT_CODE_NORMAL_EXIT);
402 // On POSIX, we must additionally reap the child.
403 #if defined(OS_POSIX)
404 #if !defined(OS_MACOSX)
405 if (zygote) {
406 // If the renderer was created via a zygote, we have to proxy the reaping
407 // through the zygote process.
408 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(handle);
409 } else
410 #endif // !OS_MACOSX
412 base::EnsureProcessTerminated(handle);
414 #endif // OS_POSIX
415 process.Close();
416 #endif // defined(OS_ANDROID)
419 Client* client_;
420 BrowserThread::ID client_thread_id_;
421 base::Process process_;
422 base::TerminationStatus termination_status_;
423 int exit_code_;
424 bool starting_;
425 // Controls whether the child process should be terminated on browser
426 // shutdown. Default behavior is to terminate the child.
427 bool terminate_child_on_shutdown_;
428 #if defined(OS_ANDROID)
429 // The fd to close after creating the process.
430 int ipcfd_;
431 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
432 bool zygote_;
433 #endif
437 ChildProcessLauncher::ChildProcessLauncher(
438 SandboxedProcessLauncherDelegate* delegate,
439 base::CommandLine* cmd_line,
440 int child_process_id,
441 Client* client) {
442 context_ = new Context();
443 context_->Launch(
444 delegate,
445 cmd_line,
446 child_process_id,
447 client);
450 ChildProcessLauncher::~ChildProcessLauncher() {
451 context_->ResetClient();
454 bool ChildProcessLauncher::IsStarting() {
455 return context_->starting_;
458 base::ProcessHandle ChildProcessLauncher::GetHandle() {
459 DCHECK(!context_->starting_);
460 return context_->process_.handle();
463 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
464 bool known_dead,
465 int* exit_code) {
466 base::ProcessHandle handle = context_->process_.handle();
467 if (handle == base::kNullProcessHandle) {
468 // Process is already gone, so return the cached termination status.
469 if (exit_code)
470 *exit_code = context_->exit_code_;
471 return context_->termination_status_;
473 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
474 if (context_->zygote_) {
475 context_->termination_status_ = ZygoteHostImpl::GetInstance()->
476 GetTerminationStatus(handle, known_dead, &context_->exit_code_);
477 } else if (known_dead) {
478 context_->termination_status_ =
479 base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_);
480 } else {
481 #elif defined(OS_MACOSX)
482 if (known_dead) {
483 context_->termination_status_ =
484 base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_);
485 } else {
486 #elif defined(OS_ANDROID)
487 if (IsChildProcessOomProtected(handle)) {
488 context_->termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
489 } else {
490 #else
492 #endif
493 context_->termination_status_ =
494 base::GetTerminationStatus(handle, &context_->exit_code_);
497 if (exit_code)
498 *exit_code = context_->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 (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
507 context_->process_.Close();
509 return context_->termination_status_;
512 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
513 BrowserThread::PostTask(
514 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
515 base::Bind(
516 &ChildProcessLauncher::Context::SetProcessBackgrounded,
517 GetHandle(), background));
520 void ChildProcessLauncher::SetTerminateChildOnShutdown(
521 bool terminate_on_shutdown) {
522 if (context_.get())
523 context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
526 } // namespace content