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