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