#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "components/flags_ui/flags_state.h"
#include <algorithm>
#include <memory>
#include <string_view>
#include <utility>
#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/feature_list.h"
#include "base/feature_list_buildflags.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
#include "base/not_fatal_until.h"
#include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/flags_ui/feature_entry.h"
#include "components/flags_ui/flags_storage.h"
#include "components/flags_ui/flags_ui_switches.h"
#include "components/variations/field_trial_config/field_trial_util.h"
#include "components/variations/variations_associated_data.h"
#include "components/variations/variations_switches.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace flags_ui {
namespace internal {
const char kTrialGroupAboutFlags[] = …;
}
namespace {
const char kOriginListValueSeparator[] = …;
const struct { … } kBitsToOs[] = …;
void AddOsStrings(unsigned bitmask, base::Value::List* list) { … }
bool IsDefaultValue(const FeatureEntry& entry,
const std::set<std::string>& enabled_entries) { … }
base::Value::List CreateOptionsData(
const FeatureEntry& entry,
const std::set<std::string>& enabled_entries) { … }
base::FieldTrial* RegisterFeatureVariationParameters(
const std::string& feature_trial_name,
const std::map<std::string, std::string>& feature_variation_params,
const std::string& trial_group) { … }
bool IsSafeValue(const std::string& value) { … }
std::vector<std::string> TokenizeOriginList(const std::string& value) { … }
std::string CombineAndSanitizeOriginLists(const std::string& value1,
const std::string& value2) { … }
std::string GetCombinedOriginListValue(const FlagsStorage& flags_storage,
const base::CommandLine& command_line,
const std::string& internal_entry_name,
const std::string& command_line_switch) { … }
std::string GetCombinedStringValue(const FlagsStorage& flags_storage,
const base::CommandLine& command_line,
const std::string& internal_entry_name,
const std::string& command_line_switch) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
void RemoveCommandLineSwitch(base::CommandLine* current_cl,
const std::string& switch_to_remove) {
base::CommandLine new_cl(current_cl->GetProgram());
const base::CommandLine::SwitchMap switches = current_cl->GetSwitches();
for (const auto& it : switches) {
const auto& switch_name = it.first;
const auto& switch_value = it.second;
if (switch_name != switch_to_remove) {
if (switch_value.empty()) {
new_cl.AppendSwitch(switch_name);
} else {
new_cl.AppendSwitchNative(switch_name, switch_value);
}
}
}
*current_cl = new_cl;
}
void DidModifyOriginListFlag(const FlagsStorage& flags_storage,
const FeatureEntry& entry) {
base::CommandLine* current_cl = base::CommandLine::ForCurrentProcess();
const std::string new_value = GetCombinedOriginListValue(
flags_storage, *current_cl, entry.internal_name,
entry.switches.command_line_switch);
RemoveCommandLineSwitch(current_cl, entry.switches.command_line_switch);
const std::string sanitized =
CombineAndSanitizeOriginLists(std::string(), new_value);
current_cl->AppendSwitchASCII(entry.switches.command_line_switch, sanitized);
}
void DidModifyStringFlag(const FlagsStorage& flags_storage,
const FeatureEntry& entry) {
base::CommandLine* current_cl = base::CommandLine::ForCurrentProcess();
const std::string new_value =
GetCombinedStringValue(flags_storage, *current_cl, entry.internal_name,
entry.switches.command_line_switch);
RemoveCommandLineSwitch(current_cl, entry.switches.command_line_switch);
current_cl->AppendSwitchASCII(entry.switches.command_line_switch, new_value);
}
#endif
}
struct FlagsState::SwitchEntry { … };
bool FlagsState::Delegate::ShouldExcludeFlag(const FlagsStorage* state,
const FeatureEntry& entry) { … }
FlagsState::Delegate::Delegate() = default;
FlagsState::Delegate::~Delegate() = default;
FlagsState::FlagsState(base::span<const FeatureEntry> feature_entries,
FlagsState::Delegate* delegate)
: … { … }
FlagsState::~FlagsState() { … }
void FlagsState::ConvertFlagsToSwitches(
FlagsStorage* flags_storage,
base::CommandLine* command_line,
SentinelsMode sentinels,
const char* enable_features_flag_name,
const char* disable_features_flag_name) { … }
void FlagsState::GetSwitchesAndFeaturesFromFlags(
FlagsStorage* flags_storage,
std::set<std::string>* switches,
std::set<std::string>* features,
std::set<std::string>* variation_ids) const { … }
bool FlagsState::IsRestartNeededToCommitChanges() { … }
void FlagsState::SetFeatureEntryEnabled(FlagsStorage* flags_storage,
const std::string& internal_name,
bool enable) { … }
void FlagsState::SetOriginListFlag(const std::string& internal_name,
const std::string& value,
FlagsStorage* flags_storage) { … }
void FlagsState::SetStringFlag(const std::string& internal_name,
const std::string& value,
FlagsStorage* flags_storage) { … }
void FlagsState::RemoveFlagsSwitches(
base::CommandLine::SwitchMap* switch_list) { … }
void FlagsState::ResetAllFlags(FlagsStorage* flags_storage) { … }
void FlagsState::Reset() { … }
std::vector<std::string> FlagsState::RegisterAllFeatureVariationParameters(
FlagsStorage* flags_storage,
base::FeatureList* feature_list) { … }
std::vector<std::string> FlagsState::RegisterEnabledFeatureVariationParameters(
const base::span<const FeatureEntry>& feature_entries,
const std::set<std::string>& enabled_entries,
const std::string& trial_group,
base::FeatureList* feature_list) { … }
void FlagsState::GetFlagFeatureEntries(
FlagsStorage* flags_storage,
FlagAccess access,
base::Value::List& supported_entries,
base::Value::List& unsupported_entries,
base::RepeatingCallback<bool(const FeatureEntry&)> skip_feature_entry) { … }
unsigned short FlagsState::GetCurrentPlatform() { … }
void FlagsState::AddSwitchMapping(
const std::string& key,
const std::string& switch_name,
const std::string& switch_value,
std::map<std::string, SwitchEntry>* name_to_switch_map) const { … }
void FlagsState::AddFeatureMapping(
const std::string& key,
const std::string& feature_name,
bool feature_state,
const std::string& variation_id,
std::map<std::string, SwitchEntry>* name_to_switch_map) const { … }
void FlagsState::AddSwitchesToCommandLine(
const std::set<std::string>& enabled_entries,
const std::map<std::string, SwitchEntry>& name_to_switch_map,
SentinelsMode sentinels,
base::CommandLine* command_line,
const char* enable_features_flag_name,
const char* disable_features_flag_name) { … }
void FlagsState::MergeFeatureCommandLineSwitch(
const std::map<std::string, bool>& feature_switches,
const char* switch_name,
bool feature_state,
base::CommandLine* command_line) { … }
void FlagsState::MergeVariationIdsCommandLineSwitch(
const std::vector<std::string>& variation_ids,
base::CommandLine* command_line) { … }
std::set<std::string> FlagsState::SanitizeList(
const FlagsStorage* storage,
const std::set<std::string>& enabled_entries,
int platform_mask) const { … }
void FlagsState::GetSanitizedEnabledFlags(FlagsStorage* flags_storage,
std::set<std::string>* result) const { … }
void FlagsState::GetSanitizedEnabledFlagsForCurrentPlatform(
FlagsStorage* flags_storage,
std::set<std::string>* result) const { … }
void FlagsState::GenerateFlagsToSwitchesMapping(
FlagsStorage* flags_storage,
const base::CommandLine& command_line,
std::set<std::string>* enabled_entries,
std::map<std::string, SwitchEntry>* name_to_switch_map) const { … }
const FeatureEntry* FlagsState::FindFeatureEntryByName(
const std::string& internal_name) const { … }
bool FlagsState::IsSupportedFeature(const FlagsStorage* storage,
const std::string& name,
int platform_mask) const { … }
}