Upstream version 9.38.198.0
[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/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"
25
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
44
45 #if defined(OS_POSIX)
46 #include "base/metrics/stats_table.h"
47 #include "base/posix/global_descriptors.h"
48 #endif
49
50 namespace content {
51
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
74         {
75   }
76
77   void Launch(
78       SandboxedProcessLauncherDelegate* delegate,
79       base::CommandLine* cmd_line,
80       int child_process_id,
81       Client* client) {
82     client_ = client;
83
84     CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
85
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));
101   }
102
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));
122     }
123   }
124 #endif
125
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;
131   }
132
133   void set_terminate_child_on_shutdown(bool terminate_on_shutdown) {
134     terminate_child_on_shutdown_ = terminate_on_shutdown;
135   }
136
137  private:
138   friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
139   friend class ChildProcessLauncher;
140
141   ~Context() {
142     Terminate();
143   }
144
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));
154     }
155   }
156
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;
166     }
167   }
168
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();
191
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);
200     }
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()));
215     }
216 #endif
217
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));
222
223     GetContentClient()->browser()->
224         GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
225                                                 &files_to_register);
226
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));
230
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);
236
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)
248     {
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));
256       }
257
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()));
265       }
266 #endif  // defined(OS_MACOSX)
267
268       // Actually launch the app.
269       base::LaunchOptions options;
270       options.environ = env;
271       options.fds_to_remap = &fds_to_map;
272
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();
283
284       // Make sure the MachBroker is running, and inform it to expect a
285       // check-in from the new process.
286       broker->EnsureRunning();
287
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);
295       }
296 #endif  // defined(OS_MACOSX)
297
298       bool launched = base::LaunchProcess(*cmd_line, options, &handle);
299       if (!launched)
300         handle = base::kNullProcessHandle;
301
302 #if defined(OS_MACOSX)
303       if (ShouldEnableBootstrapSandbox() &&
304           bootstrap_sandbox_policy != SANDBOX_TYPE_INVALID) {
305         GetBootstrapSandbox()->FinishedFork(handle);
306       }
307
308       if (launched)
309         broker->AddPlaceholderForPid(handle);
310
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)
315     }
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)
330   }
331
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";
345
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();
354       }
355     } else {
356       Terminate();
357     }
358   }
359
360   void Terminate() {
361     if (!process_.handle())
362       return;
363
364     if (!terminate_child_on_shutdown_)
365       return;
366
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);
378   }
379
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
387   }
388
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
411     {
412       base::EnsureProcessTerminated(handle);
413     }
414 #endif  // OS_POSIX
415     process.Close();
416 #endif  // defined(OS_ANDROID)
417   }
418
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
434 };
435
436
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);
448 }
449
450 ChildProcessLauncher::~ChildProcessLauncher() {
451   context_->ResetClient();
452 }
453
454 bool ChildProcessLauncher::IsStarting() {
455   return context_->starting_;
456 }
457
458 base::ProcessHandle ChildProcessLauncher::GetHandle() {
459   DCHECK(!context_->starting_);
460   return context_->process_.handle();
461 }
462
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_;
472   }
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
491   {
492 #endif
493     context_->termination_status_ =
494         base::GetTerminationStatus(handle, &context_->exit_code_);
495   }
496
497   if (exit_code)
498     *exit_code = context_->exit_code_;
499
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();
508
509   return context_->termination_status_;
510 }
511
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));
518 }
519
520 void ChildProcessLauncher::SetTerminateChildOnShutdown(
521     bool terminate_on_shutdown) {
522   if (context_.get())
523     context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
524 }
525
526 }  // namespace content