| 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/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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |