1 // Copyright 2017 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_METRICS_TAB_STATS_TRACKER_H_ 6 #define CHROME_BROWSER_METRICS_TAB_STATS_TRACKER_H_ 7 8 #include <map> 9 #include <memory> 10 #include <string> 11 #include <vector> 12 13 #include "base/containers/flat_map.h" 14 #include "base/containers/flat_set.h" 15 #include "base/gtest_prod_util.h" 16 #include "base/macros.h" 17 #include "base/power_monitor/power_observer.h" 18 #include "base/sequence_checker.h" 19 #include "base/timer/timer.h" 20 #include "build/build_config.h" 21 #include "chrome/browser/metrics/tab_stats_data_store.h" 22 #include "chrome/browser/metrics/tab_stats_tracker_delegate.h" 23 #include "chrome/browser/ui/browser_list_observer.h" 24 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" 25 #include "components/metrics/daily_event.h" 26 #include "content/public/browser/navigation_handle.h" 27 #include "content/public/browser/web_contents_observer.h" 28 29 class PrefRegistrySimple; 30 class PrefService; 31 32 namespace metrics { 33 FORWARD_DECLARE_TEST(TabStatsTrackerBrowserTest, 34 TabDeletionGetsHandledProperly); 35 36 // Class for tracking and recording the tabs and browser windows usage. 37 // 38 // This class is meant to be used as a singleton by calling the SetInstance 39 // method, e.g.: 40 // TabStatsTracker::SetInstance( 41 // std::make_unique<TabStatsTracker>(g_browser_process->local_state())); 42 class TabStatsTracker : public TabStripModelObserver, 43 public BrowserListObserver, 44 public base::PowerObserver { 45 public: 46 // Constructor. |pref_service| must outlive this object. 47 explicit TabStatsTracker(PrefService* pref_service); 48 ~TabStatsTracker() override; 49 50 // Sets the |TabStatsTracker| global instance. 51 static void SetInstance(std::unique_ptr<TabStatsTracker> instance); 52 53 // Returns the |TabStatsTracker| global instance. 54 static TabStatsTracker* GetInstance(); 55 56 // Registers prefs used to track tab stats. 57 static void RegisterPrefs(PrefRegistrySimple* registry); 58 59 void SetDelegateForTesting( 60 std::unique_ptr<TabStatsTrackerDelegate> new_delegate); 61 62 // Accessors. 63 const TabStatsDataStore::TabsStats& tab_stats() const; 64 65 protected: 66 FRIEND_TEST_ALL_PREFIXES(TabStatsTrackerBrowserTest, 67 TabDeletionGetsHandledProperly); 68 #if defined(OS_WIN) 69 FRIEND_TEST_ALL_PREFIXES(TabStatsTrackerBrowserTest, 70 TestCalculateAndRecordNativeWindowVisibilities); 71 #endif 72 73 // The UmaStatsReportingDelegate is responsible for delivering statistics 74 // reported by the TabStatsTracker via UMA. 75 class UmaStatsReportingDelegate; 76 77 // The observer that's used by |daily_event_| to report the metrics. 78 class TabStatsDailyObserver : public DailyEvent::Observer { 79 public: 80 // Constructor. |reporting_delegate| and |data_store| must outlive this 81 // object. TabStatsDailyObserver(UmaStatsReportingDelegate * reporting_delegate,TabStatsDataStore * data_store)82 TabStatsDailyObserver(UmaStatsReportingDelegate* reporting_delegate, 83 TabStatsDataStore* data_store) 84 : reporting_delegate_(reporting_delegate), data_store_(data_store) {} ~TabStatsDailyObserver()85 ~TabStatsDailyObserver() override {} 86 87 // Callback called when the daily event happen. 88 void OnDailyEvent(DailyEvent::IntervalType type) override; 89 90 private: 91 // The delegate used to report the metrics. 92 UmaStatsReportingDelegate* reporting_delegate_; 93 94 // The data store that houses the metrics. 95 TabStatsDataStore* data_store_; 96 97 DISALLOW_COPY_AND_ASSIGN(TabStatsDailyObserver); 98 }; 99 100 // Accessors, exposed for unittests: tab_stats_data_store()101 TabStatsDataStore* tab_stats_data_store() { 102 return tab_stats_data_store_.get(); 103 } daily_event_timer_for_testing()104 base::RepeatingTimer* daily_event_timer_for_testing() { 105 return &daily_event_timer_; 106 } daily_event_for_testing()107 DailyEvent* daily_event_for_testing() { return daily_event_.get(); } reporting_delegate_for_testing()108 UmaStatsReportingDelegate* reporting_delegate_for_testing() { 109 return reporting_delegate_.get(); 110 } 111 std::vector<std::unique_ptr<base::RepeatingTimer>>* usage_interval_timers_for_testing()112 usage_interval_timers_for_testing() { 113 return &usage_interval_timers_; 114 } heartbeat_timer_for_testing()115 base::RepeatingTimer* heartbeat_timer_for_testing() { 116 return &heartbeat_timer_; 117 } 118 119 // Reset the |reporting_delegate_| object to |reporting_delegate|, for testing 120 // purposes. reset_reporting_delegate_for_testing(UmaStatsReportingDelegate * reporting_delegate)121 void reset_reporting_delegate_for_testing( 122 UmaStatsReportingDelegate* reporting_delegate) { 123 reporting_delegate_.reset(reporting_delegate); 124 } 125 126 // Reset the DailyEvent object to |daily_event|, for testing purposes. reset_daily_event_for_testing(DailyEvent * daily_event)127 void reset_daily_event_for_testing(DailyEvent* daily_event) { 128 daily_event_.reset(daily_event); 129 } 130 reset_data_store_for_testing(TabStatsDataStore * data_store)131 void reset_data_store_for_testing(TabStatsDataStore* data_store) { 132 tab_stats_data_store_.reset(data_store); 133 } 134 135 // BrowserListObserver: 136 void OnBrowserAdded(Browser* browser) override; 137 void OnBrowserRemoved(Browser* browser) override; 138 139 // TabStripModelObserver: 140 void OnTabStripModelChanged( 141 TabStripModel* tab_strip_model, 142 const TabStripModelChange& change, 143 const TabStripSelectionChange& selection) override; 144 void TabChangedAt(content::WebContents* web_contents, 145 int index, 146 TabChangeType change_type) override; 147 // base::PowerObserver: 148 void OnResume() override; 149 150 // Callback when an interval timer triggers. 151 void OnInterval(base::TimeDelta interval, 152 TabStatsDataStore::TabsStateDuringIntervalMap* interval_map); 153 154 // Functions to call to start tracking a new tab. 155 void OnInitialOrInsertedTab(content::WebContents* web_contents); 156 157 // Functions to call when a WebContents get destroyed. 158 void OnWebContentsDestroyed(content::WebContents* web_contents); 159 160 #if defined(OS_WIN) 161 // Function to call aura_extra::ComputeNativeWindowOcclusionStatus() and 162 // record the Visibility of all Chrome browser windows on Windows. 163 void CalculateAndRecordNativeWindowVisibilities(); 164 #endif 165 166 // Function to call to report the tab heartbeat metrics. 167 void OnHeartbeatEvent(); 168 169 // The name of the histogram used to report that the daily event happened. 170 static const char kTabStatsDailyEventHistogramName[]; 171 172 private: 173 // Observer used to be notified when the state of a WebContents changes or 174 // when it's about to be destroyed. 175 class WebContentsUsageObserver; 176 177 // The delegate that reports the events. 178 std::unique_ptr<UmaStatsReportingDelegate> reporting_delegate_; 179 180 // Delegate to collect data; 181 std::unique_ptr<TabStatsTrackerDelegate> delegate_; 182 183 // The tab stats. 184 std::unique_ptr<TabStatsDataStore> tab_stats_data_store_; 185 186 // A daily event for collecting metrics once a day. 187 std::unique_ptr<DailyEvent> daily_event_; 188 189 // The timer used to periodically check if the daily event should be 190 // triggered. 191 base::RepeatingTimer daily_event_timer_; 192 193 #if defined(OS_WIN) 194 // The timer used to periodically calculate the occlusion status of native 195 // windows on Windows. 196 base::RepeatingTimer native_window_occlusion_timer_; 197 #endif 198 199 // The timers used to analyze how tabs are used during a given interval of 200 // time. 201 std::vector<std::unique_ptr<base::RepeatingTimer>> usage_interval_timers_; 202 203 // The timer used to report the heartbeat metrics at regular interval. 204 base::RepeatingTimer heartbeat_timer_; 205 206 // The observers that track how the tabs are used. 207 std::map<content::WebContents*, std::unique_ptr<WebContentsUsageObserver>> 208 web_contents_usage_observers_; 209 210 SEQUENCE_CHECKER(sequence_checker_); 211 212 DISALLOW_COPY_AND_ASSIGN(TabStatsTracker); 213 }; 214 215 // The reporting delegate, which reports metrics via UMA. 216 class TabStatsTracker::UmaStatsReportingDelegate { 217 public: 218 // The name of the histogram that records the number of tabs total at resume 219 // from sleep/hibernate. 220 static const char kNumberOfTabsOnResumeHistogramName[]; 221 222 // The name of the histogram that records the maximum number of tabs opened in 223 // a day. 224 static const char kMaxTabsInADayHistogramName[]; 225 226 // The name of the histogram that records the maximum number of tabs opened in 227 // the same window in a day. 228 static const char kMaxTabsPerWindowInADayHistogramName[]; 229 230 // The name of the histogram that records the maximum number of windows 231 // opened in a day. 232 static const char kMaxWindowsInADayHistogramName[]; 233 234 // The name of the histograms that records how tabs have been used during a 235 // given period of time. Will be appended with '_T' with T being the interval 236 // window (in seconds). 237 static const char kUnusedAndClosedInIntervalHistogramNameBase[]; 238 static const char kUnusedTabsInIntervalHistogramNameBase[]; 239 static const char kUsedAndClosedInIntervalHistogramNameBase[]; 240 static const char kUsedTabsInIntervalHistogramNameBase[]; 241 242 // The name of the histograms that records the current number of tabs/windows. 243 static const char kTabCountHistogramName[]; 244 static const char kWindowCountHistogramName[]; 245 246 // The name of the histogram that records each window's width, in DIPs. 247 static const char kWindowWidthHistogramName[]; 248 UmaStatsReportingDelegate()249 UmaStatsReportingDelegate() {} ~UmaStatsReportingDelegate()250 virtual ~UmaStatsReportingDelegate() {} 251 252 // Called at resume from sleep/hibernate. 253 void ReportTabCountOnResume(size_t tab_count); 254 255 // Called once per day to report the metrics. 256 void ReportDailyMetrics(const TabStatsDataStore::TabsStats& tab_stats); 257 258 // Report the tab heartbeat metrics. 259 void ReportHeartbeatMetrics(const TabStatsDataStore::TabsStats& tab_stats); 260 261 // Report some information about how tabs have been used during a given 262 // interval of time. 263 void ReportUsageDuringInterval( 264 const TabStatsDataStore::TabsStateDuringIntervalMap& interval_map, 265 base::TimeDelta interval); 266 267 #if defined(OS_WIN) 268 void RecordNativeWindowVisibilities(size_t num_occluded, 269 size_t num_visible, 270 size_t num_hidden); 271 #endif 272 273 protected: 274 // Generates the name of the histograms that will track tab usage during a 275 // given period of time. 276 static std::string GetIntervalHistogramName(const char* base_name, 277 base::TimeDelta interval); 278 279 // Checks if Chrome is running in background with no visible windows, virtual 280 // for unittesting. 281 virtual bool IsChromeBackgroundedWithoutWindows(); 282 283 private: 284 DISALLOW_COPY_AND_ASSIGN(UmaStatsReportingDelegate); 285 }; 286 287 } // namespace metrics 288 289 #endif // CHROME_BROWSER_METRICS_TAB_STATS_TRACKER_H_ 290