Commit fc9d9f7b authored by Varun Mohan's avatar Varun Mohan Committed by Commit Bot

Adding proactive tab discarding to TabManager

This is the initial simple implementation of proactive tab discarding. This will be ran on a Finch trial with various parameters in order to find balance between maximal resource savings and minimal impact to user experience.

Bug: 775644
Change-Id: If5048f622bd24d540804842c7e5448c48fabad36
Reviewed-on: https://chromium-review.googlesource.com/1014646
Commit-Queue: François Doray <fdoray@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553558}
parent f4bccc2e
......@@ -21,6 +21,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/threading/thread.h"
#include "base/trace_event/trace_event_argument.h"
#include "build/build_config.h"
......@@ -174,6 +175,8 @@ TabManager::TabManager()
new ResourceCoordinatorSignalObserver());
}
stats_collector_.reset(new TabManagerStatsCollector());
proactive_discard_params_ = GetStaticProactiveTabDiscardParams();
}
TabManager::~TabManager() {
......@@ -911,6 +914,118 @@ bool TabManager::IsForceLoadTimerRunning() const {
return force_load_timer_ && force_load_timer_->IsRunning();
}
base::TimeDelta TabManager::GetTimeInBackgroundBeforeProactiveDiscard() const {
// Exceed high threshold - in excessive state.
if (num_loaded_lifecycle_units_ >=
proactive_discard_params_.high_loaded_tab_count) {
return base::TimeDelta();
}
// Exceed moderate threshold - in high state.
if (num_loaded_lifecycle_units_ >=
proactive_discard_params_.moderate_loaded_tab_count) {
return proactive_discard_params_.high_occluded_timeout;
}
// Exceed low threshold - in moderate state.
if (num_loaded_lifecycle_units_ >=
proactive_discard_params_.low_loaded_tab_count) {
return proactive_discard_params_.moderate_occluded_timeout;
}
// Didn't meet any thresholds - in low state.
return proactive_discard_params_.low_occluded_timeout;
}
LifecycleUnit* TabManager::GetNextDiscardableLifecycleUnit() const {
LifecycleUnit* next_to_discard = nullptr;
base::TimeTicks earliest_backgrounded_time = base::TimeTicks::Max();
// TODO(fdoray), TODO(varunmohan) : switch this to use
// GetSortedLifecycleUnits(). Eventually, there will be some more advanced
// logic around LifecycleUnit importance (perhaps ML LifecycleUnit ranking)
// which will be used to determine which LifecycleUnit to discard. For now,
// choosing which LifecycleUnit to discard based on the longest duration a
// LifecycleUnit was backgrounded.
for (LifecycleUnit* lifecycle_unit : lifecycle_units_) {
// LifecycleUnits that aren't hidden cannot be discarded at this time.
if (lifecycle_unit->GetVisibility() != content::Visibility::HIDDEN)
continue;
// Ignore LifecycleUnits that cannot be discarded.
if (!lifecycle_unit->CanDiscard(DiscardReason::kProactive))
continue;
base::TimeTicks time_backgrounded =
lifecycle_unit->GetLastVisibilityChangeTime();
// This LifecycleUnit was backgrounded earlier than the current earliest
// LifecycleUnit, so it will be discarded earlier.
if (time_backgrounded < earliest_backgrounded_time) {
earliest_backgrounded_time = time_backgrounded;
next_to_discard = lifecycle_unit;
}
}
return next_to_discard;
}
void TabManager::UpdateProactiveDiscardTimerIfNecessary() {
// If the proactive discarding feature is not enabled, do nothing.
if (!base::FeatureList::IsEnabled(features::kProactiveTabDiscarding))
return;
// Create or stop |proactive_discard_timer_|.
if (!proactive_discard_timer_) {
proactive_discard_timer_ =
std::make_unique<base::OneShotTimer>(GetTickClock());
} else {
proactive_discard_timer_->Stop();
}
// No loaded LifecycleUnits. In Low threshold, but no timer is necessary.
if (num_loaded_lifecycle_units_ == 0)
return;
base::TimeDelta time_until_discard =
GetTimeInBackgroundBeforeProactiveDiscard();
LifecycleUnit* next_to_discard = GetNextDiscardableLifecycleUnit();
// There were no discardable LifecycleUnits. No timer is necessary.
if (!next_to_discard)
return;
// Get the time |next_to_discard| was backgrounded and subtract it from
// |time_until_discard| to get the exact time until the next LifecycleUnit
// should be discarded.
base::TimeDelta time_backgrounded =
NowTicks() - next_to_discard->GetLastVisibilityChangeTime();
time_until_discard -= time_backgrounded;
// Ensure |time_until_discard| is a non-negative base::TimeDelta.
time_until_discard = std::max(base::TimeDelta(), time_until_discard);
// On a |time_until_discard| long timer, discard |next_to_discard|. If for
// some reason |next_to_discard| is destroyed while this timer is waiting,
// OnLifecycleUnitDestroyed() will be called and the timer will be reset. When
// a tab is discarded, OnLifecycleUnitStateChanged() will be called, which
// will set up the timer for the next tab to be discarded.
proactive_discard_timer_->Start(
FROM_HERE, time_until_discard,
base::BindRepeating(
[](LifecycleUnit* lifecycle_unit, TabManager* tab_manager) {
// If |lifecycle_unit| can still be discarded, discard it.
// Otherwise, find a new tab to be discarded and reset
// |proactive_discard_timer|.
if (lifecycle_unit->CanDiscard(DiscardReason::kProactive))
lifecycle_unit->Discard(DiscardReason::kProactive);
else
tab_manager->UpdateProactiveDiscardTimerIfNecessary();
},
next_to_discard, this));
}
void TabManager::OnLifecycleUnitStateChanged(LifecycleUnit* lifecycle_unit) {
if (lifecycle_unit->GetState() == LifecycleUnit::State::LOADED)
num_loaded_lifecycle_units_++;
......@@ -919,6 +1034,14 @@ void TabManager::OnLifecycleUnitStateChanged(LifecycleUnit* lifecycle_unit) {
DCHECK_EQ(num_loaded_lifecycle_units_,
GetNumLoadedLifecycleUnits(lifecycle_units_));
UpdateProactiveDiscardTimerIfNecessary();
}
void TabManager::OnLifecycleUnitVisibilityChanged(
LifecycleUnit* lifecycle_unit,
content::Visibility visibility) {
UpdateProactiveDiscardTimerIfNecessary();
}
void TabManager::OnLifecycleUnitDestroyed(LifecycleUnit* lifecycle_unit) {
......@@ -928,10 +1051,13 @@ void TabManager::OnLifecycleUnitDestroyed(LifecycleUnit* lifecycle_unit) {
DCHECK_EQ(num_loaded_lifecycle_units_,
GetNumLoadedLifecycleUnits(lifecycle_units_));
UpdateProactiveDiscardTimerIfNecessary();
}
void TabManager::OnLifecycleUnitCreated(LifecycleUnit* lifecycle_unit) {
lifecycle_units_.insert(lifecycle_unit);
if (lifecycle_unit->GetState() == LifecycleUnit::State::LOADED)
num_loaded_lifecycle_units_++;
......@@ -940,6 +1066,8 @@ void TabManager::OnLifecycleUnitCreated(LifecycleUnit* lifecycle_unit) {
DCHECK_EQ(num_loaded_lifecycle_units_,
GetNumLoadedLifecycleUnits(lifecycle_units_));
UpdateProactiveDiscardTimerIfNecessary();
}
} // namespace resource_coordinator
......@@ -26,6 +26,7 @@
#include "chrome/browser/resource_coordinator/lifecycle_unit_source_observer.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_observer.h"
#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
#include "chrome/browser/resource_coordinator/tab_manager_features.h"
#include "chrome/browser/sessions/session_restore_observer.h"
#include "chrome/browser/ui/browser_tab_strip_tracker.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
......@@ -203,6 +204,7 @@ class TabManager : public LifecycleUnitObserver,
private:
friend class TabManagerStatsCollectorTest;
friend class TabManagerWithProactiveDiscardExperimentEnabledTest;
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, PurgeBackgroundRenderer);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ActivateTabResetPurgeState);
......@@ -256,6 +258,8 @@ class TabManager : public LifecycleUnitObserver,
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, FreezeTab);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
TrackingNumberOfLoadedLifecycleUnits);
FRIEND_TEST_ALL_PREFIXES(TabManagerWithProactiveDiscardExperimentEnabledTest,
GetTimeInBackgroundBeforeProactiveDiscardTest);
// The time of the first purging after a renderer is backgrounded.
// The initial value was chosen because most of users activate backgrounded
......@@ -404,7 +408,24 @@ class TabManager : public LifecycleUnitObserver,
// Returns true if the background tab force load timer is running.
bool IsForceLoadTimerRunning() const;
// Returns the threshold after which a background LifecycleUnit gets
// discarded, given the current number of alive LifecycleUnits and experiment
// parameters.
base::TimeDelta GetTimeInBackgroundBeforeProactiveDiscard() const;
// Returns the next discardable LifecycleUnit, if any, and nullptr otherwise.
// The next discardable LifecycleUnit is the LifecycleUnit that has been in
// the visibility state content::Visibility::HIDDEN for the longest time.
LifecycleUnit* GetNextDiscardableLifecycleUnit() const;
// If necessary, schedules a task to proactively discard a LifecycleUnit at
// the right time.
void UpdateProactiveDiscardTimerIfNecessary();
// LifecycleUnitObserver:
void OnLifecycleUnitVisibilityChanged(
LifecycleUnit* lifecycle_unit,
content::Visibility visibility) override;
void OnLifecycleUnitDestroyed(LifecycleUnit* lifecycle_unit) override;
void OnLifecycleUnitStateChanged(LifecycleUnit* lifecycle_unit) override;
......@@ -414,13 +435,21 @@ class TabManager : public LifecycleUnitObserver,
// LifecycleUnits managed by this.
LifecycleUnitSet lifecycle_units_;
// Number of LifecycleUnits in |lifecycle_units_| that are State::LOADED. Used
// to determine threshold for proactive tab discarding experiments.
// Number of LifecycleUnits in |lifecycle_units_| that are in State::LOADED.
// Used to determine timeout threshold for proactive discarding.
int num_loaded_lifecycle_units_ = 0;
// Parameters for proactive discarding. Used to determine the timeout
// until a LifecycleUnit should be discarded based on
// |num_loaded_lifecycle_units_|.
ProactiveTabDiscardParams proactive_discard_params_;
// Timer to periodically update the stats of the renderers.
base::RepeatingTimer update_timer_;
// Timer for proactive discarding.
std::unique_ptr<base::OneShotTimer> proactive_discard_timer_;
// A listener to global memory pressure events.
std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
......
......@@ -60,6 +60,15 @@ namespace {
const char kTestUrl[] = "http://www.example.com";
// Default parameters for testing proactive LifecycleUnit discarding.
const int kLowLoadedTabCount = 5;
const int kModerateLoadedTabCount = 10;
const int kHighLoadedTabCount = 20;
const base::TimeDelta kLowOccludedTimeout = base::TimeDelta::FromMinutes(100);
const base::TimeDelta kModerateOccludedTimeout =
base::TimeDelta::FromMinutes(10);
const base::TimeDelta kHighOccludedTimeout = base::TimeDelta::FromMinutes(1);
class NonResumingBackgroundTabNavigationThrottle
: public BackgroundTabNavigationThrottle {
public:
......@@ -293,6 +302,35 @@ class TabManagerWithExperimentDisabledTest : public TabManagerTest {
base::test::ScopedFeatureList scoped_feature_list_;
};
class TabManagerWithProactiveDiscardExperimentEnabledTest
: public TabManagerTest {
public:
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(
features::kProactiveTabDiscarding);
TabManagerTest::SetUp();
// Use test constants for proactive discarding parameters.
tab_manager_->proactive_discard_params_ = GetTestProactiveDiscardParams();
}
ProactiveTabDiscardParams GetTestProactiveDiscardParams() {
// Return a ProactiveTabDiscardParams struct with default test
// parameters.
ProactiveTabDiscardParams params;
params.low_occluded_timeout = kLowOccludedTimeout;
params.moderate_occluded_timeout = kModerateOccludedTimeout;
params.high_occluded_timeout = kHighOccludedTimeout;
params.low_loaded_tab_count = kLowLoadedTabCount;
params.moderate_loaded_tab_count = kModerateLoadedTabCount;
params.high_loaded_tab_count = kHighLoadedTabCount;
return params;
}
base::test::ScopedFeatureList scoped_feature_list_;
};
// TODO(georgesak): Add tests for protection to tabs with form input and
// playing audio;
......@@ -1079,4 +1117,400 @@ TEST_F(TabManagerTest, TrackingNumberOfLoadedLifecycleUnits) {
EXPECT_EQ(tab_manager_->num_loaded_lifecycle_units_, 0);
}
TEST_F(TabManagerWithProactiveDiscardExperimentEnabledTest,
GetTimeInBackgroundBeforeProactiveDiscardTest) {
auto window = std::make_unique<TestBrowserWindow>();
Browser::CreateParams params(profile(), true);
params.type = Browser::TYPE_TABBED;
params.window = window.get();
auto browser = std::make_unique<Browser>(params);
TabStripModel* tab_strip = browser->tab_strip_model();
// Move through every tab count in the low state and verify
// GetTimeInBackgroundBeforeProactiveDiscard returns the low threshold's
// timeout.
while (tab_manager_->num_loaded_lifecycle_units_ < kLowLoadedTabCount) {
EXPECT_EQ(tab_manager_->GetTimeInBackgroundBeforeProactiveDiscard(),
kLowOccludedTimeout);
tab_strip->AppendWebContents(CreateWebContents(), false);
}
// Move through every tab count in the moderate state and verify
// GetTimeInBackgroundBeforeProactiveDiscard returns the moderate threshold's
// timeout.
while (tab_manager_->num_loaded_lifecycle_units_ < kModerateLoadedTabCount) {
EXPECT_EQ(tab_manager_->GetTimeInBackgroundBeforeProactiveDiscard(),
kModerateOccludedTimeout);
tab_strip->AppendWebContents(CreateWebContents(), false);
}
// Move through every tab count in the high state and verify
// GetTimeInBackgroundBeforeProactiveDiscard returns the high threshold's
// timeout.
while (tab_manager_->num_loaded_lifecycle_units_ < kHighLoadedTabCount) {
EXPECT_EQ(tab_manager_->GetTimeInBackgroundBeforeProactiveDiscard(),
kHighOccludedTimeout);
tab_strip->AppendWebContents(CreateWebContents(), false);
}
// Add one tab to move from high state to excessive.
tab_strip->AppendWebContents(CreateWebContents(), false);
EXPECT_EQ(tab_manager_->GetTimeInBackgroundBeforeProactiveDiscard(),
base::TimeDelta());
tab_strip->CloseAllTabs();
EXPECT_EQ(tab_manager_->GetTimeInBackgroundBeforeProactiveDiscard(),
kLowOccludedTimeout);
}
TEST_F(TabManagerWithProactiveDiscardExperimentEnabledTest,
ProactiveDiscardTestLow) {
auto window = std::make_unique<TestBrowserWindow>();
Browser::CreateParams params(profile(), true);
params.type = Browser::TYPE_TABBED;
params.window = window.get();
auto browser = std::make_unique<Browser>(params);
TabStripModel* tab_strip = browser->tab_strip_model();
tab_strip->AppendWebContents(CreateWebContents(), false);
tab_strip->GetWebContentsAt(0)->WasShown();
tab_strip->AppendWebContents(CreateWebContents(), false);
tab_strip->GetWebContentsAt(1)->WasShown();
tab_strip->GetWebContentsAt(0)->WasHidden();
// Fast forward to just before the low threshold timeout.
base::TimeDelta less_than_low_timeout =
kLowOccludedTimeout - base::TimeDelta::FromSeconds(1);
task_runner_->FastForwardBy(less_than_low_timeout);
// Verify that 1 second before the Low threshold timeout, nothing has been
// discarded.
EXPECT_FALSE(
TabLifecycleUnitExternal::FromWebContents(tab_strip->GetWebContentsAt(0))
->IsDiscarded());
EXPECT_FALSE(
TabLifecycleUnitExternal::FromWebContents(tab_strip->GetWebContentsAt(1))
->IsDiscarded());
// Fast forward time until past the low threshold timeout
task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
// Verify that once the Low threshold timeout has passed, the hidden tab was
// discarded.
EXPECT_TRUE(
TabLifecycleUnitExternal::FromWebContents(tab_strip->GetWebContentsAt(0))
->IsDiscarded());
EXPECT_FALSE(
TabLifecycleUnitExternal::FromWebContents(tab_strip->GetWebContentsAt(1))
->IsDiscarded());
tab_strip->CloseAllTabs();
}
TEST_F(TabManagerWithProactiveDiscardExperimentEnabledTest,
ProactiveDiscardTestModerate) {
auto window = std::make_unique<TestBrowserWindow>();
Browser::CreateParams params(profile(), true);
params.type = Browser::TYPE_TABBED;
params.window = window.get();
auto browser = std::make_unique<Browser>(params);
TabStripModel* tab_strip = browser->tab_strip_model();
// Create enough tabs to enter the moderate state.
for (int tabs = 0; tabs < kLowLoadedTabCount; tabs++) {
tab_strip->AppendWebContents(CreateWebContents(), false);
tab_strip->GetWebContentsAt(tabs)->WasShown();
}
tab_strip->GetWebContentsAt(0)->WasHidden();
// Fast forward to just before the moderate threshold timeout.
base::TimeDelta less_than_moderate_timeout =
kModerateOccludedTimeout - base::TimeDelta::FromSeconds(1);
task_runner_->FastForwardBy(less_than_moderate_timeout);
for (int tab = 0; tab < kLowLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Fast forward time until past the moderate threshold timeout.
task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
// The hidden tab (at index 0) should be the only discarded tab.
EXPECT_TRUE(
TabLifecycleUnitExternal::FromWebContents(tab_strip->GetWebContentsAt(0))
->IsDiscarded());
for (int tab = 1; tab < kLowLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
tab_strip->CloseAllTabs();
}
TEST_F(TabManagerWithProactiveDiscardExperimentEnabledTest,
ProactiveDiscardTestHigh) {
auto window = std::make_unique<TestBrowserWindow>();
Browser::CreateParams params(profile(), true);
params.type = Browser::TYPE_TABBED;
params.window = window.get();
auto browser = std::make_unique<Browser>(params);
TabStripModel* tab_strip = browser->tab_strip_model();
// Create enough tabs to enter the high state.
for (int tabs = 0; tabs < kModerateLoadedTabCount; tabs++) {
tab_strip->AppendWebContents(CreateWebContents(), false);
tab_strip->GetWebContentsAt(tabs)->WasShown();
}
tab_strip->GetWebContentsAt(0)->WasHidden();
// Fast forward to just before the high threshold timeout.
base::TimeDelta less_than_high_timeout =
kHighOccludedTimeout - base::TimeDelta::FromSeconds(1);
task_runner_->FastForwardBy(less_than_high_timeout);
for (int tab = 0; tab < kModerateLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Fast forward time until past the high threshold timeout.
task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
// The hidden tab (at index 0) should be the only discarded tab.
EXPECT_TRUE(
TabLifecycleUnitExternal::FromWebContents(tab_strip->GetWebContentsAt(0))
->IsDiscarded());
for (int tab = 1; tab < kModerateLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
tab_strip->CloseAllTabs();
}
TEST_F(TabManagerWithProactiveDiscardExperimentEnabledTest,
ProactiveDiscardTestExcessive) {
auto window = std::make_unique<TestBrowserWindow>();
Browser::CreateParams params(profile(), true);
params.type = Browser::TYPE_TABBED;
params.window = window.get();
auto browser = std::make_unique<Browser>(params);
TabStripModel* tab_strip = browser->tab_strip_model();
// Create enough tabs to enter the excessive state.
for (int tabs = 0; tabs < kHighLoadedTabCount; tabs++) {
tab_strip->AppendWebContents(CreateWebContents(), false);
tab_strip->GetWebContentsAt(tabs)->WasShown();
}
tab_strip->GetWebContentsAt(0)->WasHidden();
// Nothing should be discarded initially.
for (int tab = 0; tab < kHighLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Run until idle without fast forwarding time, as discarding while in the
// excessive state should happen immediately.
task_runner_->RunUntilIdle();
// The hidden tab (at index 0) should be the only discarded tab.
EXPECT_TRUE(
TabLifecycleUnitExternal::FromWebContents(tab_strip->GetWebContentsAt(0))
->IsDiscarded());
for (int tab = 1; tab < kHighLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
tab_strip->CloseAllTabs();
}
TEST_F(TabManagerWithProactiveDiscardExperimentEnabledTest,
ProactiveDiscardTestChangingStates) {
auto window = std::make_unique<TestBrowserWindow>();
Browser::CreateParams params(profile(), true);
params.type = Browser::TYPE_TABBED;
params.window = window.get();
auto browser = std::make_unique<Browser>(params);
TabStripModel* tab_strip = browser->tab_strip_model();
// Create the minumum number of tabs to enter the high state.
for (int tabs = 0; tabs < kModerateLoadedTabCount; tabs++) {
tab_strip->AppendWebContents(CreateWebContents(), false);
tab_strip->GetWebContentsAt(tabs)->WasShown();
}
// Nothing should be discarded initially.
for (int tab = 0; tab < kModerateLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Hide the first two tabs, waiting once second between to enforce that the
// first tab is discarded first.
tab_strip->GetWebContentsAt(0)->WasHidden();
task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
tab_strip->GetWebContentsAt(1)->WasHidden();
// Fast forward the moderate state timeout.
task_runner_->FastForwardBy(kHighOccludedTimeout);
// Verify that the first tab is discarded. TabManager is now in the moderate
// state as a result of the discard.
EXPECT_TRUE(
TabLifecycleUnitExternal::FromWebContents(tab_strip->GetWebContentsAt(0))
->IsDiscarded());
// Verify the rest of the tabs are not discarded.
for (int tab = 1; tab < kModerateLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Fast forward the difference between the moderate and the high threshold
// timeouts so the second tab was hidden the moderate threshold amount of
// time. This should cause the second tab to be discarded.
task_runner_->FastForwardBy(kModerateOccludedTimeout - kHighOccludedTimeout);
// Verify that the first 2 tabs are now discarded.
for (int tab = 0; tab < 2; tab++) {
EXPECT_TRUE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Verify the rest of the tabs are not discarded.
for (int tab = 2; tab < kModerateLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Hide the next 4 tabs. Once these are discarded, TabManager will be in the
// low state.
tab_strip->GetWebContentsAt(2)->WasHidden();
tab_strip->GetWebContentsAt(3)->WasHidden();
tab_strip->GetWebContentsAt(4)->WasHidden();
tab_strip->GetWebContentsAt(5)->WasHidden();
// Fast forward by the moderate threshold timeout.
task_runner_->FastForwardBy(kModerateOccludedTimeout);
// Verify that the first 6 tabs are now discarded. Now in the low state.
for (int tab = 0; tab < 6; tab++) {
EXPECT_TRUE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Verify the rest of the tabs are not discarded.
for (int tab = 6; tab < kModerateLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Hide the seventh tab.
tab_strip->GetWebContentsAt(6)->WasHidden();
// Fast forward the moderate threshold. Currently in the low state, so nothing
// should happen.
task_runner_->FastForwardBy(kModerateOccludedTimeout);
// Verify that the first 6 tabs are now discarded.
for (int tab = 0; tab < 6; tab++) {
EXPECT_TRUE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Verify the rest of the tabs are not discarded.
for (int tab = 6; tab < kModerateLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Fast forward the difference between the low and the moderate threshold
// timeouts so the seventh tab was hidden the moderate threshold amount of
// time. This should cause the seventh tab to be discarded.
task_runner_->FastForwardBy(kLowOccludedTimeout - kModerateOccludedTimeout);
// Verify that the first 7 tabs are now discarded.
for (int tab = 0; tab < 7; tab++) {
EXPECT_TRUE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
// Verify the rest of the tabs are not discarded.
for (int tab = 7; tab < kModerateLoadedTabCount; tab++) {
EXPECT_FALSE(TabLifecycleUnitExternal::FromWebContents(
tab_strip->GetWebContentsAt(tab))
->IsDiscarded());
}
tab_strip->CloseAllTabs();
}
TEST_F(TabManagerWithProactiveDiscardExperimentEnabledTest,
ProactiveDiscardTestTabClosedPriorToDiscard) {
auto window = std::make_unique<TestBrowserWindow>();
Browser::CreateParams params(profile(), true);
params.type = Browser::TYPE_TABBED;
params.window = window.get();
auto browser = std::make_unique<Browser>(params);
TabStripModel* tab_strip = browser->tab_strip_model();
tab_strip->AppendWebContents(CreateWebContents(), false);
tab_strip->GetWebContentsAt(0)->WasShown();
tab_strip->GetWebContentsAt(0)->WasHidden();
task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
tab_strip->CloseWebContentsAt(
0, TabStripModel::CloseTypes::CLOSE_CREATE_HISTORICAL_TAB |
TabStripModel::CloseTypes::CLOSE_USER_GESTURE);
// Success in this test is no crash, meaning that closing the tab caused the
// timer to be stopped, rather than triggering after the low threshold timeout
// on a closed LifecycleUnit.
task_runner_->FastForwardBy(kLowOccludedTimeout);
}
TEST_F(TabManagerTest, ProactiveDiscardDoesNotOccurWhenDisabled) {
auto window = std::make_unique<TestBrowserWindow>();
Browser::CreateParams params(profile(), true);
params.type = Browser::TYPE_TABBED;
params.window = window.get();
auto browser = std::make_unique<Browser>(params);
TabStripModel* tab_strip = browser->tab_strip_model();
tab_strip->AppendWebContents(CreateWebContents(), false);
tab_strip->GetWebContentsAt(0)->WasShown();
tab_strip->GetWebContentsAt(0)->WasHidden();
task_runner_->FastForwardBy(kLowOccludedTimeout);
EXPECT_FALSE(
TabLifecycleUnitExternal::FromWebContents(tab_strip->GetWebContentsAt(0))
->IsDiscarded());
tab_strip->CloseAllTabs();
}
} // namespace resource_coordinator
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