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