blob: 8ad341db3e9ade6cf764673e9a3cb7a43d58e09d [file] [log] [blame]
[email protected]1ae93fb12013-06-14 03:38:561// 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.
4
5#include "chrome/browser/site_details.h"
6
asvitkineaa060312016-09-01 22:44:137#include "base/metrics/histogram_macros.h"
[email protected]1ae93fb12013-06-14 03:38:568#include "content/public/browser/browser_thread.h"
nickb2545f72015-10-30 20:05:159#include "content/public/browser/render_frame_host.h"
[email protected]1ae93fb12013-06-14 03:38:5610#include "content/public/browser/render_process_host.h"
brettw00899e62016-11-12 02:10:1711#include "extensions/features/features.h"
nickabbb4dcb2015-12-03 20:38:3412#include "url/origin.h"
nickcc0d9142015-10-14 16:27:1013
brettw00899e62016-11-12 02:10:1714#if BUILDFLAG(ENABLE_EXTENSIONS)
nickcc0d9142015-10-14 16:27:1015#include "extensions/browser/extension_registry.h"
nick37dfd9de2015-09-14 19:54:0316#include "extensions/common/constants.h"
nickcc0d9142015-10-14 16:27:1017#include "extensions/common/extension.h"
18#endif
[email protected]1ae93fb12013-06-14 03:38:5619
nickb2545f72015-10-30 20:05:1520using content::BrowserContext;
[email protected]1ae93fb12013-06-14 03:38:5621using content::BrowserThread;
nickb2545f72015-10-30 20:05:1522using content::RenderFrameHost;
[email protected]1ae93fb12013-06-14 03:38:5623using content::RenderProcessHost;
24using content::SiteInstance;
25using content::WebContents;
26
nick37dfd9de2015-09-14 19:54:0327namespace {
28
nickb2545f72015-10-30 20:05:1529bool ShouldIsolate(BrowserContext* browser_context,
dchengafb53e22016-02-04 08:11:0830 const IsolationScenario& scenario,
nickcc0d9142015-10-14 16:27:1031 const GURL& site) {
dchengafb53e22016-02-04 08:11:0832 switch (scenario.policy) {
nickb2545f72015-10-30 20:05:1533 case ISOLATE_NOTHING:
34 return false;
nick37dfd9de2015-09-14 19:54:0335 case ISOLATE_ALL_SITES:
36 return true;
37 case ISOLATE_HTTPS_SITES:
38 // Note: For estimation purposes "isolate https sites" is really
39 // implemented as "isolate non-http sites". This means that, for example,
40 // the New Tab Page gets counted as two processes under this policy, and
41 // extensions are isolated as well.
42 return !site.SchemeIs(url::kHttpScheme);
nickcc0d9142015-10-14 16:27:1043 case ISOLATE_EXTENSIONS: {
brettw00899e62016-11-12 02:10:1744#if !BUILDFLAG(ENABLE_EXTENSIONS)
nickcc0d9142015-10-14 16:27:1045 return false;
46#else
47 if (!site.SchemeIs(extensions::kExtensionScheme))
48 return false;
49 extensions::ExtensionRegistry* registry =
50 extensions::ExtensionRegistry::Get(browser_context);
51 const extensions::Extension* extension =
52 registry->enabled_extensions().GetExtensionOrAppByURL(site);
53 return extension && !extension->is_hosted_app();
54#endif
55 }
nick37dfd9de2015-09-14 19:54:0356 }
57 NOTREACHED();
58 return true;
59}
60
nasko50273712015-12-03 16:03:5061content::SiteInstance* DeterminePrimarySiteInstance(
nick6c28ecc92016-02-09 21:30:1262 content::SiteInstance* site_instance,
nasko50273712015-12-03 16:03:5063 SiteData* site_data) {
64 // Find the BrowsingInstance this WebContents belongs to by iterating over
65 // the "primary" SiteInstances of each BrowsingInstance we've seen so far.
nick6c28ecc92016-02-09 21:30:1266 for (auto& entry : site_data->browsing_instances) {
67 BrowsingInstanceInfo* browsing_instance = &entry.second;
68 content::SiteInstance* primary_for_browsing_instance = entry.first;
69
70 if (site_instance->IsRelatedSiteInstance(primary_for_browsing_instance)) {
71 browsing_instance->site_instances.insert(site_instance);
72 return primary_for_browsing_instance;
nasko50273712015-12-03 16:03:5073 }
74 }
75
76 // Add |instance| as the "primary" SiteInstance of a new BrowsingInstance.
nick6c28ecc92016-02-09 21:30:1277 BrowsingInstanceInfo* browsing_instance =
78 &site_data->browsing_instances[site_instance];
79 browsing_instance->site_instances.insert(site_instance);
nasko50273712015-12-03 16:03:5080
nick6c28ecc92016-02-09 21:30:1281 return site_instance;
nasko50273712015-12-03 16:03:5082}
83
nick37dfd9de2015-09-14 19:54:0384} // namespace
85
nick6c28ecc92016-02-09 21:30:1286ScenarioBrowsingInstanceInfo::ScenarioBrowsingInstanceInfo() {}
87
vmpstrb8aacbe2016-02-26 02:00:4888ScenarioBrowsingInstanceInfo::ScenarioBrowsingInstanceInfo(
89 const ScenarioBrowsingInstanceInfo& other) = default;
90
nick6c28ecc92016-02-09 21:30:1291ScenarioBrowsingInstanceInfo::~ScenarioBrowsingInstanceInfo() {}
92
93BrowsingInstanceInfo::BrowsingInstanceInfo() {}
94
vmpstrb8aacbe2016-02-26 02:00:4895BrowsingInstanceInfo::BrowsingInstanceInfo(const BrowsingInstanceInfo& other) =
96 default;
97
nick6c28ecc92016-02-09 21:30:1298BrowsingInstanceInfo::~BrowsingInstanceInfo() {}
99
nickde8b0272016-02-11 04:29:25100IsolationScenario::IsolationScenario() {}
nick37dfd9de2015-09-14 19:54:03101
vmpstrb8aacbe2016-02-26 02:00:48102IsolationScenario::IsolationScenario(const IsolationScenario& other) = default;
103
nick37dfd9de2015-09-14 19:54:03104IsolationScenario::~IsolationScenario() {}
105
nickde8b0272016-02-11 04:29:25106SiteData::SiteData() {
nickb2545f72015-10-30 20:05:15107 for (int i = 0; i <= ISOLATION_SCENARIO_LAST; i++)
108 scenarios[i].policy = static_cast<IsolationScenarioType>(i);
nick37dfd9de2015-09-14 19:54:03109}
[email protected]1ae93fb12013-06-14 03:38:56110
vmpstrb8aacbe2016-02-26 02:00:48111SiteData::SiteData(const SiteData& other) = default;
112
[email protected]1ae93fb12013-06-14 03:38:56113SiteData::~SiteData() {}
114
115SiteDetails::SiteDetails() {}
116
117SiteDetails::~SiteDetails() {}
118
119void SiteDetails::CollectSiteInfo(WebContents* contents,
120 SiteData* site_data) {
thestig00844cea2015-09-08 21:44:52121 DCHECK_CURRENTLY_ON(BrowserThread::UI);
nickde8b0272016-02-11 04:29:25122 BrowserContext* context = contents->GetBrowserContext();
123
124 // The primary should be the same for the whole tab.
nasko50273712015-12-03 16:03:50125 SiteInstance* primary =
126 DeterminePrimarySiteInstance(contents->GetSiteInstance(), site_data);
nickde8b0272016-02-11 04:29:25127 BrowsingInstanceInfo* browsing_instance =
128 &site_data->browsing_instances[primary];
129
130 for (RenderFrameHost* frame : contents->GetAllFrames()) {
131 // Ensure that we add the frame's SiteInstance to |site_instances|.
132 DCHECK(frame->GetSiteInstance()->IsRelatedSiteInstance(primary));
133 browsing_instance->site_instances.insert(frame->GetSiteInstance());
134 browsing_instance->proxy_count += frame->GetProxyCount();
135
136 if (frame->GetParent()) {
137 if (frame->GetSiteInstance() != frame->GetParent()->GetSiteInstance())
138 site_data->out_of_process_frames++;
139 }
140 }
[email protected]1ae93fb12013-06-14 03:38:56141
142 // Now keep track of how many sites we have in this BrowsingInstance (and
143 // overall), including sites in iframes.
nickb2545f72015-10-30 20:05:15144 for (IsolationScenario& scenario : site_data->scenarios) {
dchengafb53e22016-02-04 08:11:08145 std::map<RenderFrameHost*, GURL> frame_urls;
146 for (RenderFrameHost* frame : contents->GetAllFrames()) {
147 // Determine the site from the frame's origin, with a fallback to the
148 // frame's URL. In cases like <iframe sandbox>, we can wind up with an
149 // http URL but a unique origin. The origin of the resource will still
150 // determine process placement.
151 url::Origin origin = frame->GetLastCommittedOrigin();
152 GURL site = SiteInstance::GetSiteForURL(
csharrisonaec2c542016-10-12 19:40:36153 context,
154 origin.unique() ? frame->GetLastCommittedURL() : origin.GetURL());
dchengafb53e22016-02-04 08:11:08155
156 bool should_isolate = ShouldIsolate(context, scenario, site);
157
158 // Treat a subframe as part of its parent site if neither needs isolation.
159 if (!should_isolate && frame->GetParent()) {
160 GURL parent_site = frame_urls[frame->GetParent()];
161 if (!ShouldIsolate(context, scenario, parent_site))
162 site = parent_site;
163 }
164
165 bool process_per_site =
166 site.is_valid() &&
167 RenderProcessHost::ShouldUseProcessPerSite(context, site);
168
169 // If we don't need a dedicated process, and aren't living in a process-
170 // per-site process, we are nothing special: collapse our URL to a dummy
171 // site.
172 if (!process_per_site && !should_isolate)
173 site = GURL("http://");
174
175 // We model process-per-site by only inserting those sites into the first
176 // browsing instance in which they appear.
nick6c28ecc92016-02-09 21:30:12177 if (scenario.all_sites.insert(site).second || !process_per_site)
178 scenario.browsing_instances[primary->GetId()].sites.insert(site);
dchengafb53e22016-02-04 08:11:08179
180 // Record our result in |frame_urls| for use by children.
181 frame_urls[frame] = site;
182 }
[email protected]1ae93fb12013-06-14 03:38:56183 }
naskoaab1a442015-11-19 02:10:36184
[email protected]1ae93fb12013-06-14 03:38:56185}
186
187void SiteDetails::UpdateHistograms(
188 const BrowserContextSiteDataMap& site_data_map,
189 int all_renderer_process_count,
190 int non_renderer_process_count) {
191 // Reports a set of site-based process metrics to UMA.
192 int process_limit = RenderProcessHost::GetMaxRendererProcessCount();
193
naskoaab1a442015-11-19 02:10:36194 // Sum the number of sites and SiteInstances in each BrowserContext and
195 // the total number of out-of-process iframes.
nick37dfd9de2015-09-14 19:54:03196 int num_sites[ISOLATION_SCENARIO_LAST + 1] = {};
197 int num_isolated_site_instances[ISOLATION_SCENARIO_LAST + 1] = {};
[email protected]1ae93fb12013-06-14 03:38:56198 int num_browsing_instances = 0;
naskoaab1a442015-11-19 02:10:36199 int num_oopifs = 0;
nickde8b0272016-02-11 04:29:25200 int num_proxies = 0;
nick6c28ecc92016-02-09 21:30:12201 for (auto& site_data_map_entry : site_data_map) {
202 const SiteData& site_data = site_data_map_entry.second;
203 for (const IsolationScenario& scenario : site_data.scenarios) {
204 num_sites[scenario.policy] += scenario.all_sites.size();
205 for (auto& entry : scenario.browsing_instances) {
206 const ScenarioBrowsingInstanceInfo& scenario_browsing_instance_info =
207 entry.second;
nick37dfd9de2015-09-14 19:54:03208 num_isolated_site_instances[scenario.policy] +=
nick6c28ecc92016-02-09 21:30:12209 scenario_browsing_instance_info.sites.size();
nick37dfd9de2015-09-14 19:54:03210 }
[email protected]1ae93fb12013-06-14 03:38:56211 }
nick6c28ecc92016-02-09 21:30:12212 for (const auto& entry : site_data.browsing_instances) {
213 const BrowsingInstanceInfo& browsing_instance_info = entry.second;
nasko50273712015-12-03 16:03:50214 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.SiteInstancesPerBrowsingInstance",
nick6c28ecc92016-02-09 21:30:12215 browsing_instance_info.site_instances.size());
nickde8b0272016-02-11 04:29:25216 UMA_HISTOGRAM_COUNTS_10000("SiteIsolation.ProxyCountPerBrowsingInstance",
217 browsing_instance_info.proxy_count);
218 num_proxies += browsing_instance_info.proxy_count;
nasko50273712015-12-03 16:03:50219 }
nick6c28ecc92016-02-09 21:30:12220 num_browsing_instances += site_data.browsing_instances.size();
221 num_oopifs += site_data.out_of_process_frames;
[email protected]1ae93fb12013-06-14 03:38:56222 }
223
nick37dfd9de2015-09-14 19:54:03224 // Predict the number of processes needed when isolating all sites, when
225 // isolating only HTTPS sites, and when isolating extensions.
226 int process_count_lower_bound[ISOLATION_SCENARIO_LAST + 1];
227 int process_count_upper_bound[ISOLATION_SCENARIO_LAST + 1];
228 int process_count_estimate[ISOLATION_SCENARIO_LAST + 1];
229 for (int policy = 0; policy <= ISOLATION_SCENARIO_LAST; policy++) {
230 process_count_lower_bound[policy] = num_sites[policy];
231 process_count_upper_bound[policy] = num_sites[policy] + process_limit - 1;
232 process_count_estimate[policy] = std::min(
233 num_isolated_site_instances[policy], process_count_upper_bound[policy]);
234 }
[email protected]1ae93fb12013-06-14 03:38:56235
236 // Just renderer process count:
237 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.CurrentRendererProcessCount",
238 all_renderer_process_count);
239 UMA_HISTOGRAM_COUNTS_100(
240 "SiteIsolation.BrowsingInstanceCount",
241 num_browsing_instances);
nickde8b0272016-02-11 04:29:25242 UMA_HISTOGRAM_COUNTS_10000("SiteIsolation.ProxyCount", num_proxies);
naskoaab1a442015-11-19 02:10:36243 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.OutOfProcessIframes", num_oopifs);
nickb2545f72015-10-30 20:05:15244
245 // ISOLATE_NOTHING metrics.
246 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.IsolateNothingProcessCountNoLimit",
247 num_isolated_site_instances[ISOLATE_NOTHING]);
248 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.IsolateNothingProcessCountLowerBound",
249 process_count_lower_bound[ISOLATE_NOTHING]);
250 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.IsolateNothingProcessCountEstimate",
251 process_count_estimate[ISOLATE_NOTHING]);
252 UMA_HISTOGRAM_COUNTS_100(
253 "SiteIsolation.IsolateNothingTotalProcessCountEstimate",
254 process_count_estimate[ISOLATE_NOTHING] + non_renderer_process_count);
255
256 // ISOLATE_ALL_SITES metrics.
nick37dfd9de2015-09-14 19:54:03257 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.IsolateAllSitesProcessCountNoLimit",
258 num_isolated_site_instances[ISOLATE_ALL_SITES]);
[email protected]1ae93fb12013-06-14 03:38:56259 UMA_HISTOGRAM_COUNTS_100(
260 "SiteIsolation.IsolateAllSitesProcessCountLowerBound",
nick37dfd9de2015-09-14 19:54:03261 process_count_lower_bound[ISOLATE_ALL_SITES]);
262 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.IsolateAllSitesProcessCountEstimate",
263 process_count_estimate[ISOLATE_ALL_SITES]);
nickb2545f72015-10-30 20:05:15264 UMA_HISTOGRAM_COUNTS_100(
265 "SiteIsolation.IsolateAllSitesTotalProcessCountEstimate",
266 process_count_estimate[ISOLATE_ALL_SITES] + non_renderer_process_count);
nick37dfd9de2015-09-14 19:54:03267
nickb2545f72015-10-30 20:05:15268 // ISOLATE_HTTPS_SITES metrics.
nick37dfd9de2015-09-14 19:54:03269 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.IsolateHttpsSitesProcessCountNoLimit",
270 num_isolated_site_instances[ISOLATE_HTTPS_SITES]);
[email protected]1ae93fb12013-06-14 03:38:56271 UMA_HISTOGRAM_COUNTS_100(
272 "SiteIsolation.IsolateHttpsSitesProcessCountLowerBound",
nick37dfd9de2015-09-14 19:54:03273 process_count_lower_bound[ISOLATE_HTTPS_SITES]);
[email protected]1ae93fb12013-06-14 03:38:56274 UMA_HISTOGRAM_COUNTS_100(
275 "SiteIsolation.IsolateHttpsSitesProcessCountEstimate",
nick37dfd9de2015-09-14 19:54:03276 process_count_estimate[ISOLATE_HTTPS_SITES]);
nickb2545f72015-10-30 20:05:15277 UMA_HISTOGRAM_COUNTS_100(
278 "SiteIsolation.IsolateHttpsSitesTotalProcessCountEstimate",
279 process_count_estimate[ISOLATE_HTTPS_SITES] + non_renderer_process_count);
nick37dfd9de2015-09-14 19:54:03280
nickb2545f72015-10-30 20:05:15281 // ISOLATE_EXTENSIONS metrics.
nick37dfd9de2015-09-14 19:54:03282 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.IsolateExtensionsProcessCountNoLimit",
283 num_isolated_site_instances[ISOLATE_EXTENSIONS]);
284 UMA_HISTOGRAM_COUNTS_100(
285 "SiteIsolation.IsolateExtensionsProcessCountLowerBound",
286 process_count_lower_bound[ISOLATE_EXTENSIONS]);
287 UMA_HISTOGRAM_COUNTS_100(
288 "SiteIsolation.IsolateExtensionsProcessCountEstimate",
289 process_count_estimate[ISOLATE_EXTENSIONS]);
nick37dfd9de2015-09-14 19:54:03290 UMA_HISTOGRAM_COUNTS_100(
291 "SiteIsolation.IsolateExtensionsTotalProcessCountEstimate",
292 process_count_estimate[ISOLATE_EXTENSIONS] + non_renderer_process_count);
[email protected]1ae93fb12013-06-14 03:38:56293}