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