Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / child_process_launcher.cc
blobe497762aff8ebbd651e8467c6c0409ff7c8f8fe2
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/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/metrics/histogram.h"
15 #include "base/process_util.h"
16 #include "base/synchronization/lock.h"
17 #include "base/threading/thread.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/content_browser_client.h"
20 #include "content/public/common/content_descriptors.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/public/common/result_codes.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 #include "content/public/common/sandboxed_process_launcher_delegate.h"
29 #elif defined(OS_MACOSX)
30 #include "content/browser/mach_broker_mac.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/singleton.h"
36 #include "content/browser/renderer_host/render_sandbox_host_linux.h"
37 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
38 #endif
40 #if defined(OS_POSIX)
41 #include "base/posix/global_descriptors.h"
42 #endif
44 namespace content {
46 // Having the functionality of ChildProcessLauncher be in an internal
47 // ref counted object allows us to automatically terminate the process when the
48 // parent class destructs, while still holding on to state that we need.
49 class ChildProcessLauncher::Context
50 : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
51 public:
52 Context()
53 : client_(NULL),
54 client_thread_id_(BrowserThread::UI),
55 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
56 exit_code_(RESULT_CODE_NORMAL_EXIT),
57 starting_(true)
58 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
59 , zygote_(false)
60 #endif
62 #if defined(OS_POSIX)
63 terminate_child_on_shutdown_ = !CommandLine::ForCurrentProcess()->
64 HasSwitch(switches::kChildCleanExit);
65 #else
66 terminate_child_on_shutdown_ = true;
67 #endif
70 void Launch(
71 #if defined(OS_WIN)
72 SandboxedProcessLauncherDelegate* delegate,
73 #elif defined(OS_ANDROID)
74 int ipcfd,
75 #elif defined(OS_POSIX)
76 bool use_zygote,
77 const base::EnvironmentVector& environ,
78 int ipcfd,
79 #endif
80 CommandLine* cmd_line,
81 int child_process_id,
82 Client* client) {
83 client_ = client;
85 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
87 #if defined(OS_ANDROID)
88 // We need to close the client end of the IPC channel to reliably detect
89 // child termination. We will close this fd after we create the child
90 // process which is asynchronous on Android.
91 ipcfd_ = ipcfd;
92 #endif
93 BrowserThread::PostTask(
94 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
95 base::Bind(
96 &Context::LaunchInternal,
97 make_scoped_refptr(this),
98 client_thread_id_,
99 child_process_id,
100 #if defined(OS_WIN)
101 delegate,
102 #elif defined(OS_ANDROID)
103 ipcfd,
104 #elif defined(OS_POSIX)
105 use_zygote,
106 environ,
107 ipcfd,
108 #endif
109 cmd_line));
112 #if defined(OS_ANDROID)
113 static void OnChildProcessStarted(
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 const base::TimeTicks begin_launch_time,
118 base::ProcessHandle handle) {
119 RecordHistograms(begin_launch_time);
120 if (BrowserThread::CurrentlyOn(client_thread_id)) {
121 // This is always invoked on the UI thread which is commonly the
122 // |client_thread_id| so we can shortcut one PostTask.
123 this_object->Notify(handle);
124 } else {
125 BrowserThread::PostTask(
126 client_thread_id, FROM_HERE,
127 base::Bind(
128 &ChildProcessLauncher::Context::Notify,
129 this_object,
130 handle));
133 #endif
135 void ResetClient() {
136 // No need for locking as this function gets called on the same thread that
137 // client_ would be used.
138 CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
139 client_ = NULL;
142 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) {
143 terminate_child_on_shutdown_ = terminate_on_shutdown;
146 private:
147 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
148 friend class ChildProcessLauncher;
150 ~Context() {
151 Terminate();
154 static void RecordHistograms(const base::TimeTicks begin_launch_time) {
155 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
156 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
157 RecordLaunchHistograms(launch_time);
158 } else {
159 BrowserThread::PostTask(
160 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
161 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms,
162 launch_time));
166 static void RecordLaunchHistograms(const base::TimeDelta launch_time) {
167 // Log the launch time, separating out the first one (which will likely be
168 // slower due to the rest of the browser initializing at the same time).
169 static bool done_first_launch = false;
170 if (done_first_launch) {
171 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
172 } else {
173 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
174 done_first_launch = true;
178 static void LaunchInternal(
179 // |this_object| is NOT thread safe. Only use it to post a task back.
180 scoped_refptr<Context> this_object,
181 BrowserThread::ID client_thread_id,
182 int child_process_id,
183 #if defined(OS_WIN)
184 SandboxedProcessLauncherDelegate* delegate,
185 #elif defined(OS_ANDROID)
186 int ipcfd,
187 #elif defined(OS_POSIX)
188 bool use_zygote,
189 const base::EnvironmentVector& env,
190 int ipcfd,
191 #endif
192 CommandLine* cmd_line) {
193 scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
194 base::TimeTicks begin_launch_time = base::TimeTicks::Now();
196 #if defined(OS_WIN)
197 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
198 base::ProcessHandle handle = StartSandboxedProcess(delegate, cmd_line);
199 #elif defined(OS_ANDROID)
200 // Android WebView runs in single process, ensure that we never get here
201 // when running in single process mode.
202 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
204 std::string process_type =
205 cmd_line->GetSwitchValueASCII(switches::kProcessType);
206 std::vector<FileDescriptorInfo> files_to_register;
207 files_to_register.push_back(
208 FileDescriptorInfo(kPrimaryIPCChannel,
209 base::FileDescriptor(ipcfd, false)));
211 GetContentClient()->browser()->
212 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
213 &files_to_register);
215 StartChildProcess(cmd_line->argv(), files_to_register,
216 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
217 this_object, client_thread_id, begin_launch_time));
219 #elif defined(OS_POSIX)
220 base::ProcessHandle handle = base::kNullProcessHandle;
221 // We need to close the client end of the IPC channel to reliably detect
222 // child termination.
223 file_util::ScopedFD ipcfd_closer(&ipcfd);
225 std::string process_type =
226 cmd_line->GetSwitchValueASCII(switches::kProcessType);
227 std::vector<FileDescriptorInfo> files_to_register;
228 files_to_register.push_back(
229 FileDescriptorInfo(kPrimaryIPCChannel,
230 base::FileDescriptor(ipcfd, false)));
232 #if !defined(OS_MACOSX)
233 GetContentClient()->browser()->
234 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
235 &files_to_register);
236 if (use_zygote) {
237 handle = ZygoteHostImpl::GetInstance()->ForkRequest(cmd_line->argv(),
238 files_to_register,
239 process_type);
240 } else
241 // Fall through to the normal posix case below when we're not zygoting.
242 #endif // !defined(OS_MACOSX)
244 // Convert FD mapping to FileHandleMappingVector
245 base::FileHandleMappingVector fds_to_map;
246 for (size_t i = 0; i < files_to_register.size(); ++i) {
247 fds_to_map.push_back(std::make_pair(
248 files_to_register[i].fd.fd,
249 files_to_register[i].id +
250 base::GlobalDescriptors::kBaseDescriptor));
253 #if !defined(OS_MACOSX)
254 if (process_type == switches::kRendererProcess) {
255 const int sandbox_fd =
256 RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
257 fds_to_map.push_back(std::make_pair(
258 sandbox_fd,
259 kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
261 #endif // defined(OS_MACOSX)
263 // Actually launch the app.
264 base::LaunchOptions options;
265 options.environ = &env;
266 options.fds_to_remap = &fds_to_map;
268 #if defined(OS_MACOSX)
269 // Hold the MachBroker lock for the duration of LaunchProcess. The child
270 // will send its task port to the parent almost immediately after startup.
271 // The Mach message will be delivered to the parent, but updating the
272 // record of the launch will wait until after the placeholder PID is
273 // inserted below. This ensures that while the child process may send its
274 // port to the parent prior to the parent leaving LaunchProcess, the
275 // order in which the record in MachBroker is updated is correct.
276 MachBroker* broker = MachBroker::GetInstance();
277 broker->GetLock().Acquire();
279 // Make sure the MachBroker is running, and inform it to expect a
280 // check-in from the new process.
281 broker->EnsureRunning();
282 #endif // defined(OS_MACOSX)
284 bool launched = base::LaunchProcess(*cmd_line, options, &handle);
286 #if defined(OS_MACOSX)
287 if (launched)
288 broker->AddPlaceholderForPid(handle);
290 // After updating the broker, release the lock and let the child's
291 // messasge be processed on the broker's thread.
292 broker->GetLock().Release();
293 #endif // defined(OS_MACOSX)
295 if (!launched)
296 handle = base::kNullProcessHandle;
298 #endif // else defined(OS_POSIX)
299 #if !defined(OS_ANDROID)
300 if (handle)
301 RecordHistograms(begin_launch_time);
302 BrowserThread::PostTask(
303 client_thread_id, FROM_HERE,
304 base::Bind(
305 &Context::Notify,
306 this_object.get(),
307 #if defined(OS_POSIX) && !defined(OS_MACOSX)
308 use_zygote,
309 #endif
310 handle));
311 #endif // !defined(OS_ANDROID)
314 void Notify(
315 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
316 bool zygote,
317 #endif
318 base::ProcessHandle handle) {
319 #if defined(OS_ANDROID)
320 // Finally close the ipcfd
321 file_util::ScopedFD ipcfd_closer(&ipcfd_);
322 #endif
323 starting_ = false;
324 process_.set_handle(handle);
325 if (!handle)
326 LOG(ERROR) << "Failed to launch child process";
328 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
329 zygote_ = zygote;
330 #endif
331 if (client_) {
332 client_->OnProcessLaunched();
333 } else {
334 Terminate();
338 void Terminate() {
339 if (!process_.handle())
340 return;
342 if (!terminate_child_on_shutdown_)
343 return;
345 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So
346 // don't this on the UI/IO threads.
347 BrowserThread::PostTask(
348 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
349 base::Bind(
350 &Context::TerminateInternal,
351 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
352 zygote_,
353 #endif
354 process_.handle()));
355 process_.set_handle(base::kNullProcessHandle);
358 static void SetProcessBackgrounded(base::ProcessHandle handle,
359 bool background) {
360 base::Process process(handle);
361 process.SetProcessBackgrounded(background);
364 static void TerminateInternal(
365 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
366 bool zygote,
367 #endif
368 base::ProcessHandle handle) {
369 #if defined(OS_ANDROID)
370 LOG(INFO) << "ChromeProcess: Stopping process with handle " << handle;
371 StopChildProcess(handle);
372 #else
373 base::Process process(handle);
374 // Client has gone away, so just kill the process. Using exit code 0
375 // means that UMA won't treat this as a crash.
376 process.Terminate(RESULT_CODE_NORMAL_EXIT);
377 // On POSIX, we must additionally reap the child.
378 #if defined(OS_POSIX)
379 #if !defined(OS_MACOSX)
380 if (zygote) {
381 // If the renderer was created via a zygote, we have to proxy the reaping
382 // through the zygote process.
383 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(handle);
384 } else
385 #endif // !OS_MACOSX
387 base::EnsureProcessTerminated(handle);
389 #endif // OS_POSIX
390 process.Close();
391 #endif // defined(OS_ANDROID)
394 Client* client_;
395 BrowserThread::ID client_thread_id_;
396 base::Process process_;
397 base::TerminationStatus termination_status_;
398 int exit_code_;
399 bool starting_;
400 // Controls whether the child process should be terminated on browser
401 // shutdown. Default behavior is to terminate the child.
402 bool terminate_child_on_shutdown_;
403 #if defined(OS_ANDROID)
404 // The fd to close after creating the process.
405 int ipcfd_;
406 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
407 bool zygote_;
408 #endif
412 ChildProcessLauncher::ChildProcessLauncher(
413 #if defined(OS_WIN)
414 SandboxedProcessLauncherDelegate* delegate,
415 #elif defined(OS_POSIX)
416 bool use_zygote,
417 const base::EnvironmentVector& environ,
418 int ipcfd,
419 #endif
420 CommandLine* cmd_line,
421 int child_process_id,
422 Client* client) {
423 context_ = new Context();
424 context_->Launch(
425 #if defined(OS_WIN)
426 delegate,
427 #elif defined(OS_ANDROID)
428 ipcfd,
429 #elif defined(OS_POSIX)
430 use_zygote,
431 environ,
432 ipcfd,
433 #endif
434 cmd_line,
435 child_process_id,
436 client);
439 ChildProcessLauncher::~ChildProcessLauncher() {
440 context_->ResetClient();
443 bool ChildProcessLauncher::IsStarting() {
444 return context_->starting_;
447 base::ProcessHandle ChildProcessLauncher::GetHandle() {
448 DCHECK(!context_->starting_);
449 return context_->process_.handle();
452 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
453 bool known_dead,
454 int* exit_code) {
455 base::ProcessHandle handle = context_->process_.handle();
456 if (handle == base::kNullProcessHandle) {
457 // Process is already gone, so return the cached termination status.
458 if (exit_code)
459 *exit_code = context_->exit_code_;
460 return context_->termination_status_;
462 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
463 if (context_->zygote_) {
464 context_->termination_status_ = ZygoteHostImpl::GetInstance()->
465 GetTerminationStatus(handle, known_dead, &context_->exit_code_);
466 } else
467 #endif
469 context_->termination_status_ =
470 base::GetTerminationStatus(handle, &context_->exit_code_);
473 if (exit_code)
474 *exit_code = context_->exit_code_;
476 // POSIX: If the process crashed, then the kernel closed the socket
477 // for it and so the child has already died by the time we get
478 // here. Since GetTerminationStatus called waitpid with WNOHANG,
479 // it'll reap the process. However, if GetTerminationStatus didn't
480 // reap the child (because it was still running), we'll need to
481 // Terminate via ProcessWatcher. So we can't close the handle here.
482 if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
483 context_->process_.Close();
485 return context_->termination_status_;
488 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
489 BrowserThread::PostTask(
490 BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
491 base::Bind(
492 &ChildProcessLauncher::Context::SetProcessBackgrounded,
493 GetHandle(), background));
496 void ChildProcessLauncher::SetTerminateChildOnShutdown(
497 bool terminate_on_shutdown) {
498 if (context_.get())
499 context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
502 } // namespace content