1 // Copyright 2023 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 #ifndef COMPONENTS_METRICS_STRUCTURED_STRUCTURED_METRICS_RECORDER_H_ 5 #define COMPONENTS_METRICS_STRUCTURED_STRUCTURED_METRICS_RECORDER_H_ 6 7 #include <deque> 8 #include <memory> 9 #include <optional> 10 11 #include "base/containers/enum_set.h" 12 #include "base/containers/flat_set.h" 13 #include "base/functional/callback_forward.h" 14 #include "base/memory/raw_ptr.h" 15 #include "base/memory/weak_ptr.h" 16 #include "components/metrics/metrics_provider.h" 17 #include "components/metrics/structured/event.h" 18 #include "components/metrics/structured/lib/event_storage.h" 19 #include "components/metrics/structured/lib/key_data.h" 20 #include "components/metrics/structured/lib/key_data_provider.h" 21 #include "components/metrics/structured/project_validator.h" 22 #include "components/metrics/structured/recorder.h" 23 #include "third_party/metrics_proto/structured_data.pb.h" 24 25 namespace metrics::structured { 26 27 // StructuredMetricsRecorder is responsible for storing and managing the all 28 // Structured Metrics events recorded on-device. This class is not thread safe 29 // and should only be called on the browser UI sequence, because calls from the 30 // metrics service come on the UI sequence. 31 // 32 // This is to be used as a base class for different platform implementations. 33 // The subclass will instantiate the desired KeyDataProvider and EventStorage. 34 // 35 // This class accepts events to record from 36 // StructuredMetricsRecorder::OnRecord via Recorder::Record via 37 // Event::Record. These events are not uploaded immediately, and are cached 38 // in ready-to-upload form. 39 class StructuredMetricsRecorder : public Recorder::RecorderImpl, 40 KeyDataProvider::Observer { 41 public: 42 // Interface for watching for the recording of Structured Metrics Events. 43 class Observer : public base::CheckedObserver { 44 public: 45 virtual void OnEventRecorded(const StructuredEventProto& event) = 0; 46 }; 47 48 StructuredMetricsRecorder( 49 std::unique_ptr<KeyDataProvider> key_data_provider, 50 std::unique_ptr<EventStorage<StructuredEventProto>> event_storage); 51 ~StructuredMetricsRecorder() override; 52 StructuredMetricsRecorder(const StructuredMetricsRecorder&) = delete; 53 StructuredMetricsRecorder& operator=(const StructuredMetricsRecorder&) = 54 delete; 55 56 // Manages whether or not Structured Metrics is recording. 57 // If these functions are overloaded, make sure they are explicitly called in 58 // the overriding function. 59 virtual void EnableRecording(); 60 virtual void DisableRecording(); 61 62 void Purge(); 63 recording_enabled()64 bool recording_enabled() const { return recording_enabled_; } 65 66 void ProvideUmaEventMetrics(ChromeUserMetricsExtension& uma_proto); 67 68 // Provides event metrics stored in the recorder into |uma_proto|. 69 // 70 // This calls OnIndependentMetrics() to populate |uma_proto| with metadata 71 // fields. 72 virtual void ProvideEventMetrics(ChromeUserMetricsExtension& uma_proto); 73 74 // Returns true if ready to provide metrics via ProvideEventMetrics. 75 bool CanProvideMetrics(); 76 77 // Returns true if there are metrics to provide. 78 bool HasMetricsToProvide(); 79 80 // KeyDataProvider::Observer: 81 void OnKeyReady() override; 82 83 // Interface for adding and remove watchers. 84 void AddEventsObserver(Observer* watcher); 85 void RemoveEventsObserver(Observer* watcher); 86 event_storage()87 EventStorage<StructuredEventProto>* event_storage() { 88 return event_storage_.get(); 89 } 90 key_data_provider()91 KeyDataProvider* key_data_provider() { return key_data_provider_.get(); } 92 93 protected: 94 friend class TestStructuredMetricsProvider; 95 friend class StructuredMetricsMixin; 96 97 // Recorder::RecorderImpl: 98 void OnEventRecord(const Event& event) override; 99 100 // Different initialization states for the recorder. 101 enum State { 102 kUninitialized, 103 // Set once OnKeyReady has been called once. 104 kKeyDataInitialized, 105 // Set once the profile key data has been initialized. 106 kProfileKeyDataInitialized, 107 kMaxValue = kProfileKeyDataInitialized, 108 }; 109 110 // Collection of InitValues that represents the current initialization state 111 // of the recorder. 112 // 113 // For events to be persisted, both kKeyDataInitialized, kEventsInitialized, 114 // and kProfileKeyDataInitialized msut be set for events to be recorded. 115 using InitState = 116 base::EnumSet<State, State::kUninitialized, State::kMaxValue>; 117 118 bool HasState(State state) const; 119 120 private: 121 friend class Recorder; 122 friend class StructuredMetricsMixin; 123 friend class StructuredMetricsProviderTest; 124 friend class StructuredMetricsRecorderTest; 125 friend class StructuredMetricsRecorderHwidTest; 126 friend class TestStructuredMetricsRecorder; 127 friend class TestStructuredMetricsProvider; 128 friend class StructuredMetricsServiceTest; 129 130 // Records events before IsInitialized(). 131 void RecordEventBeforeInitialization(const Event& event); 132 133 // Records events before IsProfileInitialized(). 134 void RecordProfileEventBeforeInitialization(const Event& event); 135 136 // Records |event| to persistent disk to be eventually sent. 137 void RecordEvent(const Event& event); 138 139 // Sets the event and project fields and the identification fields. 140 void InitializeEventProto(StructuredEventProto* proto, 141 const Event& event, 142 const ProjectValidator& project_validator, 143 const EventValidator& event_validator); 144 145 // Processes the events metric to proto format. 146 void AddMetricsToProto(StructuredEventProto* proto, 147 const Event& event, 148 const ProjectValidator& project_validator, 149 const EventValidator& validator); 150 151 // Adds sequence metadata to the event. AddSequenceMetadata(StructuredEventProto * proto,const Event & event,const ProjectValidator & project_validator,const KeyData & key_data)152 virtual void AddSequenceMetadata(StructuredEventProto* proto, 153 const Event& event, 154 const ProjectValidator& project_validator, 155 const KeyData& key_data) {} 156 157 // Hashes events and persists the events to disk. Should be called once |this| 158 // has been initialized. 159 void HashUnhashedEventsAndPersist(); 160 161 // Checks if |project_name_hash| can be uploaded. 162 bool CanUploadProject(uint64_t project_name_hash) const; 163 164 // Builds a cache of disallow projects from the Finch controlled variable. 165 void CacheDisallowedProjectsSet(); 166 167 // Returns true if key data is ready to use. 168 bool IsKeyDataInitialized(); 169 170 // Returns true if ready to record events. 171 bool IsInitialized(); 172 173 // Returns true if ready to record profile events. 174 bool IsProfileInitialized(); 175 176 // Returns whether the |event| can be recorded event if metrics is opted-out. 177 // Note that uploading is still guarded by metrics opt-in state and that these 178 // events will never be uploaded. In the event that a user opts-in, these 179 // events will be purged. 180 bool CanForceRecord(const Event& event) const; 181 182 // Helper functions to determine scope of the event. 183 bool IsDeviceEvent(const Event& event) const; 184 bool IsProfileEvent(const Event& event) const; 185 186 // Helper function to get the validators for |event|. 187 std::optional<std::pair<const ProjectValidator*, const EventValidator*>> 188 GetEventValidators(const Event& event) const; 189 190 void SetOnReadyToRecord(base::OnceClosure callback); 191 192 // Sets a callback to be made every time an event is recorded. This is exposed 193 // so that tests can check if a specific event is recorded since recording 194 // happens asynchronously. 195 void SetEventRecordCallbackForTest(base::RepeatingClosure callback); 196 197 // Adds a project to the diallowed list for testing. 198 void AddDisallowedProjectForTest(uint64_t project_name_hash); 199 200 protected: 201 void NotifyEventRecorded(const StructuredEventProto& event); 202 203 // Key data provider that provides device and profile keys. 204 std::unique_ptr<KeyDataProvider> key_data_provider_; 205 206 // Storage for events while on device. 207 std::unique_ptr<EventStorage<StructuredEventProto>> event_storage_; 208 209 // Whether the metrics provider has completed initialization. Initialization 210 // occurs across OnProfileAdded and OnKeyReady. No incoming 211 // events are recorded until initialization has succeeded. 212 // 213 // Execution is: 214 // - A profile is added. 215 // - OnProfileAdded is called, which constructs |storage_| and 216 // asynchronously reads events and keys are loaded. 217 // 218 // The metrics provider does not handle multiprofile: initialization happens 219 // only once, for the first-logged-in account aka. primary user. 220 // 221 // After a profile is added, two files need to be read from disk: 222 // per-profile keys and per-device keys. |init_count_| tracks 223 // how many of these have been read and, when it reaches 2, we set 224 // |init_state_| to kInitialized. 225 InitState init_state_; 226 227 private: 228 // Tracks the recording state signalled to the metrics provider by 229 // OnRecordingEnabled and OnRecordingDisabled. This is false until 230 // OnRecordingEnabled is called, which sets it true if structured metrics' 231 // feature flag is enabled. 232 bool recording_enabled_ = false; 233 234 // Store for events that were recorded before keys are loaded. 235 std::deque<Event> unhashed_events_; 236 237 // Store for events that were recorded before profile keys are loaded. 238 std::deque<Event> unhashed_profile_events_; 239 240 // A set of projects that are not allowed to be recorded. This is a cache of 241 // GetDisabledProjects(). 242 base::flat_set<uint64_t> disallowed_projects_; 243 244 base::ObserverList<Observer> watchers_; 245 246 // Callbacks for tests whenever an event is recorded. 247 base::RepeatingClosure test_callback_on_record_ = base::DoNothing(); 248 249 // Callback to be made once recorder is ready to persist events to disk. 250 base::OnceClosure on_ready_callback_ = base::DoNothing(); 251 252 base::WeakPtrFactory<StructuredMetricsRecorder> weak_factory_{this}; 253 }; 254 } // namespace metrics::structured 255 256 #endif // COMPONENTS_METRICS_STRUCTURED_STRUCTURED_METRICS_RECORDER_H_ 257