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/files/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
50namespace 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.
55class 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
437ChildProcessLauncher::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
450ChildProcessLauncher::~ChildProcessLauncher() {
451  context_->ResetClient();
452}
453
454bool ChildProcessLauncher::IsStarting() {
455  return context_->starting_;
456}
457
458base::ProcessHandle ChildProcessLauncher::GetHandle() {
459  DCHECK(!context_->starting_);
460  return context_->process_.handle();
461}
462
463base::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
512void 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
520void 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
527