| OLD | NEW |
| 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/histogram_macros.h" | 16 #include "base/metrics/histogram_macros.h" |
| 16 #include "base/rand_util.h" | 17 #include "base/rand_util.h" |
| 17 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/time/time.h" | 19 #include "base/time/time.h" |
| 19 #include "components/metrics/metrics_log.h" | 20 #include "components/metrics/metrics_log.h" |
| 20 #include "components/metrics/metrics_log_uploader.h" | 21 #include "components/metrics/metrics_log_uploader.h" |
| 21 #include "components/metrics/metrics_service_client.h" | 22 #include "components/metrics/metrics_service_client.h" |
| 22 #include "components/metrics/proto/ukm/entry.pb.h" | 23 #include "components/metrics/proto/ukm/entry.pb.h" |
| 23 #include "components/metrics/proto/ukm/report.pb.h" | 24 #include "components/metrics/proto/ukm/report.pb.h" |
| 24 #include "components/metrics/proto/ukm/source.pb.h" | 25 #include "components/metrics/proto/ukm/source.pb.h" |
| 25 #include "components/prefs/pref_registry_simple.h" | 26 #include "components/prefs/pref_registry_simple.h" |
| 26 #include "components/prefs/pref_service.h" | 27 #include "components/prefs/pref_service.h" |
| 27 #include "components/ukm/metrics_reporting_scheduler.h" | 28 #include "components/ukm/metrics_reporting_scheduler.h" |
| 28 #include "components/ukm/persisted_logs_metrics_impl.h" | 29 #include "components/ukm/persisted_logs_metrics_impl.h" |
| 29 #include "components/ukm/ukm_entry.h" | 30 #include "components/ukm/ukm_entry.h" |
| 30 #include "components/ukm/ukm_entry_builder.h" | 31 #include "components/ukm/ukm_entry_builder.h" |
| 31 #include "components/ukm/ukm_pref_names.h" | 32 #include "components/ukm/ukm_pref_names.h" |
| 32 #include "components/ukm/ukm_source.h" | 33 #include "components/ukm/ukm_source.h" |
| 33 #include "components/variations/variations_associated_data.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"; | 39 constexpr char kMimeType[] = "application/vnd.chrome.ukm"; |
| 40 | 40 |
| 41 // The UKM server's URL. | 41 // The UKM server's URL. |
| 42 constexpr char kDefaultServerUrl[] = "https://clients4.google.com/ukm"; | 42 constexpr char kDefaultServerUrl[] = "https://clients4.google.com/ukm"; |
| 43 | 43 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 64 // Maximum number of Sources we'll keep in memory before discarding any | 64 // Maximum number of Sources we'll keep in memory before discarding any |
| 65 // new ones being added. | 65 // new ones being added. |
| 66 const size_t kMaxSources = 500; | 66 const size_t kMaxSources = 500; |
| 67 | 67 |
| 68 // Maximum number of Entries we'll keep in memory before discarding any | 68 // Maximum number of Entries we'll keep in memory before discarding any |
| 69 // new ones being added. | 69 // new ones being added. |
| 70 const size_t kMaxEntries = 5000; | 70 const size_t kMaxEntries = 5000; |
| 71 | 71 |
| 72 std::string GetServerUrl() { | 72 std::string GetServerUrl() { |
| 73 std::string server_url = | 73 std::string server_url = |
| 74 variations::GetVariationParamValueByFeature(kUkmFeature, "ServerUrl"); | 74 base::GetFieldTrialParamValueByFeature(kUkmFeature, "ServerUrl"); |
| 75 if (!server_url.empty()) | 75 if (!server_url.empty()) |
| 76 return server_url; | 76 return server_url; |
| 77 return kDefaultServerUrl; | 77 return kDefaultServerUrl; |
| 78 } | 78 } |
| 79 | 79 |
| 80 bool ShouldRecordInitialUrl() { |
| 81 return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, |
| 82 "RecordInitialUrl", false); |
| 83 } |
| 84 |
| 85 bool ShouldRecordSessionId() { |
| 86 return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, "RecordSessionId", |
| 87 false); |
| 88 } |
| 89 |
| 80 // Generates a new client id and stores it in prefs. | 90 // Generates a new client id and stores it in prefs. |
| 81 uint64_t GenerateClientId(PrefService* pref_service) { | 91 uint64_t GenerateClientId(PrefService* pref_service) { |
| 82 uint64_t client_id = 0; | 92 uint64_t client_id = 0; |
| 83 while (!client_id) | 93 while (!client_id) |
| 84 client_id = base::RandUint64(); | 94 client_id = base::RandUint64(); |
| 85 pref_service->SetInt64(prefs::kUkmClientId, client_id); | 95 pref_service->SetInt64(prefs::kUkmClientId, client_id); |
| 96 |
| 97 // Also reset the session id counter. |
| 98 pref_service->SetInteger(prefs::kUkmSessionId, 0); |
| 86 return client_id; | 99 return client_id; |
| 87 } | 100 } |
| 88 | 101 |
| 89 uint64_t LoadOrGenerateClientId(PrefService* pref_service) { | 102 uint64_t LoadOrGenerateClientId(PrefService* pref_service) { |
| 90 uint64_t client_id = pref_service->GetInt64(prefs::kUkmClientId); | 103 uint64_t client_id = pref_service->GetInt64(prefs::kUkmClientId); |
| 91 if (!client_id) | 104 if (!client_id) |
| 92 client_id = GenerateClientId(pref_service); | 105 client_id = GenerateClientId(pref_service); |
| 93 return client_id; | 106 return client_id; |
| 94 } | 107 } |
| 95 | 108 |
| 109 int32_t LoadSessionId(PrefService* pref_service) { |
| 110 int32_t session_id = pref_service->GetInteger(prefs::kUkmSessionId); |
| 111 ++session_id; // increment session id, once per session |
| 112 pref_service->SetInteger(prefs::kUkmSessionId, session_id); |
| 113 return session_id; |
| 114 } |
| 115 |
| 96 enum class DroppedDataReason { | 116 enum class DroppedDataReason { |
| 97 NOT_DROPPED = 0, | 117 NOT_DROPPED = 0, |
| 98 RECORDING_DISABLED = 1, | 118 RECORDING_DISABLED = 1, |
| 99 MAX_HIT = 2, | 119 MAX_HIT = 2, |
| 100 NUM_DROPPED_DATA_REASONS | 120 NUM_DROPPED_DATA_REASONS |
| 101 }; | 121 }; |
| 102 | 122 |
| 103 void RecordDroppedSource(DroppedDataReason reason) { | 123 void RecordDroppedSource(DroppedDataReason reason) { |
| 104 UMA_HISTOGRAM_ENUMERATION( | 124 UMA_HISTOGRAM_ENUMERATION( |
| 105 "UKM.Sources.Dropped", static_cast<int>(reason), | 125 "UKM.Sources.Dropped", static_cast<int>(reason), |
| 106 static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); | 126 static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); |
| 107 } | 127 } |
| 108 | 128 |
| 109 void RecordDroppedEntry(DroppedDataReason reason) { | 129 void RecordDroppedEntry(DroppedDataReason reason) { |
| 110 UMA_HISTOGRAM_ENUMERATION( | 130 UMA_HISTOGRAM_ENUMERATION( |
| 111 "UKM.Entries.Dropped", static_cast<int>(reason), | 131 "UKM.Entries.Dropped", static_cast<int>(reason), |
| 112 static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); | 132 static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); |
| 113 } | 133 } |
| 114 | 134 |
| 115 } // namespace | 135 } // namespace |
| 116 | 136 |
| 117 const base::Feature kUkmFeature = {"Ukm", base::FEATURE_DISABLED_BY_DEFAULT}; | 137 const base::Feature kUkmFeature = {"Ukm", base::FEATURE_DISABLED_BY_DEFAULT}; |
| 118 | 138 |
| 119 UkmService::UkmService(PrefService* pref_service, | 139 UkmService::UkmService(PrefService* pref_service, |
| 120 metrics::MetricsServiceClient* client) | 140 metrics::MetricsServiceClient* client) |
| 121 : pref_service_(pref_service), | 141 : pref_service_(pref_service), |
| 122 recording_enabled_(false), | 142 recording_enabled_(false), |
| 143 client_id_(0), |
| 144 session_id_(0), |
| 123 client_(client), | 145 client_(client), |
| 124 persisted_logs_(std::unique_ptr<ukm::PersistedLogsMetricsImpl>( | 146 persisted_logs_(std::unique_ptr<ukm::PersistedLogsMetricsImpl>( |
| 125 new ukm::PersistedLogsMetricsImpl()), | 147 new ukm::PersistedLogsMetricsImpl()), |
| 126 pref_service, | 148 pref_service, |
| 127 prefs::kUkmPersistedLogs, | 149 prefs::kUkmPersistedLogs, |
| 128 kMinPersistedLogs, | 150 kMinPersistedLogs, |
| 129 kMinPersistedBytes, | 151 kMinPersistedBytes, |
| 130 kMaxLogRetransmitSize), | 152 kMaxLogRetransmitSize), |
| 131 initialize_started_(false), | 153 initialize_started_(false), |
| 132 initialize_complete_(false), | 154 initialize_complete_(false), |
| (...skipping 18 matching lines...) Expand all Loading... |
| 151 for (auto& provider : metrics_providers_) | 173 for (auto& provider : metrics_providers_) |
| 152 provider->Init(); | 174 provider->Init(); |
| 153 } | 175 } |
| 154 | 176 |
| 155 UkmService::~UkmService() { | 177 UkmService::~UkmService() { |
| 156 DisableReporting(); | 178 DisableReporting(); |
| 157 } | 179 } |
| 158 | 180 |
| 159 void UkmService::Initialize() { | 181 void UkmService::Initialize() { |
| 160 DCHECK(thread_checker_.CalledOnValidThread()); | 182 DCHECK(thread_checker_.CalledOnValidThread()); |
| 183 DCHECK(!initialize_started_); |
| 161 DVLOG(1) << "UkmService::Initialize"; | 184 DVLOG(1) << "UkmService::Initialize"; |
| 162 initialize_started_ = true; | 185 initialize_started_ = true; |
| 163 | 186 |
| 164 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 187 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 165 FROM_HERE, | 188 FROM_HERE, |
| 166 base::Bind(&UkmService::StartInitTask, self_ptr_factory_.GetWeakPtr()), | 189 base::Bind(&UkmService::StartInitTask, self_ptr_factory_.GetWeakPtr()), |
| 167 base::TimeDelta::FromSeconds(kInitializationDelaySeconds)); | 190 base::TimeDelta::FromSeconds(kInitializationDelaySeconds)); |
| 168 } | 191 } |
| 169 | 192 |
| 170 void UkmService::EnableRecording() { | 193 void UkmService::EnableRecording() { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 | 260 |
| 238 void UkmService::Purge() { | 261 void UkmService::Purge() { |
| 239 DCHECK(thread_checker_.CalledOnValidThread()); | 262 DCHECK(thread_checker_.CalledOnValidThread()); |
| 240 DVLOG(1) << "UkmService::Purge"; | 263 DVLOG(1) << "UkmService::Purge"; |
| 241 | 264 |
| 242 persisted_logs_.Purge(); | 265 persisted_logs_.Purge(); |
| 243 sources_.clear(); | 266 sources_.clear(); |
| 244 entries_.clear(); | 267 entries_.clear(); |
| 245 } | 268 } |
| 246 | 269 |
| 270 // TODO(bmcquade): rename this to something more generic, like |
| 271 // ResetClientState. Consider resetting all prefs here. |
| 247 void UkmService::ResetClientId() { | 272 void UkmService::ResetClientId() { |
| 248 client_id_ = GenerateClientId(pref_service_); | 273 client_id_ = GenerateClientId(pref_service_); |
| 274 session_id_ = LoadSessionId(pref_service_); |
| 249 } | 275 } |
| 250 | 276 |
| 251 void UkmService::RegisterMetricsProvider( | 277 void UkmService::RegisterMetricsProvider( |
| 252 std::unique_ptr<metrics::MetricsProvider> provider) { | 278 std::unique_ptr<metrics::MetricsProvider> provider) { |
| 253 metrics_providers_.push_back(std::move(provider)); | 279 metrics_providers_.push_back(std::move(provider)); |
| 254 } | 280 } |
| 255 | 281 |
| 256 // static | 282 // static |
| 257 void UkmService::RegisterPrefs(PrefRegistrySimple* registry) { | 283 void UkmService::RegisterPrefs(PrefRegistrySimple* registry) { |
| 258 registry->RegisterInt64Pref(prefs::kUkmClientId, 0); | 284 registry->RegisterInt64Pref(prefs::kUkmClientId, 0); |
| 285 registry->RegisterIntegerPref(prefs::kUkmSessionId, 0); |
| 259 registry->RegisterListPref(prefs::kUkmPersistedLogs); | 286 registry->RegisterListPref(prefs::kUkmPersistedLogs); |
| 260 } | 287 } |
| 261 | 288 |
| 262 void UkmService::StartInitTask() { | 289 void UkmService::StartInitTask() { |
| 263 DCHECK(thread_checker_.CalledOnValidThread()); | 290 DCHECK(thread_checker_.CalledOnValidThread()); |
| 264 DVLOG(1) << "UkmService::StartInitTask"; | 291 DVLOG(1) << "UkmService::StartInitTask"; |
| 265 client_id_ = LoadOrGenerateClientId(pref_service_); | 292 client_id_ = LoadOrGenerateClientId(pref_service_); |
| 293 session_id_ = LoadSessionId(pref_service_); |
| 266 client_->InitializeSystemProfileMetrics(base::Bind( | 294 client_->InitializeSystemProfileMetrics(base::Bind( |
| 267 &UkmService::FinishedInitTask, self_ptr_factory_.GetWeakPtr())); | 295 &UkmService::FinishedInitTask, self_ptr_factory_.GetWeakPtr())); |
| 268 } | 296 } |
| 269 | 297 |
| 270 void UkmService::FinishedInitTask() { | 298 void UkmService::FinishedInitTask() { |
| 271 DCHECK(thread_checker_.CalledOnValidThread()); | 299 DCHECK(thread_checker_.CalledOnValidThread()); |
| 272 DVLOG(1) << "UkmService::FinishedInitTask"; | 300 DVLOG(1) << "UkmService::FinishedInitTask"; |
| 273 initialize_complete_ = true; | 301 initialize_complete_ = true; |
| 274 scheduler_->InitTaskComplete(); | 302 scheduler_->InitTaskComplete(); |
| 275 } | 303 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 287 DCHECK(thread_checker_.CalledOnValidThread()); | 315 DCHECK(thread_checker_.CalledOnValidThread()); |
| 288 DVLOG(1) << "UkmService::BuildAndStoreLog"; | 316 DVLOG(1) << "UkmService::BuildAndStoreLog"; |
| 289 | 317 |
| 290 // Suppress generating a log if we have no new data to include. | 318 // Suppress generating a log if we have no new data to include. |
| 291 // TODO(zhenw): add a histogram here to debug if this case is hitting a lot. | 319 // TODO(zhenw): add a histogram here to debug if this case is hitting a lot. |
| 292 if (sources_.empty() && entries_.empty()) | 320 if (sources_.empty() && entries_.empty()) |
| 293 return; | 321 return; |
| 294 | 322 |
| 295 Report report; | 323 Report report; |
| 296 report.set_client_id(client_id_); | 324 report.set_client_id(client_id_); |
| 325 if (ShouldRecordSessionId()) |
| 326 report.set_session_id(session_id_); |
| 297 | 327 |
| 298 for (const auto& source : sources_) { | 328 for (const auto& source : sources_) { |
| 299 Source* proto_source = report.add_sources(); | 329 Source* proto_source = report.add_sources(); |
| 300 source->PopulateProto(proto_source); | 330 source->PopulateProto(proto_source); |
| 331 if (!ShouldRecordInitialUrl()) |
| 332 proto_source->clear_initial_url(); |
| 301 } | 333 } |
| 302 for (const auto& entry : entries_) { | 334 for (const auto& entry : entries_) { |
| 303 Entry* proto_entry = report.add_entries(); | 335 Entry* proto_entry = report.add_entries(); |
| 304 entry->PopulateProto(proto_entry); | 336 entry->PopulateProto(proto_entry); |
| 305 } | 337 } |
| 306 | 338 |
| 307 UMA_HISTOGRAM_COUNTS_1000("UKM.Sources.SerializedCount", sources_.size()); | 339 UMA_HISTOGRAM_COUNTS_1000("UKM.Sources.SerializedCount", sources_.size()); |
| 308 UMA_HISTOGRAM_COUNTS_1000("UKM.Entries.SerializedCount", entries_.size()); | 340 UMA_HISTOGRAM_COUNTS_1000("UKM.Entries.SerializedCount", entries_.size()); |
| 309 sources_.clear(); | 341 sources_.clear(); |
| 310 entries_.clear(); | 342 entries_.clear(); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 416 return; | 448 return; |
| 417 } | 449 } |
| 418 | 450 |
| 419 // Update the pre-existing source if there is any. This happens when the | 451 // Update the pre-existing source if there is any. This happens when the |
| 420 // initial URL is different from the committed URL for the same source, e.g., | 452 // initial URL is different from the committed URL for the same source, e.g., |
| 421 // when there is redirection. | 453 // when there is redirection. |
| 422 for (auto& source : sources_) { | 454 for (auto& source : sources_) { |
| 423 if (source_id != source->id()) | 455 if (source_id != source->id()) |
| 424 continue; | 456 continue; |
| 425 | 457 |
| 426 source->set_url(url); | 458 source->UpdateUrl(url); |
| 427 return; | 459 return; |
| 428 } | 460 } |
| 429 | 461 |
| 430 if (sources_.size() >= kMaxSources) { | 462 if (sources_.size() >= kMaxSources) { |
| 431 RecordDroppedSource(DroppedDataReason::MAX_HIT); | 463 RecordDroppedSource(DroppedDataReason::MAX_HIT); |
| 432 return; | 464 return; |
| 433 } | 465 } |
| 434 std::unique_ptr<UkmSource> source = base::MakeUnique<UkmSource>(); | 466 std::unique_ptr<UkmSource> source = base::MakeUnique<UkmSource>(); |
| 435 source->set_id(source_id); | 467 source->set_id(source_id); |
| 436 source->set_url(url); | 468 source->set_url(url); |
| 437 sources_.push_back(std::move(source)); | 469 sources_.push_back(std::move(source)); |
| 438 } | 470 } |
| 439 | 471 |
| 440 void UkmService::AddEntry(std::unique_ptr<UkmEntry> entry) { | 472 void UkmService::AddEntry(std::unique_ptr<UkmEntry> entry) { |
| 441 DCHECK(thread_checker_.CalledOnValidThread()); | 473 DCHECK(thread_checker_.CalledOnValidThread()); |
| 442 | 474 |
| 443 if (!recording_enabled_) { | 475 if (!recording_enabled_) { |
| 444 RecordDroppedEntry(DroppedDataReason::RECORDING_DISABLED); | 476 RecordDroppedEntry(DroppedDataReason::RECORDING_DISABLED); |
| 445 return; | 477 return; |
| 446 } | 478 } |
| 447 if (entries_.size() >= kMaxEntries) { | 479 if (entries_.size() >= kMaxEntries) { |
| 448 RecordDroppedEntry(DroppedDataReason::MAX_HIT); | 480 RecordDroppedEntry(DroppedDataReason::MAX_HIT); |
| 449 return; | 481 return; |
| 450 } | 482 } |
| 451 | 483 |
| 452 entries_.push_back(std::move(entry)); | 484 entries_.push_back(std::move(entry)); |
| 453 } | 485 } |
| 454 | 486 |
| 455 } // namespace ukm | 487 } // namespace ukm |
| OLD | NEW |