• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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