Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(402)

Unified Diff: chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc

Issue 1214883004: Fixed the audio backgrounding bug (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed comments Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
diff --git a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
index 24c58ef9a6acd950d566e73f5f62e0f5225ad8ed..30c67742daa6e7807a84e9cc3a78382d6737dc50 100644
--- a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
+++ b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
@@ -1,533 +1,684 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/command_line.h"
-#include "base/process/process.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/devtools/devtools_window.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/singleton_tabs.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/test_switches.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host_iterator.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/test/browser_test_utils.h"
-
-using content::RenderViewHost;
-using content::RenderWidgetHost;
-using content::WebContents;
-
-namespace {
-
-int RenderProcessHostCount() {
- content::RenderProcessHost::iterator hosts =
- content::RenderProcessHost::AllHostsIterator();
- int count = 0;
- while (!hosts.IsAtEnd()) {
- if (hosts.GetCurrentValue()->HasConnection())
- count++;
- hosts.Advance();
- }
- return count;
-}
-
-WebContents* FindFirstDevToolsContents() {
- scoped_ptr<content::RenderWidgetHostIterator> widgets(
- RenderWidgetHost::GetRenderWidgetHosts());
- while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
- if (!widget->GetProcess()->HasConnection())
- continue;
- if (!widget->IsRenderView())
- continue;
- RenderViewHost* host = RenderViewHost::From(widget);
- WebContents* contents = WebContents::FromRenderViewHost(host);
- GURL url = contents->GetURL();
- if (url.SchemeIs(content::kChromeDevToolsScheme))
- return contents;
- }
- return NULL;
-}
-
-// TODO(rvargas) crbug.com/417532: Remove this code.
-base::Process ProcessFromHandle(base::ProcessHandle handle) {
-#if defined(OS_WIN)
- if (handle == GetCurrentProcess())
- return base::Process::Current();
-
- base::ProcessHandle out_handle;
- if (!::DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
- &out_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
- return base::Process();
- }
- handle = out_handle;
-#endif // defined(OS_WIN)
- return base::Process(handle);
-}
-
-} // namespace
-
-class ChromeRenderProcessHostTest : public InProcessBrowserTest {
- public:
- ChromeRenderProcessHostTest() {}
-
- // Show a tab, activating the current one if there is one, and wait for
- // the renderer process to be created or foregrounded, returning the process
- // handle.
- base::Process ShowSingletonTab(const GURL& page) {
- chrome::ShowSingletonTab(browser(), page);
- WebContents* wc = browser()->tab_strip_model()->GetActiveWebContents();
- CHECK(wc->GetURL() == page);
-
- WaitForLauncherThread();
- WaitForMessageProcessing(wc);
- return ProcessFromHandle(wc->GetRenderProcessHost()->GetHandle());
- }
-
- // Loads the given url in a new background tab and returns the handle of its
- // renderer.
- base::Process OpenBackgroundTab(const GURL& page) {
- ui_test_utils::NavigateToURLWithDisposition(browser(), page,
- NEW_BACKGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-
- TabStripModel* tab_strip = browser()->tab_strip_model();
- WebContents* wc = tab_strip->GetWebContentsAt(
- tab_strip->active_index() + 1);
- CHECK(wc->GetVisibleURL() == page);
-
- WaitForLauncherThread();
- WaitForMessageProcessing(wc);
- return ProcessFromHandle(wc->GetRenderProcessHost()->GetHandle());
- }
-
- // Ensures that the backgrounding / foregrounding gets a chance to run.
- void WaitForLauncherThread() {
- content::BrowserThread::PostTaskAndReply(
- content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
- base::Bind(&base::DoNothing), base::MessageLoop::QuitClosure());
- base::MessageLoop::current()->Run();
- }
-
- // Implicitly waits for the renderer process associated with the specified
- // WebContents to process outstanding IPC messages by running some JavaScript
- // and waiting for the result.
- void WaitForMessageProcessing(WebContents* wc) {
- bool result = false;
- ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
- wc, "window.domAutomationController.send(true);", &result));
- ASSERT_TRUE(result);
- }
-
- // When we hit the max number of renderers, verify that the way we do process
- // sharing behaves correctly. In particular, this test is verifying that even
- // when we hit the max process limit, that renderers of each type will wind up
- // in a process of that type, even if that means creating a new process.
- void TestProcessOverflow() {
- int tab_count = 1;
- int host_count = 1;
- WebContents* tab1 = NULL;
- WebContents* tab2 = NULL;
- content::RenderProcessHost* rph1 = NULL;
- content::RenderProcessHost* rph2 = NULL;
- content::RenderProcessHost* rph3 = NULL;
-
- // Change the first tab to be the omnibox page (TYPE_WEBUI).
- GURL omnibox(chrome::kChromeUIOmniboxURL);
- ui_test_utils::NavigateToURL(browser(), omnibox);
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
- rph1 = tab1->GetRenderProcessHost();
- EXPECT_EQ(omnibox, tab1->GetURL());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- // Create a new TYPE_TABBED tab. It should be in its own process.
- GURL page1("data:text/html,hello world1");
-
- ui_test_utils::WindowedTabAddedNotificationObserver observer1(
- content::NotificationService::AllSources());
- chrome::ShowSingletonTab(browser(), page1);
- observer1.Wait();
-
- tab_count++;
- host_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
- rph2 = tab1->GetRenderProcessHost();
- EXPECT_EQ(tab1->GetURL(), page1);
- EXPECT_EQ(host_count, RenderProcessHostCount());
- EXPECT_NE(rph1, rph2);
-
- // Create another TYPE_TABBED tab. It should share the previous process.
- GURL page2("data:text/html,hello world2");
- ui_test_utils::WindowedTabAddedNotificationObserver observer2(
- content::NotificationService::AllSources());
- chrome::ShowSingletonTab(browser(), page2);
- observer2.Wait();
- tab_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
- EXPECT_EQ(tab2->GetURL(), page2);
- EXPECT_EQ(host_count, RenderProcessHostCount());
- EXPECT_EQ(tab2->GetRenderProcessHost(), rph2);
-
- // Create another TYPE_WEBUI tab. It should share the process with omnibox.
- // Note: intentionally create this tab after the TYPE_TABBED tabs to
- // exercise bug 43448 where extension and WebUI tabs could get combined into
- // normal renderers.
- GURL history(chrome::kChromeUIHistoryURL);
- ui_test_utils::WindowedTabAddedNotificationObserver observer3(
- content::NotificationService::AllSources());
- chrome::ShowSingletonTab(browser(), history);
- observer3.Wait();
- tab_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
- EXPECT_EQ(tab2->GetURL(), GURL(history));
- EXPECT_EQ(host_count, RenderProcessHostCount());
- EXPECT_EQ(tab2->GetRenderProcessHost(), rph1);
-
- // Create a TYPE_EXTENSION tab. It should be in its own process.
- // (the bookmark manager is implemented as an extension)
- GURL bookmarks(chrome::kChromeUIBookmarksURL);
- ui_test_utils::WindowedTabAddedNotificationObserver observer4(
- content::NotificationService::AllSources());
- chrome::ShowSingletonTab(browser(), bookmarks);
- observer4.Wait();
- tab_count++;
- host_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
- rph3 = tab1->GetRenderProcessHost();
- EXPECT_EQ(tab1->GetURL(), bookmarks);
- EXPECT_EQ(host_count, RenderProcessHostCount());
- EXPECT_NE(rph1, rph3);
- EXPECT_NE(rph2, rph3);
- }
-};
-
-
-class ChromeRenderProcessHostTestWithCommandLine
- : public ChromeRenderProcessHostTest {
- protected:
- void SetUpCommandLine(base::CommandLine* command_line) override {
- command_line->AppendSwitchASCII(switches::kRendererProcessLimit, "1");
- }
-};
-
-// Disable on Mac and Windows due to ongoing flakiness. (crbug.com/442785)
-#if defined(OS_MACOSX) || defined(OS_WIN)
-#define MAYBE_ProcessPerTab DISABLED_ProcessPerTab
-#else
-#define MAYBE_ProcessPerTab ProcessPerTab
-#endif
-
-IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, MAYBE_ProcessPerTab) {
- // Set max renderers to 1 to force running out of processes.
- content::RenderProcessHost::SetMaxRendererProcessCount(1);
-
- base::CommandLine& parsed_command_line =
- *base::CommandLine::ForCurrentProcess();
- parsed_command_line.AppendSwitch(switches::kProcessPerTab);
-
- int tab_count = 1;
- int host_count = 1;
-
- // Change the first tab to be the new tab page (TYPE_WEBUI).
- GURL omnibox(chrome::kChromeUIOmniboxURL);
- ui_test_utils::NavigateToURL(browser(), omnibox);
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- // Create a new TYPE_TABBED tab. It should be in its own process.
- GURL page1("data:text/html,hello world1");
- ui_test_utils::WindowedTabAddedNotificationObserver observer1(
- content::NotificationService::AllSources());
- chrome::ShowSingletonTab(browser(), page1);
- observer1.Wait();
- tab_count++;
- host_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- // Create another TYPE_TABBED tab. It should share the previous process.
- GURL page2("data:text/html,hello world2");
- ui_test_utils::WindowedTabAddedNotificationObserver observer2(
- content::NotificationService::AllSources());
- chrome::ShowSingletonTab(browser(), page2);
- observer2.Wait();
- tab_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- // Create another omnibox tab. It should share the process with the other
- // WebUI.
- ui_test_utils::NavigateToURLWithDisposition(
- browser(), omnibox, NEW_FOREGROUND_TAB,
- ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
- tab_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- // Create another omnibox tab. It should share the process with the other
- // WebUI.
- ui_test_utils::NavigateToURLWithDisposition(
- browser(), omnibox, NEW_FOREGROUND_TAB,
- ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
- tab_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-}
-
-// We don't change process priorities on Mac or Posix because the user lacks the
-// permission to raise a process' priority even after lowering it.
-#if defined(OS_WIN) || defined(OS_LINUX)
-#if defined(OS_WIN)
-// Flaky test: crbug.com/394368
-#define MAYBE_Backgrounding DISABLED_Backgrounding
-#else
-#define MAYBE_Backgrounding Backgrounding
-#endif
-IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, MAYBE_Backgrounding) {
- if (!base::Process::CanBackgroundProcesses()) {
- LOG(ERROR) << "Can't background processes";
- return;
- }
- base::CommandLine& parsed_command_line =
- *base::CommandLine::ForCurrentProcess();
- parsed_command_line.AppendSwitch(switches::kProcessPerTab);
-
- // Change the first tab to be the omnibox page (TYPE_WEBUI).
- GURL omnibox(chrome::kChromeUIOmniboxURL);
- ui_test_utils::NavigateToURL(browser(), omnibox);
-
- // Create a new tab. It should be foreground.
- GURL page1("data:text/html,hello world1");
- base::Process process1 = ShowSingletonTab(page1);
- ASSERT_TRUE(process1.IsValid());
- EXPECT_FALSE(process1.IsProcessBackgrounded());
-
- // Create another tab. It should be foreground, and the first tab should
- // now be background.
- GURL page2("data:text/html,hello world2");
- base::Process process2 = ShowSingletonTab(page2);
- ASSERT_TRUE(process2.IsValid());
- EXPECT_NE(process1.Pid(), process2.Pid());
- EXPECT_TRUE(process1.IsProcessBackgrounded());
- EXPECT_FALSE(process2.IsProcessBackgrounded());
-
- // Load another tab in background. The renderer of the new tab should be
- // backgrounded, while visibility of the other renderers should not change.
- GURL page3("data:text/html,hello world3");
- base::Process process3 = OpenBackgroundTab(page3);
- ASSERT_TRUE(process3.IsValid());
- EXPECT_NE(process3.Pid(), process1.Pid());
- EXPECT_NE(process3.Pid(), process2.Pid());
- EXPECT_TRUE(process1.IsProcessBackgrounded());
- EXPECT_FALSE(process2.IsProcessBackgrounded());
- EXPECT_TRUE(process3.IsProcessBackgrounded());
-
- // Navigate back to the first page. Its renderer should be in foreground
- // again while the other renderers should be backgrounded.
- EXPECT_EQ(process1.Pid(), ShowSingletonTab(page1).Pid());
- EXPECT_FALSE(process1.IsProcessBackgrounded());
- EXPECT_TRUE(process2.IsProcessBackgrounded());
- EXPECT_TRUE(process3.IsProcessBackgrounded());
-}
-#endif
-
-// TODO(nasko): crbug.com/173137
-// Disable on Mac 10.9 due to ongoing flakiness. (crbug.com/442785)
-#if defined(OS_WIN) || defined(OS_MACOSX)
-#define MAYBE_ProcessOverflow DISABLED_ProcessOverflow
-#else
-#define MAYBE_ProcessOverflow ProcessOverflow
-#endif
-
-IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, MAYBE_ProcessOverflow) {
- // Set max renderers to 1 to force running out of processes.
- content::RenderProcessHost::SetMaxRendererProcessCount(1);
- TestProcessOverflow();
-}
-
-// Disable on Mac 10.9 due to ongoing flakiness. (crbug.com/442785)
-#if defined(OS_MACOSX) || defined(OS_WIN)
-#define MAYBE_ProcessOverflowCommandLine DISABLED_ProcessOverflow
-#else
-#define MAYBE_ProcessOverflowCommandLine ProcessOverflow
-#endif
-
-// Variation of the ProcessOverflow test, which is driven through command line
-// parameter instead of direct function call into the class.
-IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTestWithCommandLine,
- MAYBE_ProcessOverflowCommandLine) {
- TestProcessOverflow();
-}
-
-// Ensure that DevTools opened to debug DevTools is launched in a separate
-// process when --process-per-tab is set. See crbug.com/69873.
-IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
- DevToolsOnSelfInOwnProcessPPT) {
-#if defined(OS_WIN) && defined(USE_ASH)
- // Disable this test in Metro+Ash for now (http://crbug.com/262796).
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAshBrowserTests))
- return;
-#endif
-
- base::CommandLine& parsed_command_line =
- *base::CommandLine::ForCurrentProcess();
- parsed_command_line.AppendSwitch(switches::kProcessPerTab);
-
- int tab_count = 1;
- int host_count = 1;
-
- GURL page1("data:text/html,hello world1");
- ui_test_utils::WindowedTabAddedNotificationObserver observer1(
- content::NotificationService::AllSources());
- chrome::ShowSingletonTab(browser(), page1);
- observer1.Wait();
- tab_count++;
- host_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- // DevTools start in docked mode (no new tab), in a separate process.
- chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Inspect());
- host_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- WebContents* devtools = FindFirstDevToolsContents();
- DCHECK(devtools);
-
- // DevTools start in a separate process.
- DevToolsWindow::OpenDevToolsWindow(devtools, DevToolsToggleAction::Inspect());
- host_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- // close docked devtools
- content::WindowedNotificationObserver close_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::Source<WebContents>(devtools));
-
- chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Toggle());
- close_observer.Wait();
-}
-
-// Ensure that DevTools opened to debug DevTools is launched in a separate
-// process. See crbug.com/69873.
-IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
- DevToolsOnSelfInOwnProcess) {
-#if defined(OS_WIN) && defined(USE_ASH)
- // Disable this test in Metro+Ash for now (http://crbug.com/262796).
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAshBrowserTests))
- return;
-#endif
-
- int tab_count = 1;
- int host_count = 1;
-
- GURL page1("data:text/html,hello world1");
- ui_test_utils::WindowedTabAddedNotificationObserver observer1(
- content::NotificationService::AllSources());
- chrome::ShowSingletonTab(browser(), page1);
- observer1.Wait();
- tab_count++;
- host_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- // DevTools start in docked mode (no new tab), in a separate process.
- chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Inspect());
- host_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- WebContents* devtools = FindFirstDevToolsContents();
- DCHECK(devtools);
-
- // DevTools start in a separate process.
- DevToolsWindow::OpenDevToolsWindow(devtools, DevToolsToggleAction::Inspect());
- host_count++;
- EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
- EXPECT_EQ(host_count, RenderProcessHostCount());
-
- // close docked devtools
- content::WindowedNotificationObserver close_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::Source<content::WebContents>(devtools));
- chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Toggle());
- close_observer.Wait();
-}
-
-// This class's goal is to close the browser window when a renderer process has
-// crashed. It does so by monitoring WebContents for RenderProcessGone event and
-// closing the passed in TabStripModel. This is used in the following test case.
-class WindowDestroyer : public content::WebContentsObserver {
- public:
- WindowDestroyer(content::WebContents* web_contents, TabStripModel* model)
- : content::WebContentsObserver(web_contents),
- tab_strip_model_(model) {
- }
-
- void RenderProcessGone(base::TerminationStatus status) override {
- // Wait for the window to be destroyed, which will ensure all other
- // RenderViewHost objects are deleted before we return and proceed with
- // the next iteration of notifications.
- content::WindowedNotificationObserver observer(
- chrome::NOTIFICATION_BROWSER_CLOSED,
- content::NotificationService::AllSources());
- tab_strip_model_->CloseAllTabs();
- observer.Wait();
- }
-
- private:
- TabStripModel* tab_strip_model_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowDestroyer);
-};
-
-// Test to ensure that while iterating through all listeners in
-// RenderProcessHost and invalidating them, we remove them properly and don't
-// access already freed objects. See http://crbug.com/255524.
-IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
- CloseAllTabsDuringProcessDied) {
- GURL url(chrome::kChromeUIOmniboxURL);
-
- ui_test_utils::NavigateToURL(browser(), url);
- ui_test_utils::NavigateToURLWithDisposition(
- browser(), url, NEW_BACKGROUND_TAB,
- ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-
- EXPECT_EQ(2, browser()->tab_strip_model()->count());
-
- WebContents* wc1 = browser()->tab_strip_model()->GetWebContentsAt(0);
- WebContents* wc2 = browser()->tab_strip_model()->GetWebContentsAt(1);
- EXPECT_EQ(wc1->GetRenderProcessHost(), wc2->GetRenderProcessHost());
-
- // Create an object that will close the window on a process crash.
- WindowDestroyer destroyer(wc1, browser()->tab_strip_model());
-
- content::WindowedNotificationObserver observer(
- chrome::NOTIFICATION_BROWSER_CLOSED,
- content::NotificationService::AllSources());
-
- // Kill the renderer process, simulating a crash. This should the ProcessDied
- // method to be called. Alternatively, RenderProcessHost::OnChannelError can
- // be called to directly force a call to ProcessDied.
- wc1->GetRenderProcessHost()->Shutdown(-1, true);
-
- observer.Wait();
-}
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/process/process.h"
+#include "base/test/test_timeouts.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/search/search.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/test_switches.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_iterator.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/base/filename_util.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+using content::RenderViewHost;
+using content::RenderWidgetHost;
+using content::WebContents;
+
+namespace {
+
+int RenderProcessHostCount() {
+ content::RenderProcessHost::iterator hosts =
+ content::RenderProcessHost::AllHostsIterator();
+ int count = 0;
+ while (!hosts.IsAtEnd()) {
+ if (hosts.GetCurrentValue()->HasConnection())
+ count++;
+ hosts.Advance();
+ }
+ return count;
+}
+
+WebContents* FindFirstDevToolsContents() {
+ scoped_ptr<content::RenderWidgetHostIterator> widgets(
+ RenderWidgetHost::GetRenderWidgetHosts());
+ while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
+ if (!widget->GetProcess()->HasConnection())
+ continue;
+ if (!widget->IsRenderView())
+ continue;
+ RenderViewHost* host = RenderViewHost::From(widget);
+ WebContents* contents = WebContents::FromRenderViewHost(host);
+ GURL url = contents->GetURL();
+ if (url.SchemeIs(content::kChromeDevToolsScheme))
+ return contents;
+ }
+ return NULL;
+}
+
+// TODO(rvargas) crbug.com/417532: Remove this code.
+base::Process ProcessFromHandle(base::ProcessHandle handle) {
+#if defined(OS_WIN)
+ if (handle == GetCurrentProcess())
+ return base::Process::Current();
+
+ base::ProcessHandle out_handle;
+ if (!::DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
+ &out_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+ return base::Process();
+ }
+ handle = out_handle;
+#endif // defined(OS_WIN)
+ return base::Process(handle);
+}
+
+} // namespace
+
+class ChromeRenderProcessHostTest : public InProcessBrowserTest {
+ public:
+ ChromeRenderProcessHostTest() {}
+
+ // Show a tab, activating the current one if there is one, and wait for
+ // the renderer process to be created or foregrounded, returning the process
+ // handle.
+ base::Process ShowSingletonTab(const GURL& page) {
+ chrome::ShowSingletonTab(browser(), page);
+ WebContents* wc = browser()->tab_strip_model()->GetActiveWebContents();
+ CHECK(wc->GetURL() == page);
+
+ WaitForLauncherThread();
+ WaitForMessageProcessing(wc);
+ return ProcessFromHandle(wc->GetRenderProcessHost()->GetHandle());
+ }
+
+ // Loads the given url in a new background tab and returns the handle of its
+ // renderer.
+ base::Process OpenBackgroundTab(const GURL& page) {
+ ui_test_utils::NavigateToURLWithDisposition(
+ browser(), page, NEW_BACKGROUND_TAB,
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+ TabStripModel* tab_strip = browser()->tab_strip_model();
+ WebContents* wc =
+ tab_strip->GetWebContentsAt(tab_strip->active_index() + 1);
+ CHECK(wc->GetVisibleURL() == page);
+
+ WaitForLauncherThread();
+ WaitForMessageProcessing(wc);
+ return ProcessFromHandle(wc->GetRenderProcessHost()->GetHandle());
+ }
+
+ // Ensures that the backgrounding / foregrounding gets a chance to run.
+ void WaitForLauncherThread() {
+ content::BrowserThread::PostTaskAndReply(
+ content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+ base::Bind(&base::DoNothing), base::MessageLoop::QuitClosure());
+ base::MessageLoop::current()->Run();
+ }
+
+ // Implicitly waits for the renderer process associated with the specified
+ // WebContents to process outstanding IPC messages by running some JavaScript
+ // and waiting for the result.
+ void WaitForMessageProcessing(WebContents* wc) {
+ bool result = false;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+ wc, "window.domAutomationController.send(true);", &result));
+ ASSERT_TRUE(result);
+ }
+
+ // When we hit the max number of renderers, verify that the way we do process
+ // sharing behaves correctly. In particular, this test is verifying that even
+ // when we hit the max process limit, that renderers of each type will wind up
+ // in a process of that type, even if that means creating a new process.
+ void TestProcessOverflow() {
+ int tab_count = 1;
+ int host_count = 1;
+ WebContents* tab1 = NULL;
+ WebContents* tab2 = NULL;
+ content::RenderProcessHost* rph1 = NULL;
+ content::RenderProcessHost* rph2 = NULL;
+ content::RenderProcessHost* rph3 = NULL;
+
+ // Change the first tab to be the omnibox page (TYPE_WEBUI).
+ GURL omnibox(chrome::kChromeUIOmniboxURL);
+ ui_test_utils::NavigateToURL(browser(), omnibox);
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
+ rph1 = tab1->GetRenderProcessHost();
+ EXPECT_EQ(omnibox, tab1->GetURL());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ // Create a new TYPE_TABBED tab. It should be in its own process.
+ GURL page1("data:text/html,hello world1");
+
+ ui_test_utils::WindowedTabAddedNotificationObserver observer1(
+ content::NotificationService::AllSources());
+ chrome::ShowSingletonTab(browser(), page1);
+ observer1.Wait();
+
+ tab_count++;
+ host_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
+ rph2 = tab1->GetRenderProcessHost();
+ EXPECT_EQ(tab1->GetURL(), page1);
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+ EXPECT_NE(rph1, rph2);
+
+ // Create another TYPE_TABBED tab. It should share the previous process.
+ GURL page2("data:text/html,hello world2");
+ ui_test_utils::WindowedTabAddedNotificationObserver observer2(
+ content::NotificationService::AllSources());
+ chrome::ShowSingletonTab(browser(), page2);
+ observer2.Wait();
+ tab_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
+ EXPECT_EQ(tab2->GetURL(), page2);
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+ EXPECT_EQ(tab2->GetRenderProcessHost(), rph2);
+
+ // Create another TYPE_WEBUI tab. It should share the process with omnibox.
+ // Note: intentionally create this tab after the TYPE_TABBED tabs to
+ // exercise bug 43448 where extension and WebUI tabs could get combined into
+ // normal renderers.
+ GURL history(chrome::kChromeUIHistoryURL);
+ ui_test_utils::WindowedTabAddedNotificationObserver observer3(
+ content::NotificationService::AllSources());
+ chrome::ShowSingletonTab(browser(), history);
+ observer3.Wait();
+ tab_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
+ EXPECT_EQ(tab2->GetURL(), GURL(history));
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+ EXPECT_EQ(tab2->GetRenderProcessHost(), rph1);
+
+ // Create a TYPE_EXTENSION tab. It should be in its own process.
+ // (the bookmark manager is implemented as an extension)
+ GURL bookmarks(chrome::kChromeUIBookmarksURL);
+ ui_test_utils::WindowedTabAddedNotificationObserver observer4(
+ content::NotificationService::AllSources());
+ chrome::ShowSingletonTab(browser(), bookmarks);
+ observer4.Wait();
+ tab_count++;
+ host_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
+ rph3 = tab1->GetRenderProcessHost();
+ EXPECT_EQ(tab1->GetURL(), bookmarks);
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+ EXPECT_NE(rph1, rph3);
+ EXPECT_NE(rph2, rph3);
+ }
+};
+
+class ChromeRenderProcessHostTestWithCommandLine
+ : public ChromeRenderProcessHostTest {
+ protected:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitchASCII(switches::kRendererProcessLimit, "1");
+ }
+};
+
+// Disable on Mac and Windows due to ongoing flakiness. (crbug.com/442785)
+#if defined(OS_MACOSX) || defined(OS_WIN)
+#define MAYBE_ProcessPerTab DISABLED_ProcessPerTab
+#else
+#define MAYBE_ProcessPerTab ProcessPerTab
+#endif
+
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, MAYBE_ProcessPerTab) {
+ // Set max renderers to 1 to force running out of processes.
+ content::RenderProcessHost::SetMaxRendererProcessCount(1);
+
+ base::CommandLine& parsed_command_line =
+ *base::CommandLine::ForCurrentProcess();
+ parsed_command_line.AppendSwitch(switches::kProcessPerTab);
+
+ int tab_count = 1;
+ int host_count = 1;
+
+ // Change the first tab to be the new tab page (TYPE_WEBUI).
+ GURL omnibox(chrome::kChromeUIOmniboxURL);
+ ui_test_utils::NavigateToURL(browser(), omnibox);
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ // Create a new TYPE_TABBED tab. It should be in its own process.
+ GURL page1("data:text/html,hello world1");
+ ui_test_utils::WindowedTabAddedNotificationObserver observer1(
+ content::NotificationService::AllSources());
+ chrome::ShowSingletonTab(browser(), page1);
+ observer1.Wait();
+ tab_count++;
+ host_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ // Create another TYPE_TABBED tab. It should share the previous process.
+ GURL page2("data:text/html,hello world2");
+ ui_test_utils::WindowedTabAddedNotificationObserver observer2(
+ content::NotificationService::AllSources());
+ chrome::ShowSingletonTab(browser(), page2);
+ observer2.Wait();
+ tab_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ // Create another omnibox tab. It should share the process with the other
+ // WebUI.
+ ui_test_utils::NavigateToURLWithDisposition(
+ browser(), omnibox, NEW_FOREGROUND_TAB,
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+ tab_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ // Create another omnibox tab. It should share the process with the other
+ // WebUI.
+ ui_test_utils::NavigateToURLWithDisposition(
+ browser(), omnibox, NEW_FOREGROUND_TAB,
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+ tab_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+}
+
+// We don't change process priorities on Mac or Posix because the user lacks the
+// permission to raise a process' priority even after lowering it.
+#if defined(OS_WIN) || defined(OS_LINUX)
+#if defined(OS_WIN)
+// Flaky test: crbug.com/394368
+#define MAYBE_Backgrounding DISABLED_Backgrounding
+#else
+#define MAYBE_Backgrounding Backgrounding
+#endif
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, MAYBE_Backgrounding) {
+ if (!base::Process::CanBackgroundProcesses()) {
+ LOG(ERROR) << "Can't background processes";
+ return;
+ }
+ base::CommandLine& parsed_command_line =
+ *base::CommandLine::ForCurrentProcess();
+ parsed_command_line.AppendSwitch(switches::kProcessPerTab);
+
+ // Change the first tab to be the omnibox page (TYPE_WEBUI).
+ GURL omnibox(chrome::kChromeUIOmniboxURL);
+ ui_test_utils::NavigateToURL(browser(), omnibox);
+
+ // Create a new tab. It should be foreground.
+ GURL page1("data:text/html,hello world1");
+ base::Process process1 = ShowSingletonTab(page1);
+ ASSERT_TRUE(process1.IsValid());
+ EXPECT_FALSE(process1.IsProcessBackgrounded());
+
+ // Create another tab. It should be foreground, and the first tab should
+ // now be background.
+ GURL page2("data:text/html,hello world2");
+ base::Process process2 = ShowSingletonTab(page2);
+ ASSERT_TRUE(process2.IsValid());
+ EXPECT_NE(process1.Pid(), process2.Pid());
+ EXPECT_TRUE(process1.IsProcessBackgrounded());
+ EXPECT_FALSE(process2.IsProcessBackgrounded());
+
+ // Load another tab in background. The renderer of the new tab should be
+ // backgrounded, while visibility of the other renderers should not change.
+ GURL page3("data:text/html,hello world3");
+ base::Process process3 = OpenBackgroundTab(page3);
+ ASSERT_TRUE(process3.IsValid());
+ EXPECT_NE(process3.Pid(), process1.Pid());
+ EXPECT_NE(process3.Pid(), process2.Pid());
+ EXPECT_TRUE(process1.IsProcessBackgrounded());
+ EXPECT_FALSE(process2.IsProcessBackgrounded());
+ EXPECT_TRUE(process3.IsProcessBackgrounded());
+
+ // Navigate back to the first page. Its renderer should be in foreground
+ // again while the other renderers should be backgrounded.
+ EXPECT_EQ(process1.Pid(), ShowSingletonTab(page1).Pid());
+ EXPECT_FALSE(process1.IsProcessBackgrounded());
+ EXPECT_TRUE(process2.IsProcessBackgrounded());
+ EXPECT_TRUE(process3.IsProcessBackgrounded());
+}
+#endif
+
+// TODO(nasko): crbug.com/173137
+// Disable on Mac 10.9 due to ongoing flakiness. (crbug.com/442785)
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#define MAYBE_ProcessOverflow DISABLED_ProcessOverflow
+#else
+#define MAYBE_ProcessOverflow ProcessOverflow
+#endif
+
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, MAYBE_ProcessOverflow) {
+ // Set max renderers to 1 to force running out of processes.
+ content::RenderProcessHost::SetMaxRendererProcessCount(1);
+ TestProcessOverflow();
+}
+
+// Disable on Mac 10.9 due to ongoing flakiness. (crbug.com/442785)
+#if defined(OS_MACOSX) || defined(OS_WIN)
+#define MAYBE_ProcessOverflowCommandLine DISABLED_ProcessOverflow
+#else
+#define MAYBE_ProcessOverflowCommandLine ProcessOverflow
+#endif
+
+// Variation of the ProcessOverflow test, which is driven through command line
+// parameter instead of direct function call into the class.
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTestWithCommandLine,
+ MAYBE_ProcessOverflowCommandLine) {
+ TestProcessOverflow();
+}
+
+// Ensure that DevTools opened to debug DevTools is launched in a separate
+// process when --process-per-tab is set. See crbug.com/69873.
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
+ DevToolsOnSelfInOwnProcessPPT) {
+#if defined(OS_WIN) && defined(USE_ASH)
+ // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAshBrowserTests))
+ return;
+#endif
+
+ base::CommandLine& parsed_command_line =
+ *base::CommandLine::ForCurrentProcess();
+ parsed_command_line.AppendSwitch(switches::kProcessPerTab);
+
+ int tab_count = 1;
+ int host_count = 1;
+
+ GURL page1("data:text/html,hello world1");
+ ui_test_utils::WindowedTabAddedNotificationObserver observer1(
+ content::NotificationService::AllSources());
+ chrome::ShowSingletonTab(browser(), page1);
+ observer1.Wait();
+ tab_count++;
+ host_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ // DevTools start in docked mode (no new tab), in a separate process.
+ chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Inspect());
+ host_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ WebContents* devtools = FindFirstDevToolsContents();
+ DCHECK(devtools);
+
+ // DevTools start in a separate process.
+ DevToolsWindow::OpenDevToolsWindow(devtools, DevToolsToggleAction::Inspect());
+ host_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ // close docked devtools
+ content::WindowedNotificationObserver close_observer(
+ content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ content::Source<WebContents>(devtools));
+
+ chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Toggle());
+ close_observer.Wait();
+}
+
+// Ensure that DevTools opened to debug DevTools is launched in a separate
+// process. See crbug.com/69873.
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
+ DevToolsOnSelfInOwnProcess) {
+#if defined(OS_WIN) && defined(USE_ASH)
+ // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAshBrowserTests))
+ return;
+#endif
+
+ int tab_count = 1;
+ int host_count = 1;
+
+ GURL page1("data:text/html,hello world1");
+ ui_test_utils::WindowedTabAddedNotificationObserver observer1(
+ content::NotificationService::AllSources());
+ chrome::ShowSingletonTab(browser(), page1);
+ observer1.Wait();
+ tab_count++;
+ host_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ // DevTools start in docked mode (no new tab), in a separate process.
+ chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Inspect());
+ host_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ WebContents* devtools = FindFirstDevToolsContents();
+ DCHECK(devtools);
+
+ // DevTools start in a separate process.
+ DevToolsWindow::OpenDevToolsWindow(devtools, DevToolsToggleAction::Inspect());
+ host_count++;
+ EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
+ EXPECT_EQ(host_count, RenderProcessHostCount());
+
+ // close docked devtools
+ content::WindowedNotificationObserver close_observer(
+ content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ content::Source<content::WebContents>(devtools));
+ chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Toggle());
+ close_observer.Wait();
+}
+
+// This class's goal is to close the browser window when a renderer process has
+// crashed. It does so by monitoring WebContents for RenderProcessGone event and
+// closing the passed in TabStripModel. This is used in the following test case.
+class WindowDestroyer : public content::WebContentsObserver {
+ public:
+ WindowDestroyer(content::WebContents* web_contents, TabStripModel* model)
+ : content::WebContentsObserver(web_contents), tab_strip_model_(model) {}
+
+ void RenderProcessGone(base::TerminationStatus status) override {
+ // Wait for the window to be destroyed, which will ensure all other
+ // RenderViewHost objects are deleted before we return and proceed with
+ // the next iteration of notifications.
+ content::WindowedNotificationObserver observer(
+ chrome::NOTIFICATION_BROWSER_CLOSED,
+ content::NotificationService::AllSources());
+ tab_strip_model_->CloseAllTabs();
+ observer.Wait();
+ }
+
+ private:
+ TabStripModel* tab_strip_model_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowDestroyer);
+};
+
+// Test to ensure that while iterating through all listeners in
+// RenderProcessHost and invalidating them, we remove them properly and don't
+// access already freed objects. See http://crbug.com/255524.
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
+ CloseAllTabsDuringProcessDied) {
+ GURL url(chrome::kChromeUIOmniboxURL);
+
+ ui_test_utils::NavigateToURL(browser(), url);
+ ui_test_utils::NavigateToURLWithDisposition(
+ browser(), url, NEW_BACKGROUND_TAB,
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+ EXPECT_EQ(2, browser()->tab_strip_model()->count());
+
+ WebContents* wc1 = browser()->tab_strip_model()->GetWebContentsAt(0);
+ WebContents* wc2 = browser()->tab_strip_model()->GetWebContentsAt(1);
+ EXPECT_EQ(wc1->GetRenderProcessHost(), wc2->GetRenderProcessHost());
+
+ // Create an object that will close the window on a process crash.
+ WindowDestroyer destroyer(wc1, browser()->tab_strip_model());
+
+ content::WindowedNotificationObserver observer(
+ chrome::NOTIFICATION_BROWSER_CLOSED,
+ content::NotificationService::AllSources());
+
+ // Kill the renderer process, simulating a crash. This should the ProcessDied
+ // method to be called. Alternatively, RenderProcessHost::OnChannelError can
+ // be called to directly force a call to ProcessDied.
+ wc1->GetRenderProcessHost()->Shutdown(-1, true);
+
+ observer.Wait();
+}
+
+// Sets up the browser in order to start the tests with two tabs open: one
+// called "no audio" in foreground and another called "audio" in background with
+// audio in playing state. Also sets up the variables containing the process
+// associated with each tab, the urls of the two pages and the WebContents of
+// the "audio" page.
+class ChromeRenderProcessHostBackgroundingTest
+ : public ChromeRenderProcessHostTest {
+ public:
+ ChromeRenderProcessHostBackgroundingTest() {}
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kProcessPerTab);
+ }
+
+ void SetUpOnMainThread() override {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ // Set up the server and get the test pages.
+ base::FilePath test_data_dir;
+ ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+ embedded_test_server()->ServeFilesFromDirectory(
+ test_data_dir.AppendASCII("chrome/test/data/"));
+ audio_url_ = embedded_test_server()->GetURL("/extensions/loop_audio.html");
+ no_audio_url_ = embedded_test_server()->GetURL("/title1.html");
+
+ // Open a browser, navigate to the audio page and get its WebContents.
+ ui_test_utils::NavigateToURL(browser(), audio_url_);
+ audio_tab_web_contents_ =
+ browser()->tab_strip_model()->GetActiveWebContents();
+
+ // Create a new tab for the no audio page and confirm that the process of
+ // each tab is different and that both are valid.
+ audio_process_ = ProcessFromHandle(
+ audio_tab_web_contents_->GetRenderProcessHost()->GetHandle());
+ no_audio_process_ = ShowSingletonTab(no_audio_url_);
+ ASSERT_NE(audio_process_.Pid(), no_audio_process_.Pid());
+ ASSERT_TRUE(no_audio_process_.IsValid());
+ ASSERT_TRUE(audio_process_.IsValid());
+ }
+
+ protected:
+ GURL audio_url_;
+ GURL no_audio_url_;
+
+ base::Process audio_process_;
+ base::Process no_audio_process_;
+
+ content::WebContents* audio_tab_web_contents_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChromeRenderProcessHostBackgroundingTest);
+};
+
+// Test to make sure that a process is backgrounded when the audio stops playing
+// from the active tab and there is an immediate tab switch.
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostBackgroundingTest,
+ ProcessPriorityAfterStoppedAudio) {
+ // This test is invalid on platforms that can't background.
+ if (!base::Process::CanBackgroundProcesses())
+ return;
+
+ ShowSingletonTab(audio_url_);
+
+ // Wait until the no audio page is backgrounded and the audio page is not
+ // backgrounded.
+ while (!no_audio_process_.IsProcessBackgrounded() ||
+ audio_process_.IsProcessBackgrounded()) {
+ base::RunLoop().RunUntilIdle();
+ base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+ }
+
+ // Pause the audio and immediately switch to the no audio tab.
+ ASSERT_TRUE(content::ExecuteScript(
+ audio_tab_web_contents_,
+ "document.getElementById('audioPlayer').pause();"));
+ ShowSingletonTab(no_audio_url_);
+
+ // Wait until the no audio page is not backgrounded and the audio page is
+ // backgrounded.
+ while (no_audio_process_.IsProcessBackgrounded() ||
+ !audio_process_.IsProcessBackgrounded()) {
+ base::RunLoop().RunUntilIdle();
+ base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+ }
+}
+
+// Test to make sure that a process is backgrounded automatically when audio
+// stops playing from a hidden tab.
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostBackgroundingTest,
+ ProcessPriorityAfterAudioStopsOnNotVisibleTab) {
+ // This test is invalid on platforms that can't background.
+ if (!base::Process::CanBackgroundProcesses())
+ return;
+
+ // Wait until the two pages are not backgrounded.
+ while (no_audio_process_.IsProcessBackgrounded() ||
+ audio_process_.IsProcessBackgrounded()) {
+ base::RunLoop().RunUntilIdle();
+ base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+ }
+
+ // Stop the audio.
+ ASSERT_TRUE(content::ExecuteScript(
+ audio_tab_web_contents_,
+ "document.getElementById('audioPlayer').pause();"));
+
+ // Wait until the no audio page is not backgrounded and the audio page is
+ // backgrounded.
+ while (no_audio_process_.IsProcessBackgrounded() ||
+ !audio_process_.IsProcessBackgrounded()) {
+ base::RunLoop().RunUntilIdle();
+ base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+ }
+}
+
+// Test to make sure that a process is un-backgrounded automatically when audio
+// starts playing from a backgrounded tab.
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostBackgroundingTest,
+ ProcessPriorityAfterAudioStartsFromBackgroundTab) {
+ // This test is invalid on platforms that can't background.
+ if (!base::Process::CanBackgroundProcesses())
+ return;
+
+ // Stop the audio.
+ ASSERT_TRUE(content::ExecuteScript(
+ audio_tab_web_contents_,
+ "document.getElementById('audioPlayer').pause();"));
+
+ // Wait until the no audio page is not backgrounded and the audio page is
+ // backgrounded.
+ while (no_audio_process_.IsProcessBackgrounded() ||
+ !audio_process_.IsProcessBackgrounded()) {
+ base::RunLoop().RunUntilIdle();
+ base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+ }
+
+ // Start the audio from the backgrounded tab.
+ ASSERT_TRUE(
+ content::ExecuteScript(audio_tab_web_contents_,
+ "document.getElementById('audioPlayer').play();"));
+
+ // Wait until the two pages are not backgrounded.
+ while (no_audio_process_.IsProcessBackgrounded() ||
+ audio_process_.IsProcessBackgrounded()) {
+ base::RunLoop().RunUntilIdle();
+ base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+ }
+}
« no previous file with comments | « no previous file | chrome/test/data/extensions/loop_audio.html » ('j') | content/browser/renderer_host/render_process_host_impl.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698