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.
5 #ifndef COMPONENTS_UKM_UKM_RECORDER_IMPL_H_
6 #define COMPONENTS_UKM_UKM_RECORDER_IMPL_H_
12 #include <unordered_set>
15 #include "base/callback_forward.h"
16 #include "base/containers/flat_map.h"
17 #include "base/sequence_checker.h"
18 #include "base/strings/string_piece.h"
19 #include "services/metrics/public/cpp/ukm_decode.h"
20 #include "services/metrics/public/cpp/ukm_recorder.h"
21 #include "services/metrics/public/mojom/ukm_interface.mojom.h"
24 class UkmBrowserTestBase;
25 class UkmEGTestHelper;
30 class UkmRecorderImplTest;
32 class UkmUtilsForTest;
35 class UkmDebugDataExtractor;
38 class UkmRecorderImpl : public UkmRecorder {
39 using IsWebstoreExtensionCallback =
40 base::RepeatingCallback<bool(base::StringPiece id)>;
44 ~UkmRecorderImpl() override;
46 // Unconditionally attempts to create a field trial to control client side
47 // metrics/crash sampling to use as a fallback when one hasn't been
48 // provided. This is expected to occur on first-run on platforms that don't
49 // have first-run variations support. This should only be called when there is
50 // no existing field trial controlling the sampling feature.
51 static void CreateFallbackSamplingTrial(bool is_stable_channel,
52 base::FeatureList* feature_list);
54 // Enables/disables recording control if data is allowed to be collected. The
55 // |extensions| flag separately controls recording of chrome-extension://
56 // URLs; this flag should reflect the "sync extensions" user setting.
57 void EnableRecording(bool extensions);
58 void DisableRecording();
60 // Disables sampling for testing purposes.
61 void DisableSamplingForTesting() override;
63 // Deletes stored recordings.
66 // Sets a callback for determining if an extension URL can be recorded.
67 void SetIsWebstoreExtensionCallback(
68 const IsWebstoreExtensionCallback& callback);
71 // Calculates sampled in/out based on a given |rate|. This is virtual so
72 // it can be overriden by tests.
73 virtual bool IsSampledIn(int sampling_rate);
75 // Cache the list of whitelisted entries from the field trial parameter.
76 void StoreWhitelistedEntries();
78 // Writes recordings into a report proto, and clears recordings.
79 void StoreRecordingsInReport(Report* report);
81 const std::map<SourceId, std::unique_ptr<UkmSource>>& sources() const {
82 return recordings_.sources;
85 const std::vector<mojom::UkmEntryPtr>& entries() const {
86 return recordings_.entries;
90 void AddEntry(mojom::UkmEntryPtr entry) override;
91 void UpdateSourceURL(SourceId source_id, const GURL& url) override;
92 void UpdateAppURL(SourceId source_id, const GURL& url) override;
93 void RecordNavigation(
95 const UkmSource::NavigationData& navigation_data) override;
96 using UkmRecorder::RecordOtherURL;
98 virtual bool ShouldRestrictToWhitelistedSourceIds() const;
100 virtual bool ShouldRestrictToWhitelistedEntries() const;
103 friend ::metrics::UkmBrowserTestBase;
104 friend ::metrics::UkmEGTestHelper;
105 friend ::ukm::debug::UkmDebugDataExtractor;
106 friend ::ukm::UkmRecorderImplTest;
107 friend ::ukm::UkmUtilsForTest;
109 struct MetricAggregate {
110 uint64_t total_count = 0;
111 double value_sum = 0;
112 double value_square_sum = 0.0;
113 uint64_t dropped_due_to_limits = 0;
114 uint64_t dropped_due_to_sampling = 0;
115 uint64_t dropped_due_to_whitelist = 0;
118 struct EventAggregate {
122 base::flat_map<uint64_t, MetricAggregate> metrics;
123 uint64_t total_count = 0;
124 uint64_t dropped_due_to_limits = 0;
125 uint64_t dropped_due_to_sampling = 0;
126 uint64_t dropped_due_to_whitelist = 0;
129 // Container for sampling in/out choices for events within a single page
130 // load. This is important because some events are emitted multiple times
131 // with different metric values that are expected to be grouped together.
132 // For example, Blink.UseCounter is emitted for *all* used blink features
133 // on a page so its important that this metric either be on or off for
134 // the entire page. The sampling of different events is calculated
135 // independently (i.e. it can't be assumed that because one type of event
136 // is sampled-in that another will be sample-in or sampled-out) but always
137 // remembered for the entire page.
143 // Sets the sampled-in flag for a given |event_id|.
144 void Set(uint64_t event_id, bool sampled_in);
146 // Returns if there is already a flag for a given |event_id|. The value
147 // of that flag is stored in |out_sampled_in|;
148 bool Find(uint64_t event_id, bool* out_sampled_in) const;
150 // Returns if this record has been modified.
151 bool modified() const { return modified_; }
153 // Clears the |modified_| flag.
154 void clear_modified() { modified_ = false; }
157 // Per-event boolean indicating sampled-in for this page, keyed by event_id.
158 std::map<uint64_t, bool> event_sampling_;
160 // Boolean indicating if this has been modified, used to clear out old
161 // entries so they don't continue to use memory. "Modified" means Set()
162 // has been called since the last time clear_modified() was called
163 // (currently at every upload of UKM data).
164 bool modified_ = false;
166 DISALLOW_COPY_AND_ASSIGN(PageSampling);
169 using MetricAggregateMap = std::map<uint64_t, MetricAggregate>;
171 // Returns true if |sanitized_url| should be recorded.
172 bool ShouldRecordUrl(SourceId source_id, const GURL& sanitized_url) const;
174 void RecordSource(std::unique_ptr<UkmSource> source);
176 // Load sampling configurations from field-trial information.
177 void LoadExperimentSamplingInfo();
179 // Whether recording new data is currently allowed.
180 bool recording_enabled_ = false;
182 // Indicates whether recording is enabled for extensions.
183 bool extensions_enabled_ = false;
185 // Indicates whether recording continuity has been broken since last report.
186 bool recording_is_continuous_ = true;
188 // Indicates if sampling has been enabled.
189 bool sampling_enabled_ = true;
191 // Callback for checking extension IDs.
192 IsWebstoreExtensionCallback is_webstore_extension_callback_;
194 // Map from hashes to entry and metric names.
195 ukm::builders::DecodeMap decode_map_;
197 // Whitelisted Entry hashes, only the ones in this set will be recorded.
198 std::set<uint64_t> whitelisted_entry_hashes_;
200 // Sampling configurations, loaded from a field-trial.
201 int default_sampling_rate_ = 0;
202 base::flat_map<uint64_t, int> event_sampling_rates_;
204 // Result of sampling calculation per event for a source/page. This is
205 // cleared at the start of each page load and ensure that that all events
206 // within a page will be included or excluded together.
207 std::map<int64_t, PageSampling> source_event_sampling_;
209 // Contains data from various recordings which periodically get serialized
210 // and cleared by StoreRecordingsInReport() and may be Purged().
213 Recordings& operator=(Recordings&&);
216 // Data captured by UpdateSourceUrl().
217 std::map<SourceId, std::unique_ptr<UkmSource>> sources;
219 // Data captured by AddEntry().
220 std::vector<mojom::UkmEntryPtr> entries;
222 // URLs of sources that matched a whitelist url, but were not included in
223 // the report generated by the last log rotation because we haven't seen any
224 // events for that source yet.
225 std::unordered_set<std::string> carryover_urls_whitelist;
227 // Aggregate information for collected event metrics.
228 std::map<uint64_t, EventAggregate> event_aggregations;
230 // Aggregated counters about Sources recorded in the current log.
231 struct SourceCounts {
232 // Count of URLs recorded for all sources.
234 // Count of URLs recorded for all SourceIdType::NAVIGATION_ID Sources.
235 size_t navigation_sources = 0;
236 // Sources carried over (not recorded) from a previous logging rotation.
237 size_t carryover_sources = 0;
239 // Resets all of the data.
242 SourceCounts source_counts;
244 // Resets all of the data.
247 Recordings recordings_;
249 SEQUENCE_CHECKER(sequence_checker_);
254 #endif // COMPONENTS_UKM_UKM_RECORDER_IMPL_H_