Index: chrome/browser/about_flags.cc |
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc |
index 96aa9d340dd8ff37185f7f12be4b03ba44ba1304..7d362519616f5c65c12655888ce6f4736b6f110c 100644 |
--- a/chrome/browser/about_flags.cc |
+++ b/chrome/browser/about_flags.cc |
@@ -9,6 +9,8 @@ |
#include <set> |
#include <utility> |
+#include "base/bind.h" |
+#include "base/callback.h" |
#include "base/command_line.h" |
#include "base/feature_list.h" |
#include "base/memory/singleton.h" |
@@ -33,6 +35,7 @@ |
#include "components/enhanced_bookmarks/enhanced_bookmark_switches.h" |
#include "components/flags_ui/feature_entry_macros.h" |
#include "components/flags_ui/flags_storage.h" |
+#include "components/flags_ui/flags_ui_switches.h" |
#include "components/metrics/metrics_hashes.h" |
#include "components/nacl/common/nacl_switches.h" |
#include "components/offline_pages/offline_page_switches.h" |
@@ -89,77 +92,20 @@ |
#endif |
using flags_ui::FeatureEntry; |
+using flags_ui::kOsMac; |
+using flags_ui::kOsWin; |
+using flags_ui::kOsLinux; |
+using flags_ui::kOsCrOS; |
+using flags_ui::kOsAndroid; |
+using flags_ui::kOsCrOSOwnerOnly; |
namespace about_flags { |
namespace { |
-// Enumeration of OSs. |
-enum { |
- kOsMac = 1 << 0, |
- kOsWin = 1 << 1, |
- kOsLinux = 1 << 2, |
- kOsCrOS = 1 << 3, |
- kOsAndroid = 1 << 4, |
- kOsCrOSOwnerOnly = 1 << 5 |
-}; |
- |
const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid; |
const unsigned kOsDesktop = kOsMac | kOsWin | kOsLinux | kOsCrOS; |
-// Adds a |StringValue| to |list| for each platform where |bitmask| indicates |
-// whether the entry is available on that platform. |
-void AddOsStrings(unsigned bitmask, base::ListValue* list) { |
- struct { |
- unsigned bit; |
- const char* const name; |
- } kBitsToOs[] = { |
- {kOsMac, "Mac"}, |
- {kOsWin, "Windows"}, |
- {kOsLinux, "Linux"}, |
- {kOsCrOS, "Chrome OS"}, |
- {kOsAndroid, "Android"}, |
- {kOsCrOSOwnerOnly, "Chrome OS (owner only)"}, |
- }; |
- for (size_t i = 0; i < arraysize(kBitsToOs); ++i) { |
- if (bitmask & kBitsToOs[i].bit) |
- list->Append(new base::StringValue(kBitsToOs[i].name)); |
- } |
-} |
- |
-// Convert switch constants to proper CommandLine::StringType strings. |
-base::CommandLine::StringType GetSwitchString(const std::string& flag) { |
- base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM); |
- cmd_line.AppendSwitch(flag); |
- DCHECK_EQ(2U, cmd_line.argv().size()); |
- return cmd_line.argv()[1]; |
-} |
- |
-// Scoops flags from a command line. |
-std::set<base::CommandLine::StringType> ExtractFlagsFromCommandLine( |
- const base::CommandLine& cmdline) { |
- std::set<base::CommandLine::StringType> flags; |
- // First do the ones between --flag-switches-begin and --flag-switches-end. |
- base::CommandLine::StringVector::const_iterator first = |
- std::find(cmdline.argv().begin(), cmdline.argv().end(), |
- GetSwitchString(switches::kFlagSwitchesBegin)); |
- base::CommandLine::StringVector::const_iterator last = |
- std::find(cmdline.argv().begin(), cmdline.argv().end(), |
- GetSwitchString(switches::kFlagSwitchesEnd)); |
- if (first != cmdline.argv().end() && last != cmdline.argv().end()) |
- flags.insert(first + 1, last); |
-#if defined(OS_CHROMEOS) |
- // Then add those between --policy-switches-begin and --policy-switches-end. |
- first = std::find(cmdline.argv().begin(), cmdline.argv().end(), |
- GetSwitchString(chromeos::switches::kPolicySwitchesBegin)); |
- last = std::find(cmdline.argv().begin(), cmdline.argv().end(), |
- GetSwitchString(chromeos::switches::kPolicySwitchesEnd)); |
- if (first != cmdline.argv().end() && last != cmdline.argv().end()) |
- flags.insert(first + 1, last); |
-#endif |
- return flags; |
-} |
- |
const FeatureEntry::Choice kTouchEventsChoices[] = { |
{ IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC, "", "" }, |
{ IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, |
@@ -2111,193 +2057,28 @@ const FeatureEntry kFeatureEntries[] = { |
// histograms.xml and don't forget to run AboutFlagsHistogramTest unit test. |
}; |
-// Stores and encapsulates the little state that about:flags has. |
-class FlagsState { |
+class FlagsStateSingleton { |
public: |
- FlagsState() |
- : feature_entries(kFeatureEntries), |
- num_feature_entries(arraysize(kFeatureEntries)), |
- needs_restart_(false) {} |
- void ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage, |
- base::CommandLine* command_line, |
- SentinelsMode sentinels); |
- bool IsRestartNeededToCommitChanges(); |
- void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, |
- const std::string& internal_name, |
- bool enable); |
- void RemoveFlagsSwitches( |
- std::map<std::string, base::CommandLine::StringType>* switch_list); |
- void ResetAllFlags(flags_ui::FlagsStorage* flags_storage); |
- void Reset(); |
- |
- // Gets the list of feature entries. Entries that are available for the |
- // current platform are appended to |supported_entries|; all other entries are |
- // appended to |unsupported_entries|. |
- void GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage, |
- FlagAccess access, |
- base::ListValue* supported_entries, |
- base::ListValue* unsupported_entries); |
- |
- void SetFeatureEntries(const FeatureEntry* entries, size_t count); |
- const FeatureEntry* GetFeatureEntries(size_t* count); |
- |
- // Returns the singleton instance of this class |
- static FlagsState* GetInstance() { |
- return base::Singleton<FlagsState>::get(); |
- } |
+ FlagsStateSingleton() |
+ : flags_state_(kFeatureEntries, arraysize(kFeatureEntries)) {} |
+ ~FlagsStateSingleton() {} |
- private: |
- // Keeps track of affected switches for each FeatureEntry, based on which |
- // choice is selected for it. |
- struct SwitchEntry { |
- // Corresponding base::Feature to toggle. |
- std::string feature_name; |
- |
- // If |feature_name| is not empty, the state (enable/disabled) to set. |
- bool feature_state; |
- |
- // The name of the switch to add. |
- std::string switch_name; |
- |
- // If |switch_name| is not empty, the value of the switch to set. |
- std::string switch_value; |
- |
- SwitchEntry() : feature_state(false) {} |
- }; |
- |
- // Adds mapping to |name_to_switch_map| to set the given switch name/value. |
- void AddSwitchMapping(const std::string& key, |
- const std::string& switch_name, |
- const std::string& switch_value, |
- std::map<std::string, SwitchEntry>* name_to_switch_map); |
- |
- // Adds mapping to |name_to_switch_map| to toggle base::Feature |feature_name| |
- // to state |feature_state|. |
- void AddFeatureMapping( |
- const std::string& key, |
- const std::string& feature_name, |
- bool feature_state, |
- std::map<std::string, SwitchEntry>* name_to_switch_map); |
- |
- // Updates the switches in |command_line| by applying the modifications |
- // specified in |name_to_switch_map| for each entry in |enabled_entries|. |
- void AddSwitchesToCommandLine( |
- const std::set<std::string>& enabled_entries, |
- const std::map<std::string, SwitchEntry>& name_to_switch_map, |
- SentinelsMode sentinels, |
- base::CommandLine* command_line); |
- |
- // Updates |command_line| by merging the value of the --enable-features= or |
- // --disable-features= list (per the |switch_name| param) with corresponding |
- // entries in |feature_switches| that have value |feature_state|. Keeps track |
- // of the changes by updating |appended_switches|. |
- void MergeFeatureCommandLineSwitch( |
- const std::map<std::string, bool>& feature_switches, |
- const char* switch_name, |
- bool feature_state, |
- base::CommandLine* command_line); |
- |
- // Removes all entries from prefs::kEnabledLabsExperiments that are unknown, |
- // to prevent this list to become very long as entries are added and removed. |
- void SanitizeList(flags_ui::FlagsStorage* flags_storage); |
- |
- void GetSanitizedEnabledFlags(flags_ui::FlagsStorage* flags_storage, |
- std::set<std::string>* result); |
- |
- // Variant of GetSanitizedEnabledFlags that also removes any flags that aren't |
- // enabled on the current platform. |
- void GetSanitizedEnabledFlagsForCurrentPlatform( |
- flags_ui::FlagsStorage* flags_storage, |
- std::set<std::string>* result); |
- |
- const FeatureEntry* feature_entries; |
- size_t num_feature_entries; |
- |
- bool needs_restart_; |
- std::map<std::string, std::string> flags_switches_; |
- |
- // Map from switch name to a set of string, that keeps track which strings |
- // were appended to existing (list value) switches. |
- std::map<std::string, std::set<std::string>> appended_switches_; |
- |
- DISALLOW_COPY_AND_ASSIGN(FlagsState); |
-}; |
- |
-// Adds the internal names for the specified entry to |names|. |
-void AddInternalName(const FeatureEntry& e, std::set<std::string>* names) { |
- switch (e.type) { |
- case FeatureEntry::SINGLE_VALUE: |
- case FeatureEntry::SINGLE_DISABLE_VALUE: |
- names->insert(e.internal_name); |
- break; |
- case FeatureEntry::MULTI_VALUE: |
- case FeatureEntry::ENABLE_DISABLE_VALUE: |
- case FeatureEntry::FEATURE_VALUE: |
- for (int i = 0; i < e.num_choices; ++i) |
- names->insert(e.NameForChoice(i)); |
- break; |
+ static FlagsStateSingleton* GetInstance() { |
+ return base::Singleton<FlagsStateSingleton>::get(); |
} |
-} |
-// Confirms that an entry is valid, used in a DCHECK in |
-// SanitizeList below. |
-bool ValidateFeatureEntry(const FeatureEntry& e) { |
- switch (e.type) { |
- case FeatureEntry::SINGLE_VALUE: |
- case FeatureEntry::SINGLE_DISABLE_VALUE: |
- DCHECK_EQ(0, e.num_choices); |
- DCHECK(!e.choices); |
- return true; |
- case FeatureEntry::MULTI_VALUE: |
- DCHECK_GT(e.num_choices, 0); |
- DCHECK(e.choices); |
- DCHECK(e.choices[0].command_line_switch); |
- DCHECK_EQ('\0', e.choices[0].command_line_switch[0]); |
- return true; |
- case FeatureEntry::ENABLE_DISABLE_VALUE: |
- DCHECK_EQ(3, e.num_choices); |
- DCHECK(!e.choices); |
- DCHECK(e.command_line_switch); |
- DCHECK(e.command_line_value); |
- DCHECK(e.disable_command_line_switch); |
- DCHECK(e.disable_command_line_value); |
- return true; |
- case FeatureEntry::FEATURE_VALUE: |
- DCHECK_EQ(3, e.num_choices); |
- DCHECK(!e.choices); |
- DCHECK(e.feature); |
- return true; |
+ static flags_ui::FlagsState* GetFlagsState() { |
+ return &GetInstance()->flags_state_; |
} |
- NOTREACHED(); |
- return false; |
-} |
-void FlagsState::SanitizeList(flags_ui::FlagsStorage* flags_storage) { |
- std::set<std::string> known_entries; |
- for (size_t i = 0; i < num_feature_entries; ++i) { |
- DCHECK(ValidateFeatureEntry(feature_entries[i])); |
- AddInternalName(feature_entries[i], &known_entries); |
- } |
- |
- std::set<std::string> enabled_entries = flags_storage->GetFlags(); |
- |
- std::set<std::string> new_enabled_entries = |
- base::STLSetIntersection<std::set<std::string> >( |
- known_entries, enabled_entries); |
- |
- if (new_enabled_entries != enabled_entries) |
- flags_storage->SetFlags(new_enabled_entries); |
-} |
+ private: |
+ flags_ui::FlagsState flags_state_; |
-void FlagsState::GetSanitizedEnabledFlags(flags_ui::FlagsStorage* flags_storage, |
- std::set<std::string>* result) { |
- SanitizeList(flags_storage); |
- *result = flags_storage->GetFlags(); |
-} |
+ DISALLOW_COPY_AND_ASSIGN(FlagsStateSingleton); |
+}; |
bool SkipConditionalFeatureEntry(const FeatureEntry& entry) { |
version_info::Channel channel = chrome::GetChannel(); |
- |
#if defined(OS_ANDROID) |
// enable-data-reduction-proxy-dev is only available for the Dev/Beta channel. |
if (!strcmp("enable-data-reduction-proxy-dev", entry.internal_name) && |
@@ -2356,214 +2137,64 @@ bool SkipConditionalFeatureEntry(const FeatureEntry& entry) { |
return false; |
} |
-void FlagsState::GetSanitizedEnabledFlagsForCurrentPlatform( |
- flags_ui::FlagsStorage* flags_storage, |
- std::set<std::string>* result) { |
- GetSanitizedEnabledFlags(flags_storage, result); |
- |
- // Filter out any entries that aren't enabled on the current platform. We |
- // don't remove these from prefs else syncing to a platform with a different |
- // set of entries would be lossy. |
- std::set<std::string> platform_entries; |
- int current_platform = GetCurrentPlatform(); |
- for (size_t i = 0; i < num_feature_entries; ++i) { |
- const FeatureEntry& entry = feature_entries[i]; |
- if (entry.supported_platforms & current_platform) |
- AddInternalName(entry, &platform_entries); |
-#if defined(OS_CHROMEOS) |
- if (feature_entries[i].supported_platforms & kOsCrOSOwnerOnly) |
- AddInternalName(entry, &platform_entries); |
-#endif |
- } |
- |
- std::set<std::string> new_enabled_entries = |
- base::STLSetIntersection<std::set<std::string> >( |
- platform_entries, *result); |
- |
- result->swap(new_enabled_entries); |
-} |
- |
-// Returns true if none of this entry's options have been enabled. |
-bool IsDefaultValue( |
- const FeatureEntry& entry, |
- const std::set<std::string>& enabled_entries) { |
- switch (entry.type) { |
- case FeatureEntry::SINGLE_VALUE: |
- case FeatureEntry::SINGLE_DISABLE_VALUE: |
- return enabled_entries.count(entry.internal_name) == 0; |
- case FeatureEntry::MULTI_VALUE: |
- case FeatureEntry::ENABLE_DISABLE_VALUE: |
- case FeatureEntry::FEATURE_VALUE: |
- for (int i = 0; i < entry.num_choices; ++i) { |
- if (enabled_entries.count(entry.NameForChoice(i)) > 0) |
- return false; |
- } |
- return true; |
- } |
- NOTREACHED(); |
- return true; |
-} |
- |
-// Returns the Value representing the choice data in the specified entry. |
-base::Value* CreateChoiceData( |
- const FeatureEntry& entry, |
- const std::set<std::string>& enabled_entries) { |
- DCHECK(entry.type == FeatureEntry::MULTI_VALUE || |
- entry.type == FeatureEntry::ENABLE_DISABLE_VALUE || |
- entry.type == FeatureEntry::FEATURE_VALUE); |
- base::ListValue* result = new base::ListValue; |
- for (int i = 0; i < entry.num_choices; ++i) { |
- base::DictionaryValue* value = new base::DictionaryValue; |
- const std::string name = entry.NameForChoice(i); |
- value->SetString("internal_name", name); |
- value->SetString("description", entry.DescriptionForChoice(i)); |
- value->SetBoolean("selected", enabled_entries.count(name) > 0); |
- result->Append(value); |
- } |
- return result; |
-} |
- |
} // namespace |
void ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage, |
base::CommandLine* command_line, |
- SentinelsMode sentinels) { |
- FlagsState::GetInstance()->ConvertFlagsToSwitches(flags_storage, |
- command_line, |
- sentinels); |
+ flags_ui::SentinelsMode sentinels) { |
+ if (command_line->HasSwitch(switches::kNoExperiments)) |
+ return; |
+ |
+ FlagsStateSingleton::GetFlagsState()->ConvertFlagsToSwitches( |
+ flags_storage, command_line, sentinels, switches::kEnableFeatures, |
+ switches::kDisableFeatures); |
} |
bool AreSwitchesIdenticalToCurrentCommandLine( |
const base::CommandLine& new_cmdline, |
const base::CommandLine& active_cmdline, |
std::set<base::CommandLine::StringType>* out_difference) { |
- std::set<base::CommandLine::StringType> new_flags = |
- ExtractFlagsFromCommandLine(new_cmdline); |
- std::set<base::CommandLine::StringType> active_flags = |
- ExtractFlagsFromCommandLine(active_cmdline); |
- |
- bool result = false; |
- // Needed because std::equal doesn't check if the 2nd set is empty. |
- if (new_flags.size() == active_flags.size()) { |
- result = |
- std::equal(new_flags.begin(), new_flags.end(), active_flags.begin()); |
- } |
- |
- if (out_difference && !result) { |
- std::set_symmetric_difference( |
- new_flags.begin(), |
- new_flags.end(), |
- active_flags.begin(), |
- active_flags.end(), |
- std::inserter(*out_difference, out_difference->begin())); |
- } |
- |
- return result; |
-} |
- |
-void FlagsState::GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage, |
- FlagAccess access, |
- base::ListValue* supported_entries, |
- base::ListValue* unsupported_entries) { |
- std::set<std::string> enabled_entries; |
- GetSanitizedEnabledFlags(flags_storage, &enabled_entries); |
- |
- int current_platform = GetCurrentPlatform(); |
- |
- for (size_t i = 0; i < num_feature_entries; ++i) { |
- const FeatureEntry& entry = feature_entries[i]; |
- if (SkipConditionalFeatureEntry(entry)) |
- continue; |
- |
- base::DictionaryValue* data = new base::DictionaryValue(); |
- data->SetString("internal_name", entry.internal_name); |
- data->SetString("name", |
- l10n_util::GetStringUTF16(entry.visible_name_id)); |
- data->SetString("description", |
- l10n_util::GetStringUTF16( |
- entry.visible_description_id)); |
- |
- base::ListValue* supported_platforms = new base::ListValue(); |
- AddOsStrings(entry.supported_platforms, supported_platforms); |
- data->Set("supported_platforms", supported_platforms); |
- // True if the switch is not currently passed. |
- bool is_default_value = IsDefaultValue(entry, enabled_entries); |
- data->SetBoolean("is_default", is_default_value); |
- |
- switch (entry.type) { |
- case FeatureEntry::SINGLE_VALUE: |
- case FeatureEntry::SINGLE_DISABLE_VALUE: |
- data->SetBoolean( |
- "enabled", |
- (!is_default_value && |
- entry.type == FeatureEntry::SINGLE_VALUE) || |
- (is_default_value && |
- entry.type == FeatureEntry::SINGLE_DISABLE_VALUE)); |
- break; |
- case FeatureEntry::MULTI_VALUE: |
- case FeatureEntry::ENABLE_DISABLE_VALUE: |
- case FeatureEntry::FEATURE_VALUE: |
- data->Set("choices", CreateChoiceData(entry, enabled_entries)); |
- break; |
- } |
- |
- bool supported = (entry.supported_platforms & current_platform) != 0; |
+ const char* extra_flag_sentinel_begin_flag_name = nullptr; |
+ const char* extra_flag_sentinel_end_flag_name = nullptr; |
#if defined(OS_CHROMEOS) |
- if (access == kOwnerAccessToFlags && |
- (entry.supported_platforms & kOsCrOSOwnerOnly) != 0) { |
- supported = true; |
- } |
-#endif |
- if (supported) |
- supported_entries->Append(data); |
- else |
- unsupported_entries->Append(data); |
- } |
+ // Put the flags between --policy-switches--begin and --policy-switches-end on |
+ // ChromeOS. |
+ extra_flag_sentinel_begin_flag_name = |
+ chromeos::switches::kPolicySwitchesBegin; |
+ extra_flag_sentinel_end_flag_name = chromeos::switches::kPolicySwitchesEnd; |
+#endif |
+ return flags_ui::FlagsState::AreSwitchesIdenticalToCurrentCommandLine( |
+ new_cmdline, active_cmdline, out_difference, |
+ extra_flag_sentinel_begin_flag_name, extra_flag_sentinel_end_flag_name); |
} |
void GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage, |
- FlagAccess access, |
+ flags_ui::FlagAccess access, |
base::ListValue* supported_entries, |
base::ListValue* unsupported_entries) { |
- FlagsState::GetInstance()->GetFlagFeatureEntries(flags_storage, access, |
- supported_entries, |
- unsupported_entries); |
+ FlagsStateSingleton::GetFlagsState()->GetFlagFeatureEntries( |
+ flags_storage, access, supported_entries, unsupported_entries, |
+ base::Bind(&SkipConditionalFeatureEntry)); |
} |
bool IsRestartNeededToCommitChanges() { |
- return FlagsState::GetInstance()->IsRestartNeededToCommitChanges(); |
+ return FlagsStateSingleton::GetFlagsState()->IsRestartNeededToCommitChanges(); |
} |
void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, |
const std::string& internal_name, |
bool enable) { |
- FlagsState::GetInstance()->SetFeatureEntryEnabled(flags_storage, |
- internal_name, enable); |
+ FlagsStateSingleton::GetFlagsState()->SetFeatureEntryEnabled( |
+ flags_storage, internal_name, enable); |
} |
void RemoveFlagsSwitches( |
std::map<std::string, base::CommandLine::StringType>* switch_list) { |
- FlagsState::GetInstance()->RemoveFlagsSwitches(switch_list); |
+ FlagsStateSingleton::GetFlagsState()->RemoveFlagsSwitches(switch_list); |
} |
void ResetAllFlags(flags_ui::FlagsStorage* flags_storage) { |
- FlagsState::GetInstance()->ResetAllFlags(flags_storage); |
-} |
- |
-int GetCurrentPlatform() { |
-#if defined(OS_MACOSX) |
- return kOsMac; |
-#elif defined(OS_WIN) |
- return kOsWin; |
-#elif defined(OS_CHROMEOS) // Needs to be before the OS_LINUX check. |
- return kOsCrOS; |
-#elif defined(OS_LINUX) || defined(OS_OPENBSD) |
- return kOsLinux; |
-#elif defined(OS_ANDROID) |
- return kOsAndroid; |
-#else |
-#error Unknown platform |
-#endif |
+ FlagsStateSingleton::GetFlagsState()->ResetAllFlags(flags_storage); |
} |
void RecordUMAStatistics(flags_ui::FlagsStorage* flags_storage) { |
@@ -2612,310 +2243,13 @@ void ReportCustomFlags(const std::string& uma_histogram_hame, |
} |
} |
-////////////////////////////////////////////////////////////////////////////// |
-// FlagsState implementation. |
- |
-namespace { |
- |
-void FlagsState::ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage, |
- base::CommandLine* command_line, |
- SentinelsMode sentinels) { |
- if (command_line->HasSwitch(switches::kNoExperiments)) |
- return; |
- |
- std::set<std::string> enabled_entries; |
- |
- GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries); |
- |
- std::map<std::string, SwitchEntry> name_to_switch_map; |
- for (size_t i = 0; i < num_feature_entries; ++i) { |
- const FeatureEntry& e = feature_entries[i]; |
- switch (e.type) { |
- case FeatureEntry::SINGLE_VALUE: |
- case FeatureEntry::SINGLE_DISABLE_VALUE: |
- AddSwitchMapping(e.internal_name, e.command_line_switch, |
- e.command_line_value, &name_to_switch_map); |
- break; |
- case FeatureEntry::MULTI_VALUE: |
- for (int j = 0; j < e.num_choices; ++j) { |
- AddSwitchMapping(e.NameForChoice(j), e.choices[j].command_line_switch, |
- e.choices[j].command_line_value, |
- &name_to_switch_map); |
- } |
- break; |
- case FeatureEntry::ENABLE_DISABLE_VALUE: |
- AddSwitchMapping(e.NameForChoice(0), std::string(), std::string(), |
- &name_to_switch_map); |
- AddSwitchMapping(e.NameForChoice(1), e.command_line_switch, |
- e.command_line_value, &name_to_switch_map); |
- AddSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch, |
- e.disable_command_line_value, &name_to_switch_map); |
- break; |
- case FeatureEntry::FEATURE_VALUE: |
- AddFeatureMapping(e.NameForChoice(0), std::string(), false, |
- &name_to_switch_map); |
- AddFeatureMapping(e.NameForChoice(1), e.feature->name, true, |
- &name_to_switch_map); |
- AddFeatureMapping(e.NameForChoice(2), e.feature->name, false, |
- &name_to_switch_map); |
- break; |
- } |
- } |
- |
- AddSwitchesToCommandLine(enabled_entries, name_to_switch_map, sentinels, |
- command_line); |
-} |
- |
-bool FlagsState::IsRestartNeededToCommitChanges() { |
- return needs_restart_; |
-} |
- |
-void FlagsState::SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, |
- const std::string& internal_name, |
- bool enable) { |
- size_t at_index = internal_name.find(flags_ui::testing::kMultiSeparator); |
- if (at_index != std::string::npos) { |
- DCHECK(enable); |
- // We're being asked to enable a multi-choice entry. Disable the |
- // currently selected choice. |
- DCHECK_NE(at_index, 0u); |
- const std::string entry_name = internal_name.substr(0, at_index); |
- SetFeatureEntryEnabled(flags_storage, entry_name, false); |
- |
- // And enable the new choice, if it is not the default first choice. |
- if (internal_name != entry_name + "@0") { |
- std::set<std::string> enabled_entries; |
- GetSanitizedEnabledFlags(flags_storage, &enabled_entries); |
- needs_restart_ |= enabled_entries.insert(internal_name).second; |
- flags_storage->SetFlags(enabled_entries); |
- } |
- return; |
- } |
- |
- std::set<std::string> enabled_entries; |
- GetSanitizedEnabledFlags(flags_storage, &enabled_entries); |
- |
- const FeatureEntry* e = nullptr; |
- for (size_t i = 0; i < num_feature_entries; ++i) { |
- if (feature_entries[i].internal_name == internal_name) { |
- e = feature_entries + i; |
- break; |
- } |
- } |
- DCHECK(e); |
- |
- if (e->type == FeatureEntry::SINGLE_VALUE) { |
- if (enable) |
- needs_restart_ |= enabled_entries.insert(internal_name).second; |
- else |
- needs_restart_ |= (enabled_entries.erase(internal_name) > 0); |
- } else if (e->type == FeatureEntry::SINGLE_DISABLE_VALUE) { |
- if (!enable) |
- needs_restart_ |= enabled_entries.insert(internal_name).second; |
- else |
- needs_restart_ |= (enabled_entries.erase(internal_name) > 0); |
- } else { |
- if (enable) { |
- // Enable the first choice. |
- needs_restart_ |= enabled_entries.insert(e->NameForChoice(0)).second; |
- } else { |
- // Find the currently enabled choice and disable it. |
- for (int i = 0; i < e->num_choices; ++i) { |
- std::string choice_name = e->NameForChoice(i); |
- if (enabled_entries.find(choice_name) != |
- enabled_entries.end()) { |
- needs_restart_ = true; |
- enabled_entries.erase(choice_name); |
- // Continue on just in case there's a bug and more than one |
- // entry for this choice was enabled. |
- } |
- } |
- } |
- } |
- |
- flags_storage->SetFlags(enabled_entries); |
-} |
- |
-void FlagsState::RemoveFlagsSwitches( |
- std::map<std::string, base::CommandLine::StringType>* switch_list) { |
- for (const auto& entry : flags_switches_) |
- switch_list->erase(entry.first); |
- |
- // If feature entries were added to --enable-features= or --disable-features= |
- // lists, remove them here while preserving existing values. |
- for (const auto& entry : appended_switches_) { |
- const auto& switch_name = entry.first; |
- const auto& switch_added_values = entry.second; |
- |
- // The below is either a std::string or a base::string16 based on platform. |
- const auto& existing_value = (*switch_list)[switch_name]; |
-#if defined(OS_WIN) |
- const std::string existing_value_utf8 = base::UTF16ToUTF8(existing_value); |
-#else |
- const std::string& existing_value_utf8 = existing_value; |
-#endif |
- |
- std::vector<std::string> features = |
- base::FeatureList::SplitFeatureListString(existing_value_utf8); |
- std::vector<std::string> remaining_features; |
- // For any featrue name in |features| that is not in |switch_added_values| - |
- // i.e. it wasn't added by about_flags code, add it to |remaining_features|. |
- for (const std::string& feature : features) { |
- if (!ContainsKey(switch_added_values, feature)) |
- remaining_features.push_back(feature); |
- } |
- |
- // Either remove the flag entirely if |remaining_features| is empty, or set |
- // the new list. |
- if (remaining_features.empty()) { |
- switch_list->erase(switch_name); |
- } else { |
- std::string switch_value = base::JoinString(remaining_features, ","); |
-#if defined(OS_WIN) |
- (*switch_list)[switch_name] = base::UTF8ToUTF16(switch_value); |
-#else |
- (*switch_list)[switch_name] = switch_value; |
-#endif |
- } |
- } |
-} |
- |
-void FlagsState::ResetAllFlags(flags_ui::FlagsStorage* flags_storage) { |
- needs_restart_ = true; |
- |
- std::set<std::string> no_entries; |
- flags_storage->SetFlags(no_entries); |
-} |
- |
-void FlagsState::Reset() { |
- needs_restart_ = false; |
- flags_switches_.clear(); |
- appended_switches_.clear(); |
-} |
- |
-void FlagsState::SetFeatureEntries(const FeatureEntry* entries, size_t count) { |
- feature_entries = entries; |
- num_feature_entries = count; |
-} |
- |
-const FeatureEntry* FlagsState::GetFeatureEntries(size_t* count) { |
- *count = num_feature_entries; |
- return feature_entries; |
-} |
- |
-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) { |
- DCHECK(!ContainsKey(*name_to_switch_map, key)); |
- |
- SwitchEntry* entry = &(*name_to_switch_map)[key]; |
- entry->switch_name = switch_name; |
- entry->switch_value = switch_value; |
-} |
- |
-void FlagsState::AddFeatureMapping( |
- const std::string& key, |
- const std::string& feature_name, |
- bool feature_state, |
- std::map<std::string, SwitchEntry>* name_to_switch_map) { |
- DCHECK(!ContainsKey(*name_to_switch_map, key)); |
- |
- SwitchEntry* entry = &(*name_to_switch_map)[key]; |
- entry->feature_name = feature_name; |
- entry->feature_state = feature_state; |
-} |
- |
-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) { |
- std::map<std::string, bool> feature_switches; |
- if (sentinels == kAddSentinels) { |
- command_line->AppendSwitch(switches::kFlagSwitchesBegin); |
- flags_switches_[switches::kFlagSwitchesBegin] = std::string(); |
- } |
- |
- for (const std::string& entry_name : enabled_entries) { |
- const auto& entry_it = name_to_switch_map.find(entry_name); |
- if (entry_it == name_to_switch_map.end()) { |
- NOTREACHED(); |
- continue; |
- } |
- |
- const SwitchEntry& entry = entry_it->second; |
- if (!entry.feature_name.empty()) { |
- feature_switches[entry.feature_name] = entry.feature_state; |
- } else if (!entry.switch_name.empty()) { |
- command_line->AppendSwitchASCII(entry.switch_name, entry.switch_value); |
- flags_switches_[entry.switch_name] = entry.switch_value; |
- } |
- // If an entry doesn't match either of the above, then it is likely the |
- // default entry for a FEATURE_VALUE entry. Safe to ignore. |
- } |
- |
- if (!feature_switches.empty()) { |
- MergeFeatureCommandLineSwitch(feature_switches, switches::kEnableFeatures, |
- true, command_line); |
- MergeFeatureCommandLineSwitch(feature_switches, switches::kDisableFeatures, |
- false, command_line); |
- } |
- |
- if (sentinels == kAddSentinels) { |
- command_line->AppendSwitch(switches::kFlagSwitchesEnd); |
- flags_switches_[switches::kFlagSwitchesEnd] = std::string(); |
- } |
-} |
- |
-void FlagsState::MergeFeatureCommandLineSwitch( |
- const std::map<std::string, bool>& feature_switches, |
- const char* switch_name, |
- bool feature_state, |
- base::CommandLine* command_line) { |
- std::string original_switch_value = |
- command_line->GetSwitchValueASCII(switch_name); |
- std::vector<std::string> features = |
- base::FeatureList::SplitFeatureListString(original_switch_value); |
- // Only add features that don't already exist in the lists. |
- // Note: The ContainsValue() call results in O(n^2) performance, but in |
- // practice n should be very small. |
- for (const auto& entry : feature_switches) { |
- if (entry.second == feature_state && |
- !ContainsValue(features, entry.first)) { |
- features.push_back(entry.first); |
- appended_switches_[switch_name].insert(entry.first); |
- } |
- } |
- // Update the switch value only if it didn't change. This avoids setting an |
- // empty list or duplicating the same list (since AppendSwitch() adds the |
- // switch to the end but doesn't remove previous ones). |
- std::string switch_value = base::JoinString(features, ","); |
- if (switch_value != original_switch_value) |
- command_line->AppendSwitchASCII(switch_name, switch_value); |
-} |
- |
-} // namespace |
- |
namespace testing { |
const base::HistogramBase::Sample kBadSwitchFormatHistogramId = 0; |
-void ClearState() { |
- FlagsState::GetInstance()->Reset(); |
-} |
- |
-void SetFeatureEntries(const FeatureEntry* entries, size_t count) { |
- if (!entries) { |
- entries = kFeatureEntries; |
- count = arraysize(kFeatureEntries); |
- } |
- FlagsState::GetInstance()->SetFeatureEntries(entries, count); |
-} |
- |
const FeatureEntry* GetFeatureEntries(size_t* count) { |
- return FlagsState::GetInstance()->GetFeatureEntries(count); |
+ *count = arraysize(kFeatureEntries); |
+ return kFeatureEntries; |
} |
} // namespace testing |