Commit 4af5a864 authored by Zhen Wang's avatar Zhen Wang Committed by Commit Bot

Add timeout support to staggered background tab opening

Add timeout to force load the next background tab after the timer expires.

Bug: 730098
Change-Id: I6cbb26288a02fdd61ece85e42c3106fa8e20a33b
Reviewed-on: https://chromium-review.googlesource.com/580188Reviewed-by: default avatarChris Hamilton <chrisha@chromium.org>
Commit-Queue: Zhen Wang <zhenw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488704}
parent b6be2ef0
...@@ -73,6 +73,12 @@ using content::WebContents; ...@@ -73,6 +73,12 @@ using content::WebContents;
namespace resource_coordinator { namespace resource_coordinator {
namespace { namespace {
// The timeout time after which the next background tab gets loaded if the
// previous tab has not finished loading yet.
// TODO(zhenw): Ignore this when under memory pressure. Or possibly make this
// a dynamic threshold under different scenarios.
const TimeDelta kBackgroundTabLoadTimeout = TimeDelta::FromSeconds(10);
// The default interval in seconds after which to adjust the oom_score_adj // The default interval in seconds after which to adjust the oom_score_adj
// value. // value.
const int kAdjustmentIntervalSeconds = 10; const int kAdjustmentIntervalSeconds = 10;
...@@ -149,6 +155,7 @@ TabManager::TabManager() ...@@ -149,6 +155,7 @@ TabManager::TabManager()
browser_tab_strip_tracker_(this, nullptr, this), browser_tab_strip_tracker_(this, nullptr, this),
test_tick_clock_(nullptr), test_tick_clock_(nullptr),
is_session_restore_loading_tabs_(false), is_session_restore_loading_tabs_(false),
force_load_timer_(base::MakeUnique<base::OneShotTimer>()),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
delegate_.reset(new TabManagerDelegate(weak_ptr_factory_.GetWeakPtr())); delegate_.reset(new TabManagerDelegate(weak_ptr_factory_.GetWeakPtr()));
...@@ -252,6 +259,7 @@ void TabManager::Start() { ...@@ -252,6 +259,7 @@ void TabManager::Start() {
void TabManager::Stop() { void TabManager::Stop() {
update_timer_.Stop(); update_timer_.Stop();
recent_tab_discard_timer_.Stop(); recent_tab_discard_timer_.Stop();
force_load_timer_->Stop();
memory_pressure_listener_.reset(); memory_pressure_listener_.reset();
} }
...@@ -393,6 +401,7 @@ void TabManager::LogMemory(const std::string& title, ...@@ -393,6 +401,7 @@ void TabManager::LogMemory(const std::string& title,
void TabManager::set_test_tick_clock(base::TickClock* test_tick_clock) { void TabManager::set_test_tick_clock(base::TickClock* test_tick_clock) {
test_tick_clock_ = test_tick_clock; test_tick_clock_ = test_tick_clock;
force_load_timer_.reset(new base::OneShotTimer(test_tick_clock));
} }
// Things to collect on the browser thread (because TabStripModel isn't thread // Things to collect on the browser thread (because TabStripModel isn't thread
...@@ -1044,6 +1053,8 @@ TabManager::MaybeThrottleNavigation(BackgroundTabNavigationThrottle* throttle) { ...@@ -1044,6 +1053,8 @@ TabManager::MaybeThrottleNavigation(BackgroundTabNavigationThrottle* throttle) {
GetWebContentsData(navigation_handle->GetWebContents()) GetWebContentsData(navigation_handle->GetWebContents())
->SetTabLoadingState(TAB_IS_NOT_LOADING); ->SetTabLoadingState(TAB_IS_NOT_LOADING);
pending_navigations_.push_back(throttle); pending_navigations_.push_back(throttle);
StartForceLoadTimer();
return content::NavigationThrottle::DEFER; return content::NavigationThrottle::DEFER;
} }
...@@ -1081,10 +1092,17 @@ void TabManager::OnWebContentsDestroyed(content::WebContents* contents) { ...@@ -1081,10 +1092,17 @@ void TabManager::OnWebContentsDestroyed(content::WebContents* contents) {
LoadNextBackgroundTabIfNeeded(); LoadNextBackgroundTabIfNeeded();
} }
void TabManager::StartForceLoadTimer() {
force_load_timer_->Stop();
force_load_timer_->Start(FROM_HERE, kBackgroundTabLoadTimeout, this,
&TabManager::LoadNextBackgroundTabIfNeeded);
}
void TabManager::LoadNextBackgroundTabIfNeeded() { void TabManager::LoadNextBackgroundTabIfNeeded() {
// Do not load more background tabs until all currently loading tabs have // Do not load more background tabs until all currently loading tabs have
// finished. // finished. Ignore this constraint if the timer fires to force loading the
if (!loading_contents_.empty()) // next background tab.
if (force_load_timer_->IsRunning() && !loading_contents_.empty())
return; return;
if (pending_navigations_.empty()) if (pending_navigations_.empty())
...@@ -1093,6 +1111,8 @@ void TabManager::LoadNextBackgroundTabIfNeeded() { ...@@ -1093,6 +1111,8 @@ void TabManager::LoadNextBackgroundTabIfNeeded() {
BackgroundTabNavigationThrottle* throttle = pending_navigations_.front(); BackgroundTabNavigationThrottle* throttle = pending_navigations_.front();
pending_navigations_.erase(pending_navigations_.begin()); pending_navigations_.erase(pending_navigations_.begin());
ResumeNavigation(throttle); ResumeNavigation(throttle);
StartForceLoadTimer();
} }
void TabManager::ResumeTabNavigationIfNeeded(content::WebContents* contents) { void TabManager::ResumeTabNavigationIfNeeded(content::WebContents* contents) {
...@@ -1145,4 +1165,16 @@ bool TabManager::IsNavigationDelayedForTest( ...@@ -1145,4 +1165,16 @@ bool TabManager::IsNavigationDelayedForTest(
return false; return false;
} }
bool TabManager::TriggerForceLoadTimerForTest() {
if (!force_load_timer_->IsRunning() ||
(test_tick_clock_->NowTicks() < force_load_timer_->desired_run_time())) {
return false;
}
base::Closure timer_callback(force_load_timer_->user_task());
force_load_timer_->Stop();
timer_callback.Run();
return true;
}
} // namespace resource_coordinator } // namespace resource_coordinator
...@@ -225,6 +225,7 @@ class TabManager : public TabStripModelObserver, ...@@ -225,6 +225,7 @@ class TabManager : public TabStripModelObserver,
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnDidStopLoading); FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnDidStopLoading);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnWebContentsDestroyed); FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnWebContentsDestroyed);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnDelayedTabSelected); FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnDelayedTabSelected);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TimeoutWhenLoadingBackgroundTabs);
FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorTest, FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorTest,
HistogramsSessionRestoreSwitchToTab); HistogramsSessionRestoreSwitchToTab);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
...@@ -397,6 +398,10 @@ class TabManager : public TabStripModelObserver, ...@@ -397,6 +398,10 @@ class TabManager : public TabStripModelObserver,
bool ShouldDelayNavigation( bool ShouldDelayNavigation(
content::NavigationHandle* navigation_handle) const; content::NavigationHandle* navigation_handle) const;
// Start |force_load_timer_| to load the next background tab if the timer
// expires before the current tab loading is finished.
void StartForceLoadTimer();
// Start loading the next background tab if needed. // Start loading the next background tab if needed.
void LoadNextBackgroundTabIfNeeded(); void LoadNextBackgroundTabIfNeeded();
...@@ -418,6 +423,9 @@ class TabManager : public TabStripModelObserver, ...@@ -418,6 +423,9 @@ class TabManager : public TabStripModelObserver,
bool IsNavigationDelayedForTest( bool IsNavigationDelayedForTest(
const content::NavigationHandle* navigation_handle) const; const content::NavigationHandle* navigation_handle) const;
// Trigger |force_load_timer_| to fire. Use only in tests.
bool TriggerForceLoadTimerForTest();
// Timer to periodically update the stats of the renderers. // Timer to periodically update the stats of the renderers.
base::RepeatingTimer update_timer_; base::RepeatingTimer update_timer_;
...@@ -487,6 +495,9 @@ class TabManager : public TabStripModelObserver, ...@@ -487,6 +495,9 @@ class TabManager : public TabStripModelObserver,
class TabManagerSessionRestoreObserver; class TabManagerSessionRestoreObserver;
std::unique_ptr<TabManagerSessionRestoreObserver> session_restore_observer_; std::unique_ptr<TabManagerSessionRestoreObserver> session_restore_observer_;
// When the timer fires, it forces loading the next background tab if needed.
std::unique_ptr<base::OneShotTimer> force_load_timer_;
// The list of navigations that are delayed. // The list of navigations that are delayed.
std::vector<BackgroundTabNavigationThrottle*> pending_navigations_; std::vector<BackgroundTabNavigationThrottle*> pending_navigations_;
......
...@@ -797,4 +797,44 @@ TEST_F(TabManagerTest, OnDelayedTabSelected) { ...@@ -797,4 +797,44 @@ TEST_F(TabManagerTest, OnDelayedTabSelected) {
EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle2_.get())); EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle2_.get()));
} }
TEST_F(TabManagerTest, TimeoutWhenLoadingBackgroundTabs) {
TabManager* tab_manager = g_browser_process->GetTabManager();
base::SimpleTestTickClock test_clock;
tab_manager->set_test_tick_clock(&test_clock);
MaybeThrottleNavigations(tab_manager);
tab_manager->GetWebContentsData(contents1_)
->DidStartNavigation(nav_handle1_.get());
EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents1_));
EXPECT_FALSE(tab_manager->IsTabLoadingForTest(contents2_));
EXPECT_FALSE(tab_manager->IsTabLoadingForTest(contents3_));
EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle1_.get()));
EXPECT_TRUE(tab_manager->IsNavigationDelayedForTest(nav_handle2_.get()));
EXPECT_TRUE(tab_manager->IsNavigationDelayedForTest(nav_handle3_.get()));
// Simulate timout when loading the 1st tab. TabManager should start loading
// the 2nd tab.
test_clock.Advance(base::TimeDelta::FromMinutes(1));
EXPECT_TRUE(tab_manager->TriggerForceLoadTimerForTest());
EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents1_));
EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents2_));
EXPECT_FALSE(tab_manager->IsTabLoadingForTest(contents3_));
EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle1_.get()));
EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle2_.get()));
EXPECT_TRUE(tab_manager->IsNavigationDelayedForTest(nav_handle3_.get()));
// Simulate timout again. TabManager should start loading the 3rd tab.
test_clock.Advance(base::TimeDelta::FromMinutes(1));
EXPECT_TRUE(tab_manager->TriggerForceLoadTimerForTest());
EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents1_));
EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents2_));
EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents3_));
EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle1_.get()));
EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle2_.get()));
EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle3_.get()));
}
} // namespace resource_coordinator } // 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