From 37dfd9de7667e9d177edc27e208359cd0020fb26 Mon Sep 17 00:00:00 2001 From: nick Date: Mon, 14 Sep 2015 12:54:03 -0700 Subject: [PATCH] Add SiteIsolation.IsolateExtensions metrics and tests. These new UMA metrics estimate the process-count impact of a policy wherein extension content and web content never share processes, even if one contains the other in an iframe. SiteDetailsBrowserTest: add tests for the new metrics. WebContentsImpl: Fix a UMA metrics counting error where "); + GURL iframe_url = embedded_test_server()->GetURL("w.com", "/title1.html"); + dir->WriteFile(FILE_PATH_LITERAL("http_iframe.html"), + "" + name + + ", http:// iframe: " + ""); + dir->WriteManifest(manifest.ToJSON()); + + const Extension* extension = LoadExtension(dir->unpacked_path()); + EXPECT_TRUE(extension); + temp_dirs_.push_back(dir.release()); + return extension; + } + private: + ScopedVector temp_dirs_; DISALLOW_COPY_AND_ASSIGN(SiteDetailsBrowserTest); }; // Test the accuracy of SiteDetails process estimation, in the presence of // multiple iframes, navigation, multiple BrowsingInstances, and multiple tabs // in the same BrowsingInstance. -IN_PROC_BROWSER_TEST_F(SiteDetailsBrowserTest, ManyCrossSiteIframes) { +IN_PROC_BROWSER_TEST_F(SiteDetailsBrowserTest, ManyIframes) { // Page with 14 nested oopifs across 9 sites (a.com through i.com). // None of these are https. GURL abcdefghi_url = embedded_test_server()->GetURL( @@ -116,6 +168,15 @@ IN_PROC_BROWSER_TEST_F(SiteDetailsBrowserTest, ManyCrossSiteIframes) { EXPECT_THAT(details->uma()->GetAllSamples( "SiteIsolation.IsolateHttpsSitesProcessCountNoLimit"), ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(1, 1))); // Navigate to a different, disjoint set of 7 sites. GURL pqrstuv_url = embedded_test_server()->GetURL( @@ -150,6 +211,15 @@ IN_PROC_BROWSER_TEST_F(SiteDetailsBrowserTest, ManyCrossSiteIframes) { EXPECT_THAT(details->uma()->GetAllSamples( "SiteIsolation.IsolateHttpsSitesProcessCountNoLimit"), ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(1, 1))); // Open a second tab (different BrowsingInstance) with 4 sites (a through d). GURL abcd_url = embedded_test_server()->GetURL( @@ -183,6 +253,15 @@ IN_PROC_BROWSER_TEST_F(SiteDetailsBrowserTest, ManyCrossSiteIframes) { EXPECT_THAT(details->uma()->GetAllSamples( "SiteIsolation.IsolateHttpsSitesProcessCountNoLimit"), ElementsAre(Bucket(2, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(2, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(2, 1))); // Open a third tab (different BrowsingInstance) with the same 4 sites. AddTabAtIndex(2, abcd_url, ui::PAGE_TRANSITION_TYPED); @@ -215,11 +294,20 @@ IN_PROC_BROWSER_TEST_F(SiteDetailsBrowserTest, ManyCrossSiteIframes) { EXPECT_THAT(details->uma()->GetAllSamples( "SiteIsolation.IsolateHttpsSitesProcessCountNoLimit"), ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(3, 1))); - // Do a window.open() to obtain a fourth tab in the same BrowsingInstance as - // the third tab. The new page uses the same four sites "a-d" as third tab, + // From the third tab, window.open() a fourth tab in the same + // BrowsingInstance, to a page using the same four sites "a-d" as third tab, // plus an additional site "e". The estimated process counts should increase - // by one (not five) from the previous result, since the new tab can reuse the + // by one (not five) from the previous scenario, as the new tab can reuse the // four processes already in the BrowsingInstance. GURL dcbae_url = embedded_test_server()->GetURL( "a.com", "/cross_site_iframe_factory.html?d(c(b(a(e))))"); @@ -260,4 +348,230 @@ IN_PROC_BROWSER_TEST_F(SiteDetailsBrowserTest, ManyCrossSiteIframes) { EXPECT_THAT(details->uma()->GetAllSamples( "SiteIsolation.IsolateHttpsSitesProcessCountNoLimit"), ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(3, 1))); +} + +IN_PROC_BROWSER_TEST_F(SiteDetailsBrowserTest, IsolateExtensions) { + // We start on "about:blank", which should be credited with a process in this + // case. + scoped_refptr details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(1, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(1, 1))); + + // Install one script-injecting extension with background page, and an + // extension with web accessible resources. + const Extension* extension1 = CreateExtension("Extension One", true); + const Extension* extension2 = CreateExtension("Extension Two", false); + + // Open two a.com tabs (with cross site http iframes). IsolateExtensions mode + // should have no effect so far, since there are no frames straddling the + // extension/web boundary. + GURL tab1_url = embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b,c)"); + ui_test_utils::NavigateToURL(browser(), tab1_url); + WebContents* tab1 = browser()->tab_strip_model()->GetWebContentsAt(0); + GURL tab2_url = embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(d,e)"); + AddTabAtIndex(1, tab2_url, ui::PAGE_TRANSITION_TYPED); + WebContents* tab2 = browser()->tab_strip_model()->GetWebContentsAt(1); + + details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(2, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(3, 1))); + + // Test that "one process per extension" applies even when web content has an + // extension iframe. + + // Tab1 navigates its first iframe to a resource of extension1. This shouldn't + // result in a new extension process (it should share with extension1's + // background page). + content::NavigateIframeToURL( + tab1, "child-0", extension1->GetResourceURL("/blank_iframe.html")); + details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(2, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(3, 1))); + + // Tab2 navigates its first iframe to a resource of extension1. This also + // shouldn't result in a new extension process (it should share with the + // background page and the other iframe). + content::NavigateIframeToURL( + tab2, "child-0", extension1->GetResourceURL("/blank_iframe.html")); + details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(2, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(3, 1))); + + // Tab1 navigates its second iframe to a resource of extension2. This SHOULD + // result in a new process since extension2 had no existing process. + content::NavigateIframeToURL( + tab1, "child-1", extension2->GetResourceURL("/blank_iframe.html")); + details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(4, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(4, 1))); + + // Tab2 navigates its second iframe to a resource of extension2. This should + // share the existing extension2 process. + content::NavigateIframeToURL( + tab2, "child-1", extension2->GetResourceURL("/blank_iframe.html")); + details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(4, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(4, 1))); + + // Install extension3 (identical config to extension2) + const Extension* extension3 = CreateExtension("Extension Three", false); + + // Navigate Tab2 to a top-level page from extension3. There are four processes + // now: one for tab1's main frame, and one for each of the extensions: + // extension1 has a process because it has a background page; extension2 is + // used as an iframe in tab1, and extension3 is the top-level frame in tab2. + ui_test_utils::NavigateToURL(browser(), + extension3->GetResourceURL("blank_iframe.html")); + details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(4, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(4, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(4, 1))); + + // Navigate tab2 to a different extension3 page containing a web iframe. The + // iframe should get its own process. The lower bound number indicates that, + // in theory, the iframe could share a process with tab1's main frame. + ui_test_utils::NavigateToURL(browser(), + extension3->GetResourceURL("http_iframe.html")); + details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(5, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(4, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(5, 1))); + + // Navigate tab1 to an extension3 page with an extension3 iframe. There should + // be three processes estimated by IsolateExtensions: one for extension3, one + // for extension1's background page, and one for the web iframe in tab2. + browser()->tab_strip_model()->ActivateTabAt(0, true); + ui_test_utils::NavigateToURL(browser(), + extension3->GetResourceURL("blank_iframe.html")); + details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(2, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(3, 1))); + + // Now navigate tab1 to an extension3 page with a web iframe. This could share + // a process with tab2's iframe (the LowerBound number), or it could get its + // own process (the Estimate number). + ui_test_utils::NavigateToURL(browser(), + extension3->GetResourceURL("http_iframe.html")); + details = new TestMemoryDetails(); + details->StartFetchAndWait(); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.CurrentRendererProcessCount"), + ElementsAre(Bucket(2, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountEstimate"), + ElementsAre(Bucket(4, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountLowerBound"), + ElementsAre(Bucket(3, 1))); + EXPECT_THAT(details->uma()->GetAllSamples( + "SiteIsolation.IsolateExtensionsProcessCountNoLimit"), + ElementsAre(Bucket(4, 1))); } diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 99e2fa485014..7d03dc1e3299 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -171,6 +171,14 @@ void NotifyCacheOnIO( bool CollectSites(BrowserContext* context, std::set* sites, FrameTreeNode* node) { + // Record about:blank as a real (process-having) site only if the SiteInstance + // is unassigned. Do not otherwise depend on the siteinstance's site URL, + // since its value reflects the current process model, and this function + // should behave identically across all process models. + if (node->current_url() == GURL(url::kAboutBlankURL) && + node->current_frame_host()->GetSiteInstance()->HasSite()) { + return true; + } sites->insert(SiteInstance::GetSiteForURL(context, node->current_url())); return true; } diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 8a7ca4dce983..2bb468169291 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -43809,6 +43809,39 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries. + + nick@chromium.org + + The upper bound of the predicted renderer process count if we isolated only + Chrome extensions, subject to the process limit. Recorded once per UMA + ping. + + + + + nick@chromium.org + + The lower bound of the predicted renderer process count if we isolated only + Chrome extensions, subject to the process limit. Recorded once per UMA ping. + + + + + nick@chromium.org + + The predicted renderer process count if we isolated only Chrome extensions + and if there were no process limit. Recorded once per UMA ping. + + + + + nick@chromium.org + + The predicted total process count if we isolated only Chrome extensions, + subject to the process limit. Recorded once per UMA ping. + + + creis@chromium.org -- 2.11.4.GIT