Home | History | Annotate | Download | only in browser
      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     VLOG(0) << "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 if (known_dead) {
    473     context_->termination_status_ =
    474         base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_);
    475   } else {
    476 #elif defined(OS_MACOSX)
    477   if (known_dead) {
    478     context_->termination_status_ =
    479         base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_);
    480   } else {
    481 #elif defined(OS_ANDROID)
    482   if (IsChildProcessOomProtected(handle)) {
    483       context_->termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
    484   } else {
    485 #else
    486   {
    487 #endif
    488     context_->termination_status_ =
    489         base::GetTerminationStatus(handle, &context_->exit_code_);
    490   }
    491 
    492   if (exit_code)
    493     *exit_code = context_->exit_code_;
    494 
    495   // POSIX: If the process crashed, then the kernel closed the socket
    496   // for it and so the child has already died by the time we get
    497   // here. Since GetTerminationStatus called waitpid with WNOHANG,
    498   // it'll reap the process.  However, if GetTerminationStatus didn't
    499   // reap the child (because it was still running), we'll need to
    500   // Terminate via ProcessWatcher. So we can't close the handle here.
    501   if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
    502     context_->process_.Close();
    503 
    504   return context_->termination_status_;
    505 }
    506 
    507 void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
    508   BrowserThread::PostTask(
    509       BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
    510       base::Bind(
    511           &ChildProcessLauncher::Context::SetProcessBackgrounded,
    512           GetHandle(), background));
    513 }
    514 
    515 void ChildProcessLauncher::SetTerminateChildOnShutdown(
    516   bool terminate_on_shutdown) {
    517   if (context_.get())
    518     context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
    519 }
    520 
    521 }  // namespace content
    522