Upload upstream chromium 71.0.3578.0
[platform/framework/web/chromium-efl.git] / components / ukm / ukm_service.cc
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.
4
5 #include "components/ukm/ukm_service.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
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"
28
29 namespace ukm {
30
31 namespace {
32
33 // Generates a new client id and stores it in prefs.
34 uint64_t GenerateClientId(PrefService* pref_service) {
35   uint64_t client_id = 0;
36   while (!client_id)
37     client_id = base::RandUint64();
38   pref_service->SetInt64(prefs::kUkmClientId, client_id);
39
40   // Also reset the session id counter.
41   pref_service->SetInteger(prefs::kUkmSessionId, 0);
42   return client_id;
43 }
44
45 uint64_t LoadOrGenerateClientId(PrefService* pref_service) {
46   uint64_t client_id = pref_service->GetInt64(prefs::kUkmClientId);
47   if (!client_id)
48     client_id = GenerateClientId(pref_service);
49   return client_id;
50 }
51
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);
56   return session_id;
57 }
58
59 }  // namespace
60
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),
66       client_id_(0),
67       session_id_(0),
68       report_count_(0),
69       client_(client),
70       reporting_service_(client, pref_service),
71       initialize_started_(false),
72       initialize_complete_(false),
73       self_ptr_factory_(this) {
74   DCHECK(pref_service_);
75   DCHECK(client_);
76   DVLOG(1) << "UkmService::Constructor";
77
78   reporting_service_.Initialize();
79
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));
89
90   StoreWhitelistedEntries();
91
92   DelegatingUkmRecorder::Get()->AddDelegate(self_ptr_factory_.GetWeakPtr());
93 }
94
95 UkmService::~UkmService() {
96   DisableReporting();
97   DelegatingUkmRecorder::Get()->RemoveDelegate(this);
98 }
99
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;
105
106   DCHECK_EQ(0, report_count_);
107   client_id_ = LoadOrGenerateClientId(pref_service_);
108   session_id_ = LoadSessionId(pref_service_);
109   metrics_providers_.Init();
110
111   StartInitTask();
112 }
113
114 void UkmService::EnableReporting() {
115   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
116   DVLOG(1) << "UkmService::EnableReporting";
117   if (reporting_service_.reporting_active())
118     return;
119
120   metrics_providers_.OnRecordingEnabled();
121
122   if (!initialize_started_)
123     Initialize();
124   scheduler_->Start();
125   reporting_service_.EnableReporting();
126 }
127
128 void UkmService::DisableReporting() {
129   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
130   DVLOG(1) << "UkmService::DisableReporting";
131
132   reporting_service_.DisableReporting();
133
134   metrics_providers_.OnRecordingDisabled();
135
136   scheduler_->Stop();
137   Flush();
138 }
139
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";
144
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_)
148     return;
149
150   scheduler_->Start();
151 }
152
153 void UkmService::OnAppEnterBackground() {
154   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
155   DVLOG(1) << "UkmService::OnAppEnterBackground";
156
157   if (!initialize_started_)
158     return;
159
160   scheduler_->Stop();
161
162   // Give providers a chance to persist ukm data as part of being backgrounded.
163   metrics_providers_.OnAppEnterBackground();
164
165   Flush();
166 }
167 #endif
168
169 void UkmService::Flush() {
170   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
171   if (initialize_complete_)
172     BuildAndStoreLog();
173   reporting_service_.ukm_log_store()->PersistUnsentLogs();
174 }
175
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();
181 }
182
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_);
189   report_count_ = 0;
190 }
191
192 void UkmService::RegisterMetricsProvider(
193     std::unique_ptr<metrics::MetricsProvider> provider) {
194   metrics_providers_.RegisterMetricsProvider(std::move(provider));
195 }
196
197 // static
198 void UkmService::RegisterPrefs(PrefRegistrySimple* registry) {
199   registry->RegisterInt64Pref(prefs::kUkmClientId, 0);
200   registry->RegisterIntegerPref(prefs::kUkmSessionId, 0);
201   UkmReportingService::RegisterPrefs(registry);
202 }
203
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()));
209 }
210
211 void UkmService::FinishedInitTask() {
212   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
213   DVLOG(1) << "UkmService::FinishedInitTask";
214   initialize_complete_ = true;
215   scheduler_->InitTaskComplete();
216 }
217
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())
222     BuildAndStoreLog();
223   reporting_service_.Start();
224   scheduler_->RotationFinished();
225 }
226
227 void UkmService::BuildAndStoreLog() {
228   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
229   DVLOG(1) << "UkmService::BuildAndStoreLog";
230
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())
234     return;
235
236   Report report;
237   report.set_client_id(client_id_);
238   report.set_session_id(session_id_);
239   report.set_report_id(++report_count_);
240
241   StoreRecordingsInReport(&report);
242
243   metrics::MetricsLog::RecordCoreSystemProfile(client_,
244                                                report.mutable_system_profile());
245
246   metrics_providers_.ProvideSystemProfileMetrics(
247       report.mutable_system_profile());
248
249   std::string serialized_log;
250   report.SerializeToString(&serialized_log);
251   reporting_service_.ukm_log_store()->StoreLog(serialized_log);
252 }
253
254 bool UkmService::ShouldRestrictToWhitelistedEntries() const {
255   return restrict_to_whitelist_entries_;
256 }
257
258 }  // namespace ukm