| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ |
| #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ |
| |
| #include <stddef.h> |
| |
| #include <map> |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/memory/weak_ptr.h" |
| #include "base/scoped_multi_source_observation.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/sessions/session_restore.h" |
| #include "chrome/browser/sessions/session_restore_delegate.h" |
| #include "content/public/browser/render_widget_host.h" |
| #include "content/public/browser/render_widget_host_observer.h" |
| |
| namespace content { |
| class WebContents; |
| } |
| |
| // SessionRestoreStatsCollector observes SessionRestore events ands records UMA |
| // accordingly. |
| // |
| // TODO(chrisha): Many of these metrics don't make sense to collect in the |
| // presence of an unavailable network, or when tabs are closed during loading. |
| // Rethink the collection in these cases. |
| class SessionRestoreStatsCollector : public content::RenderWidgetHostObserver { |
| public: |
| // Recorded in SessionRestore.ForegroundTabFirstPaint4.FinishReason metric. |
| // Values other than PAINT_FINISHED_UMA_DONE indicate why FirstPaint time |
| // was not recorded. |
| enum SessionRestorePaintFinishReasonUma { |
| // SessionRestore.ForegroundTabFirstPaint4 successfully recorded. |
| PAINT_FINISHED_UMA_DONE = 0, |
| // No tabs were visible the whole time before first paint. |
| PAINT_FINISHED_UMA_NO_COMPLETELY_VISIBLE_TABS = 1, |
| // No restored tabs were painted. |
| PAINT_FINISHED_UMA_NO_PAINT = 2, |
| // A non-restored tab was painted first. |
| PAINT_FINISHED_NON_RESTORED_TAB_PAINTED_FIRST = 3, |
| // The size of this enum. Must be the last entry. |
| PAINT_FINISHED_UMA_MAX = 4, |
| }; |
| |
| // Houses all of the statistics gathered by the SessionRestoreStatsCollector |
| // while the underlying TabLoader is active. These statistics are all reported |
| // at once via the reporting delegate. |
| struct TabLoaderStats { |
| // Constructor that initializes everything to zero. |
| TabLoaderStats(); |
| |
| // The number of tabs involved in all overlapping session restores being |
| // tracked by this SessionRestoreStatsCollector. This is used as suffix for |
| // the "SessionRestore.ForegroundTabFirstPaint4" histogram. |
| size_t tab_count; |
| |
| // The time elapsed between |restore_started| and reception of the first |
| // NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_VISUAL_PROPERTIES event for |
| // any of the tabs involved in the session restore. If this is zero it is |
| // because it has not been recorded (all restored tabs were closed or |
| // hidden before they were painted, or were never painted). Corresponds to |
| // "SessionRestore.ForegroundTabFirstPaint4" and its ".NTabs" variants. |
| base::TimeDelta foreground_tab_first_paint; |
| |
| // Whether we recorded |foreground_tab_first_paint| and if not, why. |
| SessionRestorePaintFinishReasonUma tab_first_paint_reason; |
| |
| // Count of tabs in a session with various properties tracked in |
| // SessionRestoreDelegate::RestoredTab. |
| size_t active_tab_count = 0; |
| size_t app_tab_count = 0; |
| size_t internal_page_tab_count = 0; |
| size_t pinned_tab_count = 0; |
| size_t grouped_tab_count = 0; |
| |
| // Count of tabs in a session whose site engagement score is below the |
| // minimum to load. |
| size_t low_site_engagement_tab_count = 0; |
| |
| // Count of tabs included in `low_site_engagement_tab_count` that use |
| // background communications (notification permission or update |
| // title/favicon in background.) |
| size_t low_site_engagement_with_background_communication_tab_count = 0; |
| |
| // Count of tabs in a session with notification permission. |
| size_t notification_permission_tab_count = 0; |
| |
| // Count of tabs in a session that update title or favicon in background. |
| size_t updates_in_background_tab_count = 0; |
| }; |
| |
| // The StatsReportingDelegate is responsible for delivering statistics |
| // reported by the SessionRestoreStatsCollector. |
| class StatsReportingDelegate; |
| |
| // An implementation of StatsReportingDelegate for reporting via UMA. |
| class UmaStatsReportingDelegate; |
| |
| // Gets or creates an instance of SessionRestoreStatsCollector. An instance |
| // self-deletes once it has reported all stats. If an existing instance is |
| // returned, |restored_started| and |reporting_delegate| are ignored. |
| static SessionRestoreStatsCollector* GetOrCreateInstance( |
| base::TimeTicks restore_started, |
| std::unique_ptr<StatsReportingDelegate> reporting_delegate); |
| |
| SessionRestoreStatsCollector(const SessionRestoreStatsCollector&) = delete; |
| SessionRestoreStatsCollector& operator=(const SessionRestoreStatsCollector&) = |
| delete; |
| |
| // Tracks stats for restored tabs. Tabs from overlapping session restores can |
| // be tracked by the same SessionRestoreStatsCollector. |
| void TrackTabs(const std::vector<SessionRestoreDelegate::RestoredTab>& tabs); |
| |
| private: |
| friend class SessionRestoreStatsCollectorTest; |
| |
| // Constructs a SessionRestoreStatsCollector. |
| SessionRestoreStatsCollector( |
| const base::TimeTicks& restore_started, |
| std::unique_ptr<StatsReportingDelegate> reporting_delegate); |
| |
| ~SessionRestoreStatsCollector() override; |
| |
| // content::RenderWidgetHostObserver: |
| void RenderWidgetHostVisibilityChanged(content::RenderWidgetHost* widget_host, |
| bool became_visible) override; |
| void RenderWidgetHostDidUpdateVisualProperties( |
| content::RenderWidgetHost* widget_host) override; |
| void RenderWidgetHostDestroyed( |
| content::RenderWidgetHost* widget_host) override; |
| |
| // Registers observers for a tab and inserts the tab into |
| // |tracked_tabs_occluded_maps| map. |
| void RegisterObserverForTab(content::WebContents* tab); |
| |
| // Report stats and self-deletes. |
| void ReportStatsAndSelfDestroy(); |
| |
| // Updates counts that depend on async lookup of UpdatesFaviconInBackground() |
| // and UpdatesTitleInBackground() in SiteDataReader. |
| void OnTabUpdatesInBackground(bool low_site_engagement, |
| bool notification_permission, |
| bool updates_in_background); |
| |
| // Won't record time for foreground tab paint because a non-restored |
| // tab was painted first. |
| bool non_restored_tab_painted_first_; |
| |
| // Got first paint of tab that was hidden or occluded before being painted. |
| bool hidden_or_occluded_tab_ignored_; |
| |
| // The time the restore process started. |
| const base::TimeTicks restore_started_; |
| |
| // Tabs we are tracking paints in, keyed by their RenderWidgetHost and mapped |
| // to a bool indicating whether the tab was ever hidden or occluded. |
| std::map<content::RenderWidgetHost*, bool> tracked_tabs_occluded_map_; |
| |
| // Statistics gathered regarding the TabLoader. |
| TabLoaderStats tab_loader_stats_; |
| |
| // The reporting delegate used to report gathered statistics. |
| std::unique_ptr<StatsReportingDelegate> reporting_delegate_; |
| |
| base::ScopedMultiSourceObservation<content::RenderWidgetHost, |
| content::RenderWidgetHostObserver> |
| render_widget_host_observations_{this}; |
| |
| base::WeakPtrFactory<SessionRestoreStatsCollector> weak_factory_{this}; |
| }; |
| |
| // An abstract reporting delegate is used as a testing seam. |
| class SessionRestoreStatsCollector::StatsReportingDelegate { |
| public: |
| StatsReportingDelegate() = default; |
| |
| StatsReportingDelegate(const StatsReportingDelegate&) = delete; |
| StatsReportingDelegate& operator=(const StatsReportingDelegate&) = delete; |
| |
| virtual ~StatsReportingDelegate() = default; |
| |
| // Called when TabLoader has completed its work. |
| virtual void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) = 0; |
| }; |
| |
| // The default reporting delegate, which reports statistics via UMA. |
| class SessionRestoreStatsCollector::UmaStatsReportingDelegate |
| : public StatsReportingDelegate { |
| public: |
| UmaStatsReportingDelegate(); |
| |
| UmaStatsReportingDelegate(const UmaStatsReportingDelegate&) = delete; |
| UmaStatsReportingDelegate& operator=(const UmaStatsReportingDelegate&) = |
| delete; |
| |
| ~UmaStatsReportingDelegate() override = default; |
| |
| // StatsReportingDelegate: |
| void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) override; |
| }; |
| |
| #endif // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ |