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.
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"
20 int RenderProcessHostCount() {
21 content::RenderProcessHost::iterator hosts
=
22 content::RenderProcessHost::AllHostsIterator();
24 while (!hosts
.IsAtEnd()) {
25 if (hosts
.GetCurrentValue()->HasConnection())
32 class RenderProcessHostTest
: public ContentBrowserTest
,
33 public RenderProcessHostObserver
{
35 RenderProcessHostTest() : process_exits_(0), host_destructions_(0) {}
38 // RenderProcessHostObserver:
39 virtual void RenderProcessExited(RenderProcessHost
* host
,
40 base::ProcessHandle handle
,
41 base::TerminationStatus status
,
42 int exit_code
) OVERRIDE
{
45 virtual void RenderProcessHostDestroyed(RenderProcessHost
* host
) OVERRIDE
{
50 int host_destructions_
;
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());
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();
67 host_destructions_
= 0;
69 rph
->AddObserver(this);
70 ChildProcessHostMsg_ShutdownRequest msg
;
71 rph
->OnMessageReceived(msg
);
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
);
78 EXPECT_EQ(0, process_exits_
);
79 if (!host_destructions_
)
80 rph
->RemoveObserver(this);
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);
88 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
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());
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
);
107 // Expect that we got another process (the guest renderer was not reused).
108 EXPECT_EQ(2, RenderProcessHostCount());
111 class ShellCloser
: public RenderProcessHostObserver
{
113 ShellCloser(Shell
* shell
, std::string
* logging_string
)
114 : shell_(shell
), logging_string_(logging_string
) {}
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 ");
126 virtual void RenderProcessHostDestroyed(RenderProcessHost
* host
) OVERRIDE
{
127 logging_string_
->append("ShellCloser::RenderProcessHostDestroyed ");
131 std::string
* logging_string_
;
134 class ObserverLogger
: public RenderProcessHostObserver
{
136 explicit ObserverLogger(std::string
* logging_string
)
137 : logging_string_(logging_string
), host_destroyed_(false) {}
139 bool host_destroyed() { return host_destroyed_
; }
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 ");
150 virtual void RenderProcessHostDestroyed(RenderProcessHost
* host
) OVERRIDE
{
151 logging_string_
->append("ObserverLogger::RenderProcessHostDestroyed ");
152 host_destroyed_
= true;
155 std::string
* logging_string_
;
156 bool host_destroyed_
;
159 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest
,
160 AllProcessExitedCallsBeforeAnyHostDestroyedCalls
) {
161 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
163 GURL test_url
= embedded_test_server()->GetURL("/simple_page.html");
164 NavigateToURL(shell(), test_url
);
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();
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
);
177 // This will crash the render process, and start all the callbacks.
178 NavigateToURL(shell(), GURL(kChromeUICrashURL
));
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
);
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
);
196 } // namespace content