Commit 54eaf62e authored by sreejakshetty@chromium.org's avatar sreejakshetty@chromium.org Committed by Commit Bot

[bfcache] Implement Memory Controls for BFCache

- Add kBackForwardCacheMemoryControl feature which can be controlled via
  experiment.
- Introduce "memory_threshold_for_back_forward_cache_in_mb" to control the
  factor via experiment.

Bug: 1017090
Change-Id: I44d95da16f4023ea5b8ad890dd539784c74006c6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1875091Reviewed-by: default avatarAlex Moshchuk <alexmos@chromium.org>
Reviewed-by: default avatarArthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Commit-Queue: Sreeja Kamishetty <sreejakshetty@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718605}
parent 2ae70155
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/command_line.h" #include "base/command_line.h"
#include "base/hash/hash.h"
#include "base/metrics/metrics_hashes.h" #include "base/metrics/metrics_hashes.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/system/sys_info.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
...@@ -47,6 +49,7 @@ ...@@ -47,6 +49,7 @@
#include "services/service_manager/public/cpp/service_binding.h" #include "services/service_manager/public/cpp/service_binding.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h" #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
#include "unordered_map"
using testing::Each; using testing::Each;
using testing::ElementsAre; using testing::ElementsAre;
...@@ -58,6 +61,20 @@ namespace { ...@@ -58,6 +61,20 @@ namespace {
const char* kDisabledReasonForTest = "DisabledByBackForwardCacheBrowserTest"; const char* kDisabledReasonForTest = "DisabledByBackForwardCacheBrowserTest";
// hash for std::unordered_map.
struct FeatureHash {
size_t operator()(base::Feature feature) const {
return base::FastHash(feature.name);
}
};
// compare operator for std::unordered_map.
struct FeatureEqualOperator {
bool operator()(base::Feature feature1, base::Feature feature2) const {
return std::strcmp(feature1.name, feature2.name) == 0;
}
};
// Test about the BackForwardCache. // Test about the BackForwardCache.
class BackForwardCacheBrowserTest : public ContentBrowserTest { class BackForwardCacheBrowserTest : public ContentBrowserTest {
public: public:
...@@ -71,18 +88,32 @@ class BackForwardCacheBrowserTest : public ContentBrowserTest { ...@@ -71,18 +88,32 @@ class BackForwardCacheBrowserTest : public ContentBrowserTest {
switches::kIgnoreCertificateErrors); switches::kIgnoreCertificateErrors);
base::CommandLine::ForCurrentProcess()->AppendSwitch( base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalWebPlatformFeatures); switches::kEnableExperimentalWebPlatformFeatures);
feature_list_.InitWithFeaturesAndParameters( // TODO(sreejakshetty): Initialize ScopedFeatureLists from test constructor.
{{features::kBackForwardCache, {GetFeatureParams()}}, EnableFeatureAndSetParams(features::kBackForwardCache,
{features::kServiceWorkerOnUI, {}}}, "TimeToLiveInBackForwardCacheInSeconds", "3600");
{}); EnableFeatureAndSetParams(features::kServiceWorkerOnUI, "", "");
SetupFeaturesAndParameters();
ContentBrowserTest::SetUpCommandLine(command_line); ContentBrowserTest::SetUpCommandLine(command_line);
} }
virtual base::FieldTrialParams GetFeatureParams() { void SetupFeaturesAndParameters() {
// Set a very long TTL before expiration (longer than the test timeout) so std::vector<base::test::ScopedFeatureList::FeatureAndParams>
// tests that are expecting deletion don't pass when they shouldn't. enabled_features;
return {{"TimeToLiveInBackForwardCacheInSeconds", "3600"}};
for (auto feature_param = features_with_params_.begin();
feature_param != features_with_params_.end(); feature_param++) {
enabled_features.push_back({feature_param->first, feature_param->second});
}
feature_list_.InitWithFeaturesAndParameters(enabled_features,
/*disabled_features*/ {});
}
void EnableFeatureAndSetParams(base::Feature feature,
std::string param_name,
std::string param_value) {
features_with_params_[feature][param_name] = param_value;
} }
void SetUpOnMainThread() override { void SetUpOnMainThread() override {
...@@ -256,8 +287,12 @@ class BackForwardCacheBrowserTest : public ContentBrowserTest { ...@@ -256,8 +287,12 @@ class BackForwardCacheBrowserTest : public ContentBrowserTest {
std::vector<base::Bucket> expected_blocklisted_features_; std::vector<base::Bucket> expected_blocklisted_features_;
std::vector<base::Bucket> expected_disabled_reasons_; std::vector<base::Bucket> expected_disabled_reasons_;
std::vector<base::Bucket> expected_eviction_after_committing_; std::vector<base::Bucket> expected_eviction_after_committing_;
std::unique_ptr<net::EmbeddedTestServer> https_server_; std::unique_ptr<net::EmbeddedTestServer> https_server_;
std::unordered_map<base::Feature,
std::map<std::string, std::string>,
FeatureHash,
FeatureEqualOperator>
features_with_params_;
}; };
// Match RenderFrameHostImpl* that are in the BackForwardCache. // Match RenderFrameHostImpl* that are in the BackForwardCache.
...@@ -2593,8 +2628,11 @@ class BackForwardCacheBrowserTestWithServiceWorkerEnabled ...@@ -2593,8 +2628,11 @@ class BackForwardCacheBrowserTestWithServiceWorkerEnabled
~BackForwardCacheBrowserTestWithServiceWorkerEnabled() override {} ~BackForwardCacheBrowserTestWithServiceWorkerEnabled() override {}
protected: protected:
base::FieldTrialParams GetFeatureParams() override { void SetUpCommandLine(base::CommandLine* command_line) override {
return {{"service_worker_supported", "true"}}; EnableFeatureAndSetParams(features::kBackForwardCache,
"service_worker_supported", "true");
BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
} }
}; };
...@@ -2915,8 +2953,11 @@ class GeolocationBackForwardCacheBrowserTest ...@@ -2915,8 +2953,11 @@ class GeolocationBackForwardCacheBrowserTest
protected: protected:
GeolocationBackForwardCacheBrowserTest() : geo_override_(0.0, 0.0) {} GeolocationBackForwardCacheBrowserTest() : geo_override_(0.0, 0.0) {}
base::FieldTrialParams GetFeatureParams() override { void SetUpCommandLine(base::CommandLine* command_line) override {
return {{"geolocation_supported", "true"}}; EnableFeatureAndSetParams(features::kBackForwardCache,
"geolocation_supported", "true");
BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
} }
device::ScopedGeolocationOverrider geo_override_; device::ScopedGeolocationOverrider geo_override_;
...@@ -3058,7 +3099,7 @@ IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, TimedEviction) { ...@@ -3058,7 +3099,7 @@ IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, TimedEviction) {
base::TimeDelta time_to_live_in_back_forward_cache = base::TimeDelta time_to_live_in_back_forward_cache =
BackForwardCacheImpl::GetTimeToLiveInBackForwardCache(); BackForwardCacheImpl::GetTimeToLiveInBackForwardCache();
// This should match the value we set in GetFeatureParams. // This should match the value we set in EnableFeatureAndSetParams.
EXPECT_EQ(time_to_live_in_back_forward_cache, EXPECT_EQ(time_to_live_in_back_forward_cache,
base::TimeDelta::FromSeconds(3600)); base::TimeDelta::FromSeconds(3600));
...@@ -3286,18 +3327,16 @@ IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, MetricsNotRecorded) { ...@@ -3286,18 +3327,16 @@ IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, MetricsNotRecorded) {
class BackForwardCacheBrowserTestWithDomainControlEnabled class BackForwardCacheBrowserTestWithDomainControlEnabled
: public BackForwardCacheBrowserTest { : public BackForwardCacheBrowserTest {
protected: protected:
base::FieldTrialParams GetFeatureParams() override { void SetUpCommandLine(base::CommandLine* command_line) override {
// Sets the allowed websites for testing, additionally adding the params // Sets the allowed websites for testing, additionally adding the params
// used by BackForwardCacheBrowserTest. // used by BackForwardCacheBrowserTest.
std::map<std::string, std::string> domain_control_params = { std::string allowed_websites =
{"allowed_websites", "https://a.allowed/back_forward_cache/, "
"https://a.allowed/back_forward_cache/, " "https://b.allowed/back_forward_cache/allowed_path.html";
"https://b.allowed/back_forward_cache/allowed_path.html"}}; EnableFeatureAndSetParams(features::kBackForwardCache, "allowed_websites",
std::map<std::string, std::string> browser_test_params = allowed_websites);
BackForwardCacheBrowserTest::GetFeatureParams();
domain_control_params.insert(browser_test_params.begin(), BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
browser_test_params.end());
return domain_control_params;
} }
}; };
...@@ -3986,4 +4025,83 @@ IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, ...@@ -3986,4 +4025,83 @@ IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
FROM_HERE); FROM_HERE);
} }
// Test for functionality of memory controls in back-forward cache for low
// memory devices.
class BackForwardCacheBrowserTestForLowMemoryDevices
: public BackForwardCacheBrowserTest {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
// Set the value of memory threshold more than the physical memory and check
// if back-forward cache is disabled or not.
std::string memory_threshold =
base::NumberToString(base::SysInfo::AmountOfPhysicalMemoryMB() + 1);
EnableFeatureAndSetParams(features::kBackForwardCacheMemoryControl,
"memory_threshold_for_back_forward_cache_in_mb",
memory_threshold);
BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
}
};
// Navigate from A to B and go back.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForLowMemoryDevices,
DisableBFCacheForLowEndDevices) {
EXPECT_FALSE(IsBackForwardCacheEnabled());
ASSERT_TRUE(embedded_test_server()->Start());
const GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
const GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
// 1) Navigate to A.
EXPECT_TRUE(NavigateToURL(shell(), url_a));
RenderFrameHostImpl* rfh_a = current_frame_host();
RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
// 2) Navigate to B.
EXPECT_TRUE(NavigateToURL(shell(), url_b));
// 3) A shouldn't be stored in back-forward cache because the physical
// memory is less than the memory threshold.
delete_observer_rfh_a.WaitUntilDeleted();
// Nothing is recorded when the memory is less than the threshold value.
ExpectOutcomeDidNotChange(FROM_HERE);
ExpectNotRestoredDidNotChange(FROM_HERE);
}
// Test for functionality of memory controls in back-forward cache for high
// memory devices.
class BackForwardCacheBrowserTestForHighMemoryDevices
: public BackForwardCacheBrowserTest {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
// Set the value of memory threshold less than the physical memory and check
// if back-forward cache is enabled or not.
std::string memory_threshold =
base::NumberToString(base::SysInfo::AmountOfPhysicalMemoryMB() - 1);
EnableFeatureAndSetParams(features::kBackForwardCacheMemoryControl,
"memory_threshold_for_back_forward_cache_in_mb",
memory_threshold);
BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
}
};
// Navigate from A to B and go back.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForHighMemoryDevices,
EnableBFCacheForHighMemoryDevices) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
const GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
// 1) Navigate to A.
EXPECT_TRUE(NavigateToURL(shell(), url_a));
RenderFrameHostImpl* rfh_a = current_frame_host();
// 2) Navigate to B.
EXPECT_TRUE(NavigateToURL(shell(), url_b));
// 3) A should be stored in back-forward cache because the physical memory is
// greater than the memory threshold.
EXPECT_TRUE(rfh_a->is_in_back_forward_cache());
}
} // namespace content } // namespace content
...@@ -63,6 +63,16 @@ const base::Feature kBackgroundFetch{"BackgroundFetch", ...@@ -63,6 +63,16 @@ const base::Feature kBackgroundFetch{"BackgroundFetch",
const base::Feature kBackForwardCache{"BackForwardCache", const base::Feature kBackForwardCache{"BackForwardCache",
base::FEATURE_DISABLED_BY_DEFAULT}; base::FEATURE_DISABLED_BY_DEFAULT};
// BackForwardCache is disabled on low memory devices. The threshold is defined
// via a field trial param: "memory_threshold_for_back_forward_cache_in_mb"
// It is compared against base::SysInfo::AmountOfPhysicalMemoryMB().
// "BackForwardCacheMemoryControls" is checked before "BackForwardCache". It
// means the low memory devices will activate neither the control group nor the
// experimental group of the BackForwardCache field trial.
const base::Feature kBackForwardCacheMemoryControl{
"BackForwardCacheMemoryControls", base::FEATURE_DISABLED_BY_DEFAULT};
// Allows swipe left/right from touchpad change browser navigation. Currently // Allows swipe left/right from touchpad change browser navigation. Currently
// only enabled by default on CrOS. // only enabled by default on CrOS.
const base::Feature kTouchpadOverscrollHistoryNavigation { const base::Feature kTouchpadOverscrollHistoryNavigation {
......
...@@ -26,6 +26,7 @@ CONTENT_EXPORT extern const base::Feature kAudioServiceLaunchOnStartup; ...@@ -26,6 +26,7 @@ CONTENT_EXPORT extern const base::Feature kAudioServiceLaunchOnStartup;
CONTENT_EXPORT extern const base::Feature kAudioServiceOutOfProcess; CONTENT_EXPORT extern const base::Feature kAudioServiceOutOfProcess;
CONTENT_EXPORT extern const base::Feature kBackgroundFetch; CONTENT_EXPORT extern const base::Feature kBackgroundFetch;
CONTENT_EXPORT extern const base::Feature kBackForwardCache; CONTENT_EXPORT extern const base::Feature kBackForwardCache;
CONTENT_EXPORT extern const base::Feature kBackForwardCacheMemoryControl;
CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources; CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources;
CONTENT_EXPORT extern const base::Feature kBrowserVerifiedUserActivation; CONTENT_EXPORT extern const base::Feature kBrowserVerifiedUserActivation;
CONTENT_EXPORT extern const base::Feature kCacheInlineScriptCode; CONTENT_EXPORT extern const base::Feature kCacheInlineScriptCode;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/system/sys_info.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "services/network/public/cpp/features.h" #include "services/network/public/cpp/features.h"
...@@ -24,9 +25,32 @@ void LogArbitraryPolicyPerDownload(NavigationDownloadType type) { ...@@ -24,9 +25,32 @@ void LogArbitraryPolicyPerDownload(NavigationDownloadType type) {
"Navigation.DownloadPolicy.LogArbitraryPolicyPerDownload", type); "Navigation.DownloadPolicy.LogArbitraryPolicyPerDownload", type);
} }
bool DeviceHasEnoughMemoryForBackForwardCache() {
// This method make sure that the physical memory of device is greater than
// the allowed threshold and enables back-forward cache if the feature
// kBackForwardCacheMemoryControl is enabled.
// It is important to check the base::FeatureList to avoid activating any
// field trial groups if BFCache is disabled due to memory threshold.
if (base::FeatureList::IsEnabled(features::kBackForwardCacheMemoryControl)) {
int memory_threshold_mb = base::GetFieldTrialParamByFeatureAsInt(
features::kBackForwardCacheMemoryControl,
"memory_threshold_for_back_forward_cache_in_mb", 0);
return base::SysInfo::AmountOfPhysicalMemoryMB() > memory_threshold_mb;
}
// If the feature kBackForwardCacheMemoryControl is not enabled, all the
// devices are included by default.
return true;
}
} // namespace } // namespace
bool IsBackForwardCacheEnabled() { bool IsBackForwardCacheEnabled() {
if (!DeviceHasEnoughMemoryForBackForwardCache())
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::kBackForwardCache); return base::FeatureList::IsEnabled(features::kBackForwardCache);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment