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
|
// Copyright 2020 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_METRICS_USAGE_SCENARIO_USAGE_SCENARIO_DATA_STORE_H_
#define CHROME_BROWSER_METRICS_USAGE_SCENARIO_USAGE_SCENARIO_DATA_STORE_H_
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "base/types/pass_key.h"
#include "extensions/common/extension_id.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/origin.h"
namespace metrics {
class TabUsageScenarioTrackerBrowserTest;
}
// Stores the data necessary to analyze the usage pattern during a given
// interval of time. There are 2 types of data tracked by this class:
// - Current state data: e.g. the current uptime.
// - Interval data: e.g. whether or not there's been a user interaction since
// the last call to ResetIntervalData.
//
// By default this class assumes that no tabs exists when it's created. If this
// isn't true then the data providers need to make the appropriate calls to set
// the correct initial state.
//
// The interval's length needs to be enforced by the owner of this class, it
// should call ResetIntervalData regularly to get the usage data and reset it.
class UsageScenarioDataStore {
public:
UsageScenarioDataStore();
UsageScenarioDataStore(const UsageScenarioDataStore& rhs) = delete;
UsageScenarioDataStore& operator=(const UsageScenarioDataStore& rhs) = delete;
virtual ~UsageScenarioDataStore() = 0;
// Used to store data between 2 calls to ResetIntervalData.
struct IntervalData {
IntervalData();
IntervalData(const IntervalData&);
IntervalData& operator=(const IntervalData&);
// The uptime at the end of the interval.
base::TimeDelta uptime_at_interval_end;
// The maximum number of tabs that existed at the same time.
uint16_t max_tab_count = 0;
// The maximum number of windows that have been visible at the same time.
uint16_t max_visible_window_count = 0;
// Number of main frame different-document navigations in tabs.
uint16_t top_level_navigation_count = 0;
// The number of tabs that have been closed.
uint16_t tabs_closed_during_interval = 0;
// Number of user interaction (scroll, click or typing).
uint16_t user_interaction_count = 0;
// The time spent playing video full screen in a single-monitor situation.
base::TimeDelta time_playing_video_full_screen_single_monitor;
// The time spent with at least one opened WebRTC connection.
base::TimeDelta time_with_open_webrtc_connection;
// The time spent with at least one WebContents capturing video.
base::TimeDelta time_capturing_video;
// The time spent playing video in at least one visible tab.
base::TimeDelta time_playing_video_in_visible_tab;
// The time spent playing audio in at least one tab.
base::TimeDelta time_playing_audio;
// The time since the last user interaction with the browser at the end of
// the interval. This time can exceed the length of the interval.
base::TimeDelta time_since_last_user_interaction_with_browser;
// The SourceID that has been visible for the longest period of time for the
// origin that has been visible for the longest period of time during the
// interval. E.g.:
// - SourceID 1 and 2 are for the same origin and are visible respectively
// for 2 and 3 seconds each during the interval.
// - SourceID 3 is for a different origin and is visible for 4 second.
// - This will report Source ID 2 with a duration of 3 seconds.
//
// In case of equality for an interval a SourceID will be randomly picked.
// In case of equality between origins this will report the data for the
// origin that contains the sourceID that has been visible the longest (or
// a random one in case of equality).
ukm::SourceId source_id_for_longest_visible_origin = ukm::kInvalidSourceId;
// The visibility time for |source_id_for_longest_visible_origin|.
base::TimeDelta source_id_for_longest_visible_origin_duration;
// The visibility time for the Origin associated with
// |source_id_for_longest_visible_origin|. This could be greater than
// |source_id_for_longest_visible_origin_duration| if there's multiple tabs
// for the longest visible origin visible during the interval.
base::TimeDelta longest_visible_origin_duration;
// The number of times the system has been put to sleep during the interval.
uint8_t sleep_events = 0;
// The number of extensions that ran content scripts during the interval.
size_t num_extensions_with_content_scripts = 0;
};
// Reset the interval data with the current state information and returns the
// data for the past interval (since the last call to ResetIntervalData or the
// creation of this object if this is the first call).
virtual IntervalData ResetIntervalData() = 0;
};
// Concrete implementation of a UsageScenarioDataStore that expose the functions
// allowing to update its internal state.
//
// This class isn't thread safe and all functions should be called from a single
// sequence. This is enforced via a sequence checker.
class UsageScenarioDataStoreImpl : public UsageScenarioDataStore {
public:
UsageScenarioDataStoreImpl();
UsageScenarioDataStoreImpl(const UsageScenarioDataStoreImpl& rhs) = delete;
UsageScenarioDataStoreImpl& operator=(const UsageScenarioDataStoreImpl& rhs) =
delete;
~UsageScenarioDataStoreImpl() override;
IntervalData ResetIntervalData() override;
// Set of functions used to maintain the current state, these should only be
// called by a UsageScenarioDataInfoProvider instance. It is important to log
// all events to ensure the integrity of the data store, e.g. if a tab
// currently using WebRTC is closed the 2 following functions should be
// called:
// - OnTabStopUsingWebRTC()
// - OnTabClosed()
void OnTabAdded();
void OnTabClosed();
void OnWindowVisible();
void OnWindowHidden();
void OnTopLevelNavigation();
void OnUserInteraction();
void OnFullScreenVideoStartsOnSingleMonitor();
void OnFullScreenVideoEndsOnSingleMonitor();
void OnWebRTCConnectionOpened();
void OnWebRTCConnectionClosed();
void OnIsCapturingVideoStarted();
void OnIsCapturingVideoEnded();
void OnAudioStarts();
void OnAudioStops();
void OnSleepEvent();
// Should be called when a video starts in a visible tab or when a non visible
// tab playing video becomes visible.
void OnVideoStartsInVisibleTab();
// Should be called when a video stops in a visible tab or when a visible
// tab playing video becomes non visible.
void OnVideoStopsInVisibleTab();
void OnUkmSourceBecameVisible(
const ukm::SourceId& source,
const url::Origin& origin,
extensions::ExtensionIdSet extensions_with_content_scripts);
void OnUkmSourceBecameHidden(const ukm::SourceId& source,
const url::Origin& origin);
const IntervalData& GetIntervalDataForTesting() { return interval_data_; }
uint16_t current_tab_count_for_testing() { return current_tab_count_; }
uint16_t current_visible_window_count_for_testing() {
return current_visible_window_count_;
}
base::flat_set<ukm::SourceId> GetVisibleSourceIdsForTesting();
bool TrackingPlayingVideoInActiveTabForTesting() const;
bool TrackingPlayingFullScreenVideoSingleMonitorForTesting() const;
private:
friend class metrics::TabUsageScenarioTrackerBrowserTest;
explicit UsageScenarioDataStoreImpl(const base::TickClock* tick_clock);
// Information about a ukm::SourceId that has been visible during an interval
// of time.
struct SourceIdData {
// The timestamp when the SourceID became visible, null if the sourceID
// isn't visible.
base::TimeTicks visible_timestamp;
// The total visible time during the interval.
base::TimeDelta cumulative_visible_time;
};
using OriginData = base::flat_map<ukm::SourceId, SourceIdData>;
using OriginInfoMap = base::flat_map<url::Origin, OriginData>;
// Finalize the interval data based on the data contained in
// |interval_details_| and |origin_info_map_| and remove the SourceIdData that
// don't need to be tracked anymore.
void FinalizeIntervalData(base::TimeTicks now);
// The clock used by this class.
raw_ptr<const base::TickClock> tick_clock_;
// The current tab count.
uint16_t current_tab_count_ = 0;
// The current number of visible windows.
uint16_t current_visible_window_count_ = 0;
// The timestamp of the beginning of a full screen video session when
// there's only one monitor available. Reset to |now| when an interval ends
// (when ResetIntervalData is called).
base::TimeTicks is_playing_full_screen_video_single_monitor_since_;
// The number of opened WebRTC connections.
uint16_t webrtc_open_connection_count_ = 0;
// The timestamp of the beginning of the WebRTC session that has caused
// |webrtc_connection_count| to increase to 1. Reset to |now| when an interval
// ends (when ResetIntervalData is called).
base::TimeTicks has_opened_webrtc_connection_since_;
// The number of WebContents capturing video (e.g. webcam). Usually a tab, but
// some exceptions exist (e.g. OOBE WebUI on ChromeOS).
uint16_t web_contents_capturing_video_ = 0;
// The timestamp of the beginning of a video capture session that has caused
// |web_contents_capturing_video_| to increase to 1. Reset to |now| when an
// internal ends (when ResetIntervalData is called).
base::TimeTicks capturing_video_since_;
// The number of tabs playing audio.
uint16_t tabs_playing_audio_ = 0;
// The timestamp of the beginning of an audio session that has caused
// |tabs_playing_audio_| to increase to 1. Reset to |now| when an interval
// ends (when ResetIntervalData is called).
base::TimeTicks playing_audio_since_;
// The number of visible tabs playing at least one video.
uint16_t visible_tabs_playing_video_ = 0;
// Timestamp grabbed when |visible_tabs_playing_video_| increase to 1. Reset
// to |now| when an interval ends (when ResetIntervalData is called).
base::TimeTicks playing_video_in_active_tab_since_;
// The application start time.
const base::TimeTicks start_time_;
// The timestamp of the most recent call to OnUserInteraction(), equal to
// |start_time_| if this hasn't been called yet.
base::TimeTicks last_interaction_with_browser_timestamp_;
// Information about the origins that have been visible during the interval.
OriginInfoMap origin_info_map_;
// Extensions that ran content scripts on visible origins during the interval.
extensions::ExtensionIdSet extensions_with_content_scripts_;
IntervalData interval_data_;
SEQUENCE_CHECKER(sequence_checker_);
};
#endif // CHROME_BROWSER_METRICS_USAGE_SCENARIO_USAGE_SCENARIO_DATA_STORE_H_
|