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