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