OLD | NEW |
| (Empty) |
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 "base/bind.h" | |
6 #include "base/bind_helpers.h" | |
7 #include "base/command_line.h" | |
8 #include "base/process.h" | |
9 #include "chrome/browser/ui/browser.h" | |
10 #include "chrome/browser/ui/browser_commands.h" | |
11 #include "chrome/browser/ui/browser_tabstrip.h" | |
12 #include "chrome/browser/ui/singleton_tabs.h" | |
13 #include "chrome/test/base/in_process_browser_test.h" | |
14 #include "chrome/test/base/ui_test_utils.h" | |
15 #include "content/browser/renderer_host/render_process_host_impl.h" | |
16 #include "content/browser/web_contents/web_contents_impl.h" | |
17 #include "content/common/test_url_constants.h" | |
18 #include "content/public/browser/browser_thread.h" | |
19 #include "content/public/common/content_switches.h" | |
20 | |
21 using content::WebContents; | |
22 | |
23 void PostQuit(MessageLoop* loop) { | |
24 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | |
25 } | |
26 | |
27 class RenderProcessHostTest : public InProcessBrowserTest { | |
28 public: | |
29 RenderProcessHostTest() {} | |
30 | |
31 int RenderProcessHostCount() { | |
32 content::RenderProcessHost::iterator hosts = | |
33 content::RenderProcessHost::AllHostsIterator(); | |
34 int count = 0; | |
35 while (!hosts.IsAtEnd()) { | |
36 if (hosts.GetCurrentValue()->HasConnection()) | |
37 count++; | |
38 hosts.Advance(); | |
39 } | |
40 return count; | |
41 } | |
42 | |
43 // Show a tab, activating the current one if there is one, and wait for | |
44 // the renderer process to be created or foregrounded, returning the process | |
45 // handle. | |
46 base::ProcessHandle ShowSingletonTab(const GURL& page) { | |
47 chrome::ShowSingletonTab(browser(), page); | |
48 WebContents* wc = chrome::GetActiveWebContents(browser()); | |
49 CHECK(wc->GetURL() == page); | |
50 | |
51 // Ensure that the backgrounding / foregrounding gets a chance to run. | |
52 content::BrowserThread::PostTaskAndReply( | |
53 content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | |
54 base::Bind(&base::DoNothing), MessageLoop::QuitClosure()); | |
55 MessageLoop::current()->Run(); | |
56 | |
57 return wc->GetRenderProcessHost()->GetHandle(); | |
58 } | |
59 | |
60 // When we hit the max number of renderers, verify that the way we do process | |
61 // sharing behaves correctly. In particular, this test is verifying that even | |
62 // when we hit the max process limit, that renderers of each type will wind up | |
63 // in a process of that type, even if that means creating a new process. | |
64 void TestProcessOverflow() { | |
65 int tab_count = 1; | |
66 int host_count = 1; | |
67 WebContents* tab1 = NULL; | |
68 WebContents* tab2 = NULL; | |
69 content::RenderProcessHost* rph1 = NULL; | |
70 content::RenderProcessHost* rph2 = NULL; | |
71 content::RenderProcessHost* rph3 = NULL; | |
72 | |
73 // Change the first tab to be the new tab page (TYPE_WEBUI). | |
74 GURL newtab(content::kTestNewTabURL); | |
75 ui_test_utils::NavigateToURL(browser(), newtab); | |
76 EXPECT_EQ(tab_count, browser()->tab_count()); | |
77 tab1 = chrome::GetWebContentsAt(browser(), tab_count - 1); | |
78 rph1 = tab1->GetRenderProcessHost(); | |
79 EXPECT_EQ(tab1->GetURL(), newtab); | |
80 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
81 | |
82 // Create a new TYPE_TABBED tab. It should be in its own process. | |
83 GURL page1("data:text/html,hello world1"); | |
84 chrome::ShowSingletonTab(browser(), page1); | |
85 if (browser()->tab_count() == tab_count) | |
86 ui_test_utils::WaitForNewTab(browser()); | |
87 tab_count++; | |
88 host_count++; | |
89 EXPECT_EQ(tab_count, browser()->tab_count()); | |
90 tab1 = chrome::GetWebContentsAt(browser(), tab_count - 1); | |
91 rph2 = tab1->GetRenderProcessHost(); | |
92 EXPECT_EQ(tab1->GetURL(), page1); | |
93 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
94 EXPECT_NE(rph1, rph2); | |
95 | |
96 // Create another TYPE_TABBED tab. It should share the previous process. | |
97 GURL page2("data:text/html,hello world2"); | |
98 chrome::ShowSingletonTab(browser(), page2); | |
99 if (browser()->tab_count() == tab_count) | |
100 ui_test_utils::WaitForNewTab(browser()); | |
101 tab_count++; | |
102 EXPECT_EQ(tab_count, browser()->tab_count()); | |
103 tab2 = chrome::GetWebContentsAt(browser(), tab_count - 1); | |
104 EXPECT_EQ(tab2->GetURL(), page2); | |
105 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
106 EXPECT_EQ(tab2->GetRenderProcessHost(), rph2); | |
107 | |
108 // Create another TYPE_WEBUI tab. It should share the process with newtab. | |
109 // Note: intentionally create this tab after the TYPE_TABBED tabs to | |
110 // exercise bug 43448 where extension and WebUI tabs could get combined into | |
111 // normal renderers. | |
112 GURL history(content::kTestHistoryURL); | |
113 chrome::ShowSingletonTab(browser(), history); | |
114 if (browser()->tab_count() == tab_count) | |
115 ui_test_utils::WaitForNewTab(browser()); | |
116 tab_count++; | |
117 EXPECT_EQ(tab_count, browser()->tab_count()); | |
118 tab2 = chrome::GetWebContentsAt(browser(), tab_count - 1); | |
119 EXPECT_EQ(tab2->GetURL(), history); | |
120 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
121 EXPECT_EQ(tab2->GetRenderProcessHost(), rph1); | |
122 | |
123 // Create a TYPE_EXTENSION tab. It should be in its own process. | |
124 // (the bookmark manager is implemented as an extension) | |
125 GURL bookmarks(content::kTestBookmarksURL); | |
126 chrome::ShowSingletonTab(browser(), bookmarks); | |
127 if (browser()->tab_count() == tab_count) | |
128 ui_test_utils::WaitForNewTab(browser()); | |
129 tab_count++; | |
130 host_count++; | |
131 EXPECT_EQ(tab_count, browser()->tab_count()); | |
132 tab1 = chrome::GetWebContentsAt(browser(), tab_count - 1); | |
133 rph3 = tab1->GetRenderProcessHost(); | |
134 EXPECT_EQ(tab1->GetURL(), bookmarks); | |
135 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
136 EXPECT_NE(rph1, rph3); | |
137 EXPECT_NE(rph2, rph3); | |
138 } | |
139 }; | |
140 | |
141 | |
142 class RenderProcessHostTestWithCommandLine : public RenderProcessHostTest { | |
143 protected: | |
144 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
145 command_line->AppendSwitchASCII(switches::kRendererProcessLimit, "1"); | |
146 } | |
147 }; | |
148 | |
149 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ProcessPerTab) { | |
150 // Set max renderers to 1 to force running out of processes. | |
151 content::RenderProcessHost::SetMaxRendererProcessCount(1); | |
152 | |
153 CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
154 parsed_command_line.AppendSwitch(switches::kProcessPerTab); | |
155 | |
156 int tab_count = 1; | |
157 int host_count = 1; | |
158 | |
159 // Change the first tab to be the new tab page (TYPE_WEBUI). | |
160 GURL newtab(content::kTestNewTabURL); | |
161 ui_test_utils::NavigateToURL(browser(), newtab); | |
162 EXPECT_EQ(tab_count, browser()->tab_count()); | |
163 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
164 | |
165 // Create a new TYPE_TABBED tab. It should be in its own process. | |
166 GURL page1("data:text/html,hello world1"); | |
167 chrome::ShowSingletonTab(browser(), page1); | |
168 if (browser()->tab_count() == tab_count) | |
169 ui_test_utils::WaitForNewTab(browser()); | |
170 tab_count++; | |
171 host_count++; | |
172 EXPECT_EQ(tab_count, browser()->tab_count()); | |
173 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
174 | |
175 // Create another TYPE_TABBED tab. It should share the previous process. | |
176 GURL page2("data:text/html,hello world2"); | |
177 chrome::ShowSingletonTab(browser(), page2); | |
178 if (browser()->tab_count() == tab_count) | |
179 ui_test_utils::WaitForNewTab(browser()); | |
180 tab_count++; | |
181 EXPECT_EQ(tab_count, browser()->tab_count()); | |
182 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
183 | |
184 // Create another new tab. It should share the process with the other WebUI. | |
185 chrome::NewTab(browser()); | |
186 if (browser()->tab_count() == tab_count) | |
187 ui_test_utils::WaitForNewTab(browser()); | |
188 tab_count++; | |
189 EXPECT_EQ(tab_count, browser()->tab_count()); | |
190 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
191 | |
192 // Create another new tab. It should share the process with the other WebUI. | |
193 chrome::NewTab(browser()); | |
194 if (browser()->tab_count() == tab_count) | |
195 ui_test_utils::WaitForNewTab(browser()); | |
196 tab_count++; | |
197 EXPECT_EQ(tab_count, browser()->tab_count()); | |
198 EXPECT_EQ(host_count, RenderProcessHostCount()); | |
199 } | |
200 | |
201 // We don't change process priorities on Mac or Posix because the user lacks the | |
202 // permission to raise a process' priority even after lowering it. | |
203 #if defined(OS_WIN) || defined(OS_LINUX) | |
204 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, Backgrounding) { | |
205 if (!base::Process::CanBackgroundProcesses()) { | |
206 LOG(ERROR) << "Can't background processes"; | |
207 return; | |
208 } | |
209 CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
210 parsed_command_line.AppendSwitch(switches::kProcessPerTab); | |
211 | |
212 // Change the first tab to be the new tab page (TYPE_WEBUI). | |
213 GURL newtab(content::kTestNewTabURL); | |
214 ui_test_utils::NavigateToURL(browser(), newtab); | |
215 | |
216 // Create a new tab. It should be foreground. | |
217 GURL page1("data:text/html,hello world1"); | |
218 base::ProcessHandle pid1 = ShowSingletonTab(page1); | |
219 EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded()); | |
220 | |
221 // Create another tab. It should be foreground, and the first tab should | |
222 // now be background. | |
223 GURL page2("data:text/html,hello world2"); | |
224 base::ProcessHandle pid2 = ShowSingletonTab(page2); | |
225 EXPECT_NE(pid1, pid2); | |
226 EXPECT_TRUE(base::Process(pid1).IsProcessBackgrounded()); | |
227 EXPECT_FALSE(base::Process(pid2).IsProcessBackgrounded()); | |
228 | |
229 // Navigate back to first page. It should be foreground again, and the second | |
230 // tab should be background. | |
231 EXPECT_EQ(pid1, ShowSingletonTab(page1)); | |
232 EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded()); | |
233 EXPECT_TRUE(base::Process(pid2).IsProcessBackgrounded()); | |
234 } | |
235 #endif | |
236 | |
237 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ProcessOverflow) { | |
238 // Set max renderers to 1 to force running out of processes. | |
239 content::RenderProcessHost::SetMaxRendererProcessCount(1); | |
240 TestProcessOverflow(); | |
241 } | |
242 | |
243 // Variation of the ProcessOverflow test, which is driven through command line | |
244 // parameter instead of direct function call into the class. | |
245 IN_PROC_BROWSER_TEST_F(RenderProcessHostTestWithCommandLine, ProcessOverflow) { | |
246 TestProcessOverflow(); | |
247 } | |
OLD | NEW |