diff --git a/browser/BUILD.gn b/browser/BUILD.gn index 8b293ac30cd..13887fd927b 100644 --- a/browser/BUILD.gn +++ b/browser/BUILD.gn @@ -144,6 +144,7 @@ source_set("browser_process") { "//brave/components/resources", "//brave/components/services:brave_content_manifest_overlays", "//brave/components/speedreader:buildflags", + "//brave/components/weekly_storage", "//brave/services/network/public/cpp", "//chrome/common", "//components/autofill/core/common", diff --git a/browser/brave_profile_prefs.cc b/browser/brave_profile_prefs.cc index 720ce1f1968..088452a65b8 100644 --- a/browser/brave_profile_prefs.cc +++ b/browser/brave_profile_prefs.cc @@ -6,6 +6,7 @@ #include "brave/browser/brave_profile_prefs.h" #include "brave/browser/themes/brave_dark_mode_utils.h" +#include "brave/browser/ui/omnibox/brave_omnibox_client_impl.h" #include "brave/common/brave_wallet_constants.h" #include "brave/common/pref_names.h" #include "brave/components/binance/browser/buildflags/buildflags.h" @@ -229,6 +230,10 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { speedreader::SpeedreaderService::RegisterPrefs(registry); #endif +#if !defined(OS_ANDROID) + BraveOmniboxClientImpl::RegisterPrefs(registry); +#endif + RegisterProfilePrefsForMigration(registry); } diff --git a/browser/p3a/p3a_core_metrics.cc b/browser/p3a/p3a_core_metrics.cc index 3d4c0b9a648..9befca08bf6 100644 --- a/browser/p3a/p3a_core_metrics.cc +++ b/browser/p3a/p3a_core_metrics.cc @@ -5,7 +5,6 @@ #include "brave/browser/p3a/p3a_core_metrics.h" -#include #include #include "base/metrics/histogram_macros.h" @@ -16,7 +15,6 @@ #include "chrome/browser/ui/browser_list.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" -#include "components/prefs/scoped_user_pref_update.h" namespace brave { @@ -54,103 +52,33 @@ const char* GetPrefNameForProfile(Profile* profile) { BraveUptimeTracker* g_brave_uptime_tracker_instance = nullptr; constexpr size_t kUsageTimeQueryIntervalMinutes = 1; -constexpr size_t kNumOfSavedDailyUptimes = 7; constexpr char kDailyUptimesListPrefName[] = "daily_uptimes"; } // namespace -UsagePermanentState::UsagePermanentState(PrefService* local_state) - : local_state_(local_state) { - if (local_state) { - LoadUptimes(); +BraveUptimeTracker::BraveUptimeTracker(PrefService* local_state) + : state_(local_state, kDailyUptimesListPrefName) { + timer_.Start( + FROM_HERE, base::TimeDelta::FromMinutes(kUsageTimeQueryIntervalMinutes), + base::Bind(&BraveUptimeTracker::RecordUsage, base::Unretained(this))); +} + +void BraveUptimeTracker::RecordUsage() { + const base::TimeDelta new_total = usage_clock_.GetTotalUsageTime(); + const base::TimeDelta interval = new_total - current_total_usage_; + if (interval > base::TimeDelta()) { + state_.AddDelta(interval.InSeconds()); + current_total_usage_ = new_total; + + RecordP3A(); } } -UsagePermanentState::~UsagePermanentState() = default; - -void UsagePermanentState::AddInterval(base::TimeDelta delta) { - base::Time now_midnight = base::Time::Now().LocalMidnight(); - base::Time last_saved_midnight; - - if (!daily_uptimes_.empty()) { - last_saved_midnight = daily_uptimes_.front().day; - } - - if (now_midnight - last_saved_midnight > base::TimeDelta()) { - // Day changed. Since we consider only small incoming intervals, lets just - // save it with a new timestamp. - daily_uptimes_.push_front({now_midnight, delta}); - if (daily_uptimes_.size() > kNumOfSavedDailyUptimes) { - daily_uptimes_.pop_back(); - } - } else { - daily_uptimes_.front().uptime += delta; - } - - RecordP3A(); - SaveUptimes(); -} - -base::TimeDelta UsagePermanentState::GetTotalUsage() const { - // We record only uptime for last N days. - const base::Time n_days_ago = - base::Time::Now() - base::TimeDelta::FromDays(kNumOfSavedDailyUptimes); - return std::accumulate(daily_uptimes_.begin(), daily_uptimes_.end(), - DailyUptime(), - [n_days_ago](const auto& u1, const auto& u2) { - base::TimeDelta add; - // Check only last continious days. - if (u2.day > n_days_ago) { - add = u2.uptime; - } - return DailyUptime{{}, u1.uptime + add}; - }) - .uptime; -} - -void UsagePermanentState::LoadUptimes() { - DCHECK(daily_uptimes_.empty()); - const base::ListValue* list = - local_state_->GetList(kDailyUptimesListPrefName); - if (!list) { - return; - } - for (auto it = list->begin(); it != list->end(); ++it) { - const base::Value* day = it->FindKey("day"); - const base::Value* uptime = it->FindKey("uptime"); - if (!day || !uptime || !day->is_double() || !uptime->is_double()) { - continue; - } - if (daily_uptimes_.size() == kNumOfSavedDailyUptimes) { - break; - } - daily_uptimes_.push_back( - {base::Time::FromDoubleT(day->GetDouble()), - base::TimeDelta::FromSecondsD(uptime->GetDouble())}); - } -} - -void UsagePermanentState::SaveUptimes() { - DCHECK(!daily_uptimes_.empty()); - DCHECK_LE(daily_uptimes_.size(), kNumOfSavedDailyUptimes); - - ListPrefUpdate update(local_state_, kDailyUptimesListPrefName); - base::ListValue* list = update.Get(); - // TODO(iefremov): Optimize if needed. - list->Clear(); - for (const auto& u : daily_uptimes_) { - base::DictionaryValue value; - value.SetKey("day", base::Value(u.day.ToDoubleT())); - value.SetKey("uptime", base::Value(u.uptime.InSecondsF())); - list->Append(std::move(value)); - } -} - -void UsagePermanentState::RecordP3A() { +void BraveUptimeTracker::RecordP3A() { int answer = 0; - if (daily_uptimes_.size() == kNumOfSavedDailyUptimes) { - base::TimeDelta total = GetTotalUsage(); - const int minutes = total.InMinutes(); + if (state_.IsOneWeekPassed()) { + uint64_t total = state_.GetWeeklySum(); + const int minutes = base::TimeDelta::FromSeconds(total).InMinutes(); DCHECK_GE(minutes, 0); if (0 <= minutes && minutes < 30) { answer = 1; @@ -163,22 +91,6 @@ void UsagePermanentState::RecordP3A() { UMA_HISTOGRAM_EXACT_LINEAR("Brave.Uptime.BrowserOpenMinutes", answer, 3); } -BraveUptimeTracker::BraveUptimeTracker(PrefService* local_state) - : state_(local_state) { - timer_.Start( - FROM_HERE, base::TimeDelta::FromMinutes(kUsageTimeQueryIntervalMinutes), - base::Bind(&BraveUptimeTracker::RecordUsage, base::Unretained(this))); -} - -void BraveUptimeTracker::RecordUsage() { - const base::TimeDelta new_total = usage_clock_.GetTotalUsageTime(); - const base::TimeDelta interval = new_total - current_total_usage_; - if (interval > base::TimeDelta()) { - state_.AddInterval(interval); - current_total_usage_ = new_total; - } -} - BraveUptimeTracker::~BraveUptimeTracker() = default; void BraveUptimeTracker::CreateInstance(PrefService* local_state) { diff --git a/browser/p3a/p3a_core_metrics.h b/browser/p3a/p3a_core_metrics.h index c821f2ec88f..9e0e2cd4a2a 100644 --- a/browser/p3a/p3a_core_metrics.h +++ b/browser/p3a/p3a_core_metrics.h @@ -9,6 +9,7 @@ #include #include "base/timer/timer.h" +#include "brave/components/weekly_storage/weekly_storage.h" #include "chrome/browser/resource_coordinator/usage_clock.h" #include "chrome/browser/ui/browser_list_observer.h" @@ -17,27 +18,6 @@ class PrefRegistrySimple; namespace brave { -class UsagePermanentState { - public: - explicit UsagePermanentState(PrefService* local_state); - ~UsagePermanentState(); - - void AddInterval(base::TimeDelta delta); - base::TimeDelta GetTotalUsage() const; - - private: - struct DailyUptime { - base::Time day; - base::TimeDelta uptime; - }; - void LoadUptimes(); - void SaveUptimes(); - void RecordP3A(); - - std::list daily_uptimes_; - PrefService* local_state_ = nullptr; -}; - class BraveUptimeTracker { public: explicit BraveUptimeTracker(PrefService* local_state); @@ -49,11 +29,12 @@ class BraveUptimeTracker { private: void RecordUsage(); + void RecordP3A(); resource_coordinator::UsageClock usage_clock_; base::RepeatingTimer timer_; base::TimeDelta current_total_usage_; - UsagePermanentState state_; + WeeklyStorage state_; DISALLOW_COPY_AND_ASSIGN(BraveUptimeTracker); }; diff --git a/browser/ui/BUILD.gn b/browser/ui/BUILD.gn index cc7a7814bad..62713a1c781 100644 --- a/browser/ui/BUILD.gn +++ b/browser/ui/BUILD.gn @@ -212,6 +212,7 @@ source_set("ui") { "//brave/components/brave_wallet/browser/buildflags:buildflags", "//brave/components/brave_welcome_ui:generated_resources", "//brave/components/p3a:buildflags", + "//brave/components/weekly_storage", "//chrome/app:command_ids", "//chrome/app/vector_icons:vector_icons", "//chrome/common", diff --git a/browser/ui/omnibox/brave_omnibox_client_impl.cc b/browser/ui/omnibox/brave_omnibox_client_impl.cc index 33a099d669b..c1f65f604d6 100644 --- a/browser/ui/omnibox/brave_omnibox_client_impl.cc +++ b/browser/ui/omnibox/brave_omnibox_client_impl.cc @@ -5,22 +5,73 @@ #include "brave/browser/ui/omnibox/brave_omnibox_client_impl.h" +#include + +#include "base/metrics/histogram_macros.h" +#include "base/stl_util.h" +#include "base/values.h" #include "brave/browser/autocomplete/brave_autocomplete_scheme_classifier.h" #include "brave/common/pref_names.h" +#include "brave/components/weekly_storage/weekly_storage.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h" #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h" +#include "components/omnibox/browser/autocomplete_match.h" +#include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +namespace { + +constexpr char kSearchCountPrefName[] = "brave.weekly_storage.search_count"; + +bool IsSearchEvent(const AutocompleteMatch& match) { + switch (match.type) { + case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED: + case AutocompleteMatchType::SEARCH_HISTORY: + case AutocompleteMatchType::SEARCH_SUGGEST: + case AutocompleteMatchType::SEARCH_SUGGEST_ENTITY: + case AutocompleteMatchType::SEARCH_SUGGEST_TAIL: + case AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED: + case AutocompleteMatchType::SEARCH_SUGGEST_PROFILE: + case AutocompleteMatchType::SEARCH_OTHER_ENGINE: + return true; + default: + return false; + } + return false; +} + +void RecordSearchEventP3A(uint64_t number_of_searches) { + constexpr int kIntervals[] = {0, 5, 10, 20, 50, 100, 500}; + const int* it = + std::lower_bound(kIntervals, std::end(kIntervals), number_of_searches); + const int answer = it - kIntervals; + UMA_HISTOGRAM_EXACT_LINEAR("Brave.Omnibox.SearchCount", answer, + base::size(kIntervals)); +} + +} // namespace + BraveOmniboxClientImpl::BraveOmniboxClientImpl( - OmniboxEditController* controller, - Profile* profile) - : ChromeOmniboxClient(controller, profile), - profile_(profile), - scheme_classifier_(profile) {} + OmniboxEditController* controller, + Profile* profile) + : ChromeOmniboxClient(controller, profile), + profile_(profile), + scheme_classifier_(profile) { + // Record initial search count p3a value. + const base::Value* search_p3a = + profile_->GetPrefs()->GetList(kSearchCountPrefName); + if (search_p3a->GetList().size() == 0) { + RecordSearchEventP3A(0); + } +} BraveOmniboxClientImpl::~BraveOmniboxClientImpl() {} +void BraveOmniboxClientImpl::RegisterPrefs(PrefRegistrySimple* registry) { + registry->RegisterListPref(kSearchCountPrefName); +} + const AutocompleteSchemeClassifier& BraveOmniboxClientImpl::GetSchemeClassifier() const { return scheme_classifier_; @@ -29,3 +80,12 @@ BraveOmniboxClientImpl::GetSchemeClassifier() const { bool BraveOmniboxClientImpl::IsAutocompleteEnabled() const { return profile_->GetPrefs()->GetBoolean(kAutocompleteEnabled); } + +void BraveOmniboxClientImpl::OnInputAccepted(const AutocompleteMatch& match) { + if (IsSearchEvent(match)) { + // TODO(iefremov): Optimize this. + WeeklyStorage storage(profile_->GetPrefs(), kSearchCountPrefName); + storage.AddDelta(1); + RecordSearchEventP3A(storage.GetWeeklySum()); + } +} diff --git a/browser/ui/omnibox/brave_omnibox_client_impl.h b/browser/ui/omnibox/brave_omnibox_client_impl.h index 03cb07e2108..7e41042a1c0 100644 --- a/browser/ui/omnibox/brave_omnibox_client_impl.h +++ b/browser/ui/omnibox/brave_omnibox_client_impl.h @@ -6,20 +6,25 @@ #ifndef BRAVE_BROWSER_UI_OMNIBOX_BRAVE_OMNIBOX_CLIENT_IMPL_H_ #define BRAVE_BROWSER_UI_OMNIBOX_BRAVE_OMNIBOX_CLIENT_IMPL_H_ -#include "chrome/browser/ui/omnibox/chrome_omnibox_client.h" #include "brave/browser/autocomplete/brave_autocomplete_scheme_classifier.h" +#include "chrome/browser/ui/omnibox/chrome_omnibox_client.h" class OmniboxEditController; +class PrefRegistrySimple; class Profile; class BraveOmniboxClientImpl : public ChromeOmniboxClient { public: - BraveOmniboxClientImpl(OmniboxEditController* controller, - Profile* profile); + BraveOmniboxClientImpl(OmniboxEditController* controller, Profile* profile); ~BraveOmniboxClientImpl() override; + + static void RegisterPrefs(PrefRegistrySimple* prefs); + const AutocompleteSchemeClassifier& GetSchemeClassifier() const override; bool IsAutocompleteEnabled() const override; + void OnInputAccepted(const AutocompleteMatch& match) override; + private: Profile* profile_; BraveAutocompleteSchemeClassifier scheme_classifier_; diff --git a/components/brave_perf_predictor/browser/BUILD.gn b/components/brave_perf_predictor/browser/BUILD.gn index 3fa92e341aa..9283f209732 100644 --- a/components/brave_perf_predictor/browser/BUILD.gn +++ b/components/brave_perf_predictor/browser/BUILD.gn @@ -22,8 +22,6 @@ source_set("browser") { "bandwidth_savings_predictor.h", "named_third_party_registry.cc", "named_third_party_registry.h", - "p3a_bandwidth_savings_permanent_state.cc", - "p3a_bandwidth_savings_permanent_state.h", "p3a_bandwidth_savings_tracker.cc", "p3a_bandwidth_savings_tracker.h", "perf_predictor_page_metrics_observer.cc", @@ -36,6 +34,7 @@ source_set("browser") { "//base", "//brave/components/brave_perf_predictor/common", "//brave/components/resources", + "//brave/components/weekly_storage", "//components/page_load_metrics/browser", "//components/page_load_metrics/common", "//components/prefs", diff --git a/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state.cc b/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state.cc deleted file mode 100644 index 42a4913998d..00000000000 --- a/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* Copyright 2019 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state.h" - -#include -#include - -#include "base/time/clock.h" -#include "base/time/default_clock.h" -#include "brave/components/brave_perf_predictor/common/pref_names.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service.h" -#include "components/prefs/scoped_user_pref_update.h" - -namespace brave_perf_predictor { - -namespace { - -constexpr size_t kNumOfSavedDailyUptimes = 7; - -} // namespace - -P3ABandwidthSavingsPermanentState::P3ABandwidthSavingsPermanentState( - PrefService* user_prefs) - : P3ABandwidthSavingsPermanentState( - user_prefs, - std::make_unique()) {} - -P3ABandwidthSavingsPermanentState::P3ABandwidthSavingsPermanentState( - PrefService* user_prefs, - std::unique_ptr clock) - : clock_(std::move(clock)), user_prefs_(user_prefs) { - if (user_prefs) - LoadSavingsDaily(); -} - -P3ABandwidthSavingsPermanentState::~P3ABandwidthSavingsPermanentState() = - default; - -void P3ABandwidthSavingsPermanentState::AddSavings(uint64_t delta) { - base::Time now_midnight = clock_->Now().LocalMidnight(); - base::Time last_saved_midnight; - - if (!daily_savings_.empty()) - last_saved_midnight = daily_savings_.front().day; - - if (now_midnight - last_saved_midnight > base::TimeDelta()) { - // Day changed. - daily_savings_.emplace_front(DailySaving{now_midnight, delta}); - if (daily_savings_.size() > kNumOfSavedDailyUptimes) - daily_savings_.pop_back(); - } else { - daily_savings_.front().saving += delta; - } - - SaveSavingsDaily(); -} - -uint64_t P3ABandwidthSavingsPermanentState::GetFullPeriodSavingsBytes() const { - // We record only saving for last N days. - const base::Time n_days_ago = - clock_->Now() - base::TimeDelta::FromDays(kNumOfSavedDailyUptimes); - return std::accumulate(daily_savings_.begin(), daily_savings_.end(), 0UL, - [n_days_ago](const uint64_t acc, const auto& u2) { - uint64_t add = 0; - // Check only last continious days. - if (u2.day > n_days_ago) { - add = u2.saving; - } - return acc + add; - }); -} - -void P3ABandwidthSavingsPermanentState::LoadSavingsDaily() { - DCHECK(daily_savings_.empty()); - if (!user_prefs_) - return; - const base::ListValue* list = - user_prefs_->GetList(prefs::kBandwidthSavedDailyBytes); - if (!list) - return; - - for (auto it = list->begin(); it != list->end(); ++it) { - const base::Value* day = it->FindKey("day"); - const base::Value* saving = it->FindKey("saving"); - if (!day || !saving || !day->is_double() || !saving->is_double()) - continue; - if (daily_savings_.size() == kNumOfSavedDailyUptimes) - break; - daily_savings_.emplace_back(base::Time::FromDoubleT(day->GetDouble()), - static_cast(saving->GetDouble())); - } -} - -void P3ABandwidthSavingsPermanentState::SaveSavingsDaily() { - DCHECK(!daily_savings_.empty()); - DCHECK_LE(daily_savings_.size(), kNumOfSavedDailyUptimes); - - if (!user_prefs_) - return; - ListPrefUpdate update(user_prefs_, prefs::kBandwidthSavedDailyBytes); - base::ListValue* list = update.Get(); - list->Clear(); - for (const auto& u : daily_savings_) { - base::DictionaryValue value; - value.SetKey("day", base::Value(u.day.ToDoubleT())); - value.SetKey("saving", base::Value(static_cast(u.saving))); - list->Append(std::move(value)); - } -} - -} // namespace brave_perf_predictor diff --git a/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state.h b/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state.h deleted file mode 100644 index 6ee0df73a6e..00000000000 --- a/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright 2019 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_PERF_PREDICTOR_BROWSER_P3A_BANDWIDTH_SAVINGS_PERMANENT_STATE_H_ -#define BRAVE_COMPONENTS_BRAVE_PERF_PREDICTOR_BROWSER_P3A_BANDWIDTH_SAVINGS_PERMANENT_STATE_H_ - -#include -#include - -#include "base/time/time.h" -#include "base/values.h" - -class PrefService; - -namespace base { -class Clock; -} // namespace base - -namespace brave_perf_predictor { - -// This class accumulates savings reported via |AddSavings| over time in -// |PrefService| User Preferences for persistency and returns those for the last -// full period available when queried via |GetFullPeriodSavingsBytes|. -// -// Time interval to accumulate data for is defined internally and -// |GetFullPeriodSavingsBytes| returns 0 if there aren't enough readings to -// cover a full period. -class P3ABandwidthSavingsPermanentState { - public: - explicit P3ABandwidthSavingsPermanentState(PrefService* user_prefs); - // Constructor with injected clock for testing - P3ABandwidthSavingsPermanentState(PrefService* user_prefs, - std::unique_ptr clock); - ~P3ABandwidthSavingsPermanentState(); - P3ABandwidthSavingsPermanentState(const P3ABandwidthSavingsPermanentState&) = - delete; - P3ABandwidthSavingsPermanentState& operator=( - const P3ABandwidthSavingsPermanentState&) = delete; - - void AddSavings(uint64_t delta); - uint64_t GetFullPeriodSavingsBytes() const; - - private: - struct DailySaving { - base::Time day; - uint64_t saving; - DailySaving(base::Time day, uint64_t saving) : day(day), saving(saving) {} - }; - void LoadSavingsDaily(); - void SaveSavingsDaily(); - void RecordSavingsTotal(); - - std::unique_ptr clock_; - std::list daily_savings_; - PrefService* user_prefs_ = nullptr; -}; - -} // namespace brave_perf_predictor - -#endif // BRAVE_COMPONENTS_BRAVE_PERF_PREDICTOR_BROWSER_P3A_BANDWIDTH_SAVINGS_PERMANENT_STATE_H_ diff --git a/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state_unittest.cc b/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state_unittest.cc deleted file mode 100644 index 204d49cbb94..00000000000 --- a/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state_unittest.cc +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (c) 2020 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "brave/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state.h" - -#include -#include - -#include "base/test/simple_test_clock.h" -#include "base/time/time.h" -#include "brave/components/brave_perf_predictor/browser/p3a_bandwidth_savings_tracker.h" -#include "components/prefs/testing_pref_service.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace brave_perf_predictor { - -class P3ABandwidthSavingsPermanentStateTest : public ::testing::Test { - public: - P3ABandwidthSavingsPermanentStateTest() : clock_(new base::SimpleTestClock) { - P3ABandwidthSavingsTracker::RegisterPrefs(pref_service_.registry()); - state_ = std::make_unique( - &pref_service_, std::unique_ptr(clock_)); - clock_->SetNow(base::Time::Now()); - } - - protected: - base::SimpleTestClock* clock_; - TestingPrefServiceSimple pref_service_; - std::unique_ptr state_; -}; - -TEST_F(P3ABandwidthSavingsPermanentStateTest, StartsZero) { - EXPECT_EQ(state_->GetFullPeriodSavingsBytes(), 0ULL); -} - -TEST_F(P3ABandwidthSavingsPermanentStateTest, AddsSavings) { - uint64_t saving = 10000; - state_->AddSavings(saving); - EXPECT_EQ(state_->GetFullPeriodSavingsBytes(), saving); - - // Accumulate - state_->AddSavings(saving); - state_->AddSavings(saving); - EXPECT_EQ(state_->GetFullPeriodSavingsBytes(), saving * 3); -} - -TEST_F(P3ABandwidthSavingsPermanentStateTest, ForgetsOldSavings) { - uint64_t saving = 10000; - state_->AddSavings(saving); - EXPECT_EQ(state_->GetFullPeriodSavingsBytes(), saving); - - clock_->Advance(base::TimeDelta::FromDays(8)); - - // More savings - state_->AddSavings(saving); - state_->AddSavings(saving); - // Should have forgotten about older days - EXPECT_EQ(state_->GetFullPeriodSavingsBytes(), saving * 2); -} - -TEST_F(P3ABandwidthSavingsPermanentStateTest, RetrievesDailySavings) { - uint64_t saving = 10000; - for (int day = 0; day <= 7; day++) { - clock_->Advance(base::TimeDelta::FromDays(1)); - state_->AddSavings(saving); - } - EXPECT_EQ(state_->GetFullPeriodSavingsBytes(), 7 * saving); -} - -TEST_F(P3ABandwidthSavingsPermanentStateTest, HandlesSkippedDay) { - uint64_t saving = 10000; - for (int day = 0; day < 7; day++) { - clock_->Advance(base::TimeDelta::FromDays(1)); - if (day == 3) - continue; - state_->AddSavings(saving); - } - EXPECT_EQ(state_->GetFullPeriodSavingsBytes(), 6 * saving); -} - -TEST_F(P3ABandwidthSavingsPermanentStateTest, IntermittentUsage) { - uint64_t saving = 10000; - for (int day = 0; day < 10; day++) { - clock_->Advance(base::TimeDelta::FromDays(2)); - state_->AddSavings(saving); - } - EXPECT_EQ(state_->GetFullPeriodSavingsBytes(), 4 * saving); -} - -TEST_F(P3ABandwidthSavingsPermanentStateTest, InfrequentUsage) { - uint64_t saving = 10000; - state_->AddSavings(saving); - clock_->Advance(base::TimeDelta::FromDays(6)); - state_->AddSavings(saving); - EXPECT_EQ(state_->GetFullPeriodSavingsBytes(), 2 * saving); -} - -} // namespace brave_perf_predictor diff --git a/components/brave_perf_predictor/browser/p3a_bandwidth_savings_tracker.cc b/components/brave_perf_predictor/browser/p3a_bandwidth_savings_tracker.cc index efd948f4fe4..0c71b34f037 100644 --- a/components/brave_perf_predictor/browser/p3a_bandwidth_savings_tracker.cc +++ b/components/brave_perf_predictor/browser/p3a_bandwidth_savings_tracker.cc @@ -11,8 +11,8 @@ #include "base/metrics/histogram_macros.h" #include "base/time/clock.h" #include "base/time/default_clock.h" -#include "brave/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state.h" #include "brave/components/brave_perf_predictor/common/pref_names.h" +#include "brave/components/weekly_storage/weekly_storage.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -51,11 +51,9 @@ void P3ABandwidthSavingsTracker::RecordSavings(uint64_t savings) { if (savings > 0 && user_prefs_) { // TODO(AndriusA): optimise if needed, loading permanent state on every // record could be costly - auto permanent_state = - std::make_unique(user_prefs_); - permanent_state->AddSavings(savings); - const auto total = permanent_state->GetFullPeriodSavingsBytes(); - StoreSavingsHistogram(total); + WeeklyStorage weekly(user_prefs_, prefs::kBandwidthSavedDailyBytes); + weekly.AddDelta(savings); + StoreSavingsHistogram(weekly.GetWeeklySum()); } } diff --git a/components/p3a/brave_p3a_service.cc b/components/p3a/brave_p3a_service.cc index 74a533e640d..488ddfaceb1 100644 --- a/components/p3a/brave_p3a_service.cc +++ b/components/p3a/brave_p3a_service.cc @@ -48,27 +48,24 @@ constexpr uint64_t kDefaultUploadIntervalSeconds = 60; // 1 minute. // Whitelist for histograms that we collect. Will be replaced with something // updating on the fly. constexpr const char* kCollectedHistograms[] = { - "Brave.P3A.SentAnswersCount", - "Brave.Savings.BandwidthSavingsMB", - "Brave.Sync.Status", - // Deprecated: - // "DefaultBrowser.State", - "Brave.Importer.ImporterSource", - "Brave.Shields.UsageStatus", - // Do not gather detailed info regarding TOR usage for now. - // "Brave.Core.LastTimeTorUsed", + "Brave.Core.BookmarksCountOnProfileLoad", "Brave.Core.IsDefault", - "Brave.Core.TorEverUsed", "Brave.Core.LastTimeIncognitoUsed", "Brave.Core.NumberOfExtensions", - "Brave.Core.BookmarksCountOnProfileLoad", "Brave.Core.TabCount", + "Brave.Core.TorEverUsed", "Brave.Core.WindowCount", - "Brave.Search.DefaultEngine", - "Brave.Rewards.WalletBalance.2", + "Brave.Importer.ImporterSource", + "Brave.Omnibox.SearchCount", + "Brave.P3A.SentAnswersCount", + "Brave.Rewards.AdsState.2", "Brave.Rewards.AutoContributionsState.2", "Brave.Rewards.TipsState.2", - "Brave.Rewards.AdsState.2", + "Brave.Rewards.WalletBalance.2", + "Brave.Savings.BandwidthSavingsMB", + "Brave.Search.DefaultEngine", + "Brave.Shields.UsageStatus", + "Brave.Sync.Status", "Brave.Uptime.BrowserOpenMinutes", "Brave.Welcome.InteractionStatus", }; diff --git a/components/weekly_storage/BUILD.gn b/components/weekly_storage/BUILD.gn new file mode 100644 index 00000000000..5064fd95072 --- /dev/null +++ b/components/weekly_storage/BUILD.gn @@ -0,0 +1,10 @@ +source_set("weekly_storage") { + sources = [ + "weekly_storage.cc", + "weekly_storage.h", + ] + + deps = [ + "//components/prefs", + ] +} diff --git a/components/weekly_storage/weekly_storage.cc b/components/weekly_storage/weekly_storage.cc new file mode 100644 index 00000000000..69a87a26516 --- /dev/null +++ b/components/weekly_storage/weekly_storage.cc @@ -0,0 +1,119 @@ +/* Copyright 2020 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/weekly_storage/weekly_storage.h" + +#include +#include + +#include "base/time/clock.h" +#include "base/time/default_clock.h" +#include "base/values.h" +#include "components/prefs/pref_service.h" +#include "components/prefs/scoped_user_pref_update.h" + +namespace { +constexpr size_t kDaysInWeek = 7; +} + +WeeklyStorage::WeeklyStorage(PrefService* prefs, const char* pref_name) + : prefs_(prefs), + pref_name_(pref_name), + clock_(std::make_unique()) { + DCHECK(pref_name); + if (prefs) { + Load(); + } +} + +WeeklyStorage::WeeklyStorage(PrefService* prefs, + const char* pref_name, + std::unique_ptr clock) + : prefs_(prefs), pref_name_(pref_name), clock_(std::move(clock)) { + DCHECK(prefs); + DCHECK(pref_name); + Load(); +} + +WeeklyStorage::~WeeklyStorage() = default; + +void WeeklyStorage::AddDelta(uint64_t delta) { + base::Time now_midnight = clock_->Now().LocalMidnight(); + base::Time last_saved_midnight; + + if (!daily_values_.empty()) { + last_saved_midnight = daily_values_.front().day; + } + + if (now_midnight - last_saved_midnight > base::TimeDelta()) { + // Day changed. Since we consider only small incoming intervals, lets just + // save it with a new timestamp. + daily_values_.push_front({now_midnight, delta}); + if (daily_values_.size() > kDaysInWeek) { + daily_values_.pop_back(); + } + } else { + daily_values_.front().value += delta; + } + + Save(); +} + +uint64_t WeeklyStorage::GetWeeklySum() const { + // We record only value for last N days. + const base::Time n_days_ago = + clock_->Now() - base::TimeDelta::FromDays(kDaysInWeek); + return std::accumulate(daily_values_.begin(), daily_values_.end(), 0ull, + [n_days_ago](const uint64_t acc, const auto& u2) { + uint64_t add = 0; + // Check only last continious days. + if (u2.day > n_days_ago) { + add = u2.value; + } + return acc + add; + }); +} + +bool WeeklyStorage::IsOneWeekPassed() const { + // TODO(iefremov): This is not true 100% (if the browser was launched once + // per week just after installation, for example). + return daily_values_.size() == kDaysInWeek; +} + +void WeeklyStorage::Load() { + DCHECK(daily_values_.empty()); + const base::ListValue* list = prefs_->GetList(pref_name_); + if (!list) { + return; + } + for (auto it = list->begin(); it != list->end(); ++it) { + const base::Value* day = it->FindKey("day"); + const base::Value* value = it->FindKey("value"); + if (!day || !value || !day->is_double() || !value->is_double()) { + continue; + } + if (daily_values_.size() == kDaysInWeek) { + break; + } + daily_values_.push_back({base::Time::FromDoubleT(day->GetDouble()), + static_cast(value->GetDouble())}); + } +} + +void WeeklyStorage::Save() { + DCHECK(!daily_values_.empty()); + DCHECK_LE(daily_values_.size(), kDaysInWeek); + + ListPrefUpdate update(prefs_, pref_name_); + base::ListValue* list = update.Get(); + // TODO(iefremov): Optimize if needed. + list->Clear(); + for (const auto& u : daily_values_) { + base::DictionaryValue value; + value.SetKey("day", base::Value(u.day.ToDoubleT())); + value.SetDoubleKey("value", u.value); + list->Append(std::move(value)); + } +} diff --git a/components/weekly_storage/weekly_storage.h b/components/weekly_storage/weekly_storage.h new file mode 100644 index 00000000000..bc146fd3c57 --- /dev/null +++ b/components/weekly_storage/weekly_storage.h @@ -0,0 +1,57 @@ +/* Copyright 2020 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_WEEKLY_STORAGE_WEEKLY_STORAGE_H_ +#define BRAVE_COMPONENTS_WEEKLY_STORAGE_WEEKLY_STORAGE_H_ + +#include +#include + +#include "base/time/time.h" + +namespace base { +class Clock; +} + +class PrefService; + +// Mostly used by various P3A recorders - allows to track a sum of some +// values added from time to time via |AddDelta| over a last week. +// Requires |pref_name| to be already registered. +// Feel free to improve and refactor it - templatize a stored value type, +// change weekly interval or make a keyed service from it. +class WeeklyStorage { + public: + WeeklyStorage(PrefService* prefs, const char* pref_name); + + // For tests. + WeeklyStorage(PrefService* user_prefs, + const char* pref_name, + std::unique_ptr clock); + ~WeeklyStorage(); + + WeeklyStorage(const WeeklyStorage&) = delete; + WeeklyStorage& operator=(const WeeklyStorage&) = delete; + + void AddDelta(uint64_t delta); + uint64_t GetWeeklySum() const; + bool IsOneWeekPassed() const; + + private: + struct DailyValue { + base::Time day; + uint64_t value = 0ull; + }; + void Load(); + void Save(); + + PrefService* prefs_ = nullptr; + const char* pref_name_ = nullptr; + std::unique_ptr clock_; + + std::list daily_values_; +}; + +#endif // BRAVE_COMPONENTS_WEEKLY_STORAGE_WEEKLY_STORAGE_H_ diff --git a/components/weekly_storage/weekly_storage_unittest.cc b/components/weekly_storage/weekly_storage_unittest.cc new file mode 100644 index 00000000000..fd933ef5510 --- /dev/null +++ b/components/weekly_storage/weekly_storage_unittest.cc @@ -0,0 +1,98 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/weekly_storage/weekly_storage.h" + +#include +#include + +#include "base/test/simple_test_clock.h" +#include "base/time/time.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/testing_pref_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +class WeeklyStorageTest : public ::testing::Test { + public: + WeeklyStorageTest() : clock_(new base::SimpleTestClock) { + constexpr char kPrefName[] = "brave.weekly_test"; + pref_service_.registry()->RegisterListPref(kPrefName); + + state_ = std::make_unique( + &pref_service_, kPrefName, std::unique_ptr(clock_)); + clock_->SetNow(base::Time::Now()); + } + + protected: + base::SimpleTestClock* clock_; + TestingPrefServiceSimple pref_service_; + std::unique_ptr state_; +}; + +TEST_F(WeeklyStorageTest, StartsZero) { + EXPECT_EQ(state_->GetWeeklySum(), 0ULL); +} + +TEST_F(WeeklyStorageTest, AddsSavings) { + uint64_t saving = 10000; + state_->AddDelta(saving); + EXPECT_EQ(state_->GetWeeklySum(), saving); + + // Accumulate + state_->AddDelta(saving); + state_->AddDelta(saving); + EXPECT_EQ(state_->GetWeeklySum(), saving * 3); +} + +TEST_F(WeeklyStorageTest, ForgetsOldSavings) { + uint64_t saving = 10000; + state_->AddDelta(saving); + EXPECT_EQ(state_->GetWeeklySum(), saving); + + clock_->Advance(base::TimeDelta::FromDays(8)); + + // More savings + state_->AddDelta(saving); + state_->AddDelta(saving); + // Should have forgotten about older days + EXPECT_EQ(state_->GetWeeklySum(), saving * 2); +} + +TEST_F(WeeklyStorageTest, RetrievesDailySavings) { + uint64_t saving = 10000; + for (int day = 0; day <= 7; day++) { + clock_->Advance(base::TimeDelta::FromDays(1)); + state_->AddDelta(saving); + } + EXPECT_EQ(state_->GetWeeklySum(), 7 * saving); +} + +TEST_F(WeeklyStorageTest, HandlesSkippedDay) { + uint64_t saving = 10000; + for (int day = 0; day < 7; day++) { + clock_->Advance(base::TimeDelta::FromDays(1)); + if (day == 3) + continue; + state_->AddDelta(saving); + } + EXPECT_EQ(state_->GetWeeklySum(), 6 * saving); +} + +TEST_F(WeeklyStorageTest, IntermittentUsage) { + uint64_t saving = 10000; + for (int day = 0; day < 10; day++) { + clock_->Advance(base::TimeDelta::FromDays(2)); + state_->AddDelta(saving); + } + EXPECT_EQ(state_->GetWeeklySum(), 4 * saving); +} + +TEST_F(WeeklyStorageTest, InfrequentUsage) { + uint64_t saving = 10000; + state_->AddDelta(saving); + clock_->Advance(base::TimeDelta::FromDays(6)); + state_->AddDelta(saving); + EXPECT_EQ(state_->GetWeeklySum(), 2 * saving); +} diff --git a/test/BUILD.gn b/test/BUILD.gn index e2fe2274707..68c8cfd170a 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -118,6 +118,7 @@ test("brave_unit_tests") { "//brave/components/ntp_background_images/browser/view_counter_service_unittest.cc", "//brave/components/rappor/log_uploader_unittest.cc", "//brave/components/translate/core/browser/translate_language_list_unittest.cc", + "//brave/components/weekly_storage/weekly_storage_unittest.cc", "//brave/third_party/libaddressinput/chromium/chrome_metadata_source_unittest.cc", "//brave/vendor/brave_base/random_unittest.cc", "//components/bookmarks/browser/bookmark_model_unittest.cc", @@ -482,7 +483,6 @@ test("brave_unit_tests") { "//brave/components/brave_perf_predictor/browser/named_third_party_registry_unittest.cc", "//brave/components/brave_perf_predictor/browser/bandwidth_linreg_unittest.cc", "//brave/components/brave_perf_predictor/browser/bandwidth_savings_predictor_unittest.cc", - "//brave/components/brave_perf_predictor/browser/p3a_bandwidth_savings_permanent_state_unittest.cc", "//brave/components/brave_perf_predictor/browser/p3a_bandwidth_savings_tracker_unittest.cc", ]