Commit edb53660 authored by Chris Hamilton's avatar Chris Hamilton Committed by Commit Bot

Make TabManager use TabLoadTracker for load tracking.

This moves all of the responsibility for handling PageAlmostIdle to TabLoadTracker.

Change-Id: I9325109e896910d76b6aa6a615f9004dc1a4e67d
Reviewed-on: https://chromium-review.googlesource.com/1060569
Commit-Queue: Chris Hamilton <chrisha@chromium.org>
Reviewed-by: default avatarSébastien Marchand <sebmarchand@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#559277}
parent 668c097f
......@@ -26,20 +26,7 @@
#include "services/resource_coordinator/public/mojom/service_constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace {
// The manager currently doesn't exist on all platforms, which means the
// tab load tracker will not either.
// TODO(chrisha): Make the tab manager exist everywhere. It's going to start
// making scheduling decisions that apply to mobile devices as well, so there's
// no longer any reason for it to be mobile only.
resource_coordinator::TabLoadTracker* GetTabLoadTracker() {
if (auto* manager = g_browser_process->GetTabManager())
return &(manager->tab_load_tracker());
return nullptr;
}
} // namespace
using resource_coordinator::TabLoadTracker;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(ResourceCoordinatorWebContentsObserver);
......@@ -71,8 +58,7 @@ ResourceCoordinatorWebContentsObserver::ResourceCoordinatorWebContentsObserver(
page_resource_coordinator_->id(), web_contents);
}
if (auto* tracker = GetTabLoadTracker())
tracker->StartTracking(web_contents);
TabLoadTracker::Get()->StartTracking(web_contents);
}
ResourceCoordinatorWebContentsObserver::
......@@ -87,20 +73,16 @@ bool ResourceCoordinatorWebContentsObserver::IsEnabled() {
void ResourceCoordinatorWebContentsObserver::DidStartLoading() {
page_resource_coordinator_->SetIsLoading(true);
if (auto* tracker = GetTabLoadTracker())
tracker->DidStartLoading(web_contents());
TabLoadTracker::Get()->DidStartLoading(web_contents());
}
void ResourceCoordinatorWebContentsObserver::DidReceiveResponse() {
if (auto* tracker = GetTabLoadTracker())
tracker->DidReceiveResponse(web_contents());
TabLoadTracker::Get()->DidReceiveResponse(web_contents());
}
void ResourceCoordinatorWebContentsObserver::DidStopLoading() {
page_resource_coordinator_->SetIsLoading(false);
if (auto* tracker = GetTabLoadTracker())
tracker->DidStopLoading(web_contents());
TabLoadTracker::Get()->DidStopLoading(web_contents());
}
void ResourceCoordinatorWebContentsObserver::DidFailLoad(
......@@ -108,8 +90,7 @@ void ResourceCoordinatorWebContentsObserver::DidFailLoad(
const GURL& validated_url,
int error_code,
const base::string16& error_description) {
if (auto* tracker = GetTabLoadTracker())
tracker->DidFailLoad(web_contents());
TabLoadTracker::Get()->DidFailLoad(web_contents());
}
void ResourceCoordinatorWebContentsObserver::OnVisibilityChanged(
......@@ -127,8 +108,7 @@ void ResourceCoordinatorWebContentsObserver::WebContentsDestroyed() {
page_signal_receiver->RemoveCoordinationUnitID(
page_resource_coordinator_->id());
}
if (auto* tracker = GetTabLoadTracker())
tracker->StopTracking(web_contents());
TabLoadTracker::Get()->StopTracking(web_contents());
}
void ResourceCoordinatorWebContentsObserver::DidFinishNavigation(
......@@ -141,7 +121,7 @@ void ResourceCoordinatorWebContentsObserver::DidFinishNavigation(
content::RenderFrameHost* render_frame_host =
navigation_handle->GetRenderFrameHost();
// Make sure the hierarchical structure is constructured before sending signal
// Make sure the hierarchical structure is constructed before sending signal
// to Resource Coordinator.
auto* frame_resource_coordinator =
render_frame_host->GetFrameResourceCoordinator();
......
......@@ -14,9 +14,13 @@
namespace resource_coordinator {
TabLoadTracker::TabLoadTracker() {}
TabLoadTracker::~TabLoadTracker() = default;
TabLoadTracker::~TabLoadTracker() {}
// static
TabLoadTracker* TabLoadTracker::Get() {
static base::NoDestructor<TabLoadTracker> tab_load_tracker;
return tab_load_tracker.get();
}
TabLoadTracker::LoadingState TabLoadTracker::GetLoadingState(
content::WebContents* web_contents) const {
......@@ -61,6 +65,16 @@ void TabLoadTracker::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void TabLoadTracker::TransitionStateForTesting(
content::WebContents* web_contents,
LoadingState loading_state) {
auto it = tabs_.find(web_contents);
DCHECK(it != tabs_.end());
TransitionState(it, loading_state, false);
}
TabLoadTracker::TabLoadTracker() = default;
void TabLoadTracker::StartTracking(content::WebContents* web_contents) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!base::ContainsKey(tabs_, web_contents));
......@@ -121,7 +135,7 @@ void TabLoadTracker::DidReceiveResponse(content::WebContents* web_contents) {
// actual network requests, but not the rest of the state machinery.
if (!it->second.did_start_loading_seen)
return;
TransitionState(it, LOADING);
TransitionState(it, LOADING, true);
}
void TabLoadTracker::DidStopLoading(content::WebContents* web_contents) {
......@@ -176,29 +190,32 @@ void TabLoadTracker::MaybeTransitionToLoaded(
DCHECK(it != tabs_.end());
if (it->second.loading_state != LOADING)
return;
TransitionState(it, LOADED);
TransitionState(it, LOADED, true);
}
void TabLoadTracker::TransitionState(TabMap::iterator it,
LoadingState loading_state) {
LoadingState loading_state,
bool validate_transition) {
#if DCHECK_IS_ON()
// Validate the transition.
switch (loading_state) {
case LOADING: {
DCHECK_NE(LOADING, it->second.loading_state);
DCHECK(it->second.did_start_loading_seen);
break;
}
case LOADED: {
DCHECK_EQ(LOADING, it->second.loading_state);
DCHECK(it->second.did_start_loading_seen);
break;
if (validate_transition) {
// Validate the transition.
switch (loading_state) {
case LOADING: {
DCHECK_NE(LOADING, it->second.loading_state);
DCHECK(it->second.did_start_loading_seen);
break;
}
case LOADED: {
DCHECK_EQ(LOADING, it->second.loading_state);
DCHECK(it->second.did_start_loading_seen);
break;
}
case UNLOADED: // It never makes sense to transition to UNLOADED.
case LOADING_STATE_MAX:
NOTREACHED();
}
case UNLOADED: // It never makes sense to transition to UNLOADED.
case LOADING_STATE_MAX:
NOTREACHED();
}
#endif
......
......@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/strings/string16.h"
......@@ -33,8 +34,7 @@ class TabManagerResourceCoordinatorSignalObserverHelper;
// thread.
//
// This class is intended to be created in early startup and persists as a
// singleton in the browser process, owned by the TabManager. It is deliberately
// leaked at shutdown.
// singleton in the browser process. It is deliberately leaked at shutdown.
//
// This class isn't directly an observer of anything. An external source must
// invoke the callbacks in the protected section of the class. In the case of
......@@ -47,13 +47,15 @@ class TabLoadTracker {
// state changes.
class Observer;
// Indicates the loading state of a WebContents.
// Indicates the loading state of a WebContents. These values are written to
// logs and histograms. New enum values can be added, but existing enums must
// never be renumbered or deleted and reused.
enum LoadingState {
// An initially constructed WebContents with no loaded content is UNLOADED.
// A WebContents that started loading but that errored out before receiving
// sufficient content to render is also considered UNLOADED.
// Can only transition from here to LOADING.
UNLOADED,
UNLOADED = 0,
// A WebContents with an ongoing main-frame navigation (to a new document)
// is in a loading state. More precisely, it is considered loading once
// network data has started to be transmitted, and not simply when the
......@@ -61,22 +63,24 @@ class TabLoadTracker {
// loading, and will only transition to loading once the throttle has been
// removed.
// Can transition from here to UNLOADED or LOADED.
LOADING,
LOADING = 1,
// A WebContents with a committed navigation whose
// DidStopLoading/PageAlmostIdle event (depending on mode) or DidFailLoad
// event has fired is no longer considered to be LOADING. If any content has
// been rendered prior to the failure the document is considered LOADED,
// otherwise it is considered UNLOADED.
// Can transition from here to LOADING.
LOADED,
LOADED = 2,
// This must be last.
LOADING_STATE_MAX
};
TabLoadTracker();
~TabLoadTracker();
// Returns the singleton TabLoadTracker instance.
static TabLoadTracker* Get();
// Allows querying the state of a tab. The provided |web_contents| must be
// actively tracked.
LoadingState GetLoadingState(content::WebContents* web_contents) const;
......@@ -95,13 +99,23 @@ class TabLoadTracker {
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Exposed so that state transitions can be simulated in tests.
void TransitionStateForTesting(content::WebContents* web_contents,
LoadingState loading_state);
protected:
// This allows the various bits of TabManager plubming to forward
// notifications to the TabLoadTracker.
// This allows the singleton constructor access to the protected constructor.
friend class base::NoDestructor<TabLoadTracker>;
// These declarations allows the various bits of TabManager plumbing to
// forward notifications to the TabLoadTracker.
friend class ::ResourceCoordinatorWebContentsObserver;
friend class ::resource_coordinator::
TabManagerResourceCoordinatorSignalObserverHelper;
// This class is a singleton so the constructor is protected.
TabLoadTracker();
// Initiates tracking of a WebContents. This is fully able to determine the
// initial state of the WebContents, even if it was created long ago
// (is LOADING or LOADED) and only just attached to the tracker. See the
......@@ -144,8 +158,12 @@ class TabLoadTracker {
void MaybeTransitionToLoaded(content::WebContents* web_contents);
// Transitions a web contents to the given state. This updates the various
// |state_counts_| and |tabs_| data.
void TransitionState(TabMap::iterator it, LoadingState loading_state);
// |state_counts_| and |tabs_| data. Setting |validate_transition| to false
// means that valid state machine transitions aren't enforced via checks; this
// is only used by state transitions forced via TransitionStateForTesting.
void TransitionState(TabMap::iterator it,
LoadingState loading_state,
bool validate_transition);
// The list of known WebContents and their states.
TabMap tabs_;
......
......@@ -176,11 +176,12 @@ TabManager::TabManager()
new ResourceCoordinatorSignalObserver());
}
stats_collector_.reset(new TabManagerStatsCollector());
proactive_discard_params_ = GetStaticProactiveTabDiscardParams();
TabLoadTracker::Get()->AddObserver(this);
}
TabManager::~TabManager() {
TabLoadTracker::Get()->RemoveObserver(this);
resource_coordinator_signal_observer_.reset();
Stop();
}
......@@ -578,6 +579,35 @@ void TabManager::TabReplacedAt(TabStripModel* tab_strip_model,
WebContentsData::CopyState(old_contents, new_contents);
}
void TabManager::OnStartTracking(content::WebContents* web_contents,
LoadingState loading_state) {
GetWebContentsData(web_contents)->SetTabLoadingState(loading_state);
}
void TabManager::OnLoadingStateChange(content::WebContents* web_contents,
LoadingState loading_state) {
GetWebContentsData(web_contents)->SetTabLoadingState(loading_state);
if (loading_state == TabLoadTracker::LOADED) {
bool was_in_background_tab_opening_session =
IsInBackgroundTabOpeningSession();
loading_contents_.erase(web_contents);
stats_collector_->OnTabIsLoaded(web_contents);
LoadNextBackgroundTabIfNeeded();
if (was_in_background_tab_opening_session &&
!IsInBackgroundTabOpeningSession()) {
stats_collector_->OnBackgroundTabOpeningSessionEnded();
}
}
}
void TabManager::OnStopTracking(content::WebContents* web_contents,
LoadingState loading_state) {
GetWebContentsData(web_contents)->SetTabLoadingState(loading_state);
}
// static
TabManager::WebContentsData* TabManager::GetWebContentsData(
content::WebContents* contents) {
......@@ -661,8 +691,6 @@ TabManager::MaybeThrottleNavigation(BackgroundTabNavigationThrottle* throttle) {
// Notify TabUIHelper that the navigation is delayed, so that the tab UI such
// as favicon and title can be updated accordingly.
TabUIHelper::FromWebContents(contents)->NotifyInitialNavigationDelayed(true);
GetWebContentsData(contents)->SetTabLoadingState(TAB_IS_NOT_LOADING);
pending_navigations_.push_back(throttle);
std::stable_sort(pending_navigations_.begin(), pending_navigations_.end(),
ComparePendingNavigations);
......@@ -713,21 +741,6 @@ void TabManager::OnDidFinishNavigation(
}
}
void TabManager::OnTabIsLoaded(content::WebContents* contents) {
DCHECK_EQ(TAB_IS_LOADED, GetWebContentsData(contents)->tab_loading_state());
bool was_in_background_tab_opening_session =
IsInBackgroundTabOpeningSession();
loading_contents_.erase(contents);
stats_collector_->OnTabIsLoaded(contents);
LoadNextBackgroundTabIfNeeded();
if (was_in_background_tab_opening_session &&
!IsInBackgroundTabOpeningSession()) {
stats_collector_->OnBackgroundTabOpeningSessionEnded();
}
}
void TabManager::OnWebContentsDestroyed(content::WebContents* contents) {
bool was_in_background_tab_opening_session =
IsInBackgroundTabOpeningSession();
......@@ -801,7 +814,6 @@ void TabManager::ResumeTabNavigationIfNeeded(content::WebContents* contents) {
void TabManager::ResumeNavigation(BackgroundTabNavigationThrottle* throttle) {
content::WebContents* contents =
throttle->navigation_handle()->GetWebContents();
GetWebContentsData(contents)->SetTabLoadingState(TAB_IS_LOADING);
loading_contents_.insert(contents);
TabUIHelper::FromWebContents(contents)->NotifyInitialNavigationDelayed(false);
......@@ -855,13 +867,10 @@ int TabManager::GetNumAliveTabs() const {
}
bool TabManager::IsTabLoadingForTest(content::WebContents* contents) const {
if (loading_contents_.count(contents) == 1) {
DCHECK_EQ(TAB_IS_LOADING,
GetWebContentsData(contents)->tab_loading_state());
if (base::ContainsKey(loading_contents_, contents))
return true;
}
DCHECK_NE(TAB_IS_LOADING, GetWebContentsData(contents)->tab_loading_state());
DCHECK_NE(TabLoadTracker::LOADING,
GetWebContentsData(contents)->tab_loading_state());
return false;
}
......
......@@ -80,6 +80,7 @@ class TabManagerStatsCollector;
// TODO(fdoray): Rename to LifecycleManager. https://crbug.com/775644
class TabManager : public LifecycleUnitObserver,
public LifecycleUnitSourceObserver,
public TabLoadTracker::Observer,
public TabStripModelObserver {
public:
// Forward declaration of resource coordinator signal observer.
......@@ -147,10 +148,6 @@ class TabManager : public LifecycleUnitObserver,
// before.
void OnDidFinishNavigation(content::NavigationHandle* navigation_handle);
// Called by TabManager::WebContentsData to notify TabManager that one tab is
// considered loaded. TabManager can decide which tab to load next.
void OnTabIsLoaded(content::WebContents* contents);
// Notifies TabManager that one tab WebContents has been destroyed. TabManager
// needs to clean up data related to that tab.
void OnWebContentsDestroyed(content::WebContents* contents);
......@@ -183,67 +180,62 @@ class TabManager : public LifecycleUnitObserver,
// non-zero only during session restore.
int restored_tab_count() const;
// Accessor for the tab load tracker. This lets interested external classes
// add themselves as observers.
TabLoadTracker& tab_load_tracker() { return tab_load_tracker_; }
const TabLoadTracker& tab_load_tracker() const { return tab_load_tracker_; }
private:
friend class TabManagerStatsCollectorTest;
friend class TabManagerWithProactiveDiscardExperimentEnabledTest;
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, PurgeBackgroundRenderer);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ActivateTabResetPurgeState);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ShouldPurgeAtDefaultTime);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, DefaultTimeToPurgeInCorrectRange);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, AutoDiscardable);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, BackgroundTabLoadingMode);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, BackgroundTabLoadingSlots);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, BackgroundTabsLoadingOrdering);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, CanOnlyDiscardOnce);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ChildProcessNotifications);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, DefaultTimeToPurgeInCorrectRange);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, EnablePageAlmostIdleSignal);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, FreezeTab);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, InvalidOrEmptyURL);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsInBackgroundTabOpeningSession);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsInternalPage);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OomPressureListener);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectPDFPages);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectRecentlyUsedTabs);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectVideoTabs);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerBasics);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerWasDiscarded);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
TabManagerWasDiscardedCrossSiteSubFrame);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsTabRestoredInForeground);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, MaybeThrottleNavigation);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnDelayedTabSelected);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnDidFinishNavigation);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnTabIsLoaded);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnWebContentsDestroyed);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OnDelayedTabSelected);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TimeoutWhenLoadingBackgroundTabs);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, BackgroundTabLoadingMode);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, BackgroundTabLoadingSlots);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, BackgroundTabsLoadingOrdering);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OomPressureListener);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, PauseAndResumeBackgroundTabOpening);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsInBackgroundTabOpeningSession);
FRIEND_TEST_ALL_PREFIXES(TabManagerWithExperimentDisabledTest,
IsInBackgroundTabOpeningSession);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
SessionRestoreBeforeBackgroundTabOpeningSession);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
SessionRestoreAfterBackgroundTabOpeningSession);
ProactiveFastShutdownSharedTabProcess);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
ProactiveFastShutdownSingleTabProcess);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, UrgentFastShutdownSingleTabProcess);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
ProactiveFastShutdownSharedTabProcess);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, UrgentFastShutdownSharedTabProcess);
ProactiveFastShutdownWithBeforeunloadHandler);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
ProactiveFastShutdownWithUnloadHandler);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, UrgentFastShutdownWithUnloadHandler);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectPDFPages);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectRecentlyUsedTabs);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectVideoTabs);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, PurgeBackgroundRenderer);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
ProactiveFastShutdownWithBeforeunloadHandler);
SessionRestoreAfterBackgroundTabOpeningSession);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
UrgentFastShutdownWithBeforeunloadHandler);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsTabRestoredInForeground);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, EnablePageAlmostIdleSignal);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, FreezeTab);
SessionRestoreBeforeBackgroundTabOpeningSession);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ShouldPurgeAtDefaultTime);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerBasics);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerWasDiscarded);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
TabManagerWasDiscardedCrossSiteSubFrame);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TimeoutWhenLoadingBackgroundTabs);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
TrackingNumberOfLoadedLifecycleUnits);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, UrgentFastShutdownSharedTabProcess);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, UrgentFastShutdownSingleTabProcess);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
UrgentFastShutdownWithBeforeunloadHandler);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, UrgentFastShutdownWithUnloadHandler);
FRIEND_TEST_ALL_PREFIXES(TabManagerWithExperimentDisabledTest,
IsInBackgroundTabOpeningSession);
FRIEND_TEST_ALL_PREFIXES(TabManagerWithProactiveDiscardExperimentEnabledTest,
GetTimeInBackgroundBeforeProactiveDiscardTest);
......@@ -317,6 +309,14 @@ class TabManager : public LifecycleUnitObserver,
content::WebContents* new_contents,
int index) override;
// TabLoadTracker::Observer implementation:
void OnStartTracking(content::WebContents* web_contents,
LoadingState loading_state) override;
void OnLoadingStateChange(content::WebContents* web_contents,
LoadingState loading_state) override;
void OnStopTracking(content::WebContents* web_contents,
LoadingState loading_state) override;
// Returns the WebContentsData associated with |contents|. Also takes care of
// creating one if needed.
static WebContentsData* GetWebContentsData(content::WebContents* contents);
......@@ -486,10 +486,6 @@ class TabManager : public LifecycleUnitObserver,
// session restore.
std::unique_ptr<TabManagerStatsCollector> stats_collector_;
// Tracks tab loads, taking into account PageAlmostIdle, NavigationThrottles
// and other complications.
TabLoadTracker tab_load_tracker_;
// Weak pointer factory used for posting delayed tasks.
base::WeakPtrFactory<TabManager> weak_ptr_factory_;
......
......@@ -12,21 +12,13 @@
namespace resource_coordinator {
namespace {
TabLoadTracker& GetTabLoadTracker() {
return g_browser_process->GetTabManager()->tab_load_tracker();
}
} // namespace
// A helper class for accessing TabLoadTracker. TabLoadTracker can't directly
// friend TabManager::ResourceCoordinatorSignalObserver as it's a nested class
// and can't be forward declared.
class TabManagerResourceCoordinatorSignalObserverHelper {
public:
static void OnPageAlmostIdle(content::WebContents* web_contents) {
GetTabLoadTracker().OnPageAlmostIdle(web_contents);
TabLoadTracker::Get()->OnPageAlmostIdle(web_contents);
}
};
......@@ -46,11 +38,6 @@ void TabManager::ResourceCoordinatorSignalObserver::OnPageAlmostIdle(
content::WebContents* web_contents) {
TabManagerResourceCoordinatorSignalObserverHelper::OnPageAlmostIdle(
web_contents);
auto* web_contents_data =
TabManager::WebContentsData::FromWebContents(web_contents);
if (!web_contents_data)
return;
web_contents_data->NotifyTabIsLoaded();
}
void TabManager::ResourceCoordinatorSignalObserver::
......
......@@ -170,19 +170,19 @@ void TabManagerStatsCollector::RecordSwitchToTab(
if (is_session_restore_loading_tabs_) {
UMA_HISTOGRAM_ENUMERATION(kHistogramSessionRestoreSwitchToTab,
new_data->tab_loading_state(),
TAB_LOADING_STATE_MAX);
TabLoadTracker::LOADING_STATE_MAX);
}
if (is_in_background_tab_opening_session_) {
UMA_HISTOGRAM_ENUMERATION(kHistogramBackgroundTabOpeningSwitchToTab,
new_data->tab_loading_state(),
TAB_LOADING_STATE_MAX);
TabLoadTracker::LOADING_STATE_MAX);
}
if (old_contents)
foreground_contents_switched_to_times_.erase(old_contents);
DCHECK(
!base::ContainsKey(foreground_contents_switched_to_times_, new_contents));
if (new_data->tab_loading_state() != TAB_IS_LOADED) {
if (new_data->tab_loading_state() != TabLoadTracker::LOADED) {
foreground_contents_switched_to_times_.insert(
std::make_pair(new_contents, NowTicks()));
}
......
......@@ -14,6 +14,7 @@
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h"
#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/ukm/test_ukm_recorder.h"
......@@ -30,6 +31,12 @@ using WebContents = content::WebContents;
namespace resource_coordinator {
using LoadingState = TabLoadTracker::LoadingState;
constexpr TabLoadTracker::LoadingState UNLOADED = TabLoadTracker::UNLOADED;
constexpr TabLoadTracker::LoadingState LOADING = TabLoadTracker::LOADING;
constexpr TabLoadTracker::LoadingState LOADED = TabLoadTracker::LOADED;
class TabManagerStatsCollectorTest : public ChromeRenderViewHostTestHarness {
protected:
TabManagerStatsCollectorTest() = default;
......@@ -120,11 +127,11 @@ class TabManagerStatsCollectorTabSwitchTest
TabManagerStatsCollectorTabSwitchTest() = default;
~TabManagerStatsCollectorTabSwitchTest() override = default;
void SetForegroundTabLoadingState(TabLoadingState state) {
void SetForegroundTabLoadingState(LoadingState state) {
GetWebContentsData(foreground_tab_)->SetTabLoadingState(state);
}
void SetBackgroundTabLoadingState(TabLoadingState state) {
void SetBackgroundTabLoadingState(LoadingState state) {
GetWebContentsData(background_tab_)->SetTabLoadingState(state);
}
......@@ -139,12 +146,12 @@ class TabManagerStatsCollectorTabSwitchTest
}
void FinishLoadingForegroundTab() {
SetForegroundTabLoadingState(TAB_IS_LOADED);
SetForegroundTabLoadingState(LOADED);
tab_manager_stats_collector()->OnTabIsLoaded(foreground_tab_);
}
void FinishLoadingBackgroundTab() {
SetBackgroundTabLoadingState(TAB_IS_LOADED);
SetBackgroundTabLoadingState(LOADED);
tab_manager_stats_collector()->OnTabIsLoaded(background_tab_);
}
......@@ -184,39 +191,36 @@ TEST_P(TabManagerStatsCollectorTabSwitchTest, HistogramsSwitchToTab) {
if (should_test_background_tab_opening_)
StartBackgroundTabOpeningSession();
SetBackgroundTabLoadingState(TAB_IS_NOT_LOADING);
SetForegroundTabLoadingState(TAB_IS_NOT_LOADING);
SetBackgroundTabLoadingState(UNLOADED);
SetForegroundTabLoadingState(UNLOADED);
SwitchToBackgroundTab();
SwitchToBackgroundTab();
for (const auto& param : histogram_parameters) {
if (param.enabled && !IsTestingOverlappedSession()) {
histogram_tester_.ExpectTotalCount(param.histogram_name, 2);
histogram_tester_.ExpectBucketCount(param.histogram_name,
TAB_IS_NOT_LOADING, 2);
histogram_tester_.ExpectBucketCount(param.histogram_name, UNLOADED, 2);
} else {
histogram_tester_.ExpectTotalCount(param.histogram_name, 0);
}
}
SetBackgroundTabLoadingState(TAB_IS_LOADING);
SetForegroundTabLoadingState(TAB_IS_LOADING);
SetBackgroundTabLoadingState(LOADING);
SetForegroundTabLoadingState(LOADING);
SwitchToBackgroundTab();
SwitchToBackgroundTab();
SwitchToBackgroundTab();
for (const auto& param : histogram_parameters) {
if (param.enabled && !IsTestingOverlappedSession()) {
histogram_tester_.ExpectTotalCount(param.histogram_name, 5);
histogram_tester_.ExpectBucketCount(param.histogram_name,
TAB_IS_NOT_LOADING, 2);
histogram_tester_.ExpectBucketCount(param.histogram_name, TAB_IS_LOADING,
3);
histogram_tester_.ExpectBucketCount(param.histogram_name, UNLOADED, 2);
histogram_tester_.ExpectBucketCount(param.histogram_name, LOADING, 3);
} else {
histogram_tester_.ExpectTotalCount(param.histogram_name, 0);
}
}
SetBackgroundTabLoadingState(TAB_IS_LOADED);
SetForegroundTabLoadingState(TAB_IS_LOADED);
SetBackgroundTabLoadingState(LOADED);
SetForegroundTabLoadingState(LOADED);
SwitchToBackgroundTab();
SwitchToBackgroundTab();
SwitchToBackgroundTab();
......@@ -224,12 +228,9 @@ TEST_P(TabManagerStatsCollectorTabSwitchTest, HistogramsSwitchToTab) {
for (const auto& param : histogram_parameters) {
if (param.enabled && !IsTestingOverlappedSession()) {
histogram_tester_.ExpectTotalCount(param.histogram_name, 9);
histogram_tester_.ExpectBucketCount(param.histogram_name,
TAB_IS_NOT_LOADING, 2);
histogram_tester_.ExpectBucketCount(param.histogram_name, TAB_IS_LOADING,
3);
histogram_tester_.ExpectBucketCount(param.histogram_name, TAB_IS_LOADED,
4);
histogram_tester_.ExpectBucketCount(param.histogram_name, UNLOADED, 2);
histogram_tester_.ExpectBucketCount(param.histogram_name, LOADING, 3);
histogram_tester_.ExpectBucketCount(param.histogram_name, LOADED, 4);
} else {
histogram_tester_.ExpectTotalCount(param.histogram_name, 0);
}
......@@ -246,8 +247,8 @@ TEST_P(TabManagerStatsCollectorTabSwitchTest, HistogramsTabSwitchLoadTime) {
if (should_test_background_tab_opening_)
StartBackgroundTabOpeningSession();
SetBackgroundTabLoadingState(TAB_IS_NOT_LOADING);
SetForegroundTabLoadingState(TAB_IS_LOADED);
SetBackgroundTabLoadingState(UNLOADED);
SetForegroundTabLoadingState(LOADED);
SwitchToBackgroundTab();
FinishLoadingForegroundTab();
histogram_tester_.ExpectTotalCount(
......@@ -258,7 +259,7 @@ TEST_P(TabManagerStatsCollectorTabSwitchTest, HistogramsTabSwitchLoadTime) {
should_test_background_tab_opening_ && !IsTestingOverlappedSession() ? 1
: 0);
SetBackgroundTabLoadingState(TAB_IS_LOADING);
SetBackgroundTabLoadingState(LOADING);
SwitchToBackgroundTab();
FinishLoadingForegroundTab();
histogram_tester_.ExpectTotalCount(
......@@ -271,8 +272,8 @@ TEST_P(TabManagerStatsCollectorTabSwitchTest, HistogramsTabSwitchLoadTime) {
// Metrics aren't recorded when the foreground tab has not finished loading
// and the user switches to a different tab.
SetBackgroundTabLoadingState(TAB_IS_LOADING);
SetForegroundTabLoadingState(TAB_IS_LOADED);
SetBackgroundTabLoadingState(UNLOADED);
SetForegroundTabLoadingState(LOADED);
SwitchToBackgroundTab();
// Foreground tab is currently loading and being tracked.
SwitchToBackgroundTab();
......@@ -294,8 +295,8 @@ TEST_P(TabManagerStatsCollectorTabSwitchTest, HistogramsTabSwitchLoadTime) {
if (should_test_background_tab_opening_)
FinishBackgroundTabOpeningSession();
SetBackgroundTabLoadingState(TAB_IS_NOT_LOADING);
SetForegroundTabLoadingState(TAB_IS_LOADED);
SetBackgroundTabLoadingState(UNLOADED);
SetForegroundTabLoadingState(LOADED);
SwitchToBackgroundTab();
FinishLoadingForegroundTab();
histogram_tester_.ExpectTotalCount(
......
......@@ -29,12 +29,6 @@ TabManager::WebContentsData::WebContentsData(content::WebContents* web_contents)
TabManager::WebContentsData::~WebContentsData() {}
void TabManager::WebContentsData::DidStopLoading() {
if (IsPageAlmostIdleSignalEnabled())
return;
NotifyTabIsLoaded();
}
void TabManager::WebContentsData::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
// Only change to the loading state if there is a navigation in the main
......@@ -45,7 +39,6 @@ void TabManager::WebContentsData::DidStartNavigation(
return;
}
SetTabLoadingState(TAB_IS_LOADING);
g_browser_process->GetTabManager()
->stats_collector()
->OnDidStartMainFrameNavigation(web_contents());
......@@ -61,21 +54,10 @@ void TabManager::WebContentsData::WebContentsDestroyed() {
// If Chrome is shutting down, ignore this event.
if (g_browser_process->IsShuttingDown())
return;
SetTabLoadingState(TAB_IS_NOT_LOADING);
SetIsInSessionRestore(false);
g_browser_process->GetTabManager()->OnWebContentsDestroyed(web_contents());
}
void TabManager::WebContentsData::NotifyTabIsLoaded() {
// We may already be in the stopped state if this is being invoked due to an
// iframe loading new content.
if (tab_data_.tab_loading_state != TAB_IS_LOADED) {
SetTabLoadingState(TAB_IS_LOADED);
g_browser_process->GetTabManager()->OnTabIsLoaded(web_contents());
}
}
TimeTicks TabManager::WebContentsData::LastInactiveTime() {
return tab_data_.last_inactive_time;
}
......@@ -97,7 +79,7 @@ void TabManager::WebContentsData::CopyState(
}
TabManager::WebContentsData::Data::Data()
: tab_loading_state(TAB_IS_NOT_LOADING),
: tab_loading_state(TabLoadTracker::UNLOADED),
is_in_session_restore(false),
is_restored_in_foreground(false) {}
......
......@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "base/time/time.h"
#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
#include "chrome/browser/resource_coordinator/tab_manager.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents_observer.h"
......@@ -18,27 +19,6 @@ class WebContents;
namespace resource_coordinator {
// Tabs (WebContentsData) start in the not loading state, and transition to the
// loading state when a navigation begins in the main frame of the associated
// WebContents. The state changes to loaded when we receive the DidStopLoading*
// signal. The state can change from loaded to loading if another navigation
// occurs in the main frame, which happens if the user navigates to a new page
// and the WebContents is reused.
//
// These values are used in the TabManager.SessionRestore.SwitchToTab UMA.
//
// These values are written to logs. New enum values can be added, but existing
// enums must never be renumbered or deleted and reused.
enum TabLoadingState {
TAB_IS_NOT_LOADING = 0,
TAB_IS_LOADING = 1,
// A tab is considered loaded when DidStopLoading is called from WebContents
// for now. We are in the progress to deprecate using it, and use
// PageAlmostIdle signal from resource coordinator instead.
TAB_IS_LOADED = 2,
TAB_LOADING_STATE_MAX,
};
// Internal class used by TabManager to record the needed data for
// WebContentses.
// TODO(michaelpg): Merge implementation into
......@@ -47,21 +27,18 @@ class TabManager::WebContentsData
: public content::WebContentsObserver,
public content::WebContentsUserData<TabManager::WebContentsData> {
public:
using LoadingState = resource_coordinator::TabLoadTracker::LoadingState;
explicit WebContentsData(content::WebContents* web_contents);
~WebContentsData() override;
// WebContentsObserver implementation:
void DidStopLoading() override;
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
void WebContentsDestroyed() override;
// Called by TabManager::ResourceCoordinatorSignalObserver to notify that a
// tab is considered loaded.
void NotifyTabIsLoaded();
// Returns the timestamp of the last time the tab changed became inactive.
base::TimeTicks LastInactiveTime();
......@@ -91,14 +68,12 @@ class TabManager::WebContentsData
base::TimeDelta time_to_purge() const { return time_to_purge_; }
// Sets the tab loading state.
void SetTabLoadingState(TabLoadingState state) {
void SetTabLoadingState(LoadingState state) {
tab_data_.tab_loading_state = state;
}
// Returns the TabLoadingState of the tab.
TabLoadingState tab_loading_state() const {
return tab_data_.tab_loading_state;
}
// Returns the loading state of the tab.
LoadingState tab_loading_state() const { return tab_data_.tab_loading_state; }
void SetIsInSessionRestore(bool is_in_session_restore) {
tab_data_.is_in_session_restore = is_in_session_restore;
......@@ -127,7 +102,7 @@ class TabManager::WebContentsData
// The last time the tab switched from being active to inactive.
base::TimeTicks last_inactive_time;
// Current loading state of this tab.
TabLoadingState tab_loading_state;
LoadingState tab_loading_state;
// True if the tab was created by session restore. Remains true until the
// end of the first navigation or the tab is closed.
bool is_in_session_restore;
......
......@@ -20,6 +20,10 @@ using content::WebContentsTester;
namespace resource_coordinator {
namespace {
constexpr TabLoadTracker::LoadingState UNLOADED = TabLoadTracker::UNLOADED;
constexpr TabLoadTracker::LoadingState LOADING = TabLoadTracker::LOADING;
constexpr TabLoadTracker::LoadingState LOADED = TabLoadTracker::LOADED;
class TabManagerWebContentsDataTest : public ChromeRenderViewHostTestHarness {
public:
TabManagerWebContentsDataTest()
......@@ -70,17 +74,17 @@ TEST_F(TabManagerWebContentsDataTest, LastInactiveTime) {
}
TEST_F(TabManagerWebContentsDataTest, TabLoadingState) {
EXPECT_EQ(TAB_IS_NOT_LOADING, tab_data()->tab_loading_state());
tab_data()->SetTabLoadingState(TAB_IS_LOADING);
EXPECT_EQ(TAB_IS_LOADING, tab_data()->tab_loading_state());
tab_data()->SetTabLoadingState(TAB_IS_LOADED);
EXPECT_EQ(TAB_IS_LOADED, tab_data()->tab_loading_state());
EXPECT_EQ(UNLOADED, tab_data()->tab_loading_state());
tab_data()->SetTabLoadingState(LOADING);
EXPECT_EQ(LOADING, tab_data()->tab_loading_state());
tab_data()->SetTabLoadingState(LOADED);
EXPECT_EQ(LOADED, tab_data()->tab_loading_state());
}
TEST_F(TabManagerWebContentsDataTest, CopyState) {
tab_data()->SetLastInactiveTime(base::TimeTicks() +
base::TimeDelta::FromSeconds(42));
tab_data()->SetTabLoadingState(TAB_IS_LOADED);
tab_data()->SetTabLoadingState(LOADED);
tab_data()->SetIsInSessionRestore(true);
tab_data()->SetIsRestoredInForeground(true);
......
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