xref: /aosp_15_r20/external/cronet/components/metrics/structured/structured_metrics_service.cc (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 
5 #include "components/metrics/structured/structured_metrics_service.h"
6 
7 #include "components/metrics/metrics_log.h"
8 #include "components/metrics/metrics_service_client.h"
9 #include "components/metrics/structured/reporting/structured_metrics_reporting_service.h"
10 #include "components/metrics/structured/structured_metrics_features.h"
11 #include "third_party/metrics_proto/system_profile.pb.h"
12 
13 namespace metrics::structured {
14 
StructuredMetricsService(MetricsServiceClient * client,PrefService * local_state,std::unique_ptr<StructuredMetricsRecorder> recorder)15 StructuredMetricsService::StructuredMetricsService(
16     MetricsServiceClient* client,
17     PrefService* local_state,
18     std::unique_ptr<StructuredMetricsRecorder> recorder)
19     : recorder_(std::move(recorder)),
20       // This service is only enabled if both structured metrics and the service
21       // flags are enabled.
22       structured_metrics_enabled_(
23           base::FeatureList::IsEnabled(metrics::features::kStructuredMetrics) &&
24           base::FeatureList::IsEnabled(kEnabledStructuredMetricsService)),
25       client_(client) {
26   CHECK(client_);
27   CHECK(local_state);
28   CHECK(recorder_);
29 
30   // If the StructuredMetricsService is not enabled then return early. The
31   // recorder needs to be initialized, but not the reporting service or
32   // scheduler.
33   if (!structured_metrics_enabled_) {
34     return;
35   }
36 
37   // Setup the reporting service.
38   const UnsentLogStore::UnsentLogStoreLimits storage_limits =
39       GetLogStoreLimits();
40 
41   reporting_service_ =
42       std::make_unique<reporting::StructuredMetricsReportingService>(
43           client_, local_state, storage_limits);
44 
45   reporting_service_->Initialize();
46 
47   // Setup the log rotation scheduler.
48   base::RepeatingClosure rotate_callback = base::BindRepeating(
49       &StructuredMetricsService::RotateLogsAndSend, weak_factory_.GetWeakPtr());
50   base::RepeatingCallback<base::TimeDelta(void)> get_upload_interval_callback =
51       base::BindRepeating(&StructuredMetricsService::GetUploadTimeInterval,
52                           base::Unretained(this));
53 
54   const bool fast_startup_for_test = client->ShouldStartUpFastForTesting();
55   scheduler_ = std::make_unique<StructuredMetricsScheduler>(
56       rotate_callback, get_upload_interval_callback, fast_startup_for_test);
57 }
58 
~StructuredMetricsService()59 StructuredMetricsService::~StructuredMetricsService() {
60   // Will create a new log for all in-memory events.
61   // With this, we may be able to add a fast path initialization because flushed
62   // events do not need to be loaded.
63   if (recorder_ && recorder_->CanProvideMetrics() &&
64       recorder_->event_storage()->HasEvents()) {
65     Flush(metrics::MetricsLogsEventManager::CreateReason::kServiceShutdown);
66   }
67 }
68 
EnableRecording()69 void StructuredMetricsService::EnableRecording() {
70   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
71   if (!structured_metrics_enabled_) {
72     return;
73   }
74   if (!initialize_complete_) {
75     Initialize();
76   }
77   recorder_->EnableRecording();
78 
79   // Attempt an upload if reporting is also active.
80   if (initialize_complete_ && reporting_active()) {
81     MaybeStartUpload();
82   }
83 }
84 
DisableRecording()85 void StructuredMetricsService::DisableRecording() {
86   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
87   if (!structured_metrics_enabled_) {
88     return;
89   }
90   recorder_->DisableRecording();
91 }
92 
EnableReporting()93 void StructuredMetricsService::EnableReporting() {
94   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
95   if (!structured_metrics_enabled_) {
96     return;
97   }
98   if (!reporting_active()) {
99     scheduler_->Start();
100   }
101   reporting_service_->EnableReporting();
102 
103   // Attempt an upload if recording is also enabled.
104   if (initialize_complete_ && recording_enabled()) {
105     MaybeStartUpload();
106   }
107 }
108 
DisableReporting()109 void StructuredMetricsService::DisableReporting() {
110   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
111   if (!structured_metrics_enabled_) {
112     return;
113   }
114   reporting_service_->DisableReporting();
115   scheduler_->Stop();
116 }
117 
Flush(metrics::MetricsLogsEventManager::CreateReason reason)118 void StructuredMetricsService::Flush(
119     metrics::MetricsLogsEventManager::CreateReason reason) {
120   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
121   // The log should not be built if there aren't any events to log.
122   // This is mirroring a check in RotateLogsAndSend.
123   if (!recorder_->event_storage()->HasEvents()) {
124     return;
125   }
126   BuildAndStoreLog(reason);
127   reporting_service_->log_store()->TrimAndPersistUnsentLogs(true);
128 }
129 
Purge()130 void StructuredMetricsService::Purge() {
131   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
132   if (!structured_metrics_enabled_) {
133     return;
134   }
135   recorder_->Purge();
136   reporting_service_->Purge();
137 }
138 
GetUploadTimeInterval()139 base::TimeDelta StructuredMetricsService::GetUploadTimeInterval() {
140   return base::Seconds(GetUploadInterval());
141 }
142 
RotateLogsAndSend()143 void StructuredMetricsService::RotateLogsAndSend() {
144   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
145 
146   // Verify that the recorder has been initialized and can be providing metrics.
147   // And if it is, then see if there are any events ready to be uploaded.
148   if (!recorder_->CanProvideMetrics() ||
149       !recorder_->event_storage()->HasEvents()) {
150     return;
151   }
152 
153   if (!reporting_service_->log_store()->has_unsent_logs()) {
154     BuildAndStoreLog(metrics::MetricsLogsEventManager::CreateReason::kPeriodic);
155   }
156   reporting_service_->Start();
157   scheduler_->RotationFinished();
158 }
159 
BuildAndStoreLog(metrics::MetricsLogsEventManager::CreateReason reason)160 void StructuredMetricsService::BuildAndStoreLog(
161     metrics::MetricsLogsEventManager::CreateReason reason) {
162   ChromeUserMetricsExtension uma_proto;
163   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
164   InitializeUmaProto(uma_proto);
165   recorder_->ProvideEventMetrics(uma_proto);
166   const std::string serialized_log = SerializeLog(uma_proto);
167   reporting_service_->StoreLog(serialized_log, reason);
168 }
169 
Initialize()170 void StructuredMetricsService::Initialize() {
171   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
172   DCHECK(!initialize_complete_);
173 
174   initialize_complete_ = true;
175 
176   // Notifies the scheduler that it is ready to start creating logs.
177   scheduler_->InitTaskComplete();
178 }
179 
InitializeUmaProto(ChromeUserMetricsExtension & uma_proto)180 void StructuredMetricsService::InitializeUmaProto(
181     ChromeUserMetricsExtension& uma_proto) {
182   const int32_t product = client_->GetProduct();
183   if (product != uma_proto.product()) {
184     uma_proto.set_product(product);
185   }
186 
187   SystemProfileProto* system_profile = uma_proto.mutable_system_profile();
188   metrics::MetricsLog::RecordCoreSystemProfile(client_, system_profile);
189 }
190 
RegisterPrefs(PrefRegistrySimple * registry)191 void StructuredMetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
192   reporting::StructuredMetricsReportingService::RegisterPrefs(registry);
193 }
194 
SetRecorderForTest(std::unique_ptr<StructuredMetricsRecorder> recorder)195 void StructuredMetricsService::SetRecorderForTest(
196     std::unique_ptr<StructuredMetricsRecorder> recorder) {
197   recorder_ = std::move(recorder);
198 }
199 
GetMetricsServiceClient() const200 MetricsServiceClient* StructuredMetricsService::GetMetricsServiceClient()
201     const {
202   return client_;
203 }
204 
ManualUpload()205 void StructuredMetricsService::ManualUpload() {
206   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
207 
208   if (!recorder_->CanProvideMetrics() ||
209       !recorder_->event_storage()->HasEvents()) {
210     return;
211   }
212 
213   if (!reporting_service_->log_store()->has_unsent_logs()) {
214     BuildAndStoreLog(metrics::MetricsLogsEventManager::CreateReason::kUnknown);
215   }
216   reporting_service_->Start();
217 }
218 
MaybeStartUpload()219 void StructuredMetricsService::MaybeStartUpload() {
220   // We do not have any logs to upload. Nothing to do.
221   if (!reporting_service_->log_store()->has_unsent_logs()) {
222     return;
223   }
224 
225   if (initial_upload_started_) {
226     return;
227   }
228 
229   initial_upload_started_ = true;
230 
231   // Starts an upload. If a log is not staged the next log will be staged for
232   // upload.
233   reporting_service_->Start();
234 }
235 
236 // static:
SerializeLog(const ChromeUserMetricsExtension & uma_proto)237 std::string StructuredMetricsService::SerializeLog(
238     const ChromeUserMetricsExtension& uma_proto) {
239   std::string log_data;
240   const bool status = uma_proto.SerializeToString(&log_data);
241   DCHECK(status);
242   return log_data;
243 }
244 
245 // static:
246 UnsentLogStore::UnsentLogStoreLimits
GetLogStoreLimits()247 StructuredMetricsService::GetLogStoreLimits() {
248   return UnsentLogStore::UnsentLogStoreLimits{
249       .min_log_count = static_cast<size_t>(kMinLogQueueCount.Get()),
250       .min_queue_size_bytes = static_cast<size_t>(kMinLogQueueSizeBytes.Get()),
251       .max_log_size_bytes = static_cast<size_t>(kMaxLogSizeBytes.Get()),
252   };
253 }
254 
255 }  // namespace metrics::structured
256