Use TabLoader in TabRestoreService.
SessionService uses TabLoader to load tabs gradually.
The same behaviour is expected from TabRestoreService.
BUG=697510
Review-Url: https://codereview.chromium.org/2727663004
Cr-Commit-Position: refs/heads/master@{#454919}
diff --git a/chrome/browser/sessions/tab_loader.cc b/chrome/browser/sessions/tab_loader.cc
index ef4c3cd..753f4e04 100644
--- a/chrome/browser/sessions/tab_loader.cc
+++ b/chrome/browser/sessions/tab_loader.cc
@@ -31,6 +31,12 @@
using content::RenderWidgetHost;
using content::WebContents;
+namespace {
+
+size_t g_max_loaded_tab_count_for_testing = 0;
+
+} // namespace
+
void TabLoader::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
@@ -78,11 +84,17 @@
shared_tab_loader_->StartLoading(tabs);
}
+// static
+void TabLoader::SetMaxLoadedTabCountForTest(size_t value) {
+ g_max_loaded_tab_count_for_testing = value;
+}
+
TabLoader::TabLoader(base::TimeTicks restore_started)
: memory_pressure_listener_(
base::Bind(&TabLoader::OnMemoryPressure, base::Unretained(this))),
force_load_delay_multiplier_(1),
loading_enabled_(true),
+ started_to_load_count_(0),
restore_started_(restore_started) {
stats_collector_ = new SessionRestoreStatsCollector(
restore_started,
@@ -118,6 +130,7 @@
if (favicon_driver)
favicon_driver->FetchFavicon(favicon_driver->GetActiveURL());
} else {
+ ++started_to_load_count_;
tabs_loading_.insert(&restored_tab.contents()->GetController());
}
RegisterForNotifications(&restored_tab.contents()->GetController());
@@ -168,6 +181,7 @@
NavigationController* controller = tabs_to_load_.front();
DCHECK(controller);
+ ++started_to_load_count_;
tabs_loading_.insert(controller);
tabs_to_load_.pop_front();
controller->LoadIfNecessary();
@@ -242,6 +256,9 @@
}
bool TabLoader::ShouldStopLoadingTabs() const {
+ if (g_max_loaded_tab_count_for_testing != 0 &&
+ started_to_load_count_ >= g_max_loaded_tab_count_for_testing)
+ return true;
if (base::FeatureList::IsEnabled(features::kMemoryCoordinator))
return base::MemoryCoordinatorProxy::GetInstance()->GetCurrentMemoryState()
!= base::MemoryState::NORMAL;
diff --git a/chrome/browser/sessions/tab_loader.h b/chrome/browser/sessions/tab_loader.h
index 81c6dd0..c3528f3 100644
--- a/chrome/browser/sessions/tab_loader.h
+++ b/chrome/browser/sessions/tab_loader.h
@@ -63,6 +63,8 @@
private:
FRIEND_TEST_ALL_PREFIXES(TabLoaderTest, OnMemoryStateChange);
+ FRIEND_TEST_ALL_PREFIXES(TabRestoreTest,
+ TabsFromRestoredWindowsAreLoadedGradually);
friend class base::RefCounted<TabLoader>;
@@ -123,6 +125,11 @@
// Stops loading tabs to purge memory by stopping to load any more tabs.
void StopLoadingTabs();
+ // Limit the number of loaded tabs.
+ // Value of 0 restores default behavior. In test mode command line flags and
+ // free memory size are not taken into account.
+ static void SetMaxLoadedTabCountForTest(size_t value);
+
std::unique_ptr<TabLoaderDelegate> delegate_;
// Listens for system under memory pressure notifications and stops loading
@@ -144,6 +151,10 @@
// The tabs we need to load.
TabsToLoad tabs_to_load_;
+ // The number of tabs started to load.
+ // (This value never decreases.)
+ size_t started_to_load_count_;
+
base::OneShotTimer force_load_timer_;
// The time the restore process started.
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc
index b7e444d..70fc7a7 100644
--- a/chrome/browser/sessions/tab_restore_browsertest.cc
+++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -42,6 +42,10 @@
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "url/gurl.h"
+#if BUILDFLAG(ENABLE_SESSION_SERVICE)
+#include "chrome/browser/sessions/tab_loader.h"
+#endif // BUILDFLAG(ENABLE_SESSION_SERVICE)
+
// Class used to run a message loop waiting for the TabRestoreService to finish
// loading. Does nothing if the TabRestoreService was already loaded.
class WaitForLoadObserver : public sessions::TabRestoreServiceObserver {
@@ -638,15 +642,16 @@
EXPECT_EQ(initial_tab_count + 2, browser->tab_strip_model()->count());
load_stop_observer.Wait();
+ EXPECT_EQ(initial_tab_count + 1, browser->tab_strip_model()->active_index());
content::WebContents* restored_tab =
- browser->tab_strip_model()->GetWebContentsAt(initial_tab_count);
- EnsureTabFinishedRestoring(restored_tab);
- EXPECT_EQ(url1_, restored_tab->GetURL());
-
- restored_tab =
browser->tab_strip_model()->GetWebContentsAt(initial_tab_count + 1);
EnsureTabFinishedRestoring(restored_tab);
EXPECT_EQ(url2_, restored_tab->GetURL());
+
+ restored_tab =
+ browser->tab_strip_model()->GetWebContentsAt(initial_tab_count);
+ EnsureTabFinishedRestoring(restored_tab);
+ EXPECT_EQ(url1_, restored_tab->GetURL());
}
// Restore tab with special URL chrome://credits/ and make sure the page loads
@@ -759,3 +764,54 @@
Browser* browser = GetBrowser(0);
EXPECT_EQ(4, browser->tab_strip_model()->count());
}
+
+// TabLoader (used here) is available only when browser is built
+// with ENABLE_SESSION_SERVICE.
+#if BUILDFLAG(ENABLE_SESSION_SERVICE)
+IN_PROC_BROWSER_TEST_F(TabRestoreTest,
+ TabsFromRestoredWindowsAreLoadedGradually) {
+ ui_test_utils::NavigateToURLWithDisposition(
+ browser(), url2_, WindowOpenDisposition::NEW_WINDOW,
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
+ Browser* browser2 = GetBrowser(1);
+
+ // Add tabs and close browser.
+ const int tabs_count = 4;
+ AddSomeTabs(browser2, tabs_count - browser2->tab_strip_model()->count());
+ EXPECT_EQ(tabs_count, browser2->tab_strip_model()->count());
+ content::WindowedNotificationObserver observer(
+ chrome::NOTIFICATION_BROWSER_CLOSED,
+ content::NotificationService::AllSources());
+ chrome::CloseWindow(browser2);
+ observer.Wait();
+
+ // Limit the number of restored tabs that are loaded.
+ TabLoader::SetMaxLoadedTabCountForTest(2);
+
+ // Restore recently closed window.
+ content::WindowedNotificationObserver open_window_observer(
+ chrome::NOTIFICATION_BROWSER_OPENED,
+ content::NotificationService::AllSources());
+ chrome::OpenWindowWithRestoredTabs(browser()->profile());
+ open_window_observer.Wait();
+ browser2 = GetBrowser(1);
+
+ EXPECT_EQ(tabs_count, browser2->tab_strip_model()->count());
+ EXPECT_EQ(tabs_count - 1, browser2->tab_strip_model()->active_index());
+ // These two tabs should be loaded by TabLoader.
+ EnsureTabFinishedRestoring(
+ browser2->tab_strip_model()->GetWebContentsAt(tabs_count - 1));
+ EnsureTabFinishedRestoring(browser2->tab_strip_model()->GetWebContentsAt(0));
+
+ // The following isn't necessary but just to be sure there is no any async
+ // task that could have an impact on the expectations below.
+ content::RunAllPendingInMessageLoop();
+
+ // These tabs shouldn't want to be loaded.
+ for (int tab_idx = 1; tab_idx < tabs_count - 1; ++tab_idx) {
+ auto* contents = browser2->tab_strip_model()->GetWebContentsAt(tab_idx);
+ EXPECT_FALSE(contents->IsLoading());
+ EXPECT_TRUE(contents->GetController().NeedsReload());
+ }
+}
+#endif // BUILDFLAG(ENABLE_SESSION_SERVICE)
diff --git a/chrome/browser/ui/android/tab_model/android_live_tab_context.cc b/chrome/browser/ui/android/tab_model/android_live_tab_context.cc
index 8b298ad..7374002 100644
--- a/chrome/browser/ui/android/tab_model/android_live_tab_context.cc
+++ b/chrome/browser/ui/android/tab_model/android_live_tab_context.cc
@@ -84,6 +84,7 @@
// Create new tab.
tab_model_->CreateTab(nullptr, web_contents, -1);
+ web_contents->GetController().LoadIfNecessary();
return sessions::ContentLiveTab::GetForWebContents(web_contents);
}
diff --git a/chrome/browser/ui/browser_live_tab_context.cc b/chrome/browser/ui/browser_live_tab_context.cc
index c6ee3f0..bf3672f 100644
--- a/chrome/browser/ui/browser_live_tab_context.cc
+++ b/chrome/browser/ui/browser_live_tab_context.cc
@@ -15,6 +15,10 @@
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/session_storage_namespace.h"
+#if BUILDFLAG(ENABLE_SESSION_SERVICE)
+#include "chrome/browser/sessions/tab_loader.h"
+#endif
+
using content::NavigationController;
using content::SessionStorageNamespace;
using content::WebContents;
@@ -74,6 +78,24 @@
browser_, navigations, tab_index, selected_navigation, extension_app_id,
select, pin, from_last_session, storage_namespace, user_agent_override);
+#if BUILDFLAG(ENABLE_SESSION_SERVICE)
+ // The focused tab will be loaded by Browser, and TabLoader will load the
+ // rest.
+ if (!select) {
+ // Regression check: make sure that the tab hasn't started to load
+ // immediately.
+ DCHECK(web_contents->GetController().NeedsReload());
+ DCHECK(!web_contents->IsLoading());
+ }
+ std::vector<TabLoader::RestoredTab> restored_tabs;
+ restored_tabs.emplace_back(web_contents, select, !extension_app_id.empty(),
+ pin);
+ TabLoader::RestoreTabs(restored_tabs, base::TimeTicks::Now());
+#else // BUILDFLAG(ENABLE_SESSION_SERVICE)
+ // Load the tab manually if there is no TabLoader.
+ web_contents->GetController().LoadIfNecessary();
+#endif // BUILDFLAG(ENABLE_SESSION_SERVICE)
+
return sessions::ContentLiveTab::GetForWebContents(web_contents);
}
diff --git a/chrome/browser/ui/browser_tabrestore_browsertest.cc b/chrome/browser/ui/browser_tabrestore_browsertest.cc
index 5fd6ac3..51acd8f94 100644
--- a/chrome/browser/ui/browser_tabrestore_browsertest.cc
+++ b/chrome/browser/ui/browser_tabrestore_browsertest.cc
@@ -13,6 +13,7 @@
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "components/sessions/core/tab_restore_service.h"
+#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
@@ -90,6 +91,24 @@
EXPECT_EQ(2u, active_browser_list->size());
browser = active_browser_list->get(1);
EXPECT_EQ(3, browser->tab_strip_model()->count());
+ // For the two test tabs we've just received "READY" DOM message.
+ // But there won't be such message from the "about:blank" tab.
+ // And it is possible that TabLoader hasn't loaded it yet.
+ // Thus we should wait for "load stop" event before we will perform
+ // CheckVisbility on "about:blank".
+ {
+ const content::WebContents* about_blank_contents =
+ browser->tab_strip_model()->GetWebContentsAt(0);
+ EXPECT_EQ("about:blank", about_blank_contents->GetURL().spec());
+ if (about_blank_contents->IsLoading() ||
+ about_blank_contents->GetController().NeedsReload()) {
+ content::WindowedNotificationObserver load_stop_observer(
+ content::NOTIFICATION_LOAD_STOP,
+ content::Source<content::NavigationController>(
+ &about_blank_contents->GetController()));
+ load_stop_observer.Wait();
+ }
+ }
// The middle tab only should have visible disposition.
CheckVisbility(browser->tab_strip_model(), 1);
@@ -132,6 +151,21 @@
EXPECT_EQ(2u, active_browser_list->size());
browser = active_browser_list->get(1);
EXPECT_EQ(3, browser->tab_strip_model()->count());
+ // The same as in RecentTabsMenuTabDisposition test case.
+ // See there for the explanation.
+ {
+ const content::WebContents* about_blank_contents =
+ browser->tab_strip_model()->GetWebContentsAt(0);
+ EXPECT_EQ("about:blank", about_blank_contents->GetURL().spec());
+ if (about_blank_contents->IsLoading() ||
+ about_blank_contents->GetController().NeedsReload()) {
+ content::WindowedNotificationObserver load_stop_observer(
+ content::NOTIFICATION_LOAD_STOP,
+ content::Source<content::NavigationController>(
+ &about_blank_contents->GetController()));
+ load_stop_observer.Wait();
+ }
+ }
// The middle tab only should have visible disposition.
CheckVisbility(browser->tab_strip_model(), 1);
diff --git a/components/sessions/content/content_live_tab.cc b/components/sessions/content/content_live_tab.cc
index 7b1dff0..3f1ef66 100644
--- a/components/sessions/content/content_live_tab.cc
+++ b/components/sessions/content/content_live_tab.cc
@@ -62,10 +62,6 @@
web_contents());
}
-void ContentLiveTab::LoadIfNecessary() {
- navigation_controller().LoadIfNecessary();
-}
-
const std::string& ContentLiveTab::GetUserAgentOverride() const {
return web_contents()->GetUserAgentOverride();
}
diff --git a/components/sessions/content/content_live_tab.h b/components/sessions/content/content_live_tab.h
index f4324411..5c04ba1 100644
--- a/components/sessions/content/content_live_tab.h
+++ b/components/sessions/content/content_live_tab.h
@@ -41,7 +41,6 @@
int GetEntryCount() override;
std::unique_ptr<PlatformSpecificTabData> GetPlatformSpecificTabData()
override;
- void LoadIfNecessary() override;
const std::string& GetUserAgentOverride() const override;
content::WebContents* web_contents() { return web_contents_; }
diff --git a/components/sessions/core/live_tab.h b/components/sessions/core/live_tab.h
index bd61293..4902199 100644
--- a/components/sessions/core/live_tab.h
+++ b/components/sessions/core/live_tab.h
@@ -32,10 +32,6 @@
// implementation returns null.
virtual std::unique_ptr<PlatformSpecificTabData> GetPlatformSpecificTabData();
- // Loads the current page if necessary (where "necessary" is defined on a
- // platform-specific basis).
- virtual void LoadIfNecessary() = 0;
-
// Returns the user agent override, if any.
virtual const std::string& GetUserAgentOverride() const = 0;
};
diff --git a/components/sessions/core/tab_restore_service_helper.cc b/components/sessions/core/tab_restore_service_helper.cc
index c140cda..f4f1119 100644
--- a/components/sessions/core/tab_restore_service_helper.cc
+++ b/components/sessions/core/tab_restore_service_helper.cc
@@ -209,7 +209,6 @@
tab.from_last_session, tab.platform_data.get(),
tab.user_agent_override);
if (restored_tab) {
- restored_tab->LoadIfNecessary();
client_->OnTabRestored(
tab.navigations.at(tab.current_navigation_index).virtual_url());
live_tabs.push_back(restored_tab);
@@ -482,7 +481,6 @@
disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB, tab.pinned,
tab.from_last_session, tab.platform_data.get(),
tab.user_agent_override);
- restored_tab->LoadIfNecessary();
}
client_->OnTabRestored(
tab.navigations.at(tab.current_navigation_index).virtual_url());
diff --git a/components/sessions/ios/ios_live_tab.h b/components/sessions/ios/ios_live_tab.h
index d4363a51..17b6fe54 100644
--- a/components/sessions/ios/ios_live_tab.h
+++ b/components/sessions/ios/ios_live_tab.h
@@ -35,7 +35,6 @@
sessions::SerializedNavigationEntry GetEntryAtIndex(int index) override;
sessions::SerializedNavigationEntry GetPendingEntry() override;
int GetEntryCount() override;
- void LoadIfNecessary() override;
const std::string& GetUserAgentOverride() const override;
web::WebState* web_state() { return web_state_; }
diff --git a/components/sessions/ios/ios_live_tab.mm b/components/sessions/ios/ios_live_tab.mm
index 5f8f7dd..b34747a 100644
--- a/components/sessions/ios/ios_live_tab.mm
+++ b/components/sessions/ios/ios_live_tab.mm
@@ -54,10 +54,6 @@
return navigation_manager()->GetItemCount();
}
-void IOSLiveTab::LoadIfNecessary() {
- navigation_manager()->LoadIfNecessary();
-}
-
const std::string& IOSLiveTab::GetUserAgentOverride() const {
// Dynamic user agent overrides are not supported on iOS.
return user_agent_override_;