1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/ukm/ukm_service.h"
11 #include "base/bind.h"
12 #include "base/feature_list.h"
13 #include "base/metrics/field_trial.h"
14 #include "base/metrics/field_trial_params.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/rand_util.h"
17 #include "base/threading/sequenced_task_runner_handle.h"
18 #include "base/time/time.h"
19 #include "components/metrics/metrics_log.h"
20 #include "components/metrics/metrics_service_client.h"
21 #include "components/prefs/pref_registry_simple.h"
22 #include "components/prefs/pref_service.h"
23 #include "components/ukm/persisted_logs_metrics_impl.h"
24 #include "components/ukm/ukm_pref_names.h"
25 #include "components/ukm/ukm_rotation_scheduler.h"
26 #include "services/metrics/public/cpp/delegating_ukm_recorder.h"
27 #include "third_party/metrics_proto/ukm/report.pb.h"
33 // Generates a new client id and stores it in prefs.
34 uint64_t GenerateAndStoreClientId(PrefService* pref_service) {
35 uint64_t client_id = 0;
37 client_id = base::RandUint64();
38 pref_service->SetInt64(prefs::kUkmClientId, client_id);
40 // Also reset the session id counter.
41 pref_service->SetInteger(prefs::kUkmSessionId, 0);
45 uint64_t LoadOrGenerateAndStoreClientId(PrefService* pref_service) {
46 uint64_t client_id = pref_service->GetInt64(prefs::kUkmClientId);
48 client_id = GenerateAndStoreClientId(pref_service);
52 int32_t LoadAndIncrementSessionId(PrefService* pref_service) {
53 int32_t session_id = pref_service->GetInteger(prefs::kUkmSessionId);
54 ++session_id; // Increment session id, once per session.
55 pref_service->SetInteger(prefs::kUkmSessionId, session_id);
61 UkmService::UkmService(PrefService* pref_service,
62 metrics::MetricsServiceClient* client,
63 bool restrict_to_whitelist_entries)
64 : pref_service_(pref_service),
65 restrict_to_whitelist_entries_(restrict_to_whitelist_entries),
70 reporting_service_(client, pref_service),
71 initialize_started_(false),
72 initialize_complete_(false),
73 self_ptr_factory_(this) {
74 DCHECK(pref_service_);
76 DVLOG(1) << "UkmService::Constructor";
78 reporting_service_.Initialize();
80 base::Closure rotate_callback =
81 base::Bind(&UkmService::RotateLog, self_ptr_factory_.GetWeakPtr());
82 // MetricsServiceClient outlives UkmService, and
83 // MetricsReportingScheduler is tied to the lifetime of |this|.
84 const base::Callback<base::TimeDelta(void)>& get_upload_interval_callback =
85 base::Bind(&metrics::MetricsServiceClient::GetStandardUploadInterval,
86 base::Unretained(client_));
87 scheduler_.reset(new ukm::UkmRotationScheduler(rotate_callback,
88 get_upload_interval_callback));
90 StoreWhitelistedEntries();
92 DelegatingUkmRecorder::Get()->AddDelegate(self_ptr_factory_.GetWeakPtr());
95 UkmService::~UkmService() {
97 DelegatingUkmRecorder::Get()->RemoveDelegate(this);
100 void UkmService::Initialize() {
101 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
102 DCHECK(!initialize_started_);
103 DVLOG(1) << "UkmService::Initialize";
104 initialize_started_ = true;
106 DCHECK_EQ(0, report_count_);
107 client_id_ = LoadOrGenerateAndStoreClientId(pref_service_);
108 session_id_ = LoadAndIncrementSessionId(pref_service_);
109 metrics_providers_.Init();
114 void UkmService::EnableReporting() {
115 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
116 DVLOG(1) << "UkmService::EnableReporting";
117 if (reporting_service_.reporting_active())
120 metrics_providers_.OnRecordingEnabled();
122 if (!initialize_started_)
125 reporting_service_.EnableReporting();
128 void UkmService::DisableReporting() {
129 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
130 DVLOG(1) << "UkmService::DisableReporting";
132 reporting_service_.DisableReporting();
134 metrics_providers_.OnRecordingDisabled();
140 #if defined(OS_ANDROID) || defined(OS_IOS)
141 void UkmService::OnAppEnterForeground() {
142 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
143 DVLOG(1) << "UkmService::OnAppEnterForeground";
145 // If initialize_started_ is false, UKM has not yet been started, so bail. The
146 // scheduler will instead be started via EnableReporting().
147 if (!initialize_started_)
153 void UkmService::OnAppEnterBackground() {
154 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
155 DVLOG(1) << "UkmService::OnAppEnterBackground";
157 if (!initialize_started_)
162 // Give providers a chance to persist ukm data as part of being backgrounded.
163 metrics_providers_.OnAppEnterBackground();
169 void UkmService::Flush() {
170 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
171 if (initialize_complete_)
173 reporting_service_.ukm_log_store()->PersistUnsentLogs();
176 void UkmService::Purge() {
177 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
178 DVLOG(1) << "UkmService::Purge";
179 reporting_service_.ukm_log_store()->Purge();
180 UkmRecorderImpl::Purge();
183 void UkmService::ResetClientState(ResetReason reason) {
184 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
186 UMA_HISTOGRAM_ENUMERATION("UKM.ResetReason", reason);
188 client_id_ = GenerateAndStoreClientId(pref_service_);
189 // Note: the session_id has already been cleared by GenerateAndStoreClientId.
190 session_id_ = LoadAndIncrementSessionId(pref_service_);
194 void UkmService::RegisterMetricsProvider(
195 std::unique_ptr<metrics::MetricsProvider> provider) {
196 metrics_providers_.RegisterMetricsProvider(std::move(provider));
200 void UkmService::RegisterPrefs(PrefRegistrySimple* registry) {
201 registry->RegisterInt64Pref(prefs::kUkmClientId, 0);
202 registry->RegisterIntegerPref(prefs::kUkmSessionId, 0);
203 UkmReportingService::RegisterPrefs(registry);
206 void UkmService::StartInitTask() {
207 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
208 DVLOG(1) << "UkmService::StartInitTask";
209 metrics_providers_.AsyncInit(base::Bind(&UkmService::FinishedInitTask,
210 self_ptr_factory_.GetWeakPtr()));
213 void UkmService::FinishedInitTask() {
214 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
215 DVLOG(1) << "UkmService::FinishedInitTask";
216 initialize_complete_ = true;
217 scheduler_->InitTaskComplete();
220 void UkmService::RotateLog() {
221 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
222 DVLOG(1) << "UkmService::RotateLog";
223 if (!reporting_service_.ukm_log_store()->has_unsent_logs())
225 reporting_service_.Start();
226 scheduler_->RotationFinished();
229 void UkmService::BuildAndStoreLog() {
230 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
231 DVLOG(1) << "UkmService::BuildAndStoreLog";
233 // Suppress generating a log if we have no new data to include.
234 bool empty = sources().empty() && entries().empty();
235 UMA_HISTOGRAM_BOOLEAN("UKM.BuildAndStoreLogIsEmpty", empty);
240 report.set_client_id(client_id_);
241 report.set_session_id(session_id_);
242 report.set_report_id(++report_count_);
244 StoreRecordingsInReport(&report);
246 metrics::MetricsLog::RecordCoreSystemProfile(client_,
247 report.mutable_system_profile());
249 metrics_providers_.ProvideSystemProfileMetrics(
250 report.mutable_system_profile());
252 std::string serialized_log;
253 report.SerializeToString(&serialized_log);
254 reporting_service_.ukm_log_store()->StoreLog(serialized_log);
257 bool UkmService::ShouldRestrictToWhitelistedEntries() const {
258 return restrict_to_whitelist_entries_;