| Index: chrome/browser/sessions/session_restore_stats_collector.h
|
| diff --git a/chrome/browser/sessions/session_restore_stats_collector.h b/chrome/browser/sessions/session_restore_stats_collector.h
|
| index 668e2c01b77a52e1a1ed57ea4017da9d870f44fd..48da96e1da8fac0f53d66e9a2256828da0fb15e1 100644
|
| --- a/chrome/browser/sessions/session_restore_stats_collector.h
|
| +++ b/chrome/browser/sessions/session_restore_stats_collector.h
|
| @@ -5,9 +5,10 @@
|
| #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_
|
| #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_
|
|
|
| -#include <set>
|
| +#include <map>
|
|
|
| #include "base/callback_list.h"
|
| +#include "base/time/tick_clock.h"
|
| #include "chrome/browser/sessions/session_restore.h"
|
| #include "chrome/browser/sessions/session_restore_delegate.h"
|
| #include "content/public/browser/notification_observer.h"
|
| @@ -20,83 +21,252 @@ class NavigationController;
|
|
|
| // SessionRestoreStatsCollector observes SessionRestore events ands records UMA
|
| // accordingly.
|
| +//
|
| +// A SessionRestoreStatsCollector is tied to an instance of a session restore,
|
| +// currently being instantianted and owned by the TabLoader. It has two main
|
| +// phases to its life:
|
| +//
|
| +// 1. The session restore is active and ongoing (the TabLoader is still
|
| +// scheduling tabs for loading). This phases ends when there are no
|
| +// non-deferred tabs left to be loaded. During this phases statistics are
|
| +// gathered in a structure before being emitted as UMA metrics at the end of
|
| +// this phase. At this point the TabLoader ceases to exist and destroys it's
|
| +// reference to the SessionRestoreStatsCollector.
|
| +// 2. If any tabs have been deferred the SessionRestoreStatsCollector continues
|
| +// tracking deferred tabs. This continues to observe the tabs to see which
|
| +// (if any) of the deferred tabs are subsequently forced to be loaded by the
|
| +// user. Since such tabs may exist until the end of the browsers life the
|
| +// statistics are emitted immediately, or risk being lost entirely. When
|
| +// there are no longer deferred tabs to track the
|
| +// SessionRestoreStatsCollector will destroy itself.
|
| +//
|
| +// TODO(chrisha): Many of these metrics don't make sense to collect in the
|
| +// presence of an unavailable network, or when tabs are closed during loading.
|
| +// Rethink the collection in these cases.
|
| class SessionRestoreStatsCollector
|
| : public content::NotificationObserver,
|
| public base::RefCounted<SessionRestoreStatsCollector> {
|
| public:
|
| - // Called to start tracking tabs. If a restore is already occuring, the tabs
|
| - // are added to the existing list of tracked tabs.
|
| - static void TrackTabs(
|
| - const std::vector<SessionRestoreDelegate::RestoredTab>& tabs,
|
| - const base::TimeTicks& restore_started);
|
| -
|
| - // Called to start tracking only active tabs. If a restore is already
|
| - // occuring, the tabs are added to the existing list of tracked tabs.
|
| - static void TrackActiveTabs(
|
| - const std::vector<SessionRestoreDelegate::RestoredTab>& tabs,
|
| - const base::TimeTicks& restore_started);
|
| + // Houses all of the statistics gathered by the SessionRestoreStatsCollector
|
| + // while the underlying TabLoader is active. These statistics are all reported
|
| + // at once via the reporting delegate.
|
| + struct TabLoaderStats {
|
| + // Constructor that initializes everything to zero.
|
| + TabLoaderStats();
|
| +
|
| + // The number of tabs involved in all overlapping session restores being
|
| + // tracked by this SessionRestoreStatsCollector. This corresponds to the
|
| + // "SessionRestore.TabCount" metric and one bucket of the
|
| + // "SessionRestore.TabActions" histogram.
|
| + size_t tab_count;
|
| +
|
| + // The number of tabs loaded automatically because they are active, and
|
| + // explicitly caused to be loaded by the TabLoader. This corresponds to one
|
| + // bucket of the "SessionRestore.TabActions" histogram.
|
| + size_t tabs_loaded;
|
| +
|
| + // The time elapsed between |restore_started| and reception of the first
|
| + // NOTIFICATION_LOAD_STOP event for any of the active tabs involved in the
|
| + // session restore. If this is zero it is because it has not been
|
| + // recorded (all visible tabs were closed before they finished loading, or
|
| + // the user switched to an already loaded tab before a visible session
|
| + // restore tab finished loading). Corresponds to
|
| + // "SessionRestore.ForegroundTabFirstLoaded" and its _XX variants.
|
| + base::TimeDelta foreground_tab_first_loaded;
|
| +
|
| + // The time elapsed between |restore_started| and reception of the first
|
| + // NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE event for any of
|
| + // the tabs involved in the session restore. If this is zero it is because
|
| + // it has not been recorded (all visible tabs were closed or switched away
|
| + // from before they were painted). Corresponds to
|
| + // "SessionRestore.ForegroundTabFirstPaint3" and its _XX variants.
|
| + base::TimeDelta foreground_tab_first_paint;
|
| +
|
| + // The time taken for all non-deferred tabs to be loaded. This corresponds
|
| + // to the "SessionRestore.AllTabsLoaded" metric and its _XX variants
|
| + // (vaguely named for historical reasons, as it predates the concept of
|
| + // deferred tabs).
|
| + base::TimeDelta non_deferred_tabs_loaded;
|
| +
|
| + // The maximum number of tabs loading in parallel. This corresponds to the
|
| + // "SessionRestore.ParallelTabLoads" metric.
|
| + size_t parallel_tab_loads;
|
| + };
|
| +
|
| + // The StatsReportingDelegate is responsible for delivering statistics
|
| + // reported by the SessionRestoreStatsCollector.
|
| + class StatsReportingDelegate;
|
| +
|
| + // An implementation of StatsReportingDelegate for reporting via UMA.
|
| + class UmaStatsReportingDelegate;
|
| +
|
| + // Constructs a SessionRestoreStatsCollector.
|
| + SessionRestoreStatsCollector(
|
| + const base::TimeTicks& restore_started,
|
| + scoped_ptr<StatsReportingDelegate> reporting_delegate);
|
| +
|
| + // Adds new tabs to the list of tracked tabs.
|
| + void TrackTabs(const std::vector<SessionRestoreDelegate::RestoredTab>& tabs);
|
| +
|
| + // Called to indicate that the loading of a tab has been deferred by session
|
| + // restore.
|
| + void DeferTab(content::NavigationController* tab);
|
| +
|
| + // Exposed for unittesting.
|
| + const TabLoaderStats& tab_loader_stats() const { return tab_loader_stats_; }
|
|
|
| private:
|
| + friend class TestSessionRestoreStatsCollector;
|
| friend class base::RefCounted<SessionRestoreStatsCollector>;
|
|
|
| - using RenderWidgetHostSet = std::set<content::RenderWidgetHost*>;
|
| + enum TabLoadingState { TAB_IS_NOT_LOADING, TAB_IS_LOADING, TAB_IS_LOADED };
|
| +
|
| + // State that is tracked for a tab while it is being observed.
|
| + struct TabState {
|
| + explicit TabState(content::NavigationController* controller);
|
| +
|
| + // The NavigationController associated with the tab. This is the primary
|
| + // index for it and is never null.
|
| + content::NavigationController* controller;
|
| +
|
| + // The RenderWidgetHost associated with the tab. This is the secondary
|
| + // index and starts out being null. If it is not null it is because the tab
|
| + // is actively loading or waiting to be painted.
|
| + content::RenderWidgetHost* render_widget_host;
|
| +
|
| + // Set to true if the tab has been deferred by the TabLoader.
|
| + bool is_deferred;
|
| +
|
| + // The current loading state of the tab.
|
| + TabLoadingState loading_state;
|
| + };
|
| +
|
| + // Maps a NavigationController to its state. This is the primary map and
|
| + // physically houses the state.
|
| + using NavigationControllerMap =
|
| + std::map<content::NavigationController*, TabState>;
|
|
|
| - explicit SessionRestoreStatsCollector(const base::TimeTicks& restore_started);
|
| ~SessionRestoreStatsCollector() override;
|
|
|
| - // NotificationObserver method.
|
| + // NotificationObserver method. This is the workhorse of the class and drives
|
| + // all state transitions.
|
| void Observe(int type,
|
| const content::NotificationSource& source,
|
| const content::NotificationDetails& details) override;
|
|
|
| - // Adds new tabs to the list of tracked tabs.
|
| - void AddTabs(const std::vector<SessionRestoreDelegate::RestoredTab>& tabs);
|
| -
|
| - // Called when a tab is no longer tracked.
|
| + // Called when a tab is no longer tracked. This is called by the 'Observe'
|
| + // notification callback. Takes care of unregistering all observers and
|
| + // removing the tab from all internal data structures.
|
| void RemoveTab(content::NavigationController* tab);
|
|
|
| - // Registers for relevant notifications for a tab.
|
| - void RegisterForNotifications(content::NavigationController* tab);
|
| + // Registers for relevant notifications for a tab and inserts the tab into
|
| + // to tabs_tracked_ map. Return a pointer to the newly created TabState.
|
| + TabState* RegisterForNotifications(content::NavigationController* tab);
|
|
|
| // Returns the RenderWidgetHost of a tab.
|
| content::RenderWidgetHost* GetRenderWidgetHost(
|
| content::NavigationController* tab);
|
|
|
| - // Have we recorded the times for a foreground tab load?
|
| + // Returns the tab state, nullptr if not found.
|
| + TabState* GetTabState(content::NavigationController* tab);
|
| + TabState* GetTabState(content::RenderWidgetHost* tab);
|
| +
|
| + // Marks a tab as loading.
|
| + void MarkTabAsLoading(TabState* tab_state);
|
| +
|
| + // Checks to see if the SessionRestoreStatsCollector has finished collecting,
|
| + // and if so, releases the self reference to the shared pointer.
|
| + void ReleaseIfDoneTracking();
|
| +
|
| + // Testing seam for configuring the tick clock in use.
|
| + void set_tick_clock(scoped_ptr<base::TickClock> tick_clock) {
|
| + tick_clock_ = tick_clock.Pass();
|
| + }
|
| +
|
| + // Has ReleaseIfDoneTracking determined that there are no non-deferred tabs to
|
| + // track?
|
| + bool done_tracking_non_deferred_tabs_;
|
| +
|
| + // Has the time for foreground tab load been recorded?
|
| bool got_first_foreground_load_;
|
|
|
| - // Have we recorded the times for a foreground tab paint?
|
| + // Has the time for foreground tab paint been recorded?
|
| bool got_first_paint_;
|
|
|
| // The time the restore process started.
|
| - base::TimeTicks restore_started_;
|
| + const base::TimeTicks restore_started_;
|
|
|
| - // The renderers we have started loading into.
|
| - RenderWidgetHostSet render_widget_hosts_loading_;
|
| + // List of tracked tabs, mapped to their TabState.
|
| + NavigationControllerMap tabs_tracked_;
|
|
|
| - // The renderers we have loaded and are waiting on to paint.
|
| - RenderWidgetHostSet render_widget_hosts_to_paint_;
|
| + // Counts the number of non-deferred tabs that the
|
| + // SessionRestoreStatsCollector is waiting to see load.
|
| + size_t waiting_for_load_tab_count_;
|
|
|
| - // List of tracked tabs.
|
| - std::set<content::NavigationController*> tabs_tracked_;
|
| + // Counts the current number of actively loading tabs.
|
| + size_t loading_tab_count_;
|
|
|
| - // The number of tabs that have been restored.
|
| - int tab_count_;
|
| -
|
| - // Max number of tabs that were loaded in parallel (for metrics).
|
| - size_t max_parallel_tab_loads_;
|
| + // Counts the number of deferred tabs.
|
| + size_t deferred_tab_count_;
|
|
|
| // Notification registrar.
|
| content::NotificationRegistrar registrar_;
|
|
|
| - // To keep the collector alive as long as needed.
|
| - scoped_refptr<SessionRestoreStatsCollector> this_retainer_;
|
| + // Statistics gathered regarding the TabLoader.
|
| + TabLoaderStats tab_loader_stats_;
|
| +
|
| + // The source of ticks used for taking timing information. This is
|
| + // configurable as a testing seam. Defaults to using base::DefaultTickClock,
|
| + // which in turn uses base::TimeTicks.
|
| + scoped_ptr<base::TickClock> tick_clock_;
|
|
|
| - // The shared SessionRestoreNotifier instance for all SessionRestores running
|
| - // at this time.
|
| - static SessionRestoreStatsCollector* shared_collector_;
|
| + // The reporting delegate used to report gathered statistics.
|
| + scoped_ptr<StatsReportingDelegate> reporting_delegate_;
|
| +
|
| + // For keeping SessionRestoreStatsCollector alive while it is still working
|
| + // even if no TabLoader references it. The object only lives on if it still
|
| + // has deferred tabs remaining from an interrupted session restore.
|
| + scoped_refptr<SessionRestoreStatsCollector> this_retainer_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(SessionRestoreStatsCollector);
|
| };
|
|
|
| +// An abstract reporting delegate is used as a testing seam.
|
| +class SessionRestoreStatsCollector::StatsReportingDelegate {
|
| + public:
|
| + StatsReportingDelegate() {}
|
| + virtual ~StatsReportingDelegate() {}
|
| +
|
| + // Called when TabLoader has completed its work.
|
| + virtual void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) = 0;
|
| +
|
| + // Called when a tab has been deferred.
|
| + virtual void ReportTabDeferred() = 0;
|
| +
|
| + // Called when a deferred tab has been loaded.
|
| + virtual void ReportDeferredTabLoaded() = 0;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(StatsReportingDelegate);
|
| +};
|
| +
|
| +// The default reporting delegate, which reports statistics via UMA.
|
| +class SessionRestoreStatsCollector::UmaStatsReportingDelegate
|
| + : public StatsReportingDelegate {
|
| + public:
|
| + UmaStatsReportingDelegate();
|
| + ~UmaStatsReportingDelegate() override {}
|
| +
|
| + // StatsReportingDelegate:
|
| + void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) override;
|
| + void ReportTabDeferred() override;
|
| + void ReportDeferredTabLoaded() override;
|
| +
|
| + private:
|
| + // Has ReportTabDeferred been called?
|
| + bool got_report_tab_deferred_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(UmaStatsReportingDelegate);
|
| +};
|
| +
|
| #endif // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_
|
|
|