blob: 5f08b322d8ab0d8bc4deedf77bec5b9bd9ee2dac [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/performance_manager/public/user_tuning/prefs.h"
#include <iterator>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/json/values_util.h"
#include "base/values.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
namespace performance_manager::user_tuning::prefs {
void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kMemorySaverModeEnabled, false);
registry->RegisterIntegerPref(
kMemorySaverModeTimeBeforeDiscardInMinutes,
kDefaultMemorySaverModeTimeBeforeDiscardInMinutes);
registry->RegisterIntegerPref(
kMemorySaverModeState, static_cast<int>(MemorySaverModeState::kDisabled));
registry->RegisterIntegerPref(
kMemorySaverModeAggressiveness,
static_cast<int>(MemorySaverModeAggressiveness::kMedium));
registry->RegisterIntegerPref(
kBatterySaverModeState,
static_cast<int>(BatterySaverModeState::kEnabledBelowThreshold));
registry->RegisterTimePref(kLastBatteryUseTimestamp, base::Time());
registry->RegisterBooleanPref(kDiscardRingTreatmentEnabled, true);
registry->RegisterBooleanPref(kPerformanceInterventionNotificationEnabled,
true);
registry->RegisterTimePref(kPerformanceInterventionNotificationLastShown,
base::Time());
registry->RegisterListPref(kPerformanceInterventionNotificationAcceptHistory);
}
void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterListPref(kTabDiscardingExceptions,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterDictionaryPref(
kTabDiscardingExceptionsWithTime,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterListPref(kManagedTabDiscardingExceptions);
}
MemorySaverModeState GetCurrentMemorySaverModeState(PrefService* pref_service) {
int state = pref_service->GetInteger(kMemorySaverModeState);
if (state < static_cast<int>(MemorySaverModeState::kDisabled) ||
state > static_cast<int>(MemorySaverModeState::kEnabled)) {
int disabled_state = static_cast<int>(MemorySaverModeState::kDisabled);
pref_service->SetInteger(kMemorySaverModeState, disabled_state);
state = disabled_state;
}
return static_cast<MemorySaverModeState>(state);
}
MemorySaverModeAggressiveness GetCurrentMemorySaverMode(
PrefService* pref_service) {
int mode = pref_service->GetInteger(kMemorySaverModeAggressiveness);
if (mode < static_cast<int>(MemorySaverModeAggressiveness::kConservative) ||
mode > static_cast<int>(MemorySaverModeAggressiveness::kAggressive)) {
int medium_mode = static_cast<int>(MemorySaverModeAggressiveness::kMedium);
pref_service->SetInteger(kMemorySaverModeAggressiveness, medium_mode);
mode = medium_mode;
}
return static_cast<MemorySaverModeAggressiveness>(mode);
}
base::TimeDelta GetCurrentMemorySaverModeTimeBeforeDiscard(
PrefService* pref_service) {
int time_before_discard_in_minutes =
pref_service->GetInteger(kMemorySaverModeTimeBeforeDiscardInMinutes);
if (time_before_discard_in_minutes < 0) {
pref_service->ClearPref(kMemorySaverModeTimeBeforeDiscardInMinutes);
time_before_discard_in_minutes =
pref_service->GetInteger(kMemorySaverModeTimeBeforeDiscardInMinutes);
}
return base::Minutes(time_before_discard_in_minutes);
}
BatterySaverModeState GetCurrentBatterySaverModeState(
PrefService* pref_service) {
int state = pref_service->GetInteger(kBatterySaverModeState);
if (state < static_cast<int>(BatterySaverModeState::kDisabled) ||
state > static_cast<int>(BatterySaverModeState::kEnabled)) {
int disabled_state = static_cast<int>(BatterySaverModeState::kDisabled);
pref_service->SetInteger(kBatterySaverModeState, disabled_state);
state = disabled_state;
}
return static_cast<BatterySaverModeState>(state);
}
bool ShouldShowDiscardRingTreatment(PrefService* pref_service) {
#if BUILDFLAG(IS_ANDROID)
return false;
#else
return pref_service->GetBoolean(kDiscardRingTreatmentEnabled);
#endif
}
bool ShouldShowPerformanceInterventionNotification(PrefService* pref_service) {
#if BUILDFLAG(IS_ANDROID)
return false;
#else
return pref_service->GetBoolean(kPerformanceInterventionNotificationEnabled);
#endif
}
void MigrateMemorySaverModePref(PrefService* pref_service) {
const PrefService::Preference* state_pref =
pref_service->FindPreference(kMemorySaverModeState);
if (!state_pref->IsDefaultValue()) {
// The user has changed the new pref, no migration needed. Clear the old
// pref because it won't be used anymore. Note that this case should not
// occur.
pref_service->ClearPref(kMemorySaverModeEnabled);
return;
}
const PrefService::Preference* bool_pref =
pref_service->FindPreference(kMemorySaverModeEnabled);
bool enabled = bool_pref->GetValue()->GetBool();
int equivalent_int_pref =
enabled ? static_cast<int>(MemorySaverModeState::kEnabled)
: static_cast<int>(MemorySaverModeState::kDisabled);
if (!bool_pref->IsDefaultValue()) {
// The user has changed the old pref, but the new pref is still set to the
// default value. This means the old pref's state needs to be migrated into
// the new pref.
pref_service->SetInteger(kMemorySaverModeState, equivalent_int_pref);
// Clear the old pref because it won't be used anymore.
pref_service->ClearPref(kMemorySaverModeEnabled);
}
}
void MigrateMultiStateMemorySaverModePref(PrefService* pref_service) {
const PrefService::Preference* state_pref =
pref_service->FindPreference(kMemorySaverModeState);
if (!state_pref->IsDefaultValue() &&
static_cast<MemorySaverModeState>(state_pref->GetValue()->GetInt()) ==
MemorySaverModeState::kDeprecated) {
pref_service->SetInteger(kMemorySaverModeState,
static_cast<int>(MemorySaverModeState::kEnabled));
}
pref_service->ClearPref(kMemorySaverModeTimeBeforeDiscardInMinutes);
}
bool IsSiteInTabDiscardExceptionsList(PrefService* pref_service,
const std::string& site) {
const base::Value::Dict& discard_exceptions_map =
pref_service->GetDict(kTabDiscardingExceptionsWithTime);
return base::Contains(discard_exceptions_map, site);
}
void AddSiteToTabDiscardExceptionsList(PrefService* pref_service,
const std::string& site) {
const base::Value::Dict& discard_exceptions_original =
pref_service->GetDict(kTabDiscardingExceptionsWithTime);
if (!base::Contains(discard_exceptions_original, site)) {
base::Value::Dict discard_exceptions_map =
discard_exceptions_original.Clone();
discard_exceptions_map.Set(site, base::TimeToValue(base::Time::Now()));
pref_service->SetDict(kTabDiscardingExceptionsWithTime,
std::move(discard_exceptions_map));
}
}
std::vector<std::string> GetTabDiscardExceptionsBetween(
PrefService* pref_service,
base::Time period_start,
base::Time period_end) {
std::vector<std::string> discard_exceptions;
const base::Value::Dict& discard_exceptions_map =
pref_service->GetDict(performance_manager::user_tuning::prefs::
kTabDiscardingExceptionsWithTime);
for (const std::pair<const std::string&, const base::Value&> it :
discard_exceptions_map) {
std::optional<base::Time> time = base::ValueToTime(it.second);
if ((!time || (time > period_start && time < period_end))) {
discard_exceptions.push_back(it.first);
}
}
return discard_exceptions;
}
void ClearTabDiscardExceptions(PrefService* pref_service,
base::Time delete_begin,
base::Time delete_end) {
const base::Value::Dict& discard_exceptions_map =
pref_service->GetDict(kTabDiscardingExceptionsWithTime);
std::vector<std::pair<std::string, base::Value>> saved_exceptions;
saved_exceptions.reserve(discard_exceptions_map.size());
for (std::pair<const std::string&, const base::Value&> it :
discard_exceptions_map) {
std::optional<base::Time> time = base::ValueToTime(it.second);
if (time && (time.value() < delete_begin || time.value() > delete_end)) {
saved_exceptions.emplace_back(it.first, it.second.Clone());
}
}
pref_service->SetDict(
kTabDiscardingExceptionsWithTime,
base::Value::Dict(std::make_move_iterator(saved_exceptions.begin()),
std::make_move_iterator(saved_exceptions.end())));
}
} // namespace performance_manager::user_tuning::prefs