OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/command_line.h" | 5 #include "base/command_line.h" |
6 #include "chrome/browser/debugger/devtools_window.h" | 6 #include "chrome/browser/debugger/devtools_window.h" |
7 #include "chrome/browser/ui/browser.h" | 7 #include "chrome/browser/ui/browser.h" |
8 #include "chrome/browser/ui/browser_commands.h" | 8 #include "chrome/browser/ui/browser_commands.h" |
| 9 #include "chrome/browser/ui/browser_tabstrip.h" |
9 #include "chrome/browser/ui/singleton_tabs.h" | 10 #include "chrome/browser/ui/singleton_tabs.h" |
10 #include "chrome/common/chrome_switches.h" | 11 #include "chrome/common/chrome_switches.h" |
11 #include "chrome/common/url_constants.h" | 12 #include "chrome/common/url_constants.h" |
12 #include "chrome/test/base/in_process_browser_test.h" | 13 #include "chrome/test/base/in_process_browser_test.h" |
13 #include "chrome/test/base/ui_test_utils.h" | 14 #include "chrome/test/base/ui_test_utils.h" |
14 #include "content/public/browser/render_process_host.h" | 15 #include "content/public/browser/render_process_host.h" |
15 #include "content/public/browser/render_view_host.h" | 16 #include "content/public/browser/render_view_host.h" |
16 #include "content/public/browser/web_contents.h" | 17 #include "content/public/browser/web_contents.h" |
17 | 18 |
18 using content::RenderViewHost; | 19 using content::RenderViewHost; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 GURL url = contents->GetURL(); | 55 GURL url = contents->GetURL(); |
55 if (url.SchemeIs(chrome::kChromeDevToolsScheme)) | 56 if (url.SchemeIs(chrome::kChromeDevToolsScheme)) |
56 return host; | 57 return host; |
57 } | 58 } |
58 } | 59 } |
59 return NULL; | 60 return NULL; |
60 } | 61 } |
61 | 62 |
62 } // namespace | 63 } // namespace |
63 | 64 |
64 typedef InProcessBrowserTest ChromeRenderProcessHostTest; | 65 class ChromeRenderProcessHostTest : public InProcessBrowserTest { |
| 66 public: |
| 67 ChromeRenderProcessHostTest() {} |
| 68 |
| 69 // Show a tab, activating the current one if there is one, and wait for |
| 70 // the renderer process to be created or foregrounded, returning the process |
| 71 // handle. |
| 72 base::ProcessHandle ShowSingletonTab(const GURL& page) { |
| 73 chrome::ShowSingletonTab(browser(), page); |
| 74 WebContents* wc = chrome::GetActiveWebContents(browser()); |
| 75 CHECK(wc->GetURL() == page); |
| 76 |
| 77 // Ensure that the backgrounding / foregrounding gets a chance to run. |
| 78 content::BrowserThread::PostTaskAndReply( |
| 79 content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| 80 base::Bind(&base::DoNothing), MessageLoop::QuitClosure()); |
| 81 MessageLoop::current()->Run(); |
| 82 |
| 83 return wc->GetRenderProcessHost()->GetHandle(); |
| 84 } |
| 85 |
| 86 // When we hit the max number of renderers, verify that the way we do process |
| 87 // sharing behaves correctly. In particular, this test is verifying that even |
| 88 // when we hit the max process limit, that renderers of each type will wind up |
| 89 // in a process of that type, even if that means creating a new process. |
| 90 void TestProcessOverflow() { |
| 91 int tab_count = 1; |
| 92 int host_count = 1; |
| 93 WebContents* tab1 = NULL; |
| 94 WebContents* tab2 = NULL; |
| 95 content::RenderProcessHost* rph1 = NULL; |
| 96 content::RenderProcessHost* rph2 = NULL; |
| 97 content::RenderProcessHost* rph3 = NULL; |
| 98 |
| 99 // Change the first tab to be the new tab page (TYPE_WEBUI). |
| 100 GURL newtab(chrome::kChromeUINewTabURL); |
| 101 ui_test_utils::NavigateToURL(browser(), newtab); |
| 102 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 103 tab1 = chrome::GetWebContentsAt(browser(), tab_count - 1); |
| 104 rph1 = tab1->GetRenderProcessHost(); |
| 105 EXPECT_EQ(tab1->GetURL(), newtab); |
| 106 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 107 |
| 108 // Create a new TYPE_TABBED tab. It should be in its own process. |
| 109 GURL page1("data:text/html,hello world1"); |
| 110 chrome::ShowSingletonTab(browser(), page1); |
| 111 if (browser()->tab_count() == tab_count) |
| 112 ui_test_utils::WaitForNewTab(browser()); |
| 113 tab_count++; |
| 114 host_count++; |
| 115 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 116 tab1 = chrome::GetWebContentsAt(browser(), tab_count - 1); |
| 117 rph2 = tab1->GetRenderProcessHost(); |
| 118 EXPECT_EQ(tab1->GetURL(), page1); |
| 119 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 120 EXPECT_NE(rph1, rph2); |
| 121 |
| 122 // Create another TYPE_TABBED tab. It should share the previous process. |
| 123 GURL page2("data:text/html,hello world2"); |
| 124 chrome::ShowSingletonTab(browser(), page2); |
| 125 if (browser()->tab_count() == tab_count) |
| 126 ui_test_utils::WaitForNewTab(browser()); |
| 127 tab_count++; |
| 128 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 129 tab2 = chrome::GetWebContentsAt(browser(), tab_count - 1); |
| 130 EXPECT_EQ(tab2->GetURL(), page2); |
| 131 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 132 EXPECT_EQ(tab2->GetRenderProcessHost(), rph2); |
| 133 |
| 134 // Create another TYPE_WEBUI tab. It should share the process with newtab. |
| 135 // Note: intentionally create this tab after the TYPE_TABBED tabs to |
| 136 // exercise bug 43448 where extension and WebUI tabs could get combined into |
| 137 // normal renderers. |
| 138 GURL history(chrome::kChromeUIHistoryURL); |
| 139 chrome::ShowSingletonTab(browser(), history); |
| 140 if (browser()->tab_count() == tab_count) |
| 141 ui_test_utils::WaitForNewTab(browser()); |
| 142 tab_count++; |
| 143 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 144 tab2 = chrome::GetWebContentsAt(browser(), tab_count - 1); |
| 145 // Use chrome://chrome/history/ since the URL gets rewritten. |
| 146 EXPECT_EQ(tab2->GetURL(), GURL("chrome://chrome/history/")); |
| 147 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 148 EXPECT_EQ(tab2->GetRenderProcessHost(), rph1); |
| 149 |
| 150 // Create a TYPE_EXTENSION tab. It should be in its own process. |
| 151 // (the bookmark manager is implemented as an extension) |
| 152 GURL bookmarks(chrome::kChromeUIBookmarksURL); |
| 153 chrome::ShowSingletonTab(browser(), bookmarks); |
| 154 if (browser()->tab_count() == tab_count) |
| 155 ui_test_utils::WaitForNewTab(browser()); |
| 156 tab_count++; |
| 157 host_count++; |
| 158 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 159 tab1 = chrome::GetWebContentsAt(browser(), tab_count - 1); |
| 160 rph3 = tab1->GetRenderProcessHost(); |
| 161 EXPECT_EQ(tab1->GetURL(), bookmarks); |
| 162 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 163 EXPECT_NE(rph1, rph3); |
| 164 EXPECT_NE(rph2, rph3); |
| 165 } |
| 166 }; |
| 167 |
| 168 |
| 169 class ChromeRenderProcessHostTestWithCommandLine |
| 170 : public ChromeRenderProcessHostTest { |
| 171 protected: |
| 172 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
| 173 command_line->AppendSwitchASCII(switches::kRendererProcessLimit, "1"); |
| 174 } |
| 175 }; |
| 176 |
| 177 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, ProcessPerTab) { |
| 178 // Set max renderers to 1 to force running out of processes. |
| 179 content::RenderProcessHost::SetMaxRendererProcessCount(1); |
| 180 |
| 181 CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| 182 parsed_command_line.AppendSwitch(switches::kProcessPerTab); |
| 183 |
| 184 int tab_count = 1; |
| 185 int host_count = 1; |
| 186 |
| 187 // Change the first tab to be the new tab page (TYPE_WEBUI). |
| 188 GURL newtab(chrome::kChromeUINewTabURL); |
| 189 ui_test_utils::NavigateToURL(browser(), newtab); |
| 190 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 191 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 192 |
| 193 // Create a new TYPE_TABBED tab. It should be in its own process. |
| 194 GURL page1("data:text/html,hello world1"); |
| 195 chrome::ShowSingletonTab(browser(), page1); |
| 196 if (browser()->tab_count() == tab_count) |
| 197 ui_test_utils::WaitForNewTab(browser()); |
| 198 tab_count++; |
| 199 host_count++; |
| 200 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 201 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 202 |
| 203 // Create another TYPE_TABBED tab. It should share the previous process. |
| 204 GURL page2("data:text/html,hello world2"); |
| 205 chrome::ShowSingletonTab(browser(), page2); |
| 206 if (browser()->tab_count() == tab_count) |
| 207 ui_test_utils::WaitForNewTab(browser()); |
| 208 tab_count++; |
| 209 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 210 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 211 |
| 212 // Create another new tab. It should share the process with the other WebUI. |
| 213 chrome::NewTab(browser()); |
| 214 if (browser()->tab_count() == tab_count) |
| 215 ui_test_utils::WaitForNewTab(browser()); |
| 216 tab_count++; |
| 217 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 218 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 219 |
| 220 // Create another new tab. It should share the process with the other WebUI. |
| 221 chrome::NewTab(browser()); |
| 222 if (browser()->tab_count() == tab_count) |
| 223 ui_test_utils::WaitForNewTab(browser()); |
| 224 tab_count++; |
| 225 EXPECT_EQ(tab_count, browser()->tab_count()); |
| 226 EXPECT_EQ(host_count, RenderProcessHostCount()); |
| 227 } |
| 228 |
| 229 // We don't change process priorities on Mac or Posix because the user lacks the |
| 230 // permission to raise a process' priority even after lowering it. |
| 231 #if defined(OS_WIN) || defined(OS_LINUX) |
| 232 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, Backgrounding) { |
| 233 if (!base::Process::CanBackgroundProcesses()) { |
| 234 LOG(ERROR) << "Can't background processes"; |
| 235 return; |
| 236 } |
| 237 CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| 238 parsed_command_line.AppendSwitch(switches::kProcessPerTab); |
| 239 |
| 240 // Change the first tab to be the new tab page (TYPE_WEBUI). |
| 241 GURL newtab(chrome::kChromeUINewTabURL); |
| 242 ui_test_utils::NavigateToURL(browser(), newtab); |
| 243 |
| 244 // Create a new tab. It should be foreground. |
| 245 GURL page1("data:text/html,hello world1"); |
| 246 base::ProcessHandle pid1 = ShowSingletonTab(page1); |
| 247 EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded()); |
| 248 |
| 249 // Create another tab. It should be foreground, and the first tab should |
| 250 // now be background. |
| 251 GURL page2("data:text/html,hello world2"); |
| 252 base::ProcessHandle pid2 = ShowSingletonTab(page2); |
| 253 EXPECT_NE(pid1, pid2); |
| 254 EXPECT_TRUE(base::Process(pid1).IsProcessBackgrounded()); |
| 255 EXPECT_FALSE(base::Process(pid2).IsProcessBackgrounded()); |
| 256 |
| 257 // Navigate back to first page. It should be foreground again, and the second |
| 258 // tab should be background. |
| 259 EXPECT_EQ(pid1, ShowSingletonTab(page1)); |
| 260 EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded()); |
| 261 EXPECT_TRUE(base::Process(pid2).IsProcessBackgrounded()); |
| 262 } |
| 263 #endif |
| 264 |
| 265 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, ProcessOverflow) { |
| 266 // Set max renderers to 1 to force running out of processes. |
| 267 content::RenderProcessHost::SetMaxRendererProcessCount(1); |
| 268 TestProcessOverflow(); |
| 269 } |
| 270 |
| 271 // Variation of the ProcessOverflow test, which is driven through command line |
| 272 // parameter instead of direct function call into the class. |
| 273 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTestWithCommandLine, |
| 274 ProcessOverflow) { |
| 275 TestProcessOverflow(); |
| 276 } |
65 | 277 |
66 // Ensure that DevTools opened to debug DevTools is launched in a separate | 278 // Ensure that DevTools opened to debug DevTools is launched in a separate |
67 // process when --process-per-tab is set. See crbug.com/69873. | 279 // process when --process-per-tab is set. See crbug.com/69873. |
68 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, | 280 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, |
69 DevToolsOnSelfInOwnProcessPPT) { | 281 DevToolsOnSelfInOwnProcessPPT) { |
70 CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | 282 CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
71 parsed_command_line.AppendSwitch(switches::kProcessPerTab); | 283 parsed_command_line.AppendSwitch(switches::kProcessPerTab); |
72 | 284 |
73 int tab_count = 1; | 285 int tab_count = 1; |
74 int host_count = 1; | 286 int host_count = 1; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 RenderViewHost* devtools = FindFirstDevToolsHost(); | 336 RenderViewHost* devtools = FindFirstDevToolsHost(); |
125 DCHECK(devtools); | 337 DCHECK(devtools); |
126 | 338 |
127 // DevTools start in a separate process. | 339 // DevTools start in a separate process. |
128 DevToolsWindow::ToggleDevToolsWindow( | 340 DevToolsWindow::ToggleDevToolsWindow( |
129 devtools, DEVTOOLS_TOGGLE_ACTION_INSPECT); | 341 devtools, DEVTOOLS_TOGGLE_ACTION_INSPECT); |
130 host_count++; | 342 host_count++; |
131 EXPECT_EQ(tab_count, browser()->tab_count()); | 343 EXPECT_EQ(tab_count, browser()->tab_count()); |
132 EXPECT_EQ(host_count, RenderProcessHostCount()); | 344 EXPECT_EQ(host_count, RenderProcessHostCount()); |
133 } | 345 } |
OLD | NEW |