1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_
6 #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_
10 #include "base/callback_list.h"
11 #include "base/time/tick_clock.h"
12 #include "chrome/browser/sessions/session_restore.h"
13 #include "chrome/browser/sessions/session_restore_delegate.h"
14 #include "content/public/browser/notification_observer.h"
15 #include "content/public/browser/notification_registrar.h"
18 class NavigationController
;
19 class RenderWidgetHost
;
22 // SessionRestoreStatsCollector observes SessionRestore events ands records UMA
25 // A SessionRestoreStatsCollector is tied to an instance of a session restore,
26 // currently being instantianted and owned by the TabLoader. It has two main
27 // phases to its life:
29 // 1. The session restore is active and ongoing (the TabLoader is still
30 // scheduling tabs for loading). This phases ends when there are no
31 // non-deferred tabs left to be loaded. During this phases statistics are
32 // gathered in a structure before being emitted as UMA metrics at the end of
33 // this phase. At this point the TabLoader ceases to exist and destroys it's
34 // reference to the SessionRestoreStatsCollector.
35 // 2. If any tabs have been deferred the SessionRestoreStatsCollector continues
36 // tracking deferred tabs. This continues to observe the tabs to see which
37 // (if any) of the deferred tabs are subsequently forced to be loaded by the
38 // user. Since such tabs may exist until the end of the browsers life the
39 // statistics are emitted immediately, or risk being lost entirely. When
40 // there are no longer deferred tabs to track the
41 // SessionRestoreStatsCollector will destroy itself.
43 // TODO(chrisha): Many of these metrics don't make sense to collect in the
44 // presence of an unavailable network, or when tabs are closed during loading.
45 // Rethink the collection in these cases.
46 class SessionRestoreStatsCollector
47 : public content::NotificationObserver
,
48 public base::RefCounted
<SessionRestoreStatsCollector
> {
50 // Houses all of the statistics gathered by the SessionRestoreStatsCollector
51 // while the underlying TabLoader is active. These statistics are all reported
52 // at once via the reporting delegate.
53 struct TabLoaderStats
{
54 // Constructor that initializes everything to zero.
57 // The number of tabs involved in all overlapping session restores being
58 // tracked by this SessionRestoreStatsCollector. This corresponds to the
59 // "SessionRestore.TabCount" metric and one bucket of the
60 // "SessionRestore.TabActions" histogram. If any tabs were deferred it also
61 // corresponds to the "SessionRestore.TabCount.MemoryPressure.Total"
65 // The number of restored tabs that were deferred. Corresponds to the
66 // "SessionRestore.TabCount.MemoryPressure.Deferred" histogram.
69 // The number of tabs whose loading was automatically started because they
70 // are active or explicitly caused to be loaded by the TabLoader. This
71 // corresponds to one bucket of the "SessionRestore.TabActions" histogram
72 // and the "SessionRestore.TabCount.MemoryPressure.LoadStarted".
73 size_t tabs_load_started
;
75 // The number of tabs loaded automatically because they are active, or
76 // explicitly caused to be loaded by the TabLoader. This corresponds to one
77 // bucket of the "SessionRestore.TabActions" histogram, and the
78 // "SessionRestore.TabCount.MemoryPressure.Loaded" histogram.
81 // The time elapsed between |restore_started| and reception of the first
82 // NOTIFICATION_LOAD_STOP event for any of the active tabs involved in the
83 // session restore. If this is zero it is because it has not been
84 // recorded (all visible tabs were closed before they finished loading, or
85 // the user switched to an already loaded tab before a visible session
86 // restore tab finished loading). Corresponds to
87 // "SessionRestore.ForegroundTabFirstLoaded" and its _XX variants.
88 base::TimeDelta foreground_tab_first_loaded
;
90 // The time elapsed between |restore_started| and reception of the first
91 // NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE event for any of
92 // the tabs involved in the session restore. If this is zero it is because
93 // it has not been recorded (all visible tabs were closed or switched away
94 // from before they were painted). Corresponds to
95 // "SessionRestore.ForegroundTabFirstPaint3" and its _XX variants.
96 base::TimeDelta foreground_tab_first_paint
;
98 // The time taken for all non-deferred tabs to be loaded. This corresponds
99 // to the "SessionRestore.AllTabsLoaded" metric and its _XX variants
100 // (vaguely named for historical reasons, as it predates the concept of
102 base::TimeDelta non_deferred_tabs_loaded
;
104 // The maximum number of tabs loading in parallel. This corresponds to the
105 // "SessionRestore.ParallelTabLoads" metric.
106 size_t parallel_tab_loads
;
109 // The StatsReportingDelegate is responsible for delivering statistics
110 // reported by the SessionRestoreStatsCollector.
111 class StatsReportingDelegate
;
113 // An implementation of StatsReportingDelegate for reporting via UMA.
114 class UmaStatsReportingDelegate
;
116 // Constructs a SessionRestoreStatsCollector.
117 SessionRestoreStatsCollector(
118 const base::TimeTicks
& restore_started
,
119 scoped_ptr
<StatsReportingDelegate
> reporting_delegate
);
121 // Adds new tabs to the list of tracked tabs.
122 void TrackTabs(const std::vector
<SessionRestoreDelegate::RestoredTab
>& tabs
);
124 // Called to indicate that the loading of a tab has been deferred by session
126 void DeferTab(content::NavigationController
* tab
);
128 // Exposed for unittesting.
129 const TabLoaderStats
& tab_loader_stats() const { return tab_loader_stats_
; }
132 friend class TestSessionRestoreStatsCollector
;
133 friend class base::RefCounted
<SessionRestoreStatsCollector
>;
135 enum TabLoadingState
{ TAB_IS_NOT_LOADING
, TAB_IS_LOADING
, TAB_IS_LOADED
};
137 // State that is tracked for a tab while it is being observed.
139 explicit TabState(content::NavigationController
* controller
);
141 // The NavigationController associated with the tab. This is the primary
142 // index for it and is never null.
143 content::NavigationController
* controller
;
145 // Set to true if the tab has been deferred by the TabLoader.
148 // The current loading state of the tab.
149 TabLoadingState loading_state
;
152 // Maps a NavigationController to its state. This is the primary map and
153 // physically houses the state.
154 using NavigationControllerMap
=
155 std::map
<content::NavigationController
*, TabState
>;
157 ~SessionRestoreStatsCollector() override
;
159 // NotificationObserver method. This is the workhorse of the class and drives
160 // all state transitions.
161 void Observe(int type
,
162 const content::NotificationSource
& source
,
163 const content::NotificationDetails
& details
) override
;
165 // Called when a tab is no longer tracked. This is called by the 'Observe'
166 // notification callback. Takes care of unregistering all observers and
167 // removing the tab from all internal data structures.
168 void RemoveTab(content::NavigationController
* tab
);
170 // Registers for relevant notifications for a tab and inserts the tab into
171 // to tabs_tracked_ map. Return a pointer to the newly created TabState.
172 TabState
* RegisterForNotifications(content::NavigationController
* tab
);
174 // Returns the tab state, nullptr if not found.
175 TabState
* GetTabState(content::NavigationController
* tab
);
176 TabState
* GetTabState(content::RenderWidgetHost
* tab
);
178 // Marks a tab as loading.
179 void MarkTabAsLoading(TabState
* tab_state
);
181 // Checks to see if the SessionRestoreStatsCollector has finished collecting,
182 // and if so, releases the self reference to the shared pointer.
183 void ReleaseIfDoneTracking();
185 // Testing seam for configuring the tick clock in use.
186 void set_tick_clock(scoped_ptr
<base::TickClock
> tick_clock
) {
187 tick_clock_
= tick_clock
.Pass();
190 // Has ReleaseIfDoneTracking determined that there are no non-deferred tabs to
192 bool done_tracking_non_deferred_tabs_
;
194 // Has the time for foreground tab load been recorded?
195 bool got_first_foreground_load_
;
197 // Has the time for foreground tab paint been recorded?
198 bool got_first_paint_
;
200 // The time the restore process started.
201 const base::TimeTicks restore_started_
;
203 // List of tracked tabs, mapped to their TabState.
204 NavigationControllerMap tabs_tracked_
;
206 // Counts the number of non-deferred tabs that the
207 // SessionRestoreStatsCollector is waiting to see load.
208 size_t waiting_for_load_tab_count_
;
210 // Counts the current number of actively loading tabs.
211 size_t loading_tab_count_
;
213 // Counts the current number of deferred tabs.
214 size_t deferred_tab_count_
;
216 // Notification registrar.
217 content::NotificationRegistrar registrar_
;
219 // Statistics gathered regarding the TabLoader.
220 TabLoaderStats tab_loader_stats_
;
222 // The source of ticks used for taking timing information. This is
223 // configurable as a testing seam. Defaults to using base::DefaultTickClock,
224 // which in turn uses base::TimeTicks.
225 scoped_ptr
<base::TickClock
> tick_clock_
;
227 // The reporting delegate used to report gathered statistics.
228 scoped_ptr
<StatsReportingDelegate
> reporting_delegate_
;
230 // For keeping SessionRestoreStatsCollector alive while it is still working
231 // even if no TabLoader references it. The object only lives on if it still
232 // has deferred tabs remaining from an interrupted session restore.
233 scoped_refptr
<SessionRestoreStatsCollector
> this_retainer_
;
235 DISALLOW_COPY_AND_ASSIGN(SessionRestoreStatsCollector
);
238 // An abstract reporting delegate is used as a testing seam.
239 class SessionRestoreStatsCollector::StatsReportingDelegate
{
241 StatsReportingDelegate() {}
242 virtual ~StatsReportingDelegate() {}
244 // Called when TabLoader has completed its work.
245 virtual void ReportTabLoaderStats(const TabLoaderStats
& tab_loader_stats
) = 0;
247 // Called when a tab has been deferred.
248 virtual void ReportTabDeferred() = 0;
250 // Called when a deferred tab has been loaded.
251 virtual void ReportDeferredTabLoaded() = 0;
254 DISALLOW_COPY_AND_ASSIGN(StatsReportingDelegate
);
257 // The default reporting delegate, which reports statistics via UMA.
258 class SessionRestoreStatsCollector::UmaStatsReportingDelegate
259 : public StatsReportingDelegate
{
261 UmaStatsReportingDelegate();
262 ~UmaStatsReportingDelegate() override
{}
264 // StatsReportingDelegate:
265 void ReportTabLoaderStats(const TabLoaderStats
& tab_loader_stats
) override
;
266 void ReportTabDeferred() override
;
267 void ReportDeferredTabLoaded() override
;
270 // Has ReportTabDeferred been called?
271 bool got_report_tab_deferred_
;
273 DISALLOW_COPY_AND_ASSIGN(UmaStatsReportingDelegate
);
276 #endif // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_