summaryrefslogtreecommitdiff
path: root/chromium/components/site_isolation
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/site_isolation
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-c30a6232df03e1efbd9f3b226777b07e087a1122.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/site_isolation')
-rw-r--r--chromium/components/site_isolation/BUILD.gn26
-rw-r--r--chromium/components/site_isolation/DEPS7
-rw-r--r--chromium/components/site_isolation/features.cc44
-rw-r--r--chromium/components/site_isolation/features.h20
-rw-r--r--chromium/components/site_isolation/pref_names.cc17
-rw-r--r--chromium/components/site_isolation/pref_names.h16
-rw-r--r--chromium/components/site_isolation/site_isolation_policy.cc133
-rw-r--r--chromium/components/site_isolation/site_isolation_policy.h54
-rw-r--r--chromium/components/site_isolation/site_isolation_policy_unittest.cc938
9 files changed, 1254 insertions, 1 deletions
diff --git a/chromium/components/site_isolation/BUILD.gn b/chromium/components/site_isolation/BUILD.gn
index e079b2436c7..6e877b2c355 100644
--- a/chromium/components/site_isolation/BUILD.gn
+++ b/chromium/components/site_isolation/BUILD.gn
@@ -27,8 +27,14 @@ buildflag_header("buildflags") {
source_set("site_isolation") {
sources = [
+ "features.cc",
+ "features.h",
+ "pref_names.cc",
+ "pref_names.h",
"preloaded_isolated_origins.cc",
"preloaded_isolated_origins.h",
+ "site_isolation_policy.cc",
+ "site_isolation_policy.h",
]
if (use_internal_isolated_origins) {
@@ -41,7 +47,27 @@ source_set("site_isolation") {
deps = [
":buildflags",
"//base",
+ "//components/prefs",
+ "//components/user_prefs",
"//content/public/browser",
"//url",
]
}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [ "site_isolation_policy_unittest.cc" ]
+ deps = [
+ ":site_isolation",
+ "//base",
+ "//base/test:test_support",
+ "//build:branding_buildflags",
+ "//components/prefs",
+ "//components/prefs:test_support",
+ "//components/user_prefs",
+ "//components/variations",
+ "//content/public/browser",
+ "//content/test:test_support",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/site_isolation/DEPS b/chromium/components/site_isolation/DEPS
index f7bd8874887..aee55fdfec2 100644
--- a/chromium/components/site_isolation/DEPS
+++ b/chromium/components/site_isolation/DEPS
@@ -1,6 +1,11 @@
include_rules = [
"+base",
"+build",
+ "+components/prefs",
+ "+components/user_prefs",
+ "+components/variations",
"+content/public/browser",
+ "+content/public/common",
+ "+content/public/test",
"+url",
-] \ No newline at end of file
+]
diff --git a/chromium/components/site_isolation/features.cc b/chromium/components/site_isolation/features.cc
new file mode 100644
index 00000000000..7d180987b95
--- /dev/null
+++ b/chromium/components/site_isolation/features.cc
@@ -0,0 +1,44 @@
+// Copyright 2020 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 "components/site_isolation/features.h"
+
+#include "build/build_config.h"
+
+namespace site_isolation {
+namespace features {
+
+// Controls a mode for dynamically process-isolating sites where the user has
+// entered a password. This is intended to be used primarily when full site
+// isolation is turned off. To check whether this mode is enabled, use
+// SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled() rather than
+// checking the feature directly, since that decision is influenced by other
+// factors as well.
+const base::Feature kSiteIsolationForPasswordSites {
+ "site-isolation-for-password-sites",
+// Enabled by default on Android; see https://crbug.com/849815. Note that this
+// should not affect Android Webview, which does not include this code.
+#if defined(OS_ANDROID)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
+
+// kSitePerProcessOnlyForHighMemoryClients is checked before kSitePerProcess,
+// and (if enabled) can restrict if kSitePerProcess feature is checked at all -
+// no check will be made on devices with low memory (these devices will have no
+// Site Isolation via kSitePerProcess trials and won't activate either the
+// control or the experiment group). The threshold for what is considered a
+// "low memory" device is set (in MB) via a field trial param with the name
+// defined below ("site-per-process-low-memory-cutoff-mb") and compared against
+// base::SysInfo::AmountOfPhysicalMemoryMB().
+const base::Feature kSitePerProcessOnlyForHighMemoryClients{
+ "site-per-process-only-for-high-memory-clients",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const char kSitePerProcessOnlyForHighMemoryClientsParamName[] =
+ "site-per-process-low-memory-cutoff-mb";
+
+} // namespace features
+} // namespace site_isolation
diff --git a/chromium/components/site_isolation/features.h b/chromium/components/site_isolation/features.h
new file mode 100644
index 00000000000..4fb00df2546
--- /dev/null
+++ b/chromium/components/site_isolation/features.h
@@ -0,0 +1,20 @@
+// Copyright 2020 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.
+
+#ifndef COMPONENTS_SITE_ISOLATION_FEATURES_H_
+#define COMPONENTS_SITE_ISOLATION_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace site_isolation {
+namespace features {
+
+extern const base::Feature kSiteIsolationForPasswordSites;
+extern const base::Feature kSitePerProcessOnlyForHighMemoryClients;
+extern const char kSitePerProcessOnlyForHighMemoryClientsParamName[];
+
+} // namespace features
+} // namespace site_isolation
+
+#endif // COMPONENTS_SITE_ISOLATION_FEATURES_H_
diff --git a/chromium/components/site_isolation/pref_names.cc b/chromium/components/site_isolation/pref_names.cc
new file mode 100644
index 00000000000..403cf018f8e
--- /dev/null
+++ b/chromium/components/site_isolation/pref_names.cc
@@ -0,0 +1,17 @@
+// Copyright 2020 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 "components/site_isolation/pref_names.h"
+
+namespace site_isolation {
+namespace prefs {
+
+// A list of origins that were heuristically determined to need process
+// isolation. For example, an origin may be placed on this list in response to
+// the user typing a password on it.
+const char kUserTriggeredIsolatedOrigins[] =
+ "site_isolation.user_triggered_isolated_origins";
+
+} // namespace prefs
+} // namespace site_isolation
diff --git a/chromium/components/site_isolation/pref_names.h b/chromium/components/site_isolation/pref_names.h
new file mode 100644
index 00000000000..ffdf32f2e1e
--- /dev/null
+++ b/chromium/components/site_isolation/pref_names.h
@@ -0,0 +1,16 @@
+// Copyright 2020 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.
+
+#ifndef COMPONENTS_SITE_ISOLATION_PREF_NAMES_H_
+#define COMPONENTS_SITE_ISOLATION_PREF_NAMES_H_
+
+namespace site_isolation {
+namespace prefs {
+
+extern const char kUserTriggeredIsolatedOrigins[];
+
+} // namespace prefs
+} // namespace site_isolation
+
+#endif // COMPONENTS_SITE_ISOLATION_PREF_NAMES_H
diff --git a/chromium/components/site_isolation/site_isolation_policy.cc b/chromium/components/site_isolation/site_isolation_policy.cc
new file mode 100644
index 00000000000..9a91d3034b0
--- /dev/null
+++ b/chromium/components/site_isolation/site_isolation_policy.cc
@@ -0,0 +1,133 @@
+// Copyright 2019 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 "components/site_isolation/site_isolation_policy.h"
+
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/system/sys_info.h"
+#include "build/build_config.h"
+#include "components/prefs/pref_service.h"
+#include "components/site_isolation/features.h"
+#include "components/site_isolation/pref_names.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/site_isolation_policy.h"
+
+namespace site_isolation {
+
+// static
+bool SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled() {
+ // If the user has explicitly enabled site isolation for password sites from
+ // chrome://flags or from the command line, honor this regardless of policies
+ // that may disable site isolation. In particular, this means that the
+ // chrome://flags switch for this feature takes precedence over any memory
+ // threshold restrictions and over a switch for disabling site isolation.
+ if (base::FeatureList::GetInstance()->IsFeatureOverriddenFromCommandLine(
+ features::kSiteIsolationForPasswordSites.name,
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE)) {
+ return true;
+ }
+
+ // Don't isolate anything when site isolation is turned off by the user or
+ // policy. This includes things like the switches::kDisableSiteIsolation
+ // command-line switch, the corresponding "Disable site isolation" entry in
+ // chrome://flags, enterprise policy controlled via
+ // switches::kDisableSiteIsolationForPolicy, and memory threshold checks in
+ // ShouldDisableSiteIsolationDueToMemoryThreshold().
+ if (!content::SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled())
+ return false;
+
+ // The feature needs to be checked last, because checking the feature
+ // activates the field trial and assigns the client either to a control or an
+ // experiment group - such assignment should be final.
+ return base::FeatureList::IsEnabled(features::kSiteIsolationForPasswordSites);
+}
+
+// static
+bool SiteIsolationPolicy::IsEnterprisePolicyApplicable() {
+#if defined(OS_ANDROID)
+ // https://crbug.com/844118: Limiting policy to devices with > 1GB RAM.
+ // Using 1077 rather than 1024 because 1) it helps ensure that devices with
+ // exactly 1GB of RAM won't get included because of inaccuracies or off-by-one
+ // errors and 2) this is the bucket boundary in Memory.Stats.Win.TotalPhys2.
+ bool have_enough_memory = base::SysInfo::AmountOfPhysicalMemoryMB() > 1077;
+ return have_enough_memory;
+#else
+ return true;
+#endif
+}
+
+// static
+bool SiteIsolationPolicy::ShouldDisableSiteIsolationDueToMemoryThreshold() {
+ // The memory threshold behavior differs for desktop and Android:
+ // - Android uses a 1900MB default threshold, which is the threshold used by
+ // password-triggered site isolation - see docs in
+ // https://crbug.com/849815. This can be overridden via a param defined in
+ // a kSitePerProcessOnlyForHighMemoryClients field trial.
+ // - Desktop does not enforce a default memory threshold, but for now we
+ // still support a threshold defined via a
+ // kSitePerProcessOnlyForHighMemoryClients field trial. The trial
+ // typically carries the threshold in a param; if it doesn't, use a default
+ // that's slightly higher than 1GB (see https://crbug.com/844118).
+ //
+ // TODO(alexmos): currently, this threshold applies to all site isolation
+ // modes. Eventually, we may need separate thresholds for different modes,
+ // such as full site isolation vs. password-triggered site isolation.
+#if defined(OS_ANDROID)
+ constexpr int kDefaultMemoryThresholdMb = 1900;
+#else
+ constexpr int kDefaultMemoryThresholdMb = 1077;
+#endif
+
+ // TODO(acolwell): Rename feature since it now affects more than just the
+ // site-per-process case.
+ if (base::FeatureList::IsEnabled(
+ features::kSitePerProcessOnlyForHighMemoryClients)) {
+ int memory_threshold_mb = base::GetFieldTrialParamByFeatureAsInt(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ features::kSitePerProcessOnlyForHighMemoryClientsParamName,
+ kDefaultMemoryThresholdMb);
+ return base::SysInfo::AmountOfPhysicalMemoryMB() <= memory_threshold_mb;
+ }
+
+#if defined(OS_ANDROID)
+ if (base::SysInfo::AmountOfPhysicalMemoryMB() <= kDefaultMemoryThresholdMb) {
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+// static
+void SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(
+ content::BrowserContext* browser_context) {
+ // If the user turned off password-triggered isolation, don't apply any
+ // stored isolated origins, but also don't clear them from prefs, so that
+ // they can be used if password-triggered isolation is re-enabled later.
+ if (!IsIsolationForPasswordSitesEnabled())
+ return;
+
+ std::vector<url::Origin> origins;
+ for (const auto& value :
+ *user_prefs::UserPrefs::Get(browser_context)
+ ->GetList(prefs::kUserTriggeredIsolatedOrigins)) {
+ origins.push_back(url::Origin::Create(GURL(value.GetString())));
+ }
+
+ if (!origins.empty()) {
+ auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
+ using IsolatedOriginSource =
+ content::ChildProcessSecurityPolicy::IsolatedOriginSource;
+ policy->AddIsolatedOrigins(origins, IsolatedOriginSource::USER_TRIGGERED,
+ browser_context);
+ }
+
+ UMA_HISTOGRAM_COUNTS_1000(
+ "SiteIsolation.SavedUserTriggeredIsolatedOrigins.Size", origins.size());
+}
+
+} // namespace site_isolation
diff --git a/chromium/components/site_isolation/site_isolation_policy.h b/chromium/components/site_isolation/site_isolation_policy.h
new file mode 100644
index 00000000000..ade65a884d6
--- /dev/null
+++ b/chromium/components/site_isolation/site_isolation_policy.h
@@ -0,0 +1,54 @@
+// Copyright 2019 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.
+
+#ifndef COMPONENTS_SITE_ISOLATION_SITE_ISOLATION_POLICY_H_
+#define COMPONENTS_SITE_ISOLATION_SITE_ISOLATION_POLICY_H_
+
+#include "base/macros.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace site_isolation {
+
+// A centralized place for making policy decisions about site isolation modes
+// which can be shared between content embedders. This supplements
+// content::SiteIsolationPolicy with features that may be useful to embedders.
+//
+// These methods can be called from any thread.
+class SiteIsolationPolicy {
+ public:
+ // Returns true if the site isolation mode for isolating sites where users
+ // enter passwords is enabled.
+ static bool IsIsolationForPasswordSitesEnabled();
+
+ // Returns true if Site Isolation related enterprise policies should take
+ // effect (e.g. such policies might not be applicable to low-end Android
+ // devices because of 1) performance impact and 2) infeasibility of
+ // Spectre-like attacks on such devices).
+ static bool IsEnterprisePolicyApplicable();
+
+ // Reads and applies any isolated origins stored in user prefs associated with
+ // |browser_context|. This is expected to be called on startup after user
+ // prefs have been loaded.
+ static void ApplyPersistedIsolatedOrigins(
+ content::BrowserContext* browser_context);
+
+ // Determines whether Site Isolation should be disabled because the device
+ // does not have the minimum required amount of memory.
+ //
+ // TODO(alexmos): Currently, the memory threshold is shared for all site
+ // isolation modes, including strict site isolation and password site
+ // isolation. In the future, some site isolation modes may require their own
+ // memory threshold.
+ static bool ShouldDisableSiteIsolationDueToMemoryThreshold();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SiteIsolationPolicy);
+};
+
+} // namespace site_isolation
+
+#endif // COMPONENTS_SITE_ISOLATION_SITE_ISOLATION_POLICY_H_
diff --git a/chromium/components/site_isolation/site_isolation_policy_unittest.cc b/chromium/components/site_isolation/site_isolation_policy_unittest.cc
new file mode 100644
index 00000000000..47d16fddefb
--- /dev/null
+++ b/chromium/components/site_isolation/site_isolation_policy_unittest.cc
@@ -0,0 +1,938 @@
+// Copyright 2019 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 "components/site_isolation/site_isolation_policy.h"
+
+#include "base/base_switches.h"
+#include "base/system/sys_info.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_field_trial_list_resetter.h"
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/site_isolation/features.h"
+#include "components/site_isolation/pref_names.h"
+#include "components/site_isolation/preloaded_isolated_origins.h"
+#include "components/user_prefs/user_prefs.h"
+#include "components/variations/variations_switches.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/site_isolation_policy.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace site_isolation {
+namespace {
+
+// Some command-line switches override field trials - the tests need to be
+// skipped in this case.
+bool ShouldSkipBecauseOfConflictingCommandLineSwitches() {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return true;
+
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableSiteIsolation))
+ return true;
+
+ return false;
+}
+
+} // namespace
+
+// Base class for site isolation tests which handles setting a
+// ContentBrowserClient with logic for enabling/disabling site isolation.
+class BaseSiteIsolationTest : public testing::Test {
+ public:
+ BaseSiteIsolationTest() {
+ original_client_ = content::SetBrowserClientForTesting(&browser_client_);
+ SetEnableStrictSiteIsolation(
+ original_client_->ShouldEnableStrictSiteIsolation());
+ }
+
+ ~BaseSiteIsolationTest() override {
+ content::SetBrowserClientForTesting(original_client_);
+ }
+
+ protected:
+ void SetEnableStrictSiteIsolation(bool enable) {
+ browser_client_.strict_isolation_enabled_ = enable;
+ }
+
+ private:
+ class SiteIsolationContentBrowserClient
+ : public content::ContentBrowserClient {
+ public:
+ bool ShouldEnableStrictSiteIsolation() override {
+ return strict_isolation_enabled_;
+ }
+
+ bool ShouldDisableSiteIsolation() override {
+ return SiteIsolationPolicy::
+ ShouldDisableSiteIsolationDueToMemoryThreshold();
+ }
+
+ std::vector<url::Origin> GetOriginsRequiringDedicatedProcess() override {
+ return GetBrowserSpecificBuiltInIsolatedOrigins();
+ }
+
+ bool strict_isolation_enabled_ = false;
+ };
+
+ SiteIsolationContentBrowserClient browser_client_;
+ content::ContentBrowserClient* original_client_ = nullptr;
+};
+
+class SiteIsolationPolicyTest : public BaseSiteIsolationTest {
+ public:
+ SiteIsolationPolicyTest() {
+ prefs_.registry()->RegisterListPref(prefs::kUserTriggeredIsolatedOrigins);
+ user_prefs::UserPrefs::Set(&browser_context_, &prefs_);
+ }
+
+ protected:
+ content::BrowserContext* browser_context() { return &browser_context_; }
+
+ PrefService* prefs() { return &prefs_; }
+
+ private:
+ content::BrowserTaskEnvironment task_environment_;
+ content::TestBrowserContext browser_context_;
+ TestingPrefServiceSimple prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(SiteIsolationPolicyTest);
+};
+
+// Helper class that enables site isolation for password sites.
+class PasswordSiteIsolationPolicyTest : public SiteIsolationPolicyTest {
+ public:
+ PasswordSiteIsolationPolicyTest() = default;
+
+ protected:
+ void SetUp() override {
+ feature_list_.InitAndEnableFeature(
+ features::kSiteIsolationForPasswordSites);
+ SetEnableStrictSiteIsolation(false);
+ SiteIsolationPolicyTest::SetUp();
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordSiteIsolationPolicyTest);
+};
+
+// Verifies that SiteIsolationPolicy::ApplyPersistedIsolatedOrigins applies
+// stored isolated origins correctly when using site isolation for password
+// sites.
+TEST_F(PasswordSiteIsolationPolicyTest, ApplyPersistedIsolatedOrigins) {
+ EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+ // Add foo.com and bar.com to stored isolated origins.
+ {
+ ListPrefUpdate update(prefs(), prefs::kUserTriggeredIsolatedOrigins);
+ base::ListValue* list = update.Get();
+ list->Append("http://foo.com");
+ list->Append("https://bar.com");
+ }
+
+ // New SiteInstances for foo.com and bar.com shouldn't require a dedicated
+ // process to start with. An exception is if this test runs with a
+ // command-line --site-per-process flag (which might be the case on some
+ // bots). This will override the feature configuration in this test and make
+ // all sites isolated.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ scoped_refptr<content::SiteInstance> foo_instance =
+ content::SiteInstance::CreateForURL(browser_context(),
+ GURL("http://foo.com/1"));
+ EXPECT_FALSE(foo_instance->RequiresDedicatedProcess());
+
+ scoped_refptr<content::SiteInstance> bar_instance =
+ content::SiteInstance::CreateForURL(browser_context(),
+ GURL("https://baz.bar.com/2"));
+ EXPECT_FALSE(bar_instance->RequiresDedicatedProcess());
+ }
+
+ // Apply isolated origins and ensure that they take effect for SiteInstances
+ // in new BrowsingInstances.
+ base::HistogramTester histograms;
+ SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(browser_context());
+ histograms.ExpectUniqueSample(
+ "SiteIsolation.SavedUserTriggeredIsolatedOrigins.Size", 2, 1);
+ {
+ scoped_refptr<content::SiteInstance> foo_instance =
+ content::SiteInstance::CreateForURL(browser_context(),
+ GURL("http://foo.com/1"));
+ EXPECT_TRUE(foo_instance->RequiresDedicatedProcess());
+
+ scoped_refptr<content::SiteInstance> bar_instance =
+ content::SiteInstance::CreateForURL(browser_context(),
+ GURL("https://baz.bar.com/2"));
+ EXPECT_TRUE(bar_instance->RequiresDedicatedProcess());
+ }
+}
+
+// Helper class that disables strict site isolation as well as site isolation
+// for password sites.
+class NoPasswordSiteIsolationPolicyTest : public SiteIsolationPolicyTest {
+ public:
+ NoPasswordSiteIsolationPolicyTest() = default;
+
+ protected:
+ void SetUp() override {
+ feature_list_.InitAndDisableFeature(
+ features::kSiteIsolationForPasswordSites);
+ SetEnableStrictSiteIsolation(false);
+ SiteIsolationPolicyTest::SetUp();
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(NoPasswordSiteIsolationPolicyTest);
+};
+
+// Verifies that SiteIsolationPolicy::ApplyPersistedIsolatedOrigins ignores
+// stored isolated origins when site isolation for password sites is off.
+TEST_F(NoPasswordSiteIsolationPolicyTest,
+ PersistedIsolatedOriginsIgnoredWithoutPasswordIsolation) {
+ // Running this test with a command-line --site-per-process flag (which might
+ // be the case on some bots) doesn't make sense, as that will make all sites
+ // isolated, overriding the feature configuration in this test.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return;
+
+ EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+ // Add foo.com to stored isolated origins.
+ {
+ ListPrefUpdate update(prefs(), prefs::kUserTriggeredIsolatedOrigins);
+ base::ListValue* list = update.Get();
+ list->Append("http://foo.com");
+ }
+
+ // Applying saved isolated origins should have no effect, since site
+ // isolation for password sites is off.
+ SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(browser_context());
+ scoped_refptr<content::SiteInstance> foo_instance =
+ content::SiteInstance::CreateForURL(browser_context(),
+ GURL("http://foo.com/"));
+ EXPECT_FALSE(foo_instance->RequiresDedicatedProcess());
+}
+
+enum class SitePerProcessMemoryThreshold {
+ kNone,
+ k128MB,
+ k768MB,
+};
+
+enum class SitePerProcessMode {
+ kDisabled,
+ kEnabled,
+ kIsolatedOrigin,
+};
+
+struct SitePerProcessMemoryThresholdBrowserTestParams {
+ SitePerProcessMemoryThreshold threshold;
+ SitePerProcessMode mode;
+};
+
+const url::Origin& GetTrialOrigin() {
+ static base::NoDestructor<url::Origin> origin{
+ url::Origin::Create(GURL("http://foo.com/"))};
+ return *origin;
+}
+
+// Helper class to run tests on a simulated 512MB low-end device.
+class SitePerProcessMemoryThresholdBrowserTest
+ : public BaseSiteIsolationTest,
+ public ::testing::WithParamInterface<
+ SitePerProcessMemoryThresholdBrowserTestParams> {
+ public:
+ SitePerProcessMemoryThresholdBrowserTest() {
+ switch (GetParam().threshold) {
+ case SitePerProcessMemoryThreshold::kNone:
+ break;
+ case SitePerProcessMemoryThreshold::k128MB:
+ threshold_feature_.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName,
+ "128"}});
+ break;
+ case SitePerProcessMemoryThreshold::k768MB:
+ threshold_feature_.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName,
+ "768"}});
+ break;
+ }
+
+ switch (GetParam().mode) {
+ case SitePerProcessMode::kDisabled:
+ SetEnableStrictSiteIsolation(false);
+ break;
+ case SitePerProcessMode::kEnabled:
+ SetEnableStrictSiteIsolation(true);
+ break;
+ case SitePerProcessMode::kIsolatedOrigin:
+ mode_feature_.InitAndEnableFeatureWithParameters(
+ ::features::kIsolateOrigins,
+ {{::features::kIsolateOriginsFieldTrialParamName,
+ GetTrialOrigin().Serialize()}});
+ break;
+ }
+ }
+
+ void SetUp() override {
+ // This way the test always sees the same amount of physical memory
+ // (kLowMemoryDeviceThresholdMB = 512MB), regardless of how much memory is
+ // available in the testing environment.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableLowEndDeviceMode);
+ EXPECT_EQ(512, base::SysInfo::AmountOfPhysicalMemoryMB());
+
+ // On Android official builds, we expect to isolate an additional set of
+ // built-in origins.
+ expected_embedder_origins_ = GetBrowserSpecificBuiltInIsolatedOrigins();
+ }
+
+ protected:
+ content::BrowserTaskEnvironment task_environment_;
+
+ // These are the origins we expect to be returned by
+ // content::ChildProcessSecurityPolicy::GetIsolatedOrigins() even if
+ // ContentBrowserClient::ShouldDisableSiteIsolation() returns true.
+ std::vector<url::Origin> expected_embedder_origins_;
+
+#if defined(OS_ANDROID)
+ // On Android we don't expect any trial origins because the 512MB
+ // physical memory used for testing is below the Android specific
+ // hardcoded 1024MB memory limit that disables site isolation.
+ const std::size_t kExpectedTrialOrigins = 0;
+#else
+ // All other platforms expect the single trial origin to be returned because
+ // they don't have the memory limit that disables site isolation.
+ const std::size_t kExpectedTrialOrigins = 1;
+#endif
+
+ private:
+ base::test::ScopedFeatureList threshold_feature_;
+ base::test::ScopedFeatureList mode_feature_;
+
+ DISALLOW_COPY_AND_ASSIGN(SitePerProcessMemoryThresholdBrowserTest);
+};
+
+using SitePerProcessMemoryThresholdBrowserTestNoIsolation =
+ SitePerProcessMemoryThresholdBrowserTest;
+TEST_P(SitePerProcessMemoryThresholdBrowserTestNoIsolation, NoIsolation) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // Isolation should be disabled given the set of parameters used to
+ // instantiate these tests.
+ EXPECT_FALSE(
+ content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites());
+}
+
+using SitePerProcessMemoryThresholdBrowserTestIsolation =
+ SitePerProcessMemoryThresholdBrowserTest;
+TEST_P(SitePerProcessMemoryThresholdBrowserTestIsolation, Isolation) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // Isolation should be enabled given the set of parameters used to
+ // instantiate these tests.
+ EXPECT_TRUE(content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ NoIsolation,
+ SitePerProcessMemoryThresholdBrowserTestNoIsolation,
+ testing::Values(
+#if defined(OS_ANDROID)
+ // Expect no isolation on Android because 512MB physical memory
+ // triggered by kEnableLowEndDeviceMode in SetUp() is below the 1024MB
+ // Android specific memory limit which disables site isolation for all
+ // sites.
+ SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::kNone, SitePerProcessMode::kEnabled},
+#endif
+ SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::k768MB,
+ SitePerProcessMode::kEnabled},
+ SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::kNone,
+ SitePerProcessMode::kDisabled},
+ SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::k128MB,
+ SitePerProcessMode::kDisabled},
+ SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::k768MB,
+ SitePerProcessMode::kDisabled}));
+
+INSTANTIATE_TEST_SUITE_P(Isolation,
+ SitePerProcessMemoryThresholdBrowserTestIsolation,
+ testing::Values(
+#if !defined(OS_ANDROID)
+ // See the note above regarding why this
+ // expectation is different on Android.
+ SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::kNone,
+ SitePerProcessMode::kEnabled},
+#endif
+ SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::k128MB,
+ SitePerProcessMode::kEnabled}));
+
+using SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin =
+ SitePerProcessMemoryThresholdBrowserTest;
+TEST_P(SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin,
+ TrialNoIsolatedOrigin) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins();
+
+ auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance();
+ std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins();
+ EXPECT_EQ(expected_embedder_origins_.size(), isolated_origins.size());
+
+ // Verify that the expected embedder origins are present even though site
+ // isolation has been disabled and the trial origins should not be present.
+ EXPECT_THAT(expected_embedder_origins_,
+ ::testing::IsSubsetOf(isolated_origins));
+
+ // Verify that the trial origin is not present.
+ EXPECT_THAT(isolated_origins,
+ ::testing::Not(::testing::Contains(GetTrialOrigin())));
+}
+
+using SitePerProcessMemoryThresholdBrowserTestIsolatedOrigin =
+ SitePerProcessMemoryThresholdBrowserTest;
+TEST_P(SitePerProcessMemoryThresholdBrowserTestIsolatedOrigin,
+ TrialIsolatedOrigin) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins();
+
+ auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance();
+ std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins();
+ EXPECT_EQ(1u + expected_embedder_origins_.size(), isolated_origins.size());
+ EXPECT_THAT(expected_embedder_origins_,
+ ::testing::IsSubsetOf(isolated_origins));
+
+ // Verify that the trial origin is present.
+ EXPECT_THAT(isolated_origins, ::testing::Contains(GetTrialOrigin()));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ TrialNoIsolatedOrigin,
+ SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin,
+ testing::Values(
+#if defined(OS_ANDROID)
+ // When the memory threshold is not explicitly specified, Android uses
+ // a 1900MB global memory threshold. The 512MB simulated device memory
+ // is below 1900MB, so the test origin should not be isolated.
+ SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::kNone,
+ SitePerProcessMode::kIsolatedOrigin},
+#endif
+ // The 512MB simulated device memory is under the explicit 768MB memory
+ // threshold below, so the test origin should not be isolated.
+ SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::k768MB,
+ SitePerProcessMode::kIsolatedOrigin}));
+
+INSTANTIATE_TEST_SUITE_P(
+ TrialIsolatedOrigin,
+ SitePerProcessMemoryThresholdBrowserTestIsolatedOrigin,
+ // The 512MB simulated device memory is above the explicit 128MB memory
+ // threshold below, so the test origin should be isolated both on desktop
+ // and Android.
+ testing::Values(SitePerProcessMemoryThresholdBrowserTestParams{
+ SitePerProcessMemoryThreshold::k128MB,
+ SitePerProcessMode::kIsolatedOrigin}));
+
+// Helper class to run tests with password-triggered site isolation initialized
+// via a regular field trial and *not* via a command-line override. It
+// creates a new field trial (with 100% probability of being in the group), and
+// initializes the test class's ScopedFeatureList using it. Two derived
+// classes below control are used to initialize the feature to either enabled
+// or disabled state.
+class PasswordSiteIsolationFieldTrialTest : public BaseSiteIsolationTest {
+ public:
+ explicit PasswordSiteIsolationFieldTrialTest(bool should_enable)
+ : field_trial_list_(std::make_unique<base::MockEntropyProvider>()) {
+ const std::string kTrialName = "PasswordSiteIsolation";
+ const std::string kGroupName = "FooGroup"; // unused
+ scoped_refptr<base::FieldTrial> trial =
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->RegisterFieldTrialOverride(
+ features::kSiteIsolationForPasswordSites.name,
+ should_enable
+ ? base::FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE
+ : base::FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE,
+ trial.get());
+
+ feature_list_.InitWithFeatureList(std::move(feature_list));
+ }
+
+ void SetUp() override {
+ // This test creates and tests its own field trial group, so it needs to
+ // disable the field trial testing config, which might define an
+ // incompatible trial name/group.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ variations::switches::kDisableFieldTrialTestingConfig);
+
+ // This way the test always sees the same amount of physical memory
+ // (kLowMemoryDeviceThresholdMB = 512MB), regardless of how much memory is
+ // available in the testing environment.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableLowEndDeviceMode);
+ EXPECT_EQ(512, base::SysInfo::AmountOfPhysicalMemoryMB());
+ }
+
+ protected:
+ base::test::ScopedFieldTrialListResetter trial_list_resetter_;
+ base::test::ScopedFeatureList feature_list_;
+ base::FieldTrialList field_trial_list_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PasswordSiteIsolationFieldTrialTest);
+};
+
+class EnabledPasswordSiteIsolationFieldTrialTest
+ : public PasswordSiteIsolationFieldTrialTest {
+ public:
+ EnabledPasswordSiteIsolationFieldTrialTest()
+ : PasswordSiteIsolationFieldTrialTest(true /* should_enable */) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(EnabledPasswordSiteIsolationFieldTrialTest);
+};
+
+class DisabledPasswordSiteIsolationFieldTrialTest
+ : public PasswordSiteIsolationFieldTrialTest {
+ public:
+ DisabledPasswordSiteIsolationFieldTrialTest()
+ : PasswordSiteIsolationFieldTrialTest(false /* should_enable */) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DisabledPasswordSiteIsolationFieldTrialTest);
+};
+
+TEST_F(EnabledPasswordSiteIsolationFieldTrialTest, BelowThreshold) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // If no memory threshold is defined, password site isolation should be
+ // enabled on desktop. It should be disabled on Android, because Android
+ // defaults to a 1900MB memory threshold, which is above the 512MB physical
+ // memory that this test simulates.
+#if defined(OS_ANDROID)
+ EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+#else
+ EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+#endif
+
+ // Define a memory threshold at 768MB. Since this is above the 512MB of
+ // physical memory that this test simulates, password site isolation should
+ // now be disabled.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}});
+
+ EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+ // Simulate enabling password site isolation from command line. (Note that
+ // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+ // internally, and that triggering the feature via chrome://flags follows the
+ // same override path as well.)
+ base::test::ScopedFeatureList password_site_isolation_feature;
+ password_site_isolation_feature.InitAndEnableFeature(
+ features::kSiteIsolationForPasswordSites);
+
+ // This should override the memory threshold and enable password site
+ // isolation.
+ EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+}
+
+TEST_F(EnabledPasswordSiteIsolationFieldTrialTest, AboveThreshold) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // If no memory threshold is defined, password site isolation should be
+ // enabled on desktop. It should be disabled on Android, because Android
+ // defaults to a 1900MB memory threshold, which is above the 512MB physical
+ // memory that this test simulates.
+#if defined(OS_ANDROID)
+ EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+#else
+ EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+#endif
+
+ // Define a memory threshold at 128MB. Since this is below the 512MB of
+ // physical memory that this test simulates, password site isolation should
+ // still be enabled.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}});
+
+ EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+ // Simulate disabling password site isolation from command line. (Note that
+ // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+ // internally, and that triggering the feature via chrome://flags follows the
+ // same override path as well.) This should take precedence over the regular
+ // field trial behavior.
+ base::test::ScopedFeatureList password_site_isolation_feature;
+ password_site_isolation_feature.InitAndDisableFeature(
+ features::kSiteIsolationForPasswordSites);
+ EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+}
+
+// This test verifies that when password-triggered site isolation is disabled
+// via field trials but force-enabled via command line, it takes effect even
+// when below the memory threshold. See https://crbug.com/1009828.
+TEST_F(DisabledPasswordSiteIsolationFieldTrialTest,
+ CommandLineOverride_BelowThreshold) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // Password site isolation should be disabled at this point.
+ EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+ // Simulate enabling password site isolation from command line. (Note that
+ // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+ // internally, and that triggering the feature via chrome://flags follows the
+ // same override path as well.)
+ base::test::ScopedFeatureList password_site_isolation_feature;
+ password_site_isolation_feature.InitAndEnableFeature(
+ features::kSiteIsolationForPasswordSites);
+
+ // If no memory threshold is defined, password site isolation should be
+ // enabled.
+ EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+ // Define a memory threshold at 768MB. This is above the 512MB of physical
+ // memory that this test simulates, but password site isolation should still
+ // be enabled, because the test has simulated the user manually overriding
+ // this feature via command line.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}});
+
+ EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+}
+
+// Similar to the test above, but with device memory being above memory
+// threshold.
+TEST_F(DisabledPasswordSiteIsolationFieldTrialTest,
+ CommandLineOverride_AboveThreshold) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+ base::test::ScopedFeatureList password_site_isolation_feature;
+ password_site_isolation_feature.InitAndEnableFeature(
+ features::kSiteIsolationForPasswordSites);
+
+ // If no memory threshold is defined, password site isolation should be
+ // enabled.
+ EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}});
+
+ EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+}
+
+// Helper class to run tests with strict origin isolation initialized via
+// a regular field trial and *not* via a command-line override. It creates a
+// new field trial (with 100% probability of being in the group), and
+// initializes the test class's ScopedFeatureList using it. Two derived
+// classes below control are used to initialize the feature to either enabled
+// or disabled state.
+class StrictOriginIsolationFieldTrialTest : public BaseSiteIsolationTest {
+ public:
+ explicit StrictOriginIsolationFieldTrialTest(bool should_enable)
+ : field_trial_list_(std::make_unique<base::MockEntropyProvider>()) {
+ const std::string kTrialName = "StrictOriginIsolation";
+ const std::string kGroupName = "FooGroup"; // unused
+ scoped_refptr<base::FieldTrial> trial =
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->RegisterFieldTrialOverride(
+ ::features::kStrictOriginIsolation.name,
+ should_enable
+ ? base::FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE
+ : base::FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE,
+ trial.get());
+
+ feature_list_.InitWithFeatureList(std::move(feature_list));
+ }
+
+ void SetUp() override {
+ // This test creates and tests its own field trial group, so it needs to
+ // disable the field trial testing config, which might define an
+ // incompatible trial name/group.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ variations::switches::kDisableFieldTrialTestingConfig);
+
+ // This way the test always sees the same amount of physical memory
+ // (kLowMemoryDeviceThresholdMB = 512MB), regardless of how much memory is
+ // available in the testing environment.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableLowEndDeviceMode);
+ EXPECT_EQ(512, base::SysInfo::AmountOfPhysicalMemoryMB());
+ }
+
+ protected:
+ base::test::ScopedFieldTrialListResetter trial_list_resetter_;
+ base::test::ScopedFeatureList feature_list_;
+ base::FieldTrialList field_trial_list_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StrictOriginIsolationFieldTrialTest);
+};
+
+class EnabledStrictOriginIsolationFieldTrialTest
+ : public StrictOriginIsolationFieldTrialTest {
+ public:
+ EnabledStrictOriginIsolationFieldTrialTest()
+ : StrictOriginIsolationFieldTrialTest(true /* should_enable */) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(EnabledStrictOriginIsolationFieldTrialTest);
+};
+
+class DisabledStrictOriginIsolationFieldTrialTest
+ : public StrictOriginIsolationFieldTrialTest {
+ public:
+ DisabledStrictOriginIsolationFieldTrialTest()
+ : StrictOriginIsolationFieldTrialTest(false /* should_enable */) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DisabledStrictOriginIsolationFieldTrialTest);
+};
+
+// Check that when strict origin isolation is enabled via a field trial, and
+// the device is above the memory threshold, disabling it via the command line
+// takes precedence.
+TEST_F(EnabledStrictOriginIsolationFieldTrialTest,
+ DisabledViaCommandLineOverride) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // If no memory threshold is defined, strict origin isolation should be
+ // enabled on desktop. It should be disabled on Android, because Android
+ // defaults to a 1900MB memory threshold, which is above the 512MB physical
+ // memory that this test simulates.
+#if defined(OS_ANDROID)
+ EXPECT_FALSE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+#else
+ EXPECT_TRUE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+#endif
+
+ // Define a memory threshold at 128MB. Since this is below the 512MB of
+ // physical memory that this test simulates, strict origin isolation should
+ // still be enabled.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}});
+ EXPECT_TRUE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+
+ // Simulate disabling strict origin isolation from command line. (Note that
+ // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+ // internally, and that disabling the feature via chrome://flags follows the
+ // same override path as well.)
+ base::test::ScopedFeatureList strict_origin_isolation_feature;
+ strict_origin_isolation_feature.InitAndDisableFeature(
+ ::features::kStrictOriginIsolation);
+ EXPECT_FALSE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+}
+
+// This test verifies that when strict origin isolation is disabled
+// via field trials but force-enabled via command line, it takes effect even
+// when below the memory threshold. See https://crbug.com/1009828.
+TEST_F(DisabledStrictOriginIsolationFieldTrialTest,
+ EnabledViaCommandLineOverride_BelowThreshold) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // Strict origin isolation should be disabled at this point.
+ EXPECT_FALSE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+
+ // Simulate enabling strict origin isolation from command line. (Note that
+ // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+ // internally, and that triggering the feature via chrome://flags follows the
+ // same override path as well.)
+ base::test::ScopedFeatureList strict_origin_isolation_feature;
+ strict_origin_isolation_feature.InitAndEnableFeature(
+ ::features::kStrictOriginIsolation);
+
+ // If no memory threshold is defined, strict origin isolation should be
+ // enabled.
+ EXPECT_TRUE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+
+ // Define a memory threshold at 768MB. This is above the 512MB of physical
+ // memory that this test simulates, but strict origin isolation should still
+ // be enabled, because the test has simulated the user manually overriding
+ // this feature via command line.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}});
+
+ EXPECT_TRUE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+}
+
+// The following tests verify that the list of Android's built-in isolated
+// origins takes effect. This list is only used in official builds, and only
+// when above the memory threshold.
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_ANDROID)
+class BuiltInIsolatedOriginsTest : public SiteIsolationPolicyTest {
+ public:
+ BuiltInIsolatedOriginsTest() = default;
+
+ protected:
+ void SetUp() override {
+ // Simulate a 512MB device.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableLowEndDeviceMode);
+ EXPECT_EQ(512, base::SysInfo::AmountOfPhysicalMemoryMB());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BuiltInIsolatedOriginsTest);
+};
+
+// Check that the list of preloaded isolated origins is properly applied when
+// device RAM is above the site isolation memory threshold.
+TEST_F(BuiltInIsolatedOriginsTest, DefaultThreshold) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // Define a memory threshold at 128MB. This is below the 512MB of physical
+ // memory that this test simulates, so preloaded isolated origins should take
+ // effect.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}});
+
+ // Ensure that isolated origins that are normally loaded on browser
+ // startup are applied.
+ content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins();
+
+ EXPECT_TRUE(
+ content::SiteIsolationPolicy::ArePreloadedIsolatedOriginsEnabled());
+
+ auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance();
+ std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins(
+ content::ChildProcessSecurityPolicy::IsolatedOriginSource::BUILT_IN);
+
+ // The list of built-in origins is fairly large; we don't want to hardcode
+ // the size here as it might change, so just check that there are at least 10
+ // origins.
+ EXPECT_GT(isolated_origins.size(), 10u);
+
+ // Check that a couple of well-known origins are on the list.
+ EXPECT_THAT(
+ isolated_origins,
+ ::testing::Contains(url::Origin::Create(GURL("https://google.com/"))));
+ EXPECT_THAT(
+ isolated_origins,
+ ::testing::Contains(url::Origin::Create(GURL("https://amazon.com/"))));
+ EXPECT_THAT(
+ isolated_origins,
+ ::testing::Contains(url::Origin::Create(GURL("https://facebook.com/"))));
+
+ cpsp->ClearIsolatedOriginsForTesting();
+}
+
+TEST_F(BuiltInIsolatedOriginsTest, BelowThreshold) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // Define a memory threshold at 768MB. This is above the 512MB of physical
+ // memory that this test simulates, so preloaded isolated origins shouldn't
+ // take effect.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}});
+
+ // Ensure that isolated origins that are normally loaded on browser
+ // startup are applied.
+ content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins();
+
+ EXPECT_FALSE(
+ content::SiteIsolationPolicy::ArePreloadedIsolatedOriginsEnabled());
+
+ auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance();
+ std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins(
+ content::ChildProcessSecurityPolicy::IsolatedOriginSource::BUILT_IN);
+
+ // There shouldn't be any built-in origins on Android. (Note that desktop has
+ // some built-in origins that are applied regardless of memory threshold.)
+ EXPECT_EQ(isolated_origins.size(), 0u);
+
+ cpsp->ClearIsolatedOriginsForTesting();
+}
+
+// Check that the list of preloaded isolated origins is not applied when full
+// site isolation is used, since in that case the list is redundant.
+TEST_F(BuiltInIsolatedOriginsTest, NotAppliedWithFullSiteIsolation) {
+ // Force full site-per-process mode.
+ content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
+
+ // Define a memory threshold at 128MB. This is below the 512MB of physical
+ // memory that this test simulates, so preloaded isolated origins shouldn't
+ // be disabled by the memory threshold.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}});
+
+ // Ensure that isolated origins that are normally loaded on browser
+ // startup are applied.
+ content::SiteIsolationPolicy::ApplyGlobalIsolatedOrigins();
+
+ // Because full site-per-process is used, the preloaded isolated origins are
+ // redundant and should not be applied.
+ EXPECT_FALSE(
+ content::SiteIsolationPolicy::ArePreloadedIsolatedOriginsEnabled());
+
+ auto* cpsp = content::ChildProcessSecurityPolicy::GetInstance();
+ std::vector<url::Origin> isolated_origins = cpsp->GetIsolatedOrigins(
+ content::ChildProcessSecurityPolicy::IsolatedOriginSource::BUILT_IN);
+ EXPECT_EQ(isolated_origins.size(), 0u);
+}
+#endif
+
+} // namespace site_isolation