• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 
5 #ifndef COMPONENTS_METRICS_STRUCTURED_STRUCTURED_METRICS_PROVIDER_H_
6 #define COMPONENTS_METRICS_STRUCTURED_STRUCTURED_METRICS_PROVIDER_H_
7 
8 #include <deque>
9 #include <memory>
10 
11 #include "base/containers/flat_set.h"
12 #include "base/files/file_path.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/time/time.h"
15 #include "components/metrics/metrics_provider.h"
16 #include "components/metrics/structured/event.h"
17 #include "components/metrics/structured/key_data.h"
18 #include "components/metrics/structured/project_validator.h"
19 #include "components/metrics/structured/recorder.h"
20 
21 namespace metrics {
22 namespace structured {
23 
24 class EventsProto;
25 class ExternalMetrics;
26 
27 // StructuredMetricsProvider is responsible for filling out the
28 // |structured_metrics_event| section of the UMA proto. This class should not be
29 // instantiated except by the ChromeMetricsServiceClient. This class is not
30 // thread safe and should only be called on the browser UI sequence, because
31 // calls from the metrics service come on the UI sequence.
32 //
33 // Initialization of the StructuredMetricsProvider must wait until a profile is
34 // added, because state is stored within the profile directory. Initialization
35 // happens in several steps:
36 //
37 // 1. A StructuredMetricsProvider instance is constructed and owned by the
38 //    MetricsService. It registers itself as an observer of
39 //    metrics::structured::Recorder.
40 //
41 // 2. When a profile is added that is eligible for recording,
42 //    ChromeMetricsServiceClient calls Recorder::ProfileAdded, which notifies
43 //    this class.
44 //
45 // 3. This class then begins initialization by asynchronously reading keys and
46 //    unsent logs from the cryptohome.
47 //
48 // 4. If the read succeeds, initialization is complete and this class starts
49 //    accepting events to record.
50 //
51 // After initialization, this class accepts events to record from
52 // StructuredMetricsProvider::OnRecord via Recorder::Record via
53 // Event::Record. These events are not uploaded immediately, and are cached
54 // in ready-to-upload form.
55 //
56 // On a call to ProvideCurrentSessionData, the cache of unsent logs is added to
57 // a ChromeUserMetricsExtension for upload, and is then cleared.
58 class StructuredMetricsProvider : public metrics::MetricsProvider,
59                                   public Recorder::RecorderImpl {
60  public:
61   explicit StructuredMetricsProvider(
62       metrics::MetricsProvider* system_profile_provider);
63   ~StructuredMetricsProvider() override;
64   StructuredMetricsProvider(const StructuredMetricsProvider&) = delete;
65   StructuredMetricsProvider& operator=(const StructuredMetricsProvider&) =
66       delete;
67 
68  private:
69   friend class Recorder;
70   friend class StructuredMetricsProviderTest;
71   friend class StructuredMetricsProviderHwidTest;
72   friend class TestStructuredMetricsProvider;
73 
74   // State machine for step 4 of initialization. These are stored in three files
75   // that are asynchronously read from disk at startup. When all files have
76   // been read, the provider has been initialized.
77   enum class InitState {
78     kUninitialized = 1,
79     // Set after we observe the recorder, which happens on construction.
80     kProfileAdded = 2,
81     // Set after all key and event files are read from disk.
82     kInitialized = 3,
83   };
84 
85   // Should only be used for tests.
86   //
87   // TODO(crbug/1350322): Use this ctor to replace existing ctor.
88   StructuredMetricsProvider(const base::FilePath& device_key_path,
89                             base::TimeDelta write_delay,
90                             base::TimeDelta min_independent_metrics_interval,
91                             metrics::MetricsProvider* system_profile_provider);
92 
93   void OnKeyDataInitialized();
94   void OnRead(ReadStatus status);
95   void OnWrite(WriteStatus status);
96   void OnExternalMetricsCollected(const EventsProto& events);
97   void Purge();
98 
99   // Recorder::RecorderImpl:
100   void OnProfileAdded(const base::FilePath& profile_path) override;
101   void OnEventRecord(const Event& event) override;
102   void OnReportingStateChanged(bool enabled) override;
103   void OnSystemProfileInitialized() override;
104   absl::optional<int> LastKeyRotation(uint64_t project_name_hash) override;
105 
106   // metrics::MetricsProvider:
107   void OnRecordingEnabled() override;
108   void OnRecordingDisabled() override;
109   void ProvideCurrentSessionData(
110       metrics::ChromeUserMetricsExtension* uma_proto) override;
111   bool HasIndependentMetrics() override;
112   void ProvideIndependentMetrics(base::OnceCallback<void(bool)> done_callback,
113                                  ChromeUserMetricsExtension* uma_proto,
114                                  base::HistogramSnapshotManager*) override;
115 
116   void WriteNowForTest();
117   void SetExternalMetricsDirForTest(const base::FilePath& dir);
118 
119   // Records events before |init_state_| is kInitialized.
120   void RecordEventBeforeInitialization(const Event& event);
121 
122   // Records |event| to persistent disk to be eventually sent.
123   void RecordEvent(const Event& event);
124 
125   // Hashes events and persists the events to disk. Should be called once |this|
126   // has been initialized.
127   void HashUnhashedEventsAndPersist();
128 
129   // Populates system profile needed for Structured Metrics.
130   // Independent metric uploads will rely on a SystemProfileProvider
131   // to supply the system profile since ChromeOSMetricsProvider will
132   // not be called to populate the SystemProfile.
133   void ProvideSystemProfile(SystemProfileProto* system_profile);
134 
135   // Checks if |project_name_hash| can be uploaded.
136   bool CanUploadProject(uint64_t project_name_hash) const;
137 
138   // Builds a cache of disallow projects from the Finch controlled variable.
139   void CacheDisallowedProjectsSet();
140 
141   // Adds a project to the diallowed list for testing.
142   void AddDisallowedProjectForTest(uint64_t project_name_hash);
143 
144   // Beyond this number of logging events between successive calls to
145   // ProvideCurrentSessionData, we stop recording events.
146   static int kMaxEventsPerUpload;
147 
148   // The path used to store per-profile keys. Relative to the user's
149   // cryptohome. This file is created by chromium.
150   static char kProfileKeyDataPath[];
151 
152   // The path used to store per-device keys. This file is created by tmpfiles.d
153   // on start and has its permissions and ownership set such that it is writable
154   // by chronos.
155   static char kDeviceKeyDataPath[];
156 
157   // The directory used to store unsent logs. Relative to the user's cryptohome.
158   // This file is created by chromium.
159   static char kUnsentLogsPath[];
160 
161   // Whether the metrics provider has completed initialization. Initialization
162   // occurs across OnProfileAdded and OnInitializationCompleted. No incoming
163   // events are recorded until initialization has succeeded.
164   //
165   // Execution is:
166   //  - A profile is added.
167   //  - OnProfileAdded is called, which constructs |storage_| and
168   //    asynchronously reads events and keys.
169   //  - OnInitializationCompleted is called once reading from disk is complete,
170   //    which sets |init_count_| to kInitialized.
171   //
172   // The metrics provider does not handle multiprofile: initialization happens
173   // only once, for the first-logged-in account aka. primary user.
174   //
175   // After a profile is added, three files need to be read from disk:
176   // per-profile keys, per-device keys, and unsent events. |init_count_| tracks
177   // how many of these have been read and, when it reaches 3, we set
178   // |init_state_| to kInitialized.
179   InitState init_state_ = InitState::kUninitialized;
180   int init_count_ = 0;
181   static constexpr int kTargetInitCount = 3;
182 
183   // Tracks the recording state signalled to the metrics provider by
184   // OnRecordingEnabled and OnRecordingDisabled. This is false until
185   // OnRecordingEnabled is called, which sets it true if structured metrics'
186   // feature flag is enabled.
187   bool recording_enabled_ = false;
188 
189   // Set by OnReportingStateChanged if all keys and events should be deleted,
190   // but the files backing that state haven't been initialized yet. If set,
191   // state will be purged upon initialization.
192   bool purge_state_on_init_ = false;
193 
194   // The last time we provided independent metrics.
195   base::Time last_provided_independent_metrics_;
196 
197   // Periodically reports metrics from cros.
198   std::unique_ptr<ExternalMetrics> external_metrics_;
199 
200   // On-device storage within the user's cryptohome for unsent logs.
201   std::unique_ptr<PersistentProto<EventsProto>> events_;
202 
203   // Store for events that were recorded before user/device keys are loaded.
204   std::deque<Event> unhashed_events_;
205 
206   // Storage for all event's keys, and hashing logic for values. This stores
207   // keys on disk. |profile_key_data_| stores keys for per-profile projects,
208   // and |device_key_data_| stores keys for per-device projects.
209   std::unique_ptr<KeyData> profile_key_data_;
210   std::unique_ptr<KeyData> device_key_data_;
211 
212   // Whether the system profile has been initialized.
213   bool system_profile_initialized_ = false;
214 
215   // File path where device keys will be persisted.
216   const base::FilePath device_key_path_;
217 
218   // Delay period for PersistentProto writes. Default value of 1000 ms used if
219   // not specified in ctor.
220   base::TimeDelta write_delay_;
221 
222   // The minimum waiting time between successive deliveries of independent
223   // metrics to the metrics service via ProvideIndependentMetrics. This is set
224   // carefully: metrics logs are stored in a queue of limited size, and are
225   // uploaded roughly every 30 minutes.
226   //
227   // If this value is 0, then there will be no waiting time and events will be
228   // available on every ProvideIndependentMetrics.
229   base::TimeDelta min_independent_metrics_interval_;
230 
231   // Interface for providing the SystemProfile to metrics.
232   // See chrome/browser/metrics/chrome_metrics_service_client.h
233   base::raw_ptr<metrics::MetricsProvider> system_profile_provider_;
234 
235   // A set of projects that are not allowed to be recorded. This is a cache of
236   // GetDisabledProjects().
237   base::flat_set<uint64_t> disallowed_projects_;
238 
239   // The number of scans of external metrics that occurred since the last
240   // upload. This is only incremented if events were added by the scan.
241   int external_metrics_scans_ = 0;
242 
243   base::WeakPtrFactory<StructuredMetricsProvider> weak_factory_{this};
244 };
245 
246 }  // namespace structured
247 }  // namespace metrics
248 
249 #endif  // COMPONENTS_METRICS_STRUCTURED_STRUCTURED_METRICS_PROVIDER_H_
250