Home | History | Annotate | Download | only in renderer_host
      1 // Copyright 2013 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/renderer_host/render_process_host_impl.h"
      6 #include "content/common/child_process_messages.h"
      7 #include "content/public/browser/render_process_host.h"
      8 #include "content/public/browser/render_process_host_observer.h"
      9 #include "content/public/browser/render_view_host.h"
     10 #include "content/public/browser/web_contents.h"
     11 #include "content/public/common/url_constants.h"
     12 #include "content/public/test/content_browser_test.h"
     13 #include "content/public/test/content_browser_test_utils.h"
     14 #include "content/shell/browser/shell.h"
     15 #include "net/test/embedded_test_server/embedded_test_server.h"
     16 
     17 namespace content {
     18 namespace {
     19 
     20 int RenderProcessHostCount() {
     21   content::RenderProcessHost::iterator hosts =
     22       content::RenderProcessHost::AllHostsIterator();
     23   int count = 0;
     24   while (!hosts.IsAtEnd()) {
     25     if (hosts.GetCurrentValue()->HasConnection())
     26       count++;
     27     hosts.Advance();
     28   }
     29   return count;
     30 }
     31 
     32 class RenderProcessHostTest : public ContentBrowserTest,
     33                               public RenderProcessHostObserver {
     34  public:
     35   RenderProcessHostTest() : process_exits_(0), host_destructions_(0) {}
     36 
     37  protected:
     38   // RenderProcessHostObserver:
     39   virtual void RenderProcessExited(RenderProcessHost* host,
     40                                    base::ProcessHandle handle,
     41                                    base::TerminationStatus status,
     42                                    int exit_code) OVERRIDE {
     43     ++process_exits_;
     44   }
     45   virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE {
     46     ++host_destructions_;
     47   }
     48 
     49   int process_exits_;
     50   int host_destructions_;
     51 };
     52 
     53 // Sometimes the renderer process's ShutdownRequest (corresponding to the
     54 // ViewMsg_WasSwappedOut from a previous navigation) doesn't arrive until after
     55 // the browser process decides to re-use the renderer for a new purpose.  This
     56 // test makes sure the browser doesn't let the renderer die in that case.  See
     57 // http://crbug.com/87176.
     58 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
     59                        ShutdownRequestFromActiveTabIgnored) {
     60   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
     61 
     62   GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
     63   NavigateToURL(shell(), test_url);
     64   RenderProcessHost* rph =
     65       shell()->web_contents()->GetRenderViewHost()->GetProcess();
     66 
     67   host_destructions_ = 0;
     68   process_exits_ = 0;
     69   rph->AddObserver(this);
     70   ChildProcessHostMsg_ShutdownRequest msg;
     71   rph->OnMessageReceived(msg);
     72 
     73   // If the RPH sends a mistaken ChildProcessMsg_Shutdown, the renderer process
     74   // will take some time to die. Wait for a second tab to load in order to give
     75   // that time to happen.
     76   NavigateToURL(CreateBrowser(), test_url);
     77 
     78   EXPECT_EQ(0, process_exits_);
     79   if (!host_destructions_)
     80     rph->RemoveObserver(this);
     81 }
     82 
     83 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
     84                        GuestsAreNotSuitableHosts) {
     85   // Set max renderers to 1 to force running out of processes.
     86   content::RenderProcessHost::SetMaxRendererProcessCount(1);
     87 
     88   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
     89 
     90   GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
     91   NavigateToURL(shell(), test_url);
     92   RenderProcessHost* rph =
     93       shell()->web_contents()->GetRenderViewHost()->GetProcess();
     94   // Make it believe it's a guest.
     95   reinterpret_cast<RenderProcessHostImpl*>(rph)->
     96       set_is_isolated_guest_for_testing(true);
     97   EXPECT_EQ(1, RenderProcessHostCount());
     98 
     99   // Navigate to a different page.
    100   GURL::Replacements replace_host;
    101   std::string host_str("localhost");  // Must stay in scope with replace_host.
    102   replace_host.SetHostStr(host_str);
    103   GURL another_url = embedded_test_server()->GetURL("/simple_page.html");
    104   another_url = another_url.ReplaceComponents(replace_host);
    105   NavigateToURL(CreateBrowser(), another_url);
    106 
    107   // Expect that we got another process (the guest renderer was not reused).
    108   EXPECT_EQ(2, RenderProcessHostCount());
    109 }
    110 
    111 class ShellCloser : public RenderProcessHostObserver {
    112  public:
    113   ShellCloser(Shell* shell, std::string* logging_string)
    114       : shell_(shell), logging_string_(logging_string) {}
    115 
    116  protected:
    117   // RenderProcessHostObserver:
    118   virtual void RenderProcessExited(RenderProcessHost* host,
    119                                    base::ProcessHandle handle,
    120                                    base::TerminationStatus status,
    121                                    int exit_code) OVERRIDE {
    122     logging_string_->append("ShellCloser::RenderProcessExited ");
    123     shell_->Close();
    124   }
    125 
    126   virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE {
    127     logging_string_->append("ShellCloser::RenderProcessHostDestroyed ");
    128   }
    129 
    130   Shell* shell_;
    131   std::string* logging_string_;
    132 };
    133 
    134 class ObserverLogger : public RenderProcessHostObserver {
    135  public:
    136   explicit ObserverLogger(std::string* logging_string)
    137       : logging_string_(logging_string), host_destroyed_(false) {}
    138 
    139   bool host_destroyed() { return host_destroyed_; }
    140 
    141  protected:
    142   // RenderProcessHostObserver:
    143   virtual void RenderProcessExited(RenderProcessHost* host,
    144                                    base::ProcessHandle handle,
    145                                    base::TerminationStatus status,
    146                                    int exit_code) OVERRIDE {
    147     logging_string_->append("ObserverLogger::RenderProcessExited ");
    148   }
    149 
    150   virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE {
    151     logging_string_->append("ObserverLogger::RenderProcessHostDestroyed ");
    152     host_destroyed_ = true;
    153   }
    154 
    155   std::string* logging_string_;
    156   bool host_destroyed_;
    157 };
    158 
    159 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
    160                        AllProcessExitedCallsBeforeAnyHostDestroyedCalls) {
    161   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    162 
    163   GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
    164   NavigateToURL(shell(), test_url);
    165 
    166   std::string logging_string;
    167   ShellCloser shell_closer(shell(), &logging_string);
    168   ObserverLogger observer_logger(&logging_string);
    169   RenderProcessHost* rph =
    170       shell()->web_contents()->GetRenderViewHost()->GetProcess();
    171 
    172   // Ensure that the ShellCloser observer is first, so that it will have first
    173   // dibs on the ProcessExited callback.
    174   rph->AddObserver(&shell_closer);
    175   rph->AddObserver(&observer_logger);
    176 
    177   // This will crash the render process, and start all the callbacks.
    178   NavigateToURL(shell(), GURL(kChromeUICrashURL));
    179 
    180   // The key here is that all the RenderProcessExited callbacks precede all the
    181   // RenderProcessHostDestroyed callbacks.
    182   EXPECT_EQ("ShellCloser::RenderProcessExited "
    183             "ObserverLogger::RenderProcessExited "
    184             "ShellCloser::RenderProcessHostDestroyed "
    185             "ObserverLogger::RenderProcessHostDestroyed ", logging_string);
    186 
    187   // If the test fails, and somehow the RPH is still alive somehow, at least
    188   // deregister the observers so that the test fails and doesn't also crash.
    189   if (!observer_logger.host_destroyed()) {
    190     rph->RemoveObserver(&shell_closer);
    191     rph->RemoveObserver(&observer_logger);
    192   }
    193 }
    194 
    195 }  // namespace
    196 }  // namespace content
    197