#include "components/breadcrumbs/core/breadcrumbs_status.h"
#include <atomic>
#include <optional>
#include "base/command_line.h"
#include "base/rand_util.h"
#include "base/time/time.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/variations/variations_switches.h"
#include "components/version_info/channel.h"
namespace breadcrumbs {
namespace {
enum class BreadcrumbsEnabledMode {
kFromLocalPrefs,
kForceEnabled,
kForceDisabled
};
std::atomic<BreadcrumbsEnabledMode> breadcrumbs_enabled_mode =
BreadcrumbsEnabledMode::kFromLocalPrefs;
constexpr int kCanaryPercent = 99;
constexpr int kDevPercent = 80;
constexpr int kBetaPercent = 80;
constexpr int kStablePercent = 5;
constexpr auto kEnabledDuration = base::Days(30);
bool GetRandomIsEnabled(version_info::Channel channel) {
int enabled_percent = 0;
switch (channel) {
case version_info::Channel::CANARY:
enabled_percent = kCanaryPercent;
break;
case version_info::Channel::DEV:
enabled_percent = kDevPercent;
break;
case version_info::Channel::BETA:
enabled_percent = kBetaPercent;
break;
case version_info::Channel::STABLE:
enabled_percent = kStablePercent;
break;
case version_info::Channel::UNKNOWN:
break;
}
return base::RandInt(1, 100) <= enabled_percent;
}
bool HasRecentBreadcrumbsPrefs(PrefService* prefs) {
if (!prefs->HasPrefPath(kEnabledPref) ||
!prefs->HasPrefPath(kEnabledTimePref)) {
return false;
}
const auto enabled_time = prefs->GetTime(kEnabledTimePref);
const auto now = base::Time::Now();
if (enabled_time > now) {
return false;
}
const auto oldest_valid_time = now - kEnabledDuration;
return enabled_time > oldest_valid_time;
}
bool IsEnabled(PrefService* prefs,
std::optional<version_info::Channel> set_for_channel) {
switch (breadcrumbs_enabled_mode) {
case BreadcrumbsEnabledMode::kForceEnabled:
return true;
case BreadcrumbsEnabledMode::kForceDisabled:
return false;
case BreadcrumbsEnabledMode::kFromLocalPrefs:
if (!prefs || !prefs->FindPreference(kEnabledPref) ||
!prefs->FindPreference(kEnabledTimePref) ||
base::CommandLine::ForCurrentProcess()->HasSwitch(
variations::switches::kEnableBenchmarking)) {
breadcrumbs_enabled_mode = BreadcrumbsEnabledMode::kForceDisabled;
return false;
}
if (set_for_channel.has_value()) {
if (HasRecentBreadcrumbsPrefs(prefs)) {
return prefs->GetBoolean(kEnabledPref);
}
const bool is_enabled = GetRandomIsEnabled(set_for_channel.value());
prefs->SetBoolean(kEnabledPref, is_enabled);
prefs->SetTime(kEnabledTimePref, base::Time::Now());
}
return prefs->GetBoolean(kEnabledPref);
}
}
}
constexpr char kEnabledPref[] = "breadcrumbs.enabled";
constexpr char kEnabledTimePref[] = "breadcrumbs.enabled_time";
bool IsEnabled(PrefService* prefs) {
return IsEnabled(prefs, std::nullopt);
}
bool MaybeEnableBasedOnChannel(PrefService* prefs,
version_info::Channel channel) {
return IsEnabled(prefs, channel);
}
void RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kEnabledPref, false);
registry->RegisterTimePref(kEnabledTimePref, base::Time());
}
ScopedEnableBreadcrumbsForTesting::ScopedEnableBreadcrumbsForTesting() {
breadcrumbs_enabled_mode = BreadcrumbsEnabledMode::kForceEnabled;
}
ScopedEnableBreadcrumbsForTesting::~ScopedEnableBreadcrumbsForTesting() {
breadcrumbs_enabled_mode = BreadcrumbsEnabledMode::kFromLocalPrefs;
}
}