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 "base/command_line.h"
6 #include "content/browser/renderer_host/render_process_host_impl.h"
7 #include "content/common/child_process_messages.h"
8 #include "content/public/browser/render_process_host.h"
9 #include "content/public/browser/render_process_host_observer.h"
10 #include "content/public/browser/render_view_host.h"
11 #include "content/public/browser/web_contents.h"
12 #include "content/public/common/content_switches.h"
13 #include "content/public/common/url_constants.h"
14 #include "content/public/test/content_browser_test.h"
15 #include "content/public/test/content_browser_test_utils.h"
16 #include "content/shell/browser/shell.h"
17 #include "net/test/embedded_test_server/embedded_test_server.h"
20 #include "base/win/windows_version.h"
26 int RenderProcessHostCount() {
27 content::RenderProcessHost::iterator hosts
=
28 content::RenderProcessHost::AllHostsIterator();
30 while (!hosts
.IsAtEnd()) {
31 if (hosts
.GetCurrentValue()->HasConnection())
38 class RenderProcessHostTest
: public ContentBrowserTest
,
39 public RenderProcessHostObserver
{
41 RenderProcessHostTest() : process_exits_(0), host_destructions_(0) {}
44 // RenderProcessHostObserver:
45 void RenderProcessExited(RenderProcessHost
* host
,
46 base::TerminationStatus status
,
47 int exit_code
) override
{
50 void RenderProcessHostDestroyed(RenderProcessHost
* host
) override
{
55 int host_destructions_
;
58 // Sometimes the renderer process's ShutdownRequest (corresponding to the
59 // ViewMsg_WasSwappedOut from a previous navigation) doesn't arrive until after
60 // the browser process decides to re-use the renderer for a new purpose. This
61 // test makes sure the browser doesn't let the renderer die in that case. See
62 // http://crbug.com/87176.
63 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest
,
64 ShutdownRequestFromActiveTabIgnored
) {
65 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
67 GURL test_url
= embedded_test_server()->GetURL("/simple_page.html");
68 NavigateToURL(shell(), test_url
);
69 RenderProcessHost
* rph
=
70 shell()->web_contents()->GetRenderViewHost()->GetProcess();
72 host_destructions_
= 0;
74 rph
->AddObserver(this);
75 ChildProcessHostMsg_ShutdownRequest msg
;
76 rph
->OnMessageReceived(msg
);
78 // If the RPH sends a mistaken ChildProcessMsg_Shutdown, the renderer process
79 // will take some time to die. Wait for a second tab to load in order to give
80 // that time to happen.
81 NavigateToURL(CreateBrowser(), test_url
);
83 EXPECT_EQ(0, process_exits_
);
84 if (!host_destructions_
)
85 rph
->RemoveObserver(this);
88 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest
,
89 GuestsAreNotSuitableHosts
) {
90 // Set max renderers to 1 to force running out of processes.
91 content::RenderProcessHost::SetMaxRendererProcessCount(1);
93 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
95 GURL test_url
= embedded_test_server()->GetURL("/simple_page.html");
96 NavigateToURL(shell(), test_url
);
97 RenderProcessHost
* rph
=
98 shell()->web_contents()->GetRenderViewHost()->GetProcess();
99 // Make it believe it's a guest.
100 reinterpret_cast<RenderProcessHostImpl
*>(rph
)->
101 set_is_isolated_guest_for_testing(true);
102 EXPECT_EQ(1, RenderProcessHostCount());
104 // Navigate to a different page.
105 GURL::Replacements replace_host
;
106 replace_host
.SetHostStr("localhost");
107 GURL another_url
= embedded_test_server()->GetURL("/simple_page.html");
108 another_url
= another_url
.ReplaceComponents(replace_host
);
109 NavigateToURL(CreateBrowser(), another_url
);
111 // Expect that we got another process (the guest renderer was not reused).
112 EXPECT_EQ(2, RenderProcessHostCount());
115 class ShellCloser
: public RenderProcessHostObserver
{
117 ShellCloser(Shell
* shell
, std::string
* logging_string
)
118 : shell_(shell
), logging_string_(logging_string
) {}
121 // RenderProcessHostObserver:
122 void RenderProcessExited(RenderProcessHost
* host
,
123 base::TerminationStatus status
,
124 int exit_code
) override
{
125 logging_string_
->append("ShellCloser::RenderProcessExited ");
129 void RenderProcessHostDestroyed(RenderProcessHost
* host
) override
{
130 logging_string_
->append("ShellCloser::RenderProcessHostDestroyed ");
134 std::string
* logging_string_
;
137 class ObserverLogger
: public RenderProcessHostObserver
{
139 explicit ObserverLogger(std::string
* logging_string
)
140 : logging_string_(logging_string
), host_destroyed_(false) {}
142 bool host_destroyed() { return host_destroyed_
; }
145 // RenderProcessHostObserver:
146 void RenderProcessExited(RenderProcessHost
* host
,
147 base::TerminationStatus status
,
148 int exit_code
) override
{
149 logging_string_
->append("ObserverLogger::RenderProcessExited ");
152 void RenderProcessHostDestroyed(RenderProcessHost
* host
) override
{
153 logging_string_
->append("ObserverLogger::RenderProcessHostDestroyed ");
154 host_destroyed_
= true;
157 std::string
* logging_string_
;
158 bool host_destroyed_
;
161 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest
,
162 AllProcessExitedCallsBeforeAnyHostDestroyedCalls
) {
163 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
165 GURL test_url
= embedded_test_server()->GetURL("/simple_page.html");
166 NavigateToURL(shell(), test_url
);
168 std::string logging_string
;
169 ShellCloser
shell_closer(shell(), &logging_string
);
170 ObserverLogger
observer_logger(&logging_string
);
171 RenderProcessHost
* rph
=
172 shell()->web_contents()->GetRenderViewHost()->GetProcess();
174 // Ensure that the ShellCloser observer is first, so that it will have first
175 // dibs on the ProcessExited callback.
176 rph
->AddObserver(&shell_closer
);
177 rph
->AddObserver(&observer_logger
);
179 // This will crash the render process, and start all the callbacks.
180 // We can't use NavigateToURL here since it accesses the shell() after
181 // navigating, which the shell_closer deletes.
182 NavigateToURLBlockUntilNavigationsComplete(
183 shell(), GURL(kChromeUICrashURL
), 1);
185 // The key here is that all the RenderProcessExited callbacks precede all the
186 // RenderProcessHostDestroyed callbacks.
187 EXPECT_EQ("ShellCloser::RenderProcessExited "
188 "ObserverLogger::RenderProcessExited "
189 "ShellCloser::RenderProcessHostDestroyed "
190 "ObserverLogger::RenderProcessHostDestroyed ", logging_string
);
192 // If the test fails, and somehow the RPH is still alive somehow, at least
193 // deregister the observers so that the test fails and doesn't also crash.
194 if (!observer_logger
.host_destroyed()) {
195 rph
->RemoveObserver(&shell_closer
);
196 rph
->RemoveObserver(&observer_logger
);
201 // Provides functionality to test renderer processes with the Win32K lockdown
202 // process mitigation.
203 class Win32KLockdownRendererProcessHostTest
: public RenderProcessHostTest
{
205 Win32KLockdownRendererProcessHostTest() {}
207 virtual ~Win32KLockdownRendererProcessHostTest() {}
210 virtual void SetUp() override
{
211 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
212 command_line
->AppendSwitch(switches::kEnableWin32kRendererLockDown
);
213 RenderProcessHostTest::SetUp();
217 DISALLOW_COPY_AND_ASSIGN(Win32KLockdownRendererProcessHostTest
);
220 // Tests whether navigation requests with the Win32K lockdown mitigation set
222 IN_PROC_BROWSER_TEST_F(Win32KLockdownRendererProcessHostTest
,
223 RendererWin32KLockdownNavigationTest
) {
224 if (base::win::GetVersion() < base::win::VERSION_WIN8
)
227 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
229 GURL test_url
= embedded_test_server()->GetURL("/simple_page.html");
230 NavigateToURL(shell(), test_url
);
232 EXPECT_EQ(1, RenderProcessHostCount());
233 EXPECT_EQ(0, process_exits_
);
238 } // namespace content