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 |