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. 4 5 #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ 6 #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ 7 8 #include <stddef.h> 9 #include <map> 10 #include <memory> 11 #include <utility> 12 #include <vector> 13 14 #include "base/scoped_observer.h" 15 #include "base/macros.h" 16 #include "chrome/browser/sessions/session_restore.h" 17 #include "chrome/browser/sessions/session_restore_delegate.h" 18 #include "content/public/browser/notification_observer.h" 19 #include "content/public/browser/notification_registrar.h" 20 #include "content/public/browser/render_widget_host.h" 21 #include "content/public/browser/render_widget_host_observer.h" 22 23 namespace content { 24 class NavigationController; 25 } 26 27 // SessionRestoreStatsCollector observes SessionRestore events ands records UMA 28 // accordingly. 29 // 30 // TODO(chrisha): Many of these metrics don't make sense to collect in the 31 // presence of an unavailable network, or when tabs are closed during loading. 32 // Rethink the collection in these cases. 33 class SessionRestoreStatsCollector : public content::NotificationObserver, 34 public content::RenderWidgetHostObserver { 35 public: 36 // Recorded in SessionRestore.ForegroundTabFirstPaint4.FinishReason metric. 37 // Values other than PAINT_FINISHED_UMA_DONE indicate why FirstPaint time 38 // was not recorded. 39 enum SessionRestorePaintFinishReasonUma { 40 // SessionRestore.ForegroundTabFirstPaint4_XX successfully recorded. 41 PAINT_FINISHED_UMA_DONE = 0, 42 // No tabs were visible the whole time before first paint. 43 PAINT_FINISHED_UMA_NO_COMPLETELY_VISIBLE_TABS = 1, 44 // No restored tabs were painted. 45 PAINT_FINISHED_UMA_NO_PAINT = 2, 46 // A non-restored tab was painted first. 47 PAINT_FINISHED_NON_RESTORED_TAB_PAINTED_FIRST = 3, 48 // The size of this enum. Must be the last entry. 49 PAINT_FINISHED_UMA_MAX = 4, 50 }; 51 52 // Houses all of the statistics gathered by the SessionRestoreStatsCollector 53 // while the underlying TabLoader is active. These statistics are all reported 54 // at once via the reporting delegate. 55 struct TabLoaderStats { 56 // Constructor that initializes everything to zero. 57 TabLoaderStats(); 58 59 // The number of tabs involved in all overlapping session restores being 60 // tracked by this SessionRestoreStatsCollector. This is used as suffix for 61 // the "SessionRestore.ForegroundTabFirstPaint4" histogram. 62 size_t tab_count; 63 64 // The time elapsed between |restore_started| and reception of the first 65 // NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_VISUAL_PROPERTIES event for 66 // any of the tabs involved in the session restore. If this is zero it is 67 // because it has not been recorded (all restored tabs were closed or 68 // hidden before they were painted, or were never painted). Corresponds to 69 // "SessionRestore.ForegroundTabFirstPaint4" and its _XX variants. 70 base::TimeDelta foreground_tab_first_paint; 71 72 // Whether we recorded |foreground_tab_first_paint| and if not, why. 73 SessionRestorePaintFinishReasonUma tab_first_paint_reason; 74 }; 75 76 // The StatsReportingDelegate is responsible for delivering statistics 77 // reported by the SessionRestoreStatsCollector. 78 class StatsReportingDelegate; 79 80 // An implementation of StatsReportingDelegate for reporting via UMA. 81 class UmaStatsReportingDelegate; 82 83 // Gets or creates an instance of SessionRestoreStatsCollector. An instance 84 // self-deletes once it has reported all stats. If an existing instance is 85 // returned, |restored_started| and |reporting_delegate| are ignored. 86 static SessionRestoreStatsCollector* GetOrCreateInstance( 87 base::TimeTicks restore_started, 88 std::unique_ptr<StatsReportingDelegate> reporting_delegate); 89 90 // Tracks stats for restored tabs. Tabs from overlapping session restores can 91 // be tracked by the same SessionRestoreStatsCollector. 92 void TrackTabs(const std::vector<SessionRestoreDelegate::RestoredTab>& tabs); 93 94 private: 95 friend class SessionRestoreStatsCollectorTest; 96 97 // State that is tracked for a tab while it is being observed. 98 struct TabState { 99 explicit TabState(content::NavigationController* controller); 100 101 // The NavigationController associated with the tab. This is the primary 102 // index for it and is never null. 103 content::NavigationController* controller; 104 105 // True if the tab was ever hidden or occluded during the restore process. 106 bool was_hidden_or_occluded; 107 108 // RenderWidgetHost* SessionRestoreStatsCollector is observing for this tab, 109 // if any. 110 content::RenderWidgetHost* observed_host; 111 }; 112 113 // Maps a NavigationController to its state. This is the primary map and 114 // physically houses the state. 115 using NavigationControllerMap = 116 std::map<content::NavigationController*, TabState>; 117 118 // Constructs a SessionRestoreStatsCollector. 119 SessionRestoreStatsCollector( 120 const base::TimeTicks& restore_started, 121 std::unique_ptr<StatsReportingDelegate> reporting_delegate); 122 123 ~SessionRestoreStatsCollector() override; 124 125 // NotificationObserver method. This is the workhorse of the class and drives 126 // all state transitions. 127 void Observe(int type, 128 const content::NotificationSource& source, 129 const content::NotificationDetails& details) override; 130 131 // RenderWidgetHostObserver: 132 void RenderWidgetHostVisibilityChanged(content::RenderWidgetHost* widget_host, 133 bool became_visible) override; 134 135 void RenderWidgetHostDestroyed( 136 content::RenderWidgetHost* widget_host) override; 137 138 // Called when a tab is no longer tracked. This is called by the 'Observe' 139 // notification callback. Takes care of unregistering all observers and 140 // removing the tab from all internal data structures. 141 void RemoveTab(content::NavigationController* tab); 142 143 // Registers for relevant notifications for a tab and inserts the tab into 144 // to |tabs_tracked_| map. Return a pointer to the newly created TabState. 145 TabState* RegisterForNotifications(content::NavigationController* tab); 146 147 // Returns the tab state, nullptr if not found. 148 TabState* GetTabState(content::NavigationController* tab); 149 TabState* GetTabState(content::RenderWidgetHost* tab); 150 151 // Report stats and self-deletes. 152 void ReportStatsAndSelfDestroy(); 153 154 // Won't record time for foreground tab paint because a non-restored 155 // tab was painted first. 156 bool non_restored_tab_painted_first_; 157 158 // Got first paint of tab that was hidden or occluded before being painted. 159 bool hidden_or_occluded_tab_ignored_; 160 161 // The time the restore process started. 162 const base::TimeTicks restore_started_; 163 164 // List of tracked tabs, mapped to their TabState. 165 NavigationControllerMap tabs_tracked_; 166 167 // Notification registrar. 168 content::NotificationRegistrar registrar_; 169 170 // Statistics gathered regarding the TabLoader. 171 TabLoaderStats tab_loader_stats_; 172 173 // The reporting delegate used to report gathered statistics. 174 std::unique_ptr<StatsReportingDelegate> reporting_delegate_; 175 176 ScopedObserver<content::RenderWidgetHost, content::RenderWidgetHostObserver> 177 observer_{this}; 178 179 DISALLOW_COPY_AND_ASSIGN(SessionRestoreStatsCollector); 180 }; 181 182 // An abstract reporting delegate is used as a testing seam. 183 class SessionRestoreStatsCollector::StatsReportingDelegate { 184 public: StatsReportingDelegate()185 StatsReportingDelegate() {} ~StatsReportingDelegate()186 virtual ~StatsReportingDelegate() {} 187 188 // Called when TabLoader has completed its work. 189 virtual void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) = 0; 190 191 // Called when a tab starts being tracked. Logs the relative time since last 192 // use of the tab. 193 virtual void ReportTabTimeSinceActive(base::TimeDelta elapsed) = 0; 194 195 private: 196 DISALLOW_COPY_AND_ASSIGN(StatsReportingDelegate); 197 }; 198 199 // The default reporting delegate, which reports statistics via UMA. 200 class SessionRestoreStatsCollector::UmaStatsReportingDelegate 201 : public StatsReportingDelegate { 202 public: 203 UmaStatsReportingDelegate(); ~UmaStatsReportingDelegate()204 ~UmaStatsReportingDelegate() override {} 205 206 // StatsReportingDelegate: 207 void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) override; 208 void ReportTabTimeSinceActive(base::TimeDelta elapsed) override; 209 210 private: 211 212 DISALLOW_COPY_AND_ASSIGN(UmaStatsReportingDelegate); 213 }; 214 215 #endif // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ 216