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 GenerateClientId(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 LoadOrGenerateClientId(PrefService* pref_service) {
46 uint64_t client_id = pref_service->GetInt64(prefs::kUkmClientId);
48 client_id = GenerateClientId(pref_service);
52 int32_t LoadSessionId(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_ = LoadOrGenerateClientId(pref_service_);
108 session_id_ = LoadSessionId(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 // TODO(bmcquade): rename this to something more generic, like
184 // ResetClientState. Consider resetting all prefs here.
185 void UkmService::ResetClientId() {
186 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
187 client_id_ = GenerateClientId(pref_service_);
188 session_id_ = LoadSessionId(pref_service_);
192 void UkmService::RegisterMetricsProvider(
193 std::unique_ptr<metrics::MetricsProvider> provider) {
194 metrics_providers_.RegisterMetricsProvider(std::move(provider));
198 void UkmService::RegisterPrefs(PrefRegistrySimple* registry) {
199 registry->RegisterInt64Pref(prefs::kUkmClientId, 0);
200 registry->RegisterIntegerPref(prefs::kUkmSessionId, 0);
201 UkmReportingService::RegisterPrefs(registry);
204 void UkmService::StartInitTask() {
205 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
206 DVLOG(1) << "UkmService::StartInitTask";
207 metrics_providers_.AsyncInit(base::Bind(&UkmService::FinishedInitTask,
208 self_ptr_factory_.GetWeakPtr()));
211 void UkmService::FinishedInitTask() {
212 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
213 DVLOG(1) << "UkmService::FinishedInitTask";
214 initialize_complete_ = true;
215 scheduler_->InitTaskComplete();
218 void UkmService::RotateLog() {
219 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
220 DVLOG(1) << "UkmService::RotateLog";
221 if (!reporting_service_.ukm_log_store()->has_unsent_logs())
223 reporting_service_.Start();
224 scheduler_->RotationFinished();
227 void UkmService::BuildAndStoreLog() {
228 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
229 DVLOG(1) << "UkmService::BuildAndStoreLog";
231 // Suppress generating a log if we have no new data to include.
232 // TODO(zhenw): add a histogram here to debug if this case is hitting a lot.
233 if (sources().empty() && entries().empty())
237 report.set_client_id(client_id_);
238 report.set_session_id(session_id_);
239 report.set_report_id(++report_count_);
241 StoreRecordingsInReport(&report);
243 metrics::MetricsLog::RecordCoreSystemProfile(client_,
244 report.mutable_system_profile());
246 metrics_providers_.ProvideSystemProfileMetrics(
247 report.mutable_system_profile());
249 std::string serialized_log;
250 report.SerializeToString(&serialized_log);
251 reporting_service_.ukm_log_store()->StoreLog(serialized_log);
254 bool UkmService::ShouldRestrictToWhitelistedEntries() const {
255 return restrict_to_whitelist_entries_;