[Previews] Adds DeferAllScript support to Decider and OptGuide
Adds new opt guide proto optimization type for DeferAllScript with
whitelist checking for it from PreviewsDeciderImpl thru PreviewsHints.
Bug: 965277
Change-Id: I7be59e6eda9b64d310027ac2c3ddfb7f91ac76eb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1673754
Reviewed-by: Robert Ogden <robertogden@chromium.org>
Reviewed-by: Tarun Bansal <tbansal@chromium.org>
Commit-Queue: Doug Arnett <dougarnett@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672122}
diff --git a/components/optimization_guide/proto/hints.proto b/components/optimization_guide/proto/hints.proto
index fd24217..2f4ea430 100644
--- a/components/optimization_guide/proto/hints.proto
+++ b/components/optimization_guide/proto/hints.proto
@@ -118,6 +118,9 @@
LITE_PAGE_REDIRECT = 3;
// This optimization does nothing (no-op).
OPTIMIZATION_NONE = 4;
+ // This optimization defers execution of parser-blocking script until after
+ // parsing completes.
+ DEFER_ALL_SCRIPT = 5;
}
// Presents semantics for how page load URLs should be matched.
diff --git a/components/previews/content/hints_fetcher.cc b/components/previews/content/hints_fetcher.cc
index 7c06cd2c..9ddd2206 100644
--- a/components/previews/content/hints_fetcher.cc
+++ b/components/previews/content/hints_fetcher.cc
@@ -55,7 +55,8 @@
optimization_guide::proto::NOSCRIPT);
get_hints_request_->add_supported_optimizations(
optimization_guide::proto::RESOURCE_LOADING);
- // TODO(dougarnett): Add DEFER_ALL_SCRIPT once supported.
+ get_hints_request_->add_supported_optimizations(
+ optimization_guide::proto::DEFER_ALL_SCRIPT);
static_assert(static_cast<int>(PreviewsType::DEFER_ALL_SCRIPT) + 1 ==
static_cast<int>(PreviewsType::LAST),
"PreviewsType has been updated, make sure Optimization Guide "
diff --git a/components/previews/content/previews_decider_impl.cc b/components/previews/content/previews_decider_impl.cc
index d21753c..a523ac0 100644
--- a/components/previews/content/previews_decider_impl.cc
+++ b/components/previews/content/previews_decider_impl.cc
@@ -51,11 +51,11 @@
case PreviewsType::NOSCRIPT:
case PreviewsType::RESOURCE_LOADING_HINTS:
case PreviewsType::LITE_PAGE_REDIRECT:
+ case PreviewsType::DEFER_ALL_SCRIPT:
return true;
// These types do not have server optimization hints.
case PreviewsType::OFFLINE:
case PreviewsType::LITE_PAGE:
- case PreviewsType::DEFER_ALL_SCRIPT:
return false;
case PreviewsType::NONE:
case PreviewsType::UNSPECIFIED:
@@ -333,7 +333,8 @@
return ShouldAllowPreviewPerOptimizationHints(previews_data, url, type,
passed_reasons);
} else if (type == PreviewsType::RESOURCE_LOADING_HINTS ||
- type == PreviewsType::NOSCRIPT) {
+ type == PreviewsType::NOSCRIPT ||
+ type == PreviewsType::DEFER_ALL_SCRIPT) {
return PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER;
}
}
@@ -373,7 +374,8 @@
PreviewsType type) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(PreviewsType::NOSCRIPT == type ||
- PreviewsType::RESOURCE_LOADING_HINTS == type);
+ PreviewsType::RESOURCE_LOADING_HINTS == type ||
+ PreviewsType::DEFER_ALL_SCRIPT == type);
if (previews_black_list_ && !blacklist_ignored_) {
std::vector<PreviewsEligibilityReason> passed_reasons;
// The blacklist will disallow certain hosts for periods of time based on
@@ -412,7 +414,8 @@
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(type == PreviewsType::LITE_PAGE_REDIRECT ||
type == PreviewsType::NOSCRIPT ||
- type == PreviewsType::RESOURCE_LOADING_HINTS);
+ type == PreviewsType::RESOURCE_LOADING_HINTS ||
+ type == PreviewsType::DEFER_ALL_SCRIPT);
// For LitePageRedirect, ensure it is not blacklisted for this request, and
// hints have been fully loaded.
//
@@ -446,7 +449,8 @@
std::vector<PreviewsEligibilityReason>* passed_reasons) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(type == PreviewsType::NOSCRIPT ||
- type == PreviewsType::RESOURCE_LOADING_HINTS);
+ type == PreviewsType::RESOURCE_LOADING_HINTS ||
+ type == PreviewsType::DEFER_ALL_SCRIPT);
if (!previews_opt_guide_ || !previews_opt_guide_->has_hints())
return PreviewsEligibilityReason::OPTIMIZATION_HINTS_NOT_AVAILABLE;
diff --git a/components/previews/content/previews_decider_impl_unittest.cc b/components/previews/content/previews_decider_impl_unittest.cc
index 9efe547..5d28f9b 100644
--- a/components/previews/content/previews_decider_impl_unittest.cc
+++ b/components/previews/content/previews_decider_impl_unittest.cc
@@ -193,14 +193,16 @@
PreviewsType type,
net::EffectiveConnectionType* ect_threshold) const override {
EXPECT_TRUE(type == PreviewsType::NOSCRIPT ||
- type == PreviewsType::RESOURCE_LOADING_HINTS);
+ type == PreviewsType::RESOURCE_LOADING_HINTS ||
+ type == PreviewsType::DEFER_ALL_SCRIPT);
// Use default ect trigger threshold for the preview type.
*ect_threshold = previews::params::GetECTThresholdForPreview(type);
if (type == PreviewsType::NOSCRIPT) {
return url.host().compare("whitelisted.example.com") == 0 ||
url.host().compare("noscript_only_whitelisted.example.com") == 0;
}
- if (type == PreviewsType::RESOURCE_LOADING_HINTS) {
+ if (type == PreviewsType::RESOURCE_LOADING_HINTS ||
+ type == PreviewsType::DEFER_ALL_SCRIPT) {
return url.host().compare("whitelisted.example.com") == 0;
}
return false;
@@ -425,6 +427,7 @@
allowed_types[static_cast<int>(PreviewsType::LITE_PAGE_REDIRECT)] = 0;
allowed_types[static_cast<int>(PreviewsType::NOSCRIPT)] = 0;
allowed_types[static_cast<int>(PreviewsType::RESOURCE_LOADING_HINTS)] = 0;
+ allowed_types[static_cast<int>(PreviewsType::DEFER_ALL_SCRIPT)] = 0;
std::unique_ptr<TestPreviewsDeciderImpl> previews_decider_impl =
std::make_unique<TestPreviewsDeciderImpl>(&clock_);
@@ -1186,7 +1189,7 @@
scoped_feature_list.InitWithFeatures(
{features::kPreviews, features::kLitePageServerPreviews,
features::kOptimizationHints, features::kNoScriptPreviews,
- features::kResourceLoadingHints},
+ features::kResourceLoadingHints, features::kDeferAllScriptPreviews},
{});
InitializeUIService();
@@ -1203,6 +1206,11 @@
&user_data, GURL("https://whitelisted.example.com"), false,
PreviewsType::RESOURCE_LOADING_HINTS));
+ // DeferAllScript is allowed before commit without hints.
+ EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
+ &user_data, GURL("https://whitelisted.example.com"), false,
+ PreviewsType::DEFER_ALL_SCRIPT));
+
// LitePageRedirect is not allowed before commit without hints.
EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
&user_data, GURL("https://whitelisted.example.com"), false,
@@ -1223,6 +1231,9 @@
PreviewsType::RESOURCE_LOADING_HINTS));
EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
&user_data, GURL("https://whitelisted.example.com"), false,
+ PreviewsType::DEFER_ALL_SCRIPT));
+ EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
+ &user_data, GURL("https://whitelisted.example.com"), false,
PreviewsType::LITE_PAGE_REDIRECT));
}
@@ -1412,6 +1423,185 @@
}
}
+TEST_F(PreviewsDeciderImplTest, DeferAllScriptNotAllowedByDefault) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatures(
+ {features::kPreviews, features::kOptimizationHints}, {});
+ InitializeUIService();
+ InitializeOptimizationGuideHints();
+
+ base::HistogramTester histogram_tester;
+ PreviewsUserData user_data(kDefaultPageId);
+
+ EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
+ &user_data, GURL("https://www.google.com"), false,
+ PreviewsType::DEFER_ALL_SCRIPT));
+}
+
+TEST_F(PreviewsDeciderImplTest,
+ DeferAllScriptDisallowedWithoutOptimizationHints) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatures(
+ {features::kPreviews, features::kDeferAllScriptPreviews},
+ {features::kOptimizationHints});
+ InitializeUIService();
+
+ base::HistogramTester histogram_tester;
+ PreviewsUserData user_data(kDefaultPageId);
+ EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
+ &user_data, GURL("https://whitelisted.example.com"), false,
+ PreviewsType::DEFER_ALL_SCRIPT));
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason",
+ static_cast<int>(
+ PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER),
+ 1);
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.DeferAllScript",
+ static_cast<int>(
+ PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER),
+ 1);
+}
+
+TEST_F(PreviewsDeciderImplTest, DeferAllScriptAllowedByFeatureAndWhitelist) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatures(
+ {features::kPreviews, features::kDeferAllScriptPreviews,
+ features::kOptimizationHints},
+ {});
+ InitializeUIService();
+ InitializeOptimizationGuideHints();
+
+ for (const auto& test_ect : {net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ net::EFFECTIVE_CONNECTION_TYPE_3G}) {
+ ReportEffectiveConnectionType(test_ect);
+
+ base::HistogramTester histogram_tester;
+ PreviewsUserData user_data(kDefaultPageId);
+
+ // Check whitelisted URL.
+ EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
+ &user_data, GURL("https://whitelisted.example.com"), false,
+ PreviewsType::DEFER_ALL_SCRIPT));
+ EXPECT_EQ(test_ect, user_data.navigation_ect());
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.DeferAllScript",
+ static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
+ }
+}
+
+TEST_F(PreviewsDeciderImplTest,
+ DeferAllScriptAllowedByFeatureWithoutKnownHints) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatures(
+ {features::kPreviews, features::kDeferAllScriptPreviews,
+ features::kOptimizationHints},
+ {});
+ InitializeUIService();
+ InitializeOptimizationGuideHints();
+
+ base::HistogramTester histogram_tester;
+ PreviewsUserData user_data(kDefaultPageId);
+
+ // Verify preview allowed initially for url without known hints.
+ EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
+ &user_data, GURL("https://www.google.com"), false,
+ PreviewsType::DEFER_ALL_SCRIPT));
+
+ histogram_tester.ExpectBucketCount(
+ "Previews.EligibilityReason.DeferAllScript",
+ static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
+}
+
+TEST_F(PreviewsDeciderImplTest, DeferAllScriptCommitTimeWhitelistCheck) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatures(
+ {features::kPreviews, features::kDeferAllScriptPreviews,
+ features::kOptimizationHints},
+ {});
+ InitializeUIService();
+ InitializeOptimizationGuideHints();
+
+ // First verify not allowed for non-whitelisted url.
+ {
+ base::HistogramTester histogram_tester;
+ PreviewsUserData user_data(kDefaultPageId);
+ user_data.set_navigation_ect(net::EFFECTIVE_CONNECTION_TYPE_2G);
+ EXPECT_FALSE(previews_decider_impl()->ShouldCommitPreview(
+ &user_data, GURL("https://www.google.com"),
+ PreviewsType::DEFER_ALL_SCRIPT));
+
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.DeferAllScript",
+ static_cast<int>(
+ PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER),
+ 1);
+ }
+
+ // Now verify preview for whitelisted url.
+ {
+ base::HistogramTester histogram_tester;
+ PreviewsUserData user_data(kDefaultPageId);
+ user_data.set_navigation_ect(net::EFFECTIVE_CONNECTION_TYPE_2G);
+ EXPECT_TRUE(previews_decider_impl()->ShouldCommitPreview(
+ &user_data, GURL("https://whitelisted.example.com"),
+ PreviewsType::DEFER_ALL_SCRIPT));
+
+ // Expect no eligibility logging.
+ histogram_tester.ExpectTotalCount(
+ "Previews.EligibilityReason.DeferAllScript", 0);
+ }
+
+ // Verify preview not allowed for whitelisted url when network is not slow.
+ {
+ base::HistogramTester histogram_tester;
+ PreviewsUserData user_data(kDefaultPageId);
+ user_data.set_navigation_ect(net::EFFECTIVE_CONNECTION_TYPE_4G);
+ EXPECT_FALSE(previews_decider_impl()->ShouldCommitPreview(
+ &user_data, GURL("https://whitelisted.example.com"),
+ PreviewsType::DEFER_ALL_SCRIPT));
+
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.DeferAllScript",
+ static_cast<int>(PreviewsEligibilityReason::NETWORK_NOT_SLOW), 1);
+ }
+
+ // Verify preview not allowed for whitelisted url for unknown network quality.
+ {
+ base::HistogramTester histogram_tester;
+ PreviewsUserData user_data(kDefaultPageId);
+ user_data.set_navigation_ect(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ EXPECT_FALSE(previews_decider_impl()->ShouldCommitPreview(
+ &user_data, GURL("https://whitelisted.example.com"),
+ PreviewsType::DEFER_ALL_SCRIPT));
+
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.DeferAllScript",
+ static_cast<int>(PreviewsEligibilityReason::DEVICE_OFFLINE), 1);
+ }
+
+ // Verify preview not allowed for session limited ECT threshold.
+ {
+ base::test::ScopedFeatureList nested_scoped_list;
+ nested_scoped_list.InitAndEnableFeatureWithParameters(
+ features::kSlowPageTriggering,
+ {{"session_max_ect_trigger", "Offline"}});
+ base::HistogramTester histogram_tester;
+ PreviewsUserData user_data(kDefaultPageId);
+ user_data.set_navigation_ect(net::EFFECTIVE_CONNECTION_TYPE_2G);
+ EXPECT_FALSE(previews_decider_impl()->ShouldCommitPreview(
+ &user_data, GURL("https://whitelisted.example.com"),
+ PreviewsType::DEFER_ALL_SCRIPT));
+
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.DeferAllScript",
+ static_cast<int>(
+ PreviewsEligibilityReason::NETWORK_NOT_SLOW_FOR_SESSION),
+ 1);
+ }
+}
+
TEST_F(PreviewsDeciderImplTest, LogPreviewNavigationPassInCorrectParams) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kPreviews);
diff --git a/components/previews/content/previews_hints.cc b/components/previews/content/previews_hints.cc
index 12aa84c..e0e7204 100644
--- a/components/previews/content/previews_hints.cc
+++ b/components/previews/content/previews_hints.cc
@@ -125,6 +125,8 @@
return PreviewsType::LITE_PAGE_REDIRECT;
case optimization_guide::proto::OPTIMIZATION_NONE:
return PreviewsType::NONE;
+ case optimization_guide::proto::DEFER_ALL_SCRIPT:
+ return PreviewsType::DEFER_ALL_SCRIPT;
}
}
@@ -143,6 +145,8 @@
case optimization_guide::proto::OPTIMIZATION_NONE:
// Always consider enabled to allow as no-op optimization.
return true;
+ case optimization_guide::proto::DEFER_ALL_SCRIPT:
+ return previews::params::IsDeferAllScriptPreviewsEnabled();
}
}
diff --git a/components/previews/content/previews_hints_unittest.cc b/components/previews/content/previews_hints_unittest.cc
index 83b54ddd..66a1e11 100644
--- a/components/previews/content/previews_hints_unittest.cc
+++ b/components/previews/content/previews_hints_unittest.cc
@@ -517,9 +517,9 @@
}
TEST_F(PreviewsHintsTest,
- IsWhitelistedForSecondOptimizationNoScriptWithFirstDisabled) {
+ IsWhitelistedForSecondOptimizationDeferAllScriptWithFirstDisabled) {
base::test::ScopedFeatureList scoped_list;
- scoped_list.InitWithFeatures({features::kNoScriptPreviews},
+ scoped_list.InitWithFeatures({features::kDeferAllScriptPreviews},
{features::kResourceLoadingHints});
optimization_guide::proto::Configuration config;
@@ -528,7 +528,7 @@
hint1->set_key_representation(optimization_guide::proto::HOST_SUFFIX);
hint1->set_version("someversion");
- // Page hint with NOSCRIPT optimization
+ // Page hint with RESOURCE_LOADING and DEFER_ALL_SCRIPT optimizations
optimization_guide::proto::PageHint* page_hint1 = hint1->add_page_hints();
page_hint1->set_page_pattern("/has_multiple_optimizations/");
optimization_guide::proto::Optimization* optimization1 =
@@ -537,7 +537,8 @@
optimization_guide::proto::RESOURCE_LOADING);
optimization_guide::proto::Optimization* optimization2 =
page_hint1->add_whitelisted_optimizations();
- optimization2->set_optimization_type(optimization_guide::proto::NOSCRIPT);
+ optimization2->set_optimization_type(
+ optimization_guide::proto::DEFER_ALL_SCRIPT);
ParseConfig(config);
@@ -547,7 +548,7 @@
std::string serialized_hint_version_string;
EXPECT_TRUE(MaybeLoadHintAndCheckIsWhitelisted(
GURL("https://www.somedomain.org/has_multiple_optimizations/"),
- PreviewsType::NOSCRIPT, &inflation_percent, &ect_threshold,
+ PreviewsType::DEFER_ALL_SCRIPT, &inflation_percent, &ect_threshold,
&serialized_hint_version_string));
EXPECT_FALSE(MaybeLoadHintAndCheckIsWhitelisted(
GURL("https://www.somedomain.org/has_multiple_optimizations/"),
@@ -559,7 +560,7 @@
IsWhitelistedForSecondOptimizationResourceLoadingWithFirstDisabled) {
base::test::ScopedFeatureList scoped_list;
scoped_list.InitWithFeatures({features::kResourceLoadingHints},
- {features::kNoScriptPreviews});
+ {features::kDeferAllScriptPreviews});
optimization_guide::proto::Configuration config;
optimization_guide::proto::Hint* hint1 = config.add_hints();
@@ -567,12 +568,13 @@
hint1->set_key_representation(optimization_guide::proto::HOST_SUFFIX);
hint1->set_version("someversion");
- // Page hint with NOSCRIPT optimization
+ // Page hint with RESOURCE_LOADING and DEFER_ALL_SCRIPT optimizations
optimization_guide::proto::PageHint* page_hint1 = hint1->add_page_hints();
page_hint1->set_page_pattern("/has_multiple_optimizations/");
optimization_guide::proto::Optimization* optimization1 =
page_hint1->add_whitelisted_optimizations();
- optimization1->set_optimization_type(optimization_guide::proto::NOSCRIPT);
+ optimization1->set_optimization_type(
+ optimization_guide::proto::DEFER_ALL_SCRIPT);
optimization_guide::proto::Optimization* optimization2 =
page_hint1->add_whitelisted_optimizations();
optimization2->set_optimization_type(
diff --git a/components/previews/content/previews_optimization_guide_unittest.cc b/components/previews/content/previews_optimization_guide_unittest.cc
index ca17590f..91b78c0 100644
--- a/components/previews/content/previews_optimization_guide_unittest.cc
+++ b/components/previews/content/previews_optimization_guide_unittest.cc
@@ -673,6 +673,41 @@
}
TEST_F(PreviewsOptimizationGuideTest,
+ ProcessHintsWithValidCommandLineOverrideForDeferAllScript) {
+ base::test::ScopedFeatureList scoped_list;
+ scoped_list.InitWithFeatures({features::kDeferAllScriptPreviews}, {});
+
+ optimization_guide::proto::Configuration config;
+ optimization_guide::proto::Hint* hint = config.add_hints();
+ hint->set_key("somedomain.org");
+ hint->set_key_representation(optimization_guide::proto::HOST_SUFFIX);
+ optimization_guide::proto::PageHint* page_hint = hint->add_page_hints();
+ page_hint->set_page_pattern("defer_default_2g");
+ optimization_guide::proto::Optimization* optimization =
+ page_hint->add_whitelisted_optimizations();
+ optimization->set_optimization_type(
+ optimization_guide::proto::DEFER_ALL_SCRIPT);
+
+ std::string encoded_config;
+ config.SerializeToString(&encoded_config);
+ base::Base64Encode(encoded_config, &encoded_config);
+
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kHintsProtoOverride, encoded_config);
+ CreateServiceAndGuide();
+
+ // Verify page matches and ECT thresholds.
+ PreviewsUserData user_data(kDefaultPageId);
+ net::EffectiveConnectionType ect_threshold;
+
+ EXPECT_TRUE(guide()->GetHintsForTesting());
+ EXPECT_TRUE(MaybeLoadOptimizationHintsAndCheckIsWhitelisted(
+ &user_data, GURL("https://somedomain.org/defer_default_2g"),
+ PreviewsType::DEFER_ALL_SCRIPT, &ect_threshold));
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G, ect_threshold);
+}
+
+TEST_F(PreviewsOptimizationGuideTest,
ProcessHintsWithValidCommandLineOverrideAndPreexistingData) {
base::test::ScopedFeatureList scoped_list;
scoped_list.InitWithFeatures(