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