Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(743)

Side by Side Diff: components/ukm/ukm_service.cc

Issue 2770853002: Create Ukm ReportingService implementation. (Closed)
Patch Set: Fix register prefs Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/ukm/ukm_service.h" 5 #include "components/ukm/ukm_service.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/feature_list.h" 12 #include "base/feature_list.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/metrics/field_trial.h" 14 #include "base/metrics/field_trial.h"
15 #include "base/metrics/field_trial_params.h" 15 #include "base/metrics/field_trial_params.h"
16 #include "base/metrics/histogram_macros.h" 16 #include "base/metrics/histogram_macros.h"
17 #include "base/rand_util.h" 17 #include "base/rand_util.h"
18 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
19 #include "base/time/time.h" 19 #include "base/time/time.h"
20 #include "components/metrics/metrics_log.h" 20 #include "components/metrics/metrics_log.h"
21 #include "components/metrics/metrics_log_uploader.h" 21 #include "components/metrics/metrics_log_uploader.h"
22 #include "components/metrics/metrics_service_client.h" 22 #include "components/metrics/metrics_service_client.h"
23 #include "components/metrics/proto/ukm/entry.pb.h" 23 #include "components/metrics/proto/ukm/entry.pb.h"
24 #include "components/metrics/proto/ukm/report.pb.h" 24 #include "components/metrics/proto/ukm/report.pb.h"
25 #include "components/metrics/proto/ukm/source.pb.h" 25 #include "components/metrics/proto/ukm/source.pb.h"
26 #include "components/prefs/pref_registry_simple.h" 26 #include "components/prefs/pref_registry_simple.h"
27 #include "components/prefs/pref_service.h" 27 #include "components/prefs/pref_service.h"
28 #include "components/ukm/metrics_reporting_scheduler.h"
29 #include "components/ukm/persisted_logs_metrics_impl.h" 28 #include "components/ukm/persisted_logs_metrics_impl.h"
30 #include "components/ukm/ukm_entry.h" 29 #include "components/ukm/ukm_entry.h"
31 #include "components/ukm/ukm_entry_builder.h" 30 #include "components/ukm/ukm_entry_builder.h"
32 #include "components/ukm/ukm_pref_names.h" 31 #include "components/ukm/ukm_pref_names.h"
32 #include "components/ukm/ukm_rotation_scheduler.h"
33 #include "components/ukm/ukm_source.h" 33 #include "components/ukm/ukm_source.h"
34 34
35 namespace ukm { 35 namespace ukm {
36 36
37 namespace { 37 namespace {
38 38
39 constexpr char kMimeType[] = "application/vnd.chrome.ukm";
40
41 // The delay, in seconds, after starting recording before doing expensive 39 // The delay, in seconds, after starting recording before doing expensive
42 // initialization work. 40 // initialization work.
43 constexpr int kInitializationDelaySeconds = 5; 41 constexpr int kInitializationDelaySeconds = 5;
44 42
45 // The number of UKM logs that will be stored in PersistedLogs before logs
46 // start being dropped.
47 constexpr int kMinPersistedLogs = 8;
48
49 // The number of bytes UKM logs that will be stored in PersistedLogs before
50 // logs start being dropped.
51 // This ensures that a reasonable amount of history will be stored even if there
52 // is a long series of very small logs.
53 constexpr int kMinPersistedBytes = 300000;
54
55 // If an upload fails, and the transmission was over this byte count, then we
56 // will discard the log, and not try to retransmit it. We also don't persist
57 // the log to the prefs for transmission during the next chrome session if this
58 // limit is exceeded.
59 constexpr size_t kMaxLogRetransmitSize = 100 * 1024;
60
61 // Gets the UKM Server URL.
62 std::string GetServerUrl() {
63 constexpr char kDefaultServerUrl[] = "https://clients4.google.com/ukm";
64 std::string server_url =
65 base::GetFieldTrialParamValueByFeature(kUkmFeature, "ServerUrl");
66 if (!server_url.empty())
67 return server_url;
68 return kDefaultServerUrl;
69 }
70
71 // Gets the maximum number of Sources we'll keep in memory before discarding any 43 // Gets the maximum number of Sources we'll keep in memory before discarding any
72 // new ones being added. 44 // new ones being added.
73 size_t GetMaxSources() { 45 size_t GetMaxSources() {
74 constexpr size_t kDefaultMaxSources = 500; 46 constexpr size_t kDefaultMaxSources = 500;
75 return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt( 47 return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt(
76 kUkmFeature, "MaxSources", kDefaultMaxSources)); 48 kUkmFeature, "MaxSources", kDefaultMaxSources));
77 } 49 }
78 50
79 // Gets the maximum number of Entries we'll keep in memory before discarding any 51 // Gets the maximum number of Entries we'll keep in memory before discarding any
80 // new ones being added. 52 // new ones being added.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 117
146 const base::Feature kUkmFeature = {"Ukm", base::FEATURE_DISABLED_BY_DEFAULT}; 118 const base::Feature kUkmFeature = {"Ukm", base::FEATURE_DISABLED_BY_DEFAULT};
147 119
148 UkmService::UkmService(PrefService* pref_service, 120 UkmService::UkmService(PrefService* pref_service,
149 metrics::MetricsServiceClient* client) 121 metrics::MetricsServiceClient* client)
150 : pref_service_(pref_service), 122 : pref_service_(pref_service),
151 recording_enabled_(false), 123 recording_enabled_(false),
152 client_id_(0), 124 client_id_(0),
153 session_id_(0), 125 session_id_(0),
154 client_(client), 126 client_(client),
155 persisted_logs_(std::unique_ptr<ukm::PersistedLogsMetricsImpl>( 127 reporting_service_(client, pref_service),
156 new ukm::PersistedLogsMetricsImpl()),
157 pref_service,
158 prefs::kUkmPersistedLogs,
159 kMinPersistedLogs,
160 kMinPersistedBytes,
161 kMaxLogRetransmitSize),
162 initialize_started_(false), 128 initialize_started_(false),
163 initialize_complete_(false), 129 initialize_complete_(false),
164 log_upload_in_progress_(false),
165 self_ptr_factory_(this) { 130 self_ptr_factory_(this) {
166 DCHECK(pref_service_); 131 DCHECK(pref_service_);
167 DCHECK(client_); 132 DCHECK(client_);
168 DVLOG(1) << "UkmService::Constructor"; 133 DVLOG(1) << "UkmService::Constructor";
169 134
170 persisted_logs_.LoadPersistedUnsentLogs(); 135 reporting_service_.Initialize();
171 136
172 base::Closure rotate_callback = 137 base::Closure rotate_callback =
173 base::Bind(&UkmService::RotateLog, self_ptr_factory_.GetWeakPtr()); 138 base::Bind(&UkmService::RotateLog, self_ptr_factory_.GetWeakPtr());
174 // MetricsServiceClient outlives UkmService, and 139 // MetricsServiceClient outlives UkmService, and
175 // MetricsReportingScheduler is tied to the lifetime of |this|. 140 // MetricsReportingScheduler is tied to the lifetime of |this|.
176 const base::Callback<base::TimeDelta(void)>& get_upload_interval_callback = 141 const base::Callback<base::TimeDelta(void)>& get_upload_interval_callback =
177 base::Bind(&metrics::MetricsServiceClient::GetStandardUploadInterval, 142 base::Bind(&metrics::MetricsServiceClient::GetStandardUploadInterval,
178 base::Unretained(client_)); 143 base::Unretained(client_));
179 scheduler_.reset(new ukm::MetricsReportingScheduler( 144 scheduler_.reset(new ukm::UkmRotationScheduler(rotate_callback,
180 rotate_callback, get_upload_interval_callback)); 145 get_upload_interval_callback));
181 146
182 for (auto& provider : metrics_providers_) 147 for (auto& provider : metrics_providers_)
183 provider->Init(); 148 provider->Init();
184 } 149 }
185 150
186 UkmService::~UkmService() { 151 UkmService::~UkmService() {
187 DisableReporting(); 152 DisableReporting();
188 } 153 }
189 154
190 void UkmService::Initialize() { 155 void UkmService::Initialize() {
(...skipping 12 matching lines...) Expand all
203 recording_enabled_ = true; 168 recording_enabled_ = true;
204 } 169 }
205 170
206 void UkmService::DisableRecording() { 171 void UkmService::DisableRecording() {
207 recording_enabled_ = false; 172 recording_enabled_ = false;
208 } 173 }
209 174
210 void UkmService::EnableReporting() { 175 void UkmService::EnableReporting() {
211 DCHECK(thread_checker_.CalledOnValidThread()); 176 DCHECK(thread_checker_.CalledOnValidThread());
212 DVLOG(1) << "UkmService::EnableReporting"; 177 DVLOG(1) << "UkmService::EnableReporting";
178 if (reporting_service_.reporting_active())
179 return;
213 180
214 for (auto& provider : metrics_providers_) 181 for (auto& provider : metrics_providers_)
215 provider->OnRecordingEnabled(); 182 provider->OnRecordingEnabled();
216 183
217 if (!initialize_started_) 184 if (!initialize_started_)
218 Initialize(); 185 Initialize();
219 scheduler_->Start(); 186 scheduler_->Start();
187 reporting_service_.EnableReporting();
220 } 188 }
221 189
222 void UkmService::DisableReporting() { 190 void UkmService::DisableReporting() {
223 DCHECK(thread_checker_.CalledOnValidThread()); 191 DCHECK(thread_checker_.CalledOnValidThread());
224 DVLOG(1) << "UkmService::DisableReporting"; 192 DVLOG(1) << "UkmService::DisableReporting";
225 193
194 reporting_service_.DisableReporting();
195
226 for (auto& provider : metrics_providers_) 196 for (auto& provider : metrics_providers_)
227 provider->OnRecordingDisabled(); 197 provider->OnRecordingDisabled();
228 198
229 scheduler_->Stop(); 199 scheduler_->Stop();
230 Flush(); 200 Flush();
231 } 201 }
232 202
233 #if defined(OS_ANDROID) || defined(OS_IOS) 203 #if defined(OS_ANDROID) || defined(OS_IOS)
234 void UkmService::OnAppEnterForeground() { 204 void UkmService::OnAppEnterForeground() {
235 DCHECK(thread_checker_.CalledOnValidThread()); 205 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 21 matching lines...) Expand all
257 provider->OnAppEnterBackground(); 227 provider->OnAppEnterBackground();
258 228
259 Flush(); 229 Flush();
260 } 230 }
261 #endif 231 #endif
262 232
263 void UkmService::Flush() { 233 void UkmService::Flush() {
264 DCHECK(thread_checker_.CalledOnValidThread()); 234 DCHECK(thread_checker_.CalledOnValidThread());
265 if (initialize_complete_) 235 if (initialize_complete_)
266 BuildAndStoreLog(); 236 BuildAndStoreLog();
267 persisted_logs_.PersistUnsentLogs(); 237 reporting_service_.ukm_log_store()->PersistUnsentLogs();
268 } 238 }
269 239
270 void UkmService::Purge() { 240 void UkmService::Purge() {
271 DCHECK(thread_checker_.CalledOnValidThread()); 241 DCHECK(thread_checker_.CalledOnValidThread());
272 DVLOG(1) << "UkmService::Purge"; 242 DVLOG(1) << "UkmService::Purge";
273 243 reporting_service_.ukm_log_store()->Purge();
274 persisted_logs_.Purge();
275 sources_.clear(); 244 sources_.clear();
276 entries_.clear(); 245 entries_.clear();
277 } 246 }
278 247
279 // TODO(bmcquade): rename this to something more generic, like 248 // TODO(bmcquade): rename this to something more generic, like
280 // ResetClientState. Consider resetting all prefs here. 249 // ResetClientState. Consider resetting all prefs here.
281 void UkmService::ResetClientId() { 250 void UkmService::ResetClientId() {
282 client_id_ = GenerateClientId(pref_service_); 251 client_id_ = GenerateClientId(pref_service_);
283 session_id_ = LoadSessionId(pref_service_); 252 session_id_ = LoadSessionId(pref_service_);
284 } 253 }
285 254
286 void UkmService::RegisterMetricsProvider( 255 void UkmService::RegisterMetricsProvider(
287 std::unique_ptr<metrics::MetricsProvider> provider) { 256 std::unique_ptr<metrics::MetricsProvider> provider) {
288 metrics_providers_.push_back(std::move(provider)); 257 metrics_providers_.push_back(std::move(provider));
289 } 258 }
290 259
291 // static 260 // static
292 void UkmService::RegisterPrefs(PrefRegistrySimple* registry) { 261 void UkmService::RegisterPrefs(PrefRegistrySimple* registry) {
293 registry->RegisterInt64Pref(prefs::kUkmClientId, 0); 262 registry->RegisterInt64Pref(prefs::kUkmClientId, 0);
294 registry->RegisterIntegerPref(prefs::kUkmSessionId, 0); 263 registry->RegisterIntegerPref(prefs::kUkmSessionId, 0);
295 registry->RegisterListPref(prefs::kUkmPersistedLogs); 264 UkmReportingService::RegisterPrefs(registry);
296 } 265 }
297 266
298 void UkmService::StartInitTask() { 267 void UkmService::StartInitTask() {
299 DCHECK(thread_checker_.CalledOnValidThread()); 268 DCHECK(thread_checker_.CalledOnValidThread());
300 DVLOG(1) << "UkmService::StartInitTask"; 269 DVLOG(1) << "UkmService::StartInitTask";
301 client_id_ = LoadOrGenerateClientId(pref_service_); 270 client_id_ = LoadOrGenerateClientId(pref_service_);
302 session_id_ = LoadSessionId(pref_service_); 271 session_id_ = LoadSessionId(pref_service_);
303 client_->InitializeSystemProfileMetrics(base::Bind( 272 client_->InitializeSystemProfileMetrics(base::Bind(
304 &UkmService::FinishedInitTask, self_ptr_factory_.GetWeakPtr())); 273 &UkmService::FinishedInitTask, self_ptr_factory_.GetWeakPtr()));
305 } 274 }
306 275
307 void UkmService::FinishedInitTask() { 276 void UkmService::FinishedInitTask() {
308 DCHECK(thread_checker_.CalledOnValidThread()); 277 DCHECK(thread_checker_.CalledOnValidThread());
309 DVLOG(1) << "UkmService::FinishedInitTask"; 278 DVLOG(1) << "UkmService::FinishedInitTask";
310 initialize_complete_ = true; 279 initialize_complete_ = true;
311 scheduler_->InitTaskComplete(); 280 scheduler_->InitTaskComplete();
312 } 281 }
313 282
314 void UkmService::RotateLog() { 283 void UkmService::RotateLog() {
315 DCHECK(thread_checker_.CalledOnValidThread()); 284 DCHECK(thread_checker_.CalledOnValidThread());
316 DCHECK(!log_upload_in_progress_);
317 DVLOG(1) << "UkmService::RotateLog"; 285 DVLOG(1) << "UkmService::RotateLog";
318 if (!persisted_logs_.has_unsent_logs()) 286 if (!reporting_service_.ukm_log_store()->has_unsent_logs())
319 BuildAndStoreLog(); 287 BuildAndStoreLog();
320 StartScheduledUpload(); 288 reporting_service_.Start();
321 } 289 }
322 290
323 void UkmService::BuildAndStoreLog() { 291 void UkmService::BuildAndStoreLog() {
324 DCHECK(thread_checker_.CalledOnValidThread()); 292 DCHECK(thread_checker_.CalledOnValidThread());
325 DVLOG(1) << "UkmService::BuildAndStoreLog"; 293 DVLOG(1) << "UkmService::BuildAndStoreLog";
326 294
327 // Suppress generating a log if we have no new data to include. 295 // Suppress generating a log if we have no new data to include.
328 // TODO(zhenw): add a histogram here to debug if this case is hitting a lot. 296 // TODO(zhenw): add a histogram here to debug if this case is hitting a lot.
329 if (sources_.empty() && entries_.empty()) 297 if (sources_.empty() && entries_.empty())
330 return; 298 return;
(...skipping 21 matching lines...) Expand all
352 320
353 metrics::MetricsLog::RecordCoreSystemProfile(client_, 321 metrics::MetricsLog::RecordCoreSystemProfile(client_,
354 report.mutable_system_profile()); 322 report.mutable_system_profile());
355 323
356 for (auto& provider : metrics_providers_) { 324 for (auto& provider : metrics_providers_) {
357 provider->ProvideSystemProfileMetrics(report.mutable_system_profile()); 325 provider->ProvideSystemProfileMetrics(report.mutable_system_profile());
358 } 326 }
359 327
360 std::string serialized_log; 328 std::string serialized_log;
361 report.SerializeToString(&serialized_log); 329 report.SerializeToString(&serialized_log);
362 persisted_logs_.StoreLog(serialized_log); 330 reporting_service_.ukm_log_store()->StoreLog(serialized_log);
363 }
364
365 void UkmService::StartScheduledUpload() {
366 DCHECK(thread_checker_.CalledOnValidThread());
367 DCHECK(!log_upload_in_progress_);
368 if (!persisted_logs_.has_unsent_logs()) {
369 // No logs to send, so early out and schedule the next rotation.
370 scheduler_->UploadFinished(true, /* has_unsent_logs */ false);
371 return;
372 }
373 if (!persisted_logs_.has_staged_log())
374 persisted_logs_.StageNextLog();
375 // TODO(holte): Handle data usage on cellular, etc.
376 if (!log_uploader_) {
377 log_uploader_ = client_->CreateUploader(
378 GetServerUrl(), kMimeType, metrics::MetricsLogUploader::UKM,
379 base::Bind(&UkmService::OnLogUploadComplete,
380 self_ptr_factory_.GetWeakPtr()));
381 }
382 log_upload_in_progress_ = true;
383
384 const std::string hash =
385 base::HexEncode(persisted_logs_.staged_log_hash().data(),
386 persisted_logs_.staged_log_hash().size());
387 log_uploader_->UploadLog(persisted_logs_.staged_log(), hash);
388 }
389
390 void UkmService::OnLogUploadComplete(int response_code) {
391 DCHECK(thread_checker_.CalledOnValidThread());
392 DCHECK(log_upload_in_progress_);
393 DVLOG(1) << "UkmService::OnLogUploadComplete";
394 log_upload_in_progress_ = false;
395
396 UMA_HISTOGRAM_SPARSE_SLOWLY("UKM.Upload.ResponseCode", response_code);
397
398 bool upload_succeeded = response_code == 200;
399
400 // Staged log may have been deleted by Purge already, otherwise we may
401 // remove it from the log store here.
402 if (persisted_logs_.has_staged_log()) {
403 // Provide boolean for error recovery (allow us to ignore response_code).
404 bool discard_log = false;
405 const size_t log_size_bytes = persisted_logs_.staged_log().length();
406 if (upload_succeeded) {
407 UMA_HISTOGRAM_COUNTS_10000("UKM.LogSize.OnSuccess",
408 log_size_bytes / 1024);
409 } else if (response_code == 400) {
410 // Bad syntax. Retransmission won't work.
411 discard_log = true;
412 }
413
414 if (upload_succeeded || discard_log) {
415 persisted_logs_.DiscardStagedLog();
416 // Store the updated list to disk now that the removed log is uploaded.
417 persisted_logs_.PersistUnsentLogs();
418 }
419 }
420
421 // Error 400 indicates a problem with the log, not with the server, so
422 // don't consider that a sign that the server is in trouble.
423 bool server_is_healthy = upload_succeeded || response_code == 400;
424 scheduler_->UploadFinished(server_is_healthy,
425 persisted_logs_.has_unsent_logs());
426 } 331 }
427 332
428 // static 333 // static
429 int32_t UkmService::GetNewSourceID() { 334 int32_t UkmService::GetNewSourceID() {
430 static int32_t next_source_id = 0; 335 static int32_t next_source_id = 0;
431 return next_source_id++; 336 return next_source_id++;
432 } 337 }
433 338
434 std::unique_ptr<UkmEntryBuilder> UkmService::GetEntryBuilder( 339 std::unique_ptr<UkmEntryBuilder> UkmService::GetEntryBuilder(
435 int32_t source_id, 340 int32_t source_id,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 } 379 }
475 if (entries_.size() >= GetMaxEntries()) { 380 if (entries_.size() >= GetMaxEntries()) {
476 RecordDroppedEntry(DroppedDataReason::MAX_HIT); 381 RecordDroppedEntry(DroppedDataReason::MAX_HIT);
477 return; 382 return;
478 } 383 }
479 384
480 entries_.push_back(std::move(entry)); 385 entries_.push_back(std::move(entry));
481 } 386 }
482 387
483 } // namespace ukm 388 } // namespace ukm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698