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 virtual void RenderProcessExited(RenderProcessHost* host,
46 base::ProcessHandle handle,
47 base::TerminationStatus status,
48 int exit_code) OVERRIDE {
51 virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE {
56 int host_destructions_;
59 // Sometimes the renderer process's ShutdownRequest (corresponding to the
60 // ViewMsg_WasSwappedOut from a previous navigation) doesn't arrive until after
61 // the browser process decides to re-use the renderer for a new purpose. This
62 // test makes sure the browser doesn't let the renderer die in that case. See
63 // http://crbug.com/87176.
64 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
65 ShutdownRequestFromActiveTabIgnored) {
66 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
68 GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
69 NavigateToURL(shell(), test_url);
70 RenderProcessHost* rph =
71 shell()->web_contents()->GetRenderViewHost()->GetProcess();
73 host_destructions_ = 0;
75 rph->AddObserver(this);
76 ChildProcessHostMsg_ShutdownRequest msg;
77 rph->OnMessageReceived(msg);
79 // If the RPH sends a mistaken ChildProcessMsg_Shutdown, the renderer process
80 // will take some time to die. Wait for a second tab to load in order to give
81 // that time to happen.
82 NavigateToURL(CreateBrowser(), test_url);
84 EXPECT_EQ(0, process_exits_);
85 if (!host_destructions_)
86 rph->RemoveObserver(this);
89 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
90 GuestsAreNotSuitableHosts) {
91 // Set max renderers to 1 to force running out of processes.
92 content::RenderProcessHost::SetMaxRendererProcessCount(1);
94 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
96 GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
97 NavigateToURL(shell(), test_url);
98 RenderProcessHost* rph =
99 shell()->web_contents()->GetRenderViewHost()->GetProcess();
100 // Make it believe it's a guest.
101 reinterpret_cast<RenderProcessHostImpl*>(rph)->
102 set_is_isolated_guest_for_testing(true);
103 EXPECT_EQ(1, RenderProcessHostCount());
105 // Navigate to a different page.
106 GURL::Replacements replace_host;
107 std::string host_str("localhost"); // Must stay in scope with replace_host.
108 replace_host.SetHostStr(host_str);
109 GURL another_url = embedded_test_server()->GetURL("/simple_page.html");
110 another_url = another_url.ReplaceComponents(replace_host);
111 NavigateToURL(CreateBrowser(), another_url);
113 // Expect that we got another process (the guest renderer was not reused).
114 EXPECT_EQ(2, RenderProcessHostCount());
117 class ShellCloser : public RenderProcessHostObserver {
119 ShellCloser(Shell* shell, std::string* logging_string)
120 : shell_(shell), logging_string_(logging_string) {}
123 // RenderProcessHostObserver:
124 virtual void RenderProcessExited(RenderProcessHost* host,
125 base::ProcessHandle handle,
126 base::TerminationStatus status,
127 int exit_code) OVERRIDE {
128 logging_string_->append("ShellCloser::RenderProcessExited ");
132 virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE {
133 logging_string_->append("ShellCloser::RenderProcessHostDestroyed ");
137 std::string* logging_string_;
140 class ObserverLogger : public RenderProcessHostObserver {
142 explicit ObserverLogger(std::string* logging_string)
143 : logging_string_(logging_string), host_destroyed_(false) {}
145 bool host_destroyed() { return host_destroyed_; }
148 // RenderProcessHostObserver:
149 virtual void RenderProcessExited(RenderProcessHost* host,
150 base::ProcessHandle handle,
151 base::TerminationStatus status,
152 int exit_code) OVERRIDE {
153 logging_string_->append("ObserverLogger::RenderProcessExited ");
156 virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE {
157 logging_string_->append("ObserverLogger::RenderProcessHostDestroyed ");
158 host_destroyed_ = true;
161 std::string* logging_string_;
162 bool host_destroyed_;
165 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
166 AllProcessExitedCallsBeforeAnyHostDestroyedCalls) {
167 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
169 GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
170 NavigateToURL(shell(), test_url);
172 std::string logging_string;
173 ShellCloser shell_closer(shell(), &logging_string);
174 ObserverLogger observer_logger(&logging_string);
175 RenderProcessHost* rph =
176 shell()->web_contents()->GetRenderViewHost()->GetProcess();
178 // Ensure that the ShellCloser observer is first, so that it will have first
179 // dibs on the ProcessExited callback.
180 rph->AddObserver(&shell_closer);
181 rph->AddObserver(&observer_logger);
183 // This will crash the render process, and start all the callbacks.
184 NavigateToURL(shell(), GURL(kChromeUICrashURL));
186 // The key here is that all the RenderProcessExited callbacks precede all the
187 // RenderProcessHostDestroyed callbacks.
188 EXPECT_EQ("ShellCloser::RenderProcessExited "
189 "ObserverLogger::RenderProcessExited "
190 "ShellCloser::RenderProcessHostDestroyed "
191 "ObserverLogger::RenderProcessHostDestroyed ", logging_string);
193 // If the test fails, and somehow the RPH is still alive somehow, at least
194 // deregister the observers so that the test fails and doesn't also crash.
195 if (!observer_logger.host_destroyed()) {
196 rph->RemoveObserver(&shell_closer);
197 rph->RemoveObserver(&observer_logger);
202 // Provides functionality to test renderer processes with the Win32K lockdown
203 // process mitigation.
204 class Win32KLockdownRendererProcessHostTest : public RenderProcessHostTest {
206 Win32KLockdownRendererProcessHostTest() {}
208 virtual ~Win32KLockdownRendererProcessHostTest() {}
211 virtual void SetUp() OVERRIDE {
212 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
213 command_line->AppendSwitch(switches::kEnableWin32kRendererLockDown);
214 RenderProcessHostTest::SetUp();
218 DISALLOW_COPY_AND_ASSIGN(Win32KLockdownRendererProcessHostTest);
221 // Tests whether navigation requests with the Win32K lockdown mitigation set
223 IN_PROC_BROWSER_TEST_F(Win32KLockdownRendererProcessHostTest,
224 RendererWin32KLockdownNavigationTest) {
225 if (base::win::GetVersion() < base::win::VERSION_WIN8)
228 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
230 GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
231 NavigateToURL(shell(), test_url);
233 EXPECT_EQ(1, RenderProcessHostCount());
234 EXPECT_EQ(0, process_exits_);
239 } // namespace content