OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ | 5 #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ |
6 #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ | 6 #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ |
7 | 7 |
8 #include <set> | 8 #include <map> |
9 | 9 |
10 #include "base/callback_list.h" | 10 #include "base/callback_list.h" |
| 11 #include "base/time/tick_clock.h" |
11 #include "chrome/browser/sessions/session_restore.h" | 12 #include "chrome/browser/sessions/session_restore.h" |
12 #include "chrome/browser/sessions/session_restore_delegate.h" | 13 #include "chrome/browser/sessions/session_restore_delegate.h" |
13 #include "content/public/browser/notification_observer.h" | 14 #include "content/public/browser/notification_observer.h" |
14 #include "content/public/browser/notification_registrar.h" | 15 #include "content/public/browser/notification_registrar.h" |
15 #include "content/public/browser/render_widget_host.h" | 16 #include "content/public/browser/render_widget_host.h" |
16 | 17 |
17 namespace content { | 18 namespace content { |
18 class NavigationController; | 19 class NavigationController; |
19 } | 20 } |
20 | 21 |
21 // SessionRestoreStatsCollector observes SessionRestore events ands records UMA | 22 // SessionRestoreStatsCollector observes SessionRestore events ands records UMA |
22 // accordingly. | 23 // accordingly. |
| 24 // |
| 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: |
| 28 // |
| 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. |
| 42 // |
| 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. |
23 class SessionRestoreStatsCollector | 46 class SessionRestoreStatsCollector |
24 : public content::NotificationObserver, | 47 : public content::NotificationObserver, |
25 public base::RefCounted<SessionRestoreStatsCollector> { | 48 public base::RefCounted<SessionRestoreStatsCollector> { |
26 public: | 49 public: |
27 // Called to start tracking tabs. If a restore is already occuring, the tabs | 50 // Houses all of the statistics gathered by the SessionRestoreStatsCollector |
28 // are added to the existing list of tracked tabs. | 51 // while the underlying TabLoader is active. These statistics are all reported |
29 static void TrackTabs( | 52 // at once via the reporting delegate. |
30 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, | 53 struct TabLoaderStats { |
31 const base::TimeTicks& restore_started); | 54 // Constructor that initializes everything to zero. |
32 | 55 TabLoaderStats(); |
33 // Called to start tracking only active tabs. If a restore is already | 56 |
34 // occuring, the tabs are added to the existing list of tracked tabs. | 57 // The number of tabs involved in all overlapping session restores being |
35 static void TrackActiveTabs( | 58 // tracked by this SessionRestoreStatsCollector. This corresponds to the |
36 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, | 59 // "SessionRestore.TabCount" metric and one bucket of the |
37 const base::TimeTicks& restore_started); | 60 // "SessionRestore.TabActions" histogram. |
| 61 size_t tab_count; |
| 62 |
| 63 // The number of tabs loaded automatically because they are active, and |
| 64 // explicitly caused to be loaded by the TabLoader. This corresponds to one |
| 65 // bucket of the "SessionRestore.TabActions" histogram. |
| 66 size_t tabs_loaded; |
| 67 |
| 68 // The time elapsed between |restore_started| and reception of the first |
| 69 // NOTIFICATION_LOAD_STOP event for any of the active tabs involved in the |
| 70 // session restore. If this is zero it is because it has not been |
| 71 // recorded (all visible tabs were closed before they finished loading, or |
| 72 // the user switched to an already loaded tab before a visible session |
| 73 // restore tab finished loading). Corresponds to |
| 74 // "SessionRestore.ForegroundTabFirstLoaded" and its _XX variants. |
| 75 base::TimeDelta foreground_tab_first_loaded; |
| 76 |
| 77 // The time elapsed between |restore_started| and reception of the first |
| 78 // NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE event for any of |
| 79 // the tabs involved in the session restore. If this is zero it is because |
| 80 // it has not been recorded (all visible tabs were closed or switched away |
| 81 // from before they were painted). Corresponds to |
| 82 // "SessionRestore.ForegroundTabFirstPaint3" and its _XX variants. |
| 83 base::TimeDelta foreground_tab_first_paint; |
| 84 |
| 85 // The time taken for all non-deferred tabs to be loaded. This corresponds |
| 86 // to the "SessionRestore.AllTabsLoaded" metric and its _XX variants |
| 87 // (vaguely named for historical reasons, as it predates the concept of |
| 88 // deferred tabs). |
| 89 base::TimeDelta non_deferred_tabs_loaded; |
| 90 |
| 91 // The maximum number of tabs loading in parallel. This corresponds to the |
| 92 // "SessionRestore.ParallelTabLoads" metric. |
| 93 size_t parallel_tab_loads; |
| 94 }; |
| 95 |
| 96 // The StatsReportingDelegate is responsible for delivering statistics |
| 97 // reported by the SessionRestoreStatsCollector. |
| 98 class StatsReportingDelegate; |
| 99 |
| 100 // An implementation of StatsReportingDelegate for reporting via UMA. |
| 101 class UmaStatsReportingDelegate; |
| 102 |
| 103 // Constructs a SessionRestoreStatsCollector. |
| 104 SessionRestoreStatsCollector( |
| 105 const base::TimeTicks& restore_started, |
| 106 scoped_ptr<StatsReportingDelegate> reporting_delegate); |
| 107 |
| 108 // Adds new tabs to the list of tracked tabs. |
| 109 void TrackTabs(const std::vector<SessionRestoreDelegate::RestoredTab>& tabs); |
| 110 |
| 111 // Called to indicate that the loading of a tab has been deferred by session |
| 112 // restore. |
| 113 void DeferTab(content::NavigationController* tab); |
| 114 |
| 115 // Exposed for unittesting. |
| 116 const TabLoaderStats& tab_loader_stats() const { return tab_loader_stats_; } |
38 | 117 |
39 private: | 118 private: |
| 119 friend class TestSessionRestoreStatsCollector; |
40 friend class base::RefCounted<SessionRestoreStatsCollector>; | 120 friend class base::RefCounted<SessionRestoreStatsCollector>; |
41 | 121 |
42 using RenderWidgetHostSet = std::set<content::RenderWidgetHost*>; | 122 enum TabLoadingState { TAB_IS_NOT_LOADING, TAB_IS_LOADING, TAB_IS_LOADED }; |
43 | 123 |
44 explicit SessionRestoreStatsCollector(const base::TimeTicks& restore_started); | 124 // State that is tracked for a tab while it is being observed. |
| 125 struct TabState { |
| 126 explicit TabState(content::NavigationController* controller); |
| 127 |
| 128 // The NavigationController associated with the tab. This is the primary |
| 129 // index for it and is never null. |
| 130 content::NavigationController* controller; |
| 131 |
| 132 // The RenderWidgetHost associated with the tab. This is the secondary |
| 133 // index and starts out being null. If it is not null it is because the tab |
| 134 // is actively loading or waiting to be painted. |
| 135 content::RenderWidgetHost* render_widget_host; |
| 136 |
| 137 // Set to true if the tab has been deferred by the TabLoader. |
| 138 bool is_deferred; |
| 139 |
| 140 // The current loading state of the tab. |
| 141 TabLoadingState loading_state; |
| 142 }; |
| 143 |
| 144 // Maps a NavigationController to its state. This is the primary map and |
| 145 // physically houses the state. |
| 146 using NavigationControllerMap = |
| 147 std::map<content::NavigationController*, TabState>; |
| 148 |
45 ~SessionRestoreStatsCollector() override; | 149 ~SessionRestoreStatsCollector() override; |
46 | 150 |
47 // NotificationObserver method. | 151 // NotificationObserver method. This is the workhorse of the class and drives |
| 152 // all state transitions. |
48 void Observe(int type, | 153 void Observe(int type, |
49 const content::NotificationSource& source, | 154 const content::NotificationSource& source, |
50 const content::NotificationDetails& details) override; | 155 const content::NotificationDetails& details) override; |
51 | 156 |
52 // Adds new tabs to the list of tracked tabs. | 157 // Called when a tab is no longer tracked. This is called by the 'Observe' |
53 void AddTabs(const std::vector<SessionRestoreDelegate::RestoredTab>& tabs); | 158 // notification callback. Takes care of unregistering all observers and |
54 | 159 // removing the tab from all internal data structures. |
55 // Called when a tab is no longer tracked. | |
56 void RemoveTab(content::NavigationController* tab); | 160 void RemoveTab(content::NavigationController* tab); |
57 | 161 |
58 // Registers for relevant notifications for a tab. | 162 // Registers for relevant notifications for a tab and inserts the tab into |
59 void RegisterForNotifications(content::NavigationController* tab); | 163 // to tabs_tracked_ map. Return a pointer to the newly created TabState. |
| 164 TabState* RegisterForNotifications(content::NavigationController* tab); |
60 | 165 |
61 // Returns the RenderWidgetHost of a tab. | 166 // Returns the RenderWidgetHost of a tab. |
62 content::RenderWidgetHost* GetRenderWidgetHost( | 167 content::RenderWidgetHost* GetRenderWidgetHost( |
63 content::NavigationController* tab); | 168 content::NavigationController* tab); |
64 | 169 |
65 // Have we recorded the times for a foreground tab load? | 170 // Returns the tab state, nullptr if not found. |
| 171 TabState* GetTabState(content::NavigationController* tab); |
| 172 TabState* GetTabState(content::RenderWidgetHost* tab); |
| 173 |
| 174 // Marks a tab as loading. |
| 175 void MarkTabAsLoading(TabState* tab_state); |
| 176 |
| 177 // Checks to see if the SessionRestoreStatsCollector has finished collecting, |
| 178 // and if so, releases the self reference to the shared pointer. |
| 179 void ReleaseIfDoneTracking(); |
| 180 |
| 181 // Testing seam for configuring the tick clock in use. |
| 182 void set_tick_clock(scoped_ptr<base::TickClock> tick_clock) { |
| 183 tick_clock_ = tick_clock.Pass(); |
| 184 } |
| 185 |
| 186 // Has ReleaseIfDoneTracking determined that there are no non-deferred tabs to |
| 187 // track? |
| 188 bool done_tracking_non_deferred_tabs_; |
| 189 |
| 190 // Has the time for foreground tab load been recorded? |
66 bool got_first_foreground_load_; | 191 bool got_first_foreground_load_; |
67 | 192 |
68 // Have we recorded the times for a foreground tab paint? | 193 // Has the time for foreground tab paint been recorded? |
69 bool got_first_paint_; | 194 bool got_first_paint_; |
70 | 195 |
71 // The time the restore process started. | 196 // The time the restore process started. |
72 base::TimeTicks restore_started_; | 197 const base::TimeTicks restore_started_; |
73 | 198 |
74 // The renderers we have started loading into. | 199 // List of tracked tabs, mapped to their TabState. |
75 RenderWidgetHostSet render_widget_hosts_loading_; | 200 NavigationControllerMap tabs_tracked_; |
76 | 201 |
77 // The renderers we have loaded and are waiting on to paint. | 202 // Counts the number of non-deferred tabs that the |
78 RenderWidgetHostSet render_widget_hosts_to_paint_; | 203 // SessionRestoreStatsCollector is waiting to see load. |
79 | 204 size_t waiting_for_load_tab_count_; |
80 // List of tracked tabs. | 205 |
81 std::set<content::NavigationController*> tabs_tracked_; | 206 // Counts the current number of actively loading tabs. |
82 | 207 size_t loading_tab_count_; |
83 // The number of tabs that have been restored. | 208 |
84 int tab_count_; | 209 // Counts the number of deferred tabs. |
85 | 210 size_t deferred_tab_count_; |
86 // Max number of tabs that were loaded in parallel (for metrics). | |
87 size_t max_parallel_tab_loads_; | |
88 | 211 |
89 // Notification registrar. | 212 // Notification registrar. |
90 content::NotificationRegistrar registrar_; | 213 content::NotificationRegistrar registrar_; |
91 | 214 |
92 // To keep the collector alive as long as needed. | 215 // Statistics gathered regarding the TabLoader. |
| 216 TabLoaderStats tab_loader_stats_; |
| 217 |
| 218 // The source of ticks used for taking timing information. This is |
| 219 // configurable as a testing seam. Defaults to using base::DefaultTickClock, |
| 220 // which in turn uses base::TimeTicks. |
| 221 scoped_ptr<base::TickClock> tick_clock_; |
| 222 |
| 223 // The reporting delegate used to report gathered statistics. |
| 224 scoped_ptr<StatsReportingDelegate> reporting_delegate_; |
| 225 |
| 226 // For keeping SessionRestoreStatsCollector alive while it is still working |
| 227 // even if no TabLoader references it. The object only lives on if it still |
| 228 // has deferred tabs remaining from an interrupted session restore. |
93 scoped_refptr<SessionRestoreStatsCollector> this_retainer_; | 229 scoped_refptr<SessionRestoreStatsCollector> this_retainer_; |
94 | 230 |
95 // The shared SessionRestoreNotifier instance for all SessionRestores running | |
96 // at this time. | |
97 static SessionRestoreStatsCollector* shared_collector_; | |
98 | |
99 DISALLOW_COPY_AND_ASSIGN(SessionRestoreStatsCollector); | 231 DISALLOW_COPY_AND_ASSIGN(SessionRestoreStatsCollector); |
100 }; | 232 }; |
101 | 233 |
| 234 // An abstract reporting delegate is used as a testing seam. |
| 235 class SessionRestoreStatsCollector::StatsReportingDelegate { |
| 236 public: |
| 237 StatsReportingDelegate() {} |
| 238 virtual ~StatsReportingDelegate() {} |
| 239 |
| 240 // Called when TabLoader has completed its work. |
| 241 virtual void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) = 0; |
| 242 |
| 243 // Called when a tab has been deferred. |
| 244 virtual void ReportTabDeferred() = 0; |
| 245 |
| 246 // Called when a deferred tab has been loaded. |
| 247 virtual void ReportDeferredTabLoaded() = 0; |
| 248 |
| 249 private: |
| 250 DISALLOW_COPY_AND_ASSIGN(StatsReportingDelegate); |
| 251 }; |
| 252 |
| 253 // The default reporting delegate, which reports statistics via UMA. |
| 254 class SessionRestoreStatsCollector::UmaStatsReportingDelegate |
| 255 : public StatsReportingDelegate { |
| 256 public: |
| 257 UmaStatsReportingDelegate(); |
| 258 ~UmaStatsReportingDelegate() override {} |
| 259 |
| 260 // StatsReportingDelegate: |
| 261 void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) override; |
| 262 void ReportTabDeferred() override; |
| 263 void ReportDeferredTabLoaded() override; |
| 264 |
| 265 private: |
| 266 // Has ReportTabDeferred been called? |
| 267 bool got_report_tab_deferred_; |
| 268 |
| 269 DISALLOW_COPY_AND_ASSIGN(UmaStatsReportingDelegate); |
| 270 }; |
| 271 |
102 #endif // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ | 272 #endif // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ |
OLD | NEW |