domain_diversity_reporter.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright 2019 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. #include "components/history/metrics/domain_diversity_reporter.h"
  5. #include "base/metrics/histogram_functions.h"
  6. #include "base/task/task_traits.h"
  7. #include "base/threading/thread_task_runner_handle.h"
  8. #include "components/pref_registry/pref_registry_syncable.h"
  9. #include "components/prefs/pref_service.h"
  10. namespace {
  11. // The interval between two successive domain metrics reports.
  12. constexpr base::TimeDelta kDomainDiversityReportingInterval = base::Days(1);
  13. // Pref name for the persistent timestamp of the last report. This pref is
  14. // per local profile but not synced.
  15. constexpr char kDomainDiversityReportingTimestamp[] =
  16. "domain_diversity.last_reporting_timestamp";
  17. } // namespace
  18. DomainDiversityReporter::DomainDiversityReporter(
  19. history::HistoryService* history_service,
  20. PrefService* prefs,
  21. base::Clock* clock)
  22. : history_service_(history_service),
  23. prefs_(prefs),
  24. clock_(clock),
  25. history_service_observer_(this) {
  26. DCHECK_NE(prefs_, nullptr);
  27. DCHECK_NE(history_service_, nullptr);
  28. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  29. base::SequencedTaskRunnerHandle::Get()->PostTask(
  30. FROM_HERE,
  31. base::BindOnce(&DomainDiversityReporter::MaybeComputeDomainMetrics,
  32. weak_ptr_factory_.GetWeakPtr()));
  33. }
  34. DomainDiversityReporter::~DomainDiversityReporter() = default;
  35. // static
  36. void DomainDiversityReporter::RegisterProfilePrefs(
  37. user_prefs::PrefRegistrySyncable* registry) {
  38. registry->RegisterTimePref(kDomainDiversityReportingTimestamp, base::Time());
  39. }
  40. void DomainDiversityReporter::MaybeComputeDomainMetrics() {
  41. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  42. if (history_service_->BackendLoaded()) {
  43. // HistoryService is ready; proceed to start the domain metrics
  44. // computation task.
  45. ComputeDomainMetrics();
  46. }
  47. // Observe history service and start reporting as soon as
  48. // the former is ready.
  49. DCHECK(!history_service_observer_.IsObservingSource(history_service_.get()));
  50. history_service_observer_.Observe(history_service_.get());
  51. }
  52. void DomainDiversityReporter::ComputeDomainMetrics() {
  53. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  54. base::Time time_last_report_triggered =
  55. prefs_->GetTime(kDomainDiversityReportingTimestamp);
  56. base::Time time_current_report_triggered = clock_->Now();
  57. if (time_last_report_triggered < time_current_report_triggered) {
  58. // The lower boundary of all times is set at Unix epoch, since
  59. // LocalMidnight() may fail on times represented by a very small value
  60. // (e.g. Windows epoch).
  61. if (time_last_report_triggered < base::Time::UnixEpoch())
  62. time_last_report_triggered = base::Time::UnixEpoch();
  63. if (time_current_report_triggered < base::Time::UnixEpoch())
  64. time_current_report_triggered = base::Time::UnixEpoch();
  65. // Will only report up to 7 days x 3 results.
  66. int number_of_days_to_report = 7;
  67. // If the last report time is too far back in the past, simply use the
  68. // highest possible value for `number_of_days_to_report` and skip its
  69. // computation. This avoids calling LocalMidnight() on some very old
  70. // timestamp that may cause unexpected behaviors on certain
  71. // platforms/timezones (see https://crbug.com/1048145).
  72. // The beginning and the end of a 7-day period may differ by at most
  73. // 24 * 8 + 1(DST offset) hours; round up to FromDays(9) here.
  74. if (time_current_report_triggered - time_last_report_triggered <
  75. base::Days(number_of_days_to_report + 2)) {
  76. // Compute the number of days that needs to be reported for based on
  77. // the last report time and current time.
  78. base::TimeDelta report_time_range =
  79. time_current_report_triggered.LocalMidnight() -
  80. time_last_report_triggered.LocalMidnight();
  81. // Due to daylight saving time, `report_time_range` may not be a multiple
  82. // of 24 hours. A small time offset is therefore added to
  83. // `report_time_range` so that the resulting time range is guaranteed to
  84. // be at least the correct number of days times 24. The number of days to
  85. // report is capped at 7 days.
  86. number_of_days_to_report =
  87. std::min((report_time_range + base::Hours(4)).InDaysFloored(),
  88. number_of_days_to_report);
  89. }
  90. if (number_of_days_to_report >= 1) {
  91. history_service_->GetDomainDiversity(
  92. /*report_time=*/time_current_report_triggered,
  93. /*number_of_days_to_report=*/number_of_days_to_report,
  94. /*metric_type_bitmask=*/history::kEnableLast1DayMetric |
  95. history::kEnableLast7DayMetric | history::kEnableLast28DayMetric,
  96. base::BindOnce(&DomainDiversityReporter::ReportDomainMetrics,
  97. weak_ptr_factory_.GetWeakPtr(),
  98. time_current_report_triggered),
  99. &cancelable_task_tracker_);
  100. }
  101. }
  102. // The next reporting task is scheduled to run 24 hours later.
  103. base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
  104. FROM_HERE,
  105. base::BindOnce(&DomainDiversityReporter::ComputeDomainMetrics,
  106. weak_ptr_factory_.GetWeakPtr()),
  107. kDomainDiversityReportingInterval);
  108. }
  109. void DomainDiversityReporter::ReportDomainMetrics(
  110. base::Time time_current_report_triggered,
  111. history::DomainDiversityResults result) {
  112. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  113. // An empty DomainDiversityResults indicates that `db_` is null in
  114. // HistoryBackend.
  115. if (result.empty())
  116. return;
  117. for (auto& result_one_day : result) {
  118. base::UmaHistogramCounts1000("History.DomainCount1Day_V2",
  119. result_one_day.one_day_metric.value().count);
  120. base::UmaHistogramCounts1000("History.DomainCount7Day_V2",
  121. result_one_day.seven_day_metric.value().count);
  122. base::UmaHistogramCounts1000(
  123. "History.DomainCount28Day_V2",
  124. result_one_day.twenty_eight_day_metric.value().count);
  125. }
  126. prefs_->SetTime(kDomainDiversityReportingTimestamp,
  127. time_current_report_triggered);
  128. }
  129. void DomainDiversityReporter::OnHistoryServiceLoaded(
  130. history::HistoryService* history_service) {
  131. DCHECK_EQ(history_service, history_service_);
  132. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  133. ComputeDomainMetrics();
  134. }
  135. void DomainDiversityReporter::HistoryServiceBeingDeleted(
  136. history::HistoryService* history_service) {
  137. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  138. history_service_observer_.Reset();
  139. cancelable_task_tracker_.TryCancelAll();
  140. }