xref: /aosp_15_r20/external/cronet/components/metrics/structured/structured_metrics_recorder.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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