Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/about_flags.h" | 5 #include "chrome/browser/about_flags.h" |
| 6 | 6 |
| 7 #include <iterator> | 7 #include <iterator> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/bind.h" | |
| 13 #include "base/callback.h" | |
| 12 #include "base/command_line.h" | 14 #include "base/command_line.h" |
| 13 #include "base/feature_list.h" | 15 #include "base/feature_list.h" |
| 14 #include "base/memory/singleton.h" | 16 #include "base/memory/singleton.h" |
| 15 #include "base/metrics/sparse_histogram.h" | 17 #include "base/metrics/sparse_histogram.h" |
| 16 #include "base/stl_util.h" | 18 #include "base/stl_util.h" |
| 17 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 19 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
| 20 #include "base/values.h" | 22 #include "base/values.h" |
| 21 #include "cc/base/switches.h" | 23 #include "cc/base/switches.h" |
| 22 #include "chrome/common/channel_info.h" | 24 #include "chrome/common/channel_info.h" |
| 23 #include "chrome/common/chrome_content_client.h" | 25 #include "chrome/common/chrome_content_client.h" |
| 24 #include "chrome/common/chrome_switches.h" | 26 #include "chrome/common/chrome_switches.h" |
| 25 #include "chrome/grit/chromium_strings.h" | 27 #include "chrome/grit/chromium_strings.h" |
| 26 #include "chrome/grit/generated_resources.h" | 28 #include "chrome/grit/generated_resources.h" |
| 27 #include "chrome/grit/google_chrome_strings.h" | 29 #include "chrome/grit/google_chrome_strings.h" |
| 28 #include "components/autofill/core/common/autofill_switches.h" | 30 #include "components/autofill/core/common/autofill_switches.h" |
| 29 #include "components/browser_sync/common/browser_sync_switches.h" | 31 #include "components/browser_sync/common/browser_sync_switches.h" |
| 30 #include "components/cloud_devices/common/cloud_devices_switches.h" | 32 #include "components/cloud_devices/common/cloud_devices_switches.h" |
| 31 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switc hes.h" | 33 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switc hes.h" |
| 32 #include "components/dom_distiller/core/dom_distiller_switches.h" | 34 #include "components/dom_distiller/core/dom_distiller_switches.h" |
| 33 #include "components/enhanced_bookmarks/enhanced_bookmark_switches.h" | 35 #include "components/enhanced_bookmarks/enhanced_bookmark_switches.h" |
| 34 #include "components/flags_ui/feature_entry_macros.h" | 36 #include "components/flags_ui/feature_entry_macros.h" |
| 35 #include "components/flags_ui/flags_storage.h" | 37 #include "components/flags_ui/flags_storage.h" |
| 38 #include "components/flags_ui/flags_ui_switches.h" | |
| 36 #include "components/metrics/metrics_hashes.h" | 39 #include "components/metrics/metrics_hashes.h" |
| 37 #include "components/nacl/common/nacl_switches.h" | 40 #include "components/nacl/common/nacl_switches.h" |
| 38 #include "components/offline_pages/offline_page_switches.h" | 41 #include "components/offline_pages/offline_page_switches.h" |
| 39 #include "components/omnibox/browser/omnibox_switches.h" | 42 #include "components/omnibox/browser/omnibox_switches.h" |
| 40 #include "components/password_manager/core/common/password_manager_switches.h" | 43 #include "components/password_manager/core/common/password_manager_switches.h" |
| 41 #include "components/proximity_auth/switches.h" | 44 #include "components/proximity_auth/switches.h" |
| 42 #include "components/search/search_switches.h" | 45 #include "components/search/search_switches.h" |
| 43 #include "components/signin/core/common/signin_switches.h" | 46 #include "components/signin/core/common/signin_switches.h" |
| 44 #include "components/sync_driver/sync_driver_switches.h" | 47 #include "components/sync_driver/sync_driver_switches.h" |
| 45 #include "components/tracing/tracing_switches.h" | 48 #include "components/tracing/tracing_switches.h" |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 | 85 |
| 83 #if defined(ENABLE_PRINT_PREVIEW) | 86 #if defined(ENABLE_PRINT_PREVIEW) |
| 84 #include "chrome/browser/ui/webui/print_preview/print_preview_distiller.h" | 87 #include "chrome/browser/ui/webui/print_preview/print_preview_distiller.h" |
| 85 #endif | 88 #endif |
| 86 | 89 |
| 87 #if defined(USE_OZONE) | 90 #if defined(USE_OZONE) |
| 88 #include "ui/ozone/public/ozone_switches.h" | 91 #include "ui/ozone/public/ozone_switches.h" |
| 89 #endif | 92 #endif |
| 90 | 93 |
| 91 using flags_ui::FeatureEntry; | 94 using flags_ui::FeatureEntry; |
| 95 using flags_ui::kOsMac; | |
| 96 using flags_ui::kOsWin; | |
| 97 using flags_ui::kOsLinux; | |
| 98 using flags_ui::kOsCrOS; | |
| 99 using flags_ui::kOsAndroid; | |
| 100 using flags_ui::kOsCrOSOwnerOnly; | |
| 92 | 101 |
| 93 namespace about_flags { | 102 namespace about_flags { |
| 94 | 103 |
| 95 namespace { | 104 namespace { |
| 96 | 105 |
| 97 // Enumeration of OSs. | |
| 98 enum { | |
| 99 kOsMac = 1 << 0, | |
| 100 kOsWin = 1 << 1, | |
| 101 kOsLinux = 1 << 2, | |
| 102 kOsCrOS = 1 << 3, | |
| 103 kOsAndroid = 1 << 4, | |
| 104 kOsCrOSOwnerOnly = 1 << 5 | |
| 105 }; | |
| 106 | |
| 107 const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid; | 106 const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid; |
| 108 const unsigned kOsDesktop = kOsMac | kOsWin | kOsLinux | kOsCrOS; | 107 const unsigned kOsDesktop = kOsMac | kOsWin | kOsLinux | kOsCrOS; |
| 109 | 108 |
| 110 // Adds a |StringValue| to |list| for each platform where |bitmask| indicates | |
| 111 // whether the entry is available on that platform. | |
| 112 void AddOsStrings(unsigned bitmask, base::ListValue* list) { | |
| 113 struct { | |
| 114 unsigned bit; | |
| 115 const char* const name; | |
| 116 } kBitsToOs[] = { | |
| 117 {kOsMac, "Mac"}, | |
| 118 {kOsWin, "Windows"}, | |
| 119 {kOsLinux, "Linux"}, | |
| 120 {kOsCrOS, "Chrome OS"}, | |
| 121 {kOsAndroid, "Android"}, | |
| 122 {kOsCrOSOwnerOnly, "Chrome OS (owner only)"}, | |
| 123 }; | |
| 124 for (size_t i = 0; i < arraysize(kBitsToOs); ++i) { | |
| 125 if (bitmask & kBitsToOs[i].bit) | |
| 126 list->Append(new base::StringValue(kBitsToOs[i].name)); | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 // Convert switch constants to proper CommandLine::StringType strings. | |
| 131 base::CommandLine::StringType GetSwitchString(const std::string& flag) { | |
| 132 base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM); | |
| 133 cmd_line.AppendSwitch(flag); | |
| 134 DCHECK_EQ(2U, cmd_line.argv().size()); | |
| 135 return cmd_line.argv()[1]; | |
| 136 } | |
| 137 | |
| 138 // Scoops flags from a command line. | |
| 139 std::set<base::CommandLine::StringType> ExtractFlagsFromCommandLine( | |
| 140 const base::CommandLine& cmdline) { | |
| 141 std::set<base::CommandLine::StringType> flags; | |
| 142 // First do the ones between --flag-switches-begin and --flag-switches-end. | |
| 143 base::CommandLine::StringVector::const_iterator first = | |
| 144 std::find(cmdline.argv().begin(), cmdline.argv().end(), | |
| 145 GetSwitchString(switches::kFlagSwitchesBegin)); | |
| 146 base::CommandLine::StringVector::const_iterator last = | |
| 147 std::find(cmdline.argv().begin(), cmdline.argv().end(), | |
| 148 GetSwitchString(switches::kFlagSwitchesEnd)); | |
| 149 if (first != cmdline.argv().end() && last != cmdline.argv().end()) | |
| 150 flags.insert(first + 1, last); | |
| 151 #if defined(OS_CHROMEOS) | |
| 152 // Then add those between --policy-switches-begin and --policy-switches-end. | |
| 153 first = std::find(cmdline.argv().begin(), cmdline.argv().end(), | |
| 154 GetSwitchString(chromeos::switches::kPolicySwitchesBegin)); | |
| 155 last = std::find(cmdline.argv().begin(), cmdline.argv().end(), | |
| 156 GetSwitchString(chromeos::switches::kPolicySwitchesEnd)); | |
| 157 if (first != cmdline.argv().end() && last != cmdline.argv().end()) | |
| 158 flags.insert(first + 1, last); | |
| 159 #endif | |
| 160 return flags; | |
| 161 } | |
| 162 | |
| 163 const FeatureEntry::Choice kTouchEventsChoices[] = { | 109 const FeatureEntry::Choice kTouchEventsChoices[] = { |
| 164 { IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC, "", "" }, | 110 { IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC, "", "" }, |
| 165 { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, | 111 { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, |
| 166 switches::kTouchEvents, | 112 switches::kTouchEvents, |
| 167 switches::kTouchEventsEnabled }, | 113 switches::kTouchEventsEnabled }, |
| 168 { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED, | 114 { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED, |
| 169 switches::kTouchEvents, | 115 switches::kTouchEvents, |
| 170 switches::kTouchEventsDisabled } | 116 switches::kTouchEventsDisabled } |
| 171 }; | 117 }; |
| 172 | 118 |
| (...skipping 1936 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2109 kOsCrOS | kOsWin | kOsLinux, | 2055 kOsCrOS | kOsWin | kOsLinux, |
| 2110 ENABLE_DISABLE_VALUE_TYPE( | 2056 ENABLE_DISABLE_VALUE_TYPE( |
| 2111 autofill::switches::kEnableOfferUploadCreditCards, | 2057 autofill::switches::kEnableOfferUploadCreditCards, |
| 2112 autofill::switches::kDisableOfferUploadCreditCards)}, | 2058 autofill::switches::kDisableOfferUploadCreditCards)}, |
| 2113 #endif // defined(TOOLKIT_VIEWS) | 2059 #endif // defined(TOOLKIT_VIEWS) |
| 2114 // NOTE: Adding new command-line switches requires adding corresponding | 2060 // NOTE: Adding new command-line switches requires adding corresponding |
| 2115 // entries to enum "LoginCustomFlags" in histograms.xml. See note in | 2061 // entries to enum "LoginCustomFlags" in histograms.xml. See note in |
| 2116 // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test. | 2062 // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test. |
| 2117 }; | 2063 }; |
| 2118 | 2064 |
| 2119 // Stores and encapsulates the little state that about:flags has. | 2065 class FlagsStateSingleton { |
| 2120 class FlagsState { | |
| 2121 public: | 2066 public: |
| 2122 FlagsState() | 2067 FlagsStateSingleton() |
| 2123 : feature_entries(kFeatureEntries), | 2068 : flags_state_(kFeatureEntries, arraysize(kFeatureEntries)) {} |
| 2124 num_feature_entries(arraysize(kFeatureEntries)), | 2069 ~FlagsStateSingleton() {} |
| 2125 needs_restart_(false) {} | |
| 2126 void ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage, | |
| 2127 base::CommandLine* command_line, | |
| 2128 SentinelsMode sentinels); | |
| 2129 bool IsRestartNeededToCommitChanges(); | |
| 2130 void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, | |
| 2131 const std::string& internal_name, | |
| 2132 bool enable); | |
| 2133 void RemoveFlagsSwitches( | |
| 2134 std::map<std::string, base::CommandLine::StringType>* switch_list); | |
| 2135 void ResetAllFlags(flags_ui::FlagsStorage* flags_storage); | |
| 2136 void Reset(); | |
| 2137 | 2070 |
| 2138 // Gets the list of feature entries. Entries that are available for the | 2071 static FlagsStateSingleton* GetInstance() { |
| 2139 // current platform are appended to |supported_entries|; all other entries are | 2072 return base::Singleton<FlagsStateSingleton>::get(); |
| 2140 // appended to |unsupported_entries|. | 2073 } |
| 2141 void GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage, | |
| 2142 FlagAccess access, | |
| 2143 base::ListValue* supported_entries, | |
| 2144 base::ListValue* unsupported_entries); | |
| 2145 | 2074 |
| 2146 void SetFeatureEntries(const FeatureEntry* entries, size_t count); | 2075 static flags_ui::FlagsState* GetFlagsState() { |
| 2147 const FeatureEntry* GetFeatureEntries(size_t* count); | 2076 return &GetInstance()->flags_state_; |
| 2148 | |
| 2149 // Returns the singleton instance of this class | |
| 2150 static FlagsState* GetInstance() { | |
| 2151 return base::Singleton<FlagsState>::get(); | |
| 2152 } | 2077 } |
| 2153 | 2078 |
| 2154 private: | 2079 private: |
| 2155 // Keeps track of affected switches for each FeatureEntry, based on which | 2080 flags_ui::FlagsState flags_state_; |
| 2156 // choice is selected for it. | |
| 2157 struct SwitchEntry { | |
| 2158 // Corresponding base::Feature to toggle. | |
| 2159 std::string feature_name; | |
| 2160 | 2081 |
| 2161 // If |feature_name| is not empty, the state (enable/disabled) to set. | 2082 DISALLOW_COPY_AND_ASSIGN(FlagsStateSingleton); |
| 2162 bool feature_state; | |
| 2163 | |
| 2164 // The name of the switch to add. | |
| 2165 std::string switch_name; | |
| 2166 | |
| 2167 // If |switch_name| is not empty, the value of the switch to set. | |
| 2168 std::string switch_value; | |
| 2169 | |
| 2170 SwitchEntry() : feature_state(false) {} | |
| 2171 }; | |
| 2172 | |
| 2173 // Adds mapping to |name_to_switch_map| to set the given switch name/value. | |
| 2174 void AddSwitchMapping(const std::string& key, | |
| 2175 const std::string& switch_name, | |
| 2176 const std::string& switch_value, | |
| 2177 std::map<std::string, SwitchEntry>* name_to_switch_map); | |
| 2178 | |
| 2179 // Adds mapping to |name_to_switch_map| to toggle base::Feature |feature_name| | |
| 2180 // to state |feature_state|. | |
| 2181 void AddFeatureMapping( | |
| 2182 const std::string& key, | |
| 2183 const std::string& feature_name, | |
| 2184 bool feature_state, | |
| 2185 std::map<std::string, SwitchEntry>* name_to_switch_map); | |
| 2186 | |
| 2187 // Updates the switches in |command_line| by applying the modifications | |
| 2188 // specified in |name_to_switch_map| for each entry in |enabled_entries|. | |
| 2189 void AddSwitchesToCommandLine( | |
| 2190 const std::set<std::string>& enabled_entries, | |
| 2191 const std::map<std::string, SwitchEntry>& name_to_switch_map, | |
| 2192 SentinelsMode sentinels, | |
| 2193 base::CommandLine* command_line); | |
| 2194 | |
| 2195 // Updates |command_line| by merging the value of the --enable-features= or | |
| 2196 // --disable-features= list (per the |switch_name| param) with corresponding | |
| 2197 // entries in |feature_switches| that have value |feature_state|. Keeps track | |
| 2198 // of the changes by updating |appended_switches|. | |
| 2199 void MergeFeatureCommandLineSwitch( | |
| 2200 const std::map<std::string, bool>& feature_switches, | |
| 2201 const char* switch_name, | |
| 2202 bool feature_state, | |
| 2203 base::CommandLine* command_line); | |
| 2204 | |
| 2205 // Removes all entries from prefs::kEnabledLabsExperiments that are unknown, | |
| 2206 // to prevent this list to become very long as entries are added and removed. | |
| 2207 void SanitizeList(flags_ui::FlagsStorage* flags_storage); | |
| 2208 | |
| 2209 void GetSanitizedEnabledFlags(flags_ui::FlagsStorage* flags_storage, | |
| 2210 std::set<std::string>* result); | |
| 2211 | |
| 2212 // Variant of GetSanitizedEnabledFlags that also removes any flags that aren't | |
| 2213 // enabled on the current platform. | |
| 2214 void GetSanitizedEnabledFlagsForCurrentPlatform( | |
| 2215 flags_ui::FlagsStorage* flags_storage, | |
| 2216 std::set<std::string>* result); | |
| 2217 | |
| 2218 const FeatureEntry* feature_entries; | |
| 2219 size_t num_feature_entries; | |
| 2220 | |
| 2221 bool needs_restart_; | |
| 2222 std::map<std::string, std::string> flags_switches_; | |
| 2223 | |
| 2224 // Map from switch name to a set of string, that keeps track which strings | |
| 2225 // were appended to existing (list value) switches. | |
| 2226 std::map<std::string, std::set<std::string>> appended_switches_; | |
| 2227 | |
| 2228 DISALLOW_COPY_AND_ASSIGN(FlagsState); | |
| 2229 }; | 2083 }; |
| 2230 | 2084 |
| 2231 // Adds the internal names for the specified entry to |names|. | 2085 bool SkipConditionalFeatureEntry(version_info::Channel channel, |
|
Alexei Svitkine (slow)
2015/11/16 21:52:54
Nit: Seems like it's not really needed to add a ch
sdefresne
2015/11/17 16:28:56
Reverted.
| |
| 2232 void AddInternalName(const FeatureEntry& e, std::set<std::string>* names) { | 2086 const FeatureEntry& entry) { |
| 2233 switch (e.type) { | |
| 2234 case FeatureEntry::SINGLE_VALUE: | |
| 2235 case FeatureEntry::SINGLE_DISABLE_VALUE: | |
| 2236 names->insert(e.internal_name); | |
| 2237 break; | |
| 2238 case FeatureEntry::MULTI_VALUE: | |
| 2239 case FeatureEntry::ENABLE_DISABLE_VALUE: | |
| 2240 case FeatureEntry::FEATURE_VALUE: | |
| 2241 for (int i = 0; i < e.num_choices; ++i) | |
| 2242 names->insert(e.NameForChoice(i)); | |
| 2243 break; | |
| 2244 } | |
| 2245 } | |
| 2246 | |
| 2247 // Confirms that an entry is valid, used in a DCHECK in | |
| 2248 // SanitizeList below. | |
| 2249 bool ValidateFeatureEntry(const FeatureEntry& e) { | |
| 2250 switch (e.type) { | |
| 2251 case FeatureEntry::SINGLE_VALUE: | |
| 2252 case FeatureEntry::SINGLE_DISABLE_VALUE: | |
| 2253 DCHECK_EQ(0, e.num_choices); | |
| 2254 DCHECK(!e.choices); | |
| 2255 return true; | |
| 2256 case FeatureEntry::MULTI_VALUE: | |
| 2257 DCHECK_GT(e.num_choices, 0); | |
| 2258 DCHECK(e.choices); | |
| 2259 DCHECK(e.choices[0].command_line_switch); | |
| 2260 DCHECK_EQ('\0', e.choices[0].command_line_switch[0]); | |
| 2261 return true; | |
| 2262 case FeatureEntry::ENABLE_DISABLE_VALUE: | |
| 2263 DCHECK_EQ(3, e.num_choices); | |
| 2264 DCHECK(!e.choices); | |
| 2265 DCHECK(e.command_line_switch); | |
| 2266 DCHECK(e.command_line_value); | |
| 2267 DCHECK(e.disable_command_line_switch); | |
| 2268 DCHECK(e.disable_command_line_value); | |
| 2269 return true; | |
| 2270 case FeatureEntry::FEATURE_VALUE: | |
| 2271 DCHECK_EQ(3, e.num_choices); | |
| 2272 DCHECK(!e.choices); | |
| 2273 DCHECK(e.feature); | |
| 2274 return true; | |
| 2275 } | |
| 2276 NOTREACHED(); | |
| 2277 return false; | |
| 2278 } | |
| 2279 | |
| 2280 void FlagsState::SanitizeList(flags_ui::FlagsStorage* flags_storage) { | |
| 2281 std::set<std::string> known_entries; | |
| 2282 for (size_t i = 0; i < num_feature_entries; ++i) { | |
| 2283 DCHECK(ValidateFeatureEntry(feature_entries[i])); | |
| 2284 AddInternalName(feature_entries[i], &known_entries); | |
| 2285 } | |
| 2286 | |
| 2287 std::set<std::string> enabled_entries = flags_storage->GetFlags(); | |
| 2288 | |
| 2289 std::set<std::string> new_enabled_entries = | |
| 2290 base::STLSetIntersection<std::set<std::string> >( | |
| 2291 known_entries, enabled_entries); | |
| 2292 | |
| 2293 if (new_enabled_entries != enabled_entries) | |
| 2294 flags_storage->SetFlags(new_enabled_entries); | |
| 2295 } | |
| 2296 | |
| 2297 void FlagsState::GetSanitizedEnabledFlags(flags_ui::FlagsStorage* flags_storage, | |
| 2298 std::set<std::string>* result) { | |
| 2299 SanitizeList(flags_storage); | |
| 2300 *result = flags_storage->GetFlags(); | |
| 2301 } | |
| 2302 | |
| 2303 bool SkipConditionalFeatureEntry(const FeatureEntry& entry) { | |
| 2304 version_info::Channel channel = chrome::GetChannel(); | |
| 2305 | |
| 2306 #if defined(OS_ANDROID) | 2087 #if defined(OS_ANDROID) |
| 2307 // enable-data-reduction-proxy-dev is only available for the Dev/Beta channel. | 2088 // enable-data-reduction-proxy-dev is only available for the Dev/Beta channel. |
| 2308 if (!strcmp("enable-data-reduction-proxy-dev", entry.internal_name) && | 2089 if (!strcmp("enable-data-reduction-proxy-dev", entry.internal_name) && |
| 2309 channel != version_info::Channel::BETA && | 2090 channel != version_info::Channel::BETA && |
| 2310 channel != version_info::Channel::DEV) { | 2091 channel != version_info::Channel::DEV) { |
| 2311 return true; | 2092 return true; |
| 2312 } | 2093 } |
| 2313 // enable-data-reduction-proxy-alt is only available for the Dev channel. | 2094 // enable-data-reduction-proxy-alt is only available for the Dev channel. |
| 2314 if (!strcmp("enable-data-reduction-proxy-alt", entry.internal_name) && | 2095 if (!strcmp("enable-data-reduction-proxy-alt", entry.internal_name) && |
| 2315 channel != version_info::Channel::DEV) { | 2096 channel != version_info::Channel::DEV) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2354 channel != version_info::Channel::UNKNOWN && | 2135 channel != version_info::Channel::UNKNOWN && |
| 2355 channel != version_info::Channel::CANARY && | 2136 channel != version_info::Channel::CANARY && |
| 2356 channel != version_info::Channel::DEV) { | 2137 channel != version_info::Channel::DEV) { |
| 2357 return true; | 2138 return true; |
| 2358 } | 2139 } |
| 2359 #endif | 2140 #endif |
| 2360 | 2141 |
| 2361 return false; | 2142 return false; |
| 2362 } | 2143 } |
| 2363 | 2144 |
| 2364 void FlagsState::GetSanitizedEnabledFlagsForCurrentPlatform( | |
| 2365 flags_ui::FlagsStorage* flags_storage, | |
| 2366 std::set<std::string>* result) { | |
| 2367 GetSanitizedEnabledFlags(flags_storage, result); | |
| 2368 | |
| 2369 // Filter out any entries that aren't enabled on the current platform. We | |
| 2370 // don't remove these from prefs else syncing to a platform with a different | |
| 2371 // set of entries would be lossy. | |
| 2372 std::set<std::string> platform_entries; | |
| 2373 int current_platform = GetCurrentPlatform(); | |
| 2374 for (size_t i = 0; i < num_feature_entries; ++i) { | |
| 2375 const FeatureEntry& entry = feature_entries[i]; | |
| 2376 if (entry.supported_platforms & current_platform) | |
| 2377 AddInternalName(entry, &platform_entries); | |
| 2378 #if defined(OS_CHROMEOS) | |
| 2379 if (feature_entries[i].supported_platforms & kOsCrOSOwnerOnly) | |
| 2380 AddInternalName(entry, &platform_entries); | |
| 2381 #endif | |
| 2382 } | |
| 2383 | |
| 2384 std::set<std::string> new_enabled_entries = | |
| 2385 base::STLSetIntersection<std::set<std::string> >( | |
| 2386 platform_entries, *result); | |
| 2387 | |
| 2388 result->swap(new_enabled_entries); | |
| 2389 } | |
| 2390 | |
| 2391 // Returns true if none of this entry's options have been enabled. | |
| 2392 bool IsDefaultValue( | |
| 2393 const FeatureEntry& entry, | |
| 2394 const std::set<std::string>& enabled_entries) { | |
| 2395 switch (entry.type) { | |
| 2396 case FeatureEntry::SINGLE_VALUE: | |
| 2397 case FeatureEntry::SINGLE_DISABLE_VALUE: | |
| 2398 return enabled_entries.count(entry.internal_name) == 0; | |
| 2399 case FeatureEntry::MULTI_VALUE: | |
| 2400 case FeatureEntry::ENABLE_DISABLE_VALUE: | |
| 2401 case FeatureEntry::FEATURE_VALUE: | |
| 2402 for (int i = 0; i < entry.num_choices; ++i) { | |
| 2403 if (enabled_entries.count(entry.NameForChoice(i)) > 0) | |
| 2404 return false; | |
| 2405 } | |
| 2406 return true; | |
| 2407 } | |
| 2408 NOTREACHED(); | |
| 2409 return true; | |
| 2410 } | |
| 2411 | |
| 2412 // Returns the Value representing the choice data in the specified entry. | |
| 2413 base::Value* CreateChoiceData( | |
| 2414 const FeatureEntry& entry, | |
| 2415 const std::set<std::string>& enabled_entries) { | |
| 2416 DCHECK(entry.type == FeatureEntry::MULTI_VALUE || | |
| 2417 entry.type == FeatureEntry::ENABLE_DISABLE_VALUE || | |
| 2418 entry.type == FeatureEntry::FEATURE_VALUE); | |
| 2419 base::ListValue* result = new base::ListValue; | |
| 2420 for (int i = 0; i < entry.num_choices; ++i) { | |
| 2421 base::DictionaryValue* value = new base::DictionaryValue; | |
| 2422 const std::string name = entry.NameForChoice(i); | |
| 2423 value->SetString("internal_name", name); | |
| 2424 value->SetString("description", entry.DescriptionForChoice(i)); | |
| 2425 value->SetBoolean("selected", enabled_entries.count(name) > 0); | |
| 2426 result->Append(value); | |
| 2427 } | |
| 2428 return result; | |
| 2429 } | |
| 2430 | |
| 2431 } // namespace | 2145 } // namespace |
| 2432 | 2146 |
| 2433 void ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage, | 2147 void ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage, |
| 2434 base::CommandLine* command_line, | 2148 base::CommandLine* command_line, |
| 2435 SentinelsMode sentinels) { | 2149 flags_ui::SentinelsMode sentinels) { |
| 2436 FlagsState::GetInstance()->ConvertFlagsToSwitches(flags_storage, | 2150 if (command_line->HasSwitch(switches::kNoExperiments)) |
| 2437 command_line, | 2151 return; |
| 2438 sentinels); | 2152 |
| 2153 FlagsStateSingleton::GetFlagsState()->ConvertFlagsToSwitches( | |
| 2154 flags_storage, command_line, sentinels, switches::kEnableFeatures, | |
| 2155 switches::kDisableFeatures); | |
| 2439 } | 2156 } |
| 2440 | 2157 |
| 2441 bool AreSwitchesIdenticalToCurrentCommandLine( | 2158 bool AreSwitchesIdenticalToCurrentCommandLine( |
| 2442 const base::CommandLine& new_cmdline, | 2159 const base::CommandLine& new_cmdline, |
| 2443 const base::CommandLine& active_cmdline, | 2160 const base::CommandLine& active_cmdline, |
| 2444 std::set<base::CommandLine::StringType>* out_difference) { | 2161 std::set<base::CommandLine::StringType>* out_difference) { |
| 2445 std::set<base::CommandLine::StringType> new_flags = | 2162 #if !defined(OS_CHROMEOS) |
| 2446 ExtractFlagsFromCommandLine(new_cmdline); | 2163 const char* extra_flag_sentinel_begin_flag_name = nullptr; |
| 2447 std::set<base::CommandLine::StringType> active_flags = | 2164 const char* extra_flag_sentinel_end_flag_name = nullptr; |
| 2448 ExtractFlagsFromCommandLine(active_cmdline); | 2165 #else |
| 2449 | 2166 const char* extra_flag_sentinel_begin_flag_name = |
|
Alexei Svitkine (slow)
2015/11/16 21:52:54
Add a comment about this logic.
Nit: Also, how ab
sdefresne
2015/11/17 16:28:56
Done.
| |
| 2450 bool result = false; | 2167 chromeos::switches::kPolicySwitchesBegin; |
| 2451 // Needed because std::equal doesn't check if the 2nd set is empty. | 2168 const char* extra_flag_sentinel_end_flag_name = |
| 2452 if (new_flags.size() == active_flags.size()) { | 2169 chromeos::switches::kPolicySwitchesEnd; |
| 2453 result = | |
| 2454 std::equal(new_flags.begin(), new_flags.end(), active_flags.begin()); | |
| 2455 } | |
| 2456 | |
| 2457 if (out_difference && !result) { | |
| 2458 std::set_symmetric_difference( | |
| 2459 new_flags.begin(), | |
| 2460 new_flags.end(), | |
| 2461 active_flags.begin(), | |
| 2462 active_flags.end(), | |
| 2463 std::inserter(*out_difference, out_difference->begin())); | |
| 2464 } | |
| 2465 | |
| 2466 return result; | |
| 2467 } | |
| 2468 | |
| 2469 void FlagsState::GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage, | |
| 2470 FlagAccess access, | |
| 2471 base::ListValue* supported_entries, | |
| 2472 base::ListValue* unsupported_entries) { | |
| 2473 std::set<std::string> enabled_entries; | |
| 2474 GetSanitizedEnabledFlags(flags_storage, &enabled_entries); | |
| 2475 | |
| 2476 int current_platform = GetCurrentPlatform(); | |
| 2477 | |
| 2478 for (size_t i = 0; i < num_feature_entries; ++i) { | |
| 2479 const FeatureEntry& entry = feature_entries[i]; | |
| 2480 if (SkipConditionalFeatureEntry(entry)) | |
| 2481 continue; | |
| 2482 | |
| 2483 base::DictionaryValue* data = new base::DictionaryValue(); | |
| 2484 data->SetString("internal_name", entry.internal_name); | |
| 2485 data->SetString("name", | |
| 2486 l10n_util::GetStringUTF16(entry.visible_name_id)); | |
| 2487 data->SetString("description", | |
| 2488 l10n_util::GetStringUTF16( | |
| 2489 entry.visible_description_id)); | |
| 2490 | |
| 2491 base::ListValue* supported_platforms = new base::ListValue(); | |
| 2492 AddOsStrings(entry.supported_platforms, supported_platforms); | |
| 2493 data->Set("supported_platforms", supported_platforms); | |
| 2494 // True if the switch is not currently passed. | |
| 2495 bool is_default_value = IsDefaultValue(entry, enabled_entries); | |
| 2496 data->SetBoolean("is_default", is_default_value); | |
| 2497 | |
| 2498 switch (entry.type) { | |
| 2499 case FeatureEntry::SINGLE_VALUE: | |
| 2500 case FeatureEntry::SINGLE_DISABLE_VALUE: | |
| 2501 data->SetBoolean( | |
| 2502 "enabled", | |
| 2503 (!is_default_value && | |
| 2504 entry.type == FeatureEntry::SINGLE_VALUE) || | |
| 2505 (is_default_value && | |
| 2506 entry.type == FeatureEntry::SINGLE_DISABLE_VALUE)); | |
| 2507 break; | |
| 2508 case FeatureEntry::MULTI_VALUE: | |
| 2509 case FeatureEntry::ENABLE_DISABLE_VALUE: | |
| 2510 case FeatureEntry::FEATURE_VALUE: | |
| 2511 data->Set("choices", CreateChoiceData(entry, enabled_entries)); | |
| 2512 break; | |
| 2513 } | |
| 2514 | |
| 2515 bool supported = (entry.supported_platforms & current_platform) != 0; | |
| 2516 #if defined(OS_CHROMEOS) | |
| 2517 if (access == kOwnerAccessToFlags && | |
| 2518 (entry.supported_platforms & kOsCrOSOwnerOnly) != 0) { | |
| 2519 supported = true; | |
| 2520 } | |
| 2521 #endif | 2170 #endif |
| 2522 if (supported) | 2171 return flags_ui::FlagsState::AreSwitchesIdenticalToCurrentCommandLine( |
| 2523 supported_entries->Append(data); | 2172 new_cmdline, active_cmdline, out_difference, |
| 2524 else | 2173 extra_flag_sentinel_begin_flag_name, extra_flag_sentinel_end_flag_name); |
| 2525 unsupported_entries->Append(data); | |
| 2526 } | |
| 2527 } | 2174 } |
| 2528 | 2175 |
| 2529 void GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage, | 2176 void GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage, |
| 2530 FlagAccess access, | 2177 flags_ui::FlagAccess access, |
| 2531 base::ListValue* supported_entries, | 2178 base::ListValue* supported_entries, |
| 2532 base::ListValue* unsupported_entries) { | 2179 base::ListValue* unsupported_entries) { |
| 2533 FlagsState::GetInstance()->GetFlagFeatureEntries(flags_storage, access, | 2180 version_info::Channel channel = chrome::GetChannel(); |
| 2534 supported_entries, | 2181 FlagsStateSingleton::GetFlagsState()->GetFlagFeatureEntries( |
| 2535 unsupported_entries); | 2182 flags_storage, access, supported_entries, unsupported_entries, |
| 2183 base::Bind(&SkipConditionalFeatureEntry, channel)); | |
| 2536 } | 2184 } |
| 2537 | 2185 |
| 2538 bool IsRestartNeededToCommitChanges() { | 2186 bool IsRestartNeededToCommitChanges() { |
| 2539 return FlagsState::GetInstance()->IsRestartNeededToCommitChanges(); | 2187 return FlagsStateSingleton::GetFlagsState()->IsRestartNeededToCommitChanges(); |
| 2540 } | 2188 } |
| 2541 | 2189 |
| 2542 void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, | 2190 void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, |
| 2543 const std::string& internal_name, | 2191 const std::string& internal_name, |
| 2544 bool enable) { | 2192 bool enable) { |
| 2545 FlagsState::GetInstance()->SetFeatureEntryEnabled(flags_storage, | 2193 FlagsStateSingleton::GetFlagsState()->SetFeatureEntryEnabled( |
| 2546 internal_name, enable); | 2194 flags_storage, internal_name, enable); |
| 2547 } | 2195 } |
| 2548 | 2196 |
| 2549 void RemoveFlagsSwitches( | 2197 void RemoveFlagsSwitches( |
| 2550 std::map<std::string, base::CommandLine::StringType>* switch_list) { | 2198 std::map<std::string, base::CommandLine::StringType>* switch_list) { |
| 2551 FlagsState::GetInstance()->RemoveFlagsSwitches(switch_list); | 2199 FlagsStateSingleton::GetFlagsState()->RemoveFlagsSwitches(switch_list); |
| 2552 } | 2200 } |
| 2553 | 2201 |
| 2554 void ResetAllFlags(flags_ui::FlagsStorage* flags_storage) { | 2202 void ResetAllFlags(flags_ui::FlagsStorage* flags_storage) { |
| 2555 FlagsState::GetInstance()->ResetAllFlags(flags_storage); | 2203 FlagsStateSingleton::GetFlagsState()->ResetAllFlags(flags_storage); |
| 2556 } | |
| 2557 | |
| 2558 int GetCurrentPlatform() { | |
| 2559 #if defined(OS_MACOSX) | |
| 2560 return kOsMac; | |
| 2561 #elif defined(OS_WIN) | |
| 2562 return kOsWin; | |
| 2563 #elif defined(OS_CHROMEOS) // Needs to be before the OS_LINUX check. | |
| 2564 return kOsCrOS; | |
| 2565 #elif defined(OS_LINUX) || defined(OS_OPENBSD) | |
| 2566 return kOsLinux; | |
| 2567 #elif defined(OS_ANDROID) | |
| 2568 return kOsAndroid; | |
| 2569 #else | |
| 2570 #error Unknown platform | |
| 2571 #endif | |
| 2572 } | 2204 } |
| 2573 | 2205 |
| 2574 void RecordUMAStatistics(flags_ui::FlagsStorage* flags_storage) { | 2206 void RecordUMAStatistics(flags_ui::FlagsStorage* flags_storage) { |
| 2575 std::set<std::string> flags = flags_storage->GetFlags(); | 2207 std::set<std::string> flags = flags_storage->GetFlags(); |
| 2576 for (const std::string& flag : flags) { | 2208 for (const std::string& flag : flags) { |
| 2577 std::string action("AboutFlags_"); | 2209 std::string action("AboutFlags_"); |
| 2578 action += flag; | 2210 action += flag; |
| 2579 content::RecordComputedAction(action); | 2211 content::RecordComputedAction(action); |
| 2580 } | 2212 } |
| 2581 // Since flag metrics are recorded every startup, add a tick so that the | 2213 // Since flag metrics are recorded every startup, add a tick so that the |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 2610 } | 2242 } |
| 2611 DVLOG(1) << "ReportCustomFlags(): histogram='" << uma_histogram_hame | 2243 DVLOG(1) << "ReportCustomFlags(): histogram='" << uma_histogram_hame |
| 2612 << "' '" << flag << "', uma_id=" << uma_id; | 2244 << "' '" << flag << "', uma_id=" << uma_id; |
| 2613 | 2245 |
| 2614 // Sparse histogram macro does not cache the histogram, so it's safe | 2246 // Sparse histogram macro does not cache the histogram, so it's safe |
| 2615 // to use macro with non-static histogram name here. | 2247 // to use macro with non-static histogram name here. |
| 2616 UMA_HISTOGRAM_SPARSE_SLOWLY(uma_histogram_hame, uma_id); | 2248 UMA_HISTOGRAM_SPARSE_SLOWLY(uma_histogram_hame, uma_id); |
| 2617 } | 2249 } |
| 2618 } | 2250 } |
| 2619 | 2251 |
| 2620 ////////////////////////////////////////////////////////////////////////////// | |
| 2621 // FlagsState implementation. | |
| 2622 | |
| 2623 namespace { | |
| 2624 | |
| 2625 void FlagsState::ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage, | |
| 2626 base::CommandLine* command_line, | |
| 2627 SentinelsMode sentinels) { | |
| 2628 if (command_line->HasSwitch(switches::kNoExperiments)) | |
| 2629 return; | |
| 2630 | |
| 2631 std::set<std::string> enabled_entries; | |
| 2632 | |
| 2633 GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries); | |
| 2634 | |
| 2635 std::map<std::string, SwitchEntry> name_to_switch_map; | |
| 2636 for (size_t i = 0; i < num_feature_entries; ++i) { | |
| 2637 const FeatureEntry& e = feature_entries[i]; | |
| 2638 switch (e.type) { | |
| 2639 case FeatureEntry::SINGLE_VALUE: | |
| 2640 case FeatureEntry::SINGLE_DISABLE_VALUE: | |
| 2641 AddSwitchMapping(e.internal_name, e.command_line_switch, | |
| 2642 e.command_line_value, &name_to_switch_map); | |
| 2643 break; | |
| 2644 case FeatureEntry::MULTI_VALUE: | |
| 2645 for (int j = 0; j < e.num_choices; ++j) { | |
| 2646 AddSwitchMapping(e.NameForChoice(j), e.choices[j].command_line_switch, | |
| 2647 e.choices[j].command_line_value, | |
| 2648 &name_to_switch_map); | |
| 2649 } | |
| 2650 break; | |
| 2651 case FeatureEntry::ENABLE_DISABLE_VALUE: | |
| 2652 AddSwitchMapping(e.NameForChoice(0), std::string(), std::string(), | |
| 2653 &name_to_switch_map); | |
| 2654 AddSwitchMapping(e.NameForChoice(1), e.command_line_switch, | |
| 2655 e.command_line_value, &name_to_switch_map); | |
| 2656 AddSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch, | |
| 2657 e.disable_command_line_value, &name_to_switch_map); | |
| 2658 break; | |
| 2659 case FeatureEntry::FEATURE_VALUE: | |
| 2660 AddFeatureMapping(e.NameForChoice(0), std::string(), false, | |
| 2661 &name_to_switch_map); | |
| 2662 AddFeatureMapping(e.NameForChoice(1), e.feature->name, true, | |
| 2663 &name_to_switch_map); | |
| 2664 AddFeatureMapping(e.NameForChoice(2), e.feature->name, false, | |
| 2665 &name_to_switch_map); | |
| 2666 break; | |
| 2667 } | |
| 2668 } | |
| 2669 | |
| 2670 AddSwitchesToCommandLine(enabled_entries, name_to_switch_map, sentinels, | |
| 2671 command_line); | |
| 2672 } | |
| 2673 | |
| 2674 bool FlagsState::IsRestartNeededToCommitChanges() { | |
| 2675 return needs_restart_; | |
| 2676 } | |
| 2677 | |
| 2678 void FlagsState::SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, | |
| 2679 const std::string& internal_name, | |
| 2680 bool enable) { | |
| 2681 size_t at_index = internal_name.find(flags_ui::testing::kMultiSeparator); | |
| 2682 if (at_index != std::string::npos) { | |
| 2683 DCHECK(enable); | |
| 2684 // We're being asked to enable a multi-choice entry. Disable the | |
| 2685 // currently selected choice. | |
| 2686 DCHECK_NE(at_index, 0u); | |
| 2687 const std::string entry_name = internal_name.substr(0, at_index); | |
| 2688 SetFeatureEntryEnabled(flags_storage, entry_name, false); | |
| 2689 | |
| 2690 // And enable the new choice, if it is not the default first choice. | |
| 2691 if (internal_name != entry_name + "@0") { | |
| 2692 std::set<std::string> enabled_entries; | |
| 2693 GetSanitizedEnabledFlags(flags_storage, &enabled_entries); | |
| 2694 needs_restart_ |= enabled_entries.insert(internal_name).second; | |
| 2695 flags_storage->SetFlags(enabled_entries); | |
| 2696 } | |
| 2697 return; | |
| 2698 } | |
| 2699 | |
| 2700 std::set<std::string> enabled_entries; | |
| 2701 GetSanitizedEnabledFlags(flags_storage, &enabled_entries); | |
| 2702 | |
| 2703 const FeatureEntry* e = nullptr; | |
| 2704 for (size_t i = 0; i < num_feature_entries; ++i) { | |
| 2705 if (feature_entries[i].internal_name == internal_name) { | |
| 2706 e = feature_entries + i; | |
| 2707 break; | |
| 2708 } | |
| 2709 } | |
| 2710 DCHECK(e); | |
| 2711 | |
| 2712 if (e->type == FeatureEntry::SINGLE_VALUE) { | |
| 2713 if (enable) | |
| 2714 needs_restart_ |= enabled_entries.insert(internal_name).second; | |
| 2715 else | |
| 2716 needs_restart_ |= (enabled_entries.erase(internal_name) > 0); | |
| 2717 } else if (e->type == FeatureEntry::SINGLE_DISABLE_VALUE) { | |
| 2718 if (!enable) | |
| 2719 needs_restart_ |= enabled_entries.insert(internal_name).second; | |
| 2720 else | |
| 2721 needs_restart_ |= (enabled_entries.erase(internal_name) > 0); | |
| 2722 } else { | |
| 2723 if (enable) { | |
| 2724 // Enable the first choice. | |
| 2725 needs_restart_ |= enabled_entries.insert(e->NameForChoice(0)).second; | |
| 2726 } else { | |
| 2727 // Find the currently enabled choice and disable it. | |
| 2728 for (int i = 0; i < e->num_choices; ++i) { | |
| 2729 std::string choice_name = e->NameForChoice(i); | |
| 2730 if (enabled_entries.find(choice_name) != | |
| 2731 enabled_entries.end()) { | |
| 2732 needs_restart_ = true; | |
| 2733 enabled_entries.erase(choice_name); | |
| 2734 // Continue on just in case there's a bug and more than one | |
| 2735 // entry for this choice was enabled. | |
| 2736 } | |
| 2737 } | |
| 2738 } | |
| 2739 } | |
| 2740 | |
| 2741 flags_storage->SetFlags(enabled_entries); | |
| 2742 } | |
| 2743 | |
| 2744 void FlagsState::RemoveFlagsSwitches( | |
| 2745 std::map<std::string, base::CommandLine::StringType>* switch_list) { | |
| 2746 for (const auto& entry : flags_switches_) | |
| 2747 switch_list->erase(entry.first); | |
| 2748 | |
| 2749 // If feature entries were added to --enable-features= or --disable-features= | |
| 2750 // lists, remove them here while preserving existing values. | |
| 2751 for (const auto& entry : appended_switches_) { | |
| 2752 const auto& switch_name = entry.first; | |
| 2753 const auto& switch_added_values = entry.second; | |
| 2754 | |
| 2755 // The below is either a std::string or a base::string16 based on platform. | |
| 2756 const auto& existing_value = (*switch_list)[switch_name]; | |
| 2757 #if defined(OS_WIN) | |
| 2758 const std::string existing_value_utf8 = base::UTF16ToUTF8(existing_value); | |
| 2759 #else | |
| 2760 const std::string& existing_value_utf8 = existing_value; | |
| 2761 #endif | |
| 2762 | |
| 2763 std::vector<std::string> features = | |
| 2764 base::FeatureList::SplitFeatureListString(existing_value_utf8); | |
| 2765 std::vector<std::string> remaining_features; | |
| 2766 // For any featrue name in |features| that is not in |switch_added_values| - | |
| 2767 // i.e. it wasn't added by about_flags code, add it to |remaining_features|. | |
| 2768 for (const std::string& feature : features) { | |
| 2769 if (!ContainsKey(switch_added_values, feature)) | |
| 2770 remaining_features.push_back(feature); | |
| 2771 } | |
| 2772 | |
| 2773 // Either remove the flag entirely if |remaining_features| is empty, or set | |
| 2774 // the new list. | |
| 2775 if (remaining_features.empty()) { | |
| 2776 switch_list->erase(switch_name); | |
| 2777 } else { | |
| 2778 std::string switch_value = base::JoinString(remaining_features, ","); | |
| 2779 #if defined(OS_WIN) | |
| 2780 (*switch_list)[switch_name] = base::UTF8ToUTF16(switch_value); | |
| 2781 #else | |
| 2782 (*switch_list)[switch_name] = switch_value; | |
| 2783 #endif | |
| 2784 } | |
| 2785 } | |
| 2786 } | |
| 2787 | |
| 2788 void FlagsState::ResetAllFlags(flags_ui::FlagsStorage* flags_storage) { | |
| 2789 needs_restart_ = true; | |
| 2790 | |
| 2791 std::set<std::string> no_entries; | |
| 2792 flags_storage->SetFlags(no_entries); | |
| 2793 } | |
| 2794 | |
| 2795 void FlagsState::Reset() { | |
| 2796 needs_restart_ = false; | |
| 2797 flags_switches_.clear(); | |
| 2798 appended_switches_.clear(); | |
| 2799 } | |
| 2800 | |
| 2801 void FlagsState::SetFeatureEntries(const FeatureEntry* entries, size_t count) { | |
| 2802 feature_entries = entries; | |
| 2803 num_feature_entries = count; | |
| 2804 } | |
| 2805 | |
| 2806 const FeatureEntry* FlagsState::GetFeatureEntries(size_t* count) { | |
| 2807 *count = num_feature_entries; | |
| 2808 return feature_entries; | |
| 2809 } | |
| 2810 | |
| 2811 void FlagsState::AddSwitchMapping( | |
| 2812 const std::string& key, | |
| 2813 const std::string& switch_name, | |
| 2814 const std::string& switch_value, | |
| 2815 std::map<std::string, SwitchEntry>* name_to_switch_map) { | |
| 2816 DCHECK(!ContainsKey(*name_to_switch_map, key)); | |
| 2817 | |
| 2818 SwitchEntry* entry = &(*name_to_switch_map)[key]; | |
| 2819 entry->switch_name = switch_name; | |
| 2820 entry->switch_value = switch_value; | |
| 2821 } | |
| 2822 | |
| 2823 void FlagsState::AddFeatureMapping( | |
| 2824 const std::string& key, | |
| 2825 const std::string& feature_name, | |
| 2826 bool feature_state, | |
| 2827 std::map<std::string, SwitchEntry>* name_to_switch_map) { | |
| 2828 DCHECK(!ContainsKey(*name_to_switch_map, key)); | |
| 2829 | |
| 2830 SwitchEntry* entry = &(*name_to_switch_map)[key]; | |
| 2831 entry->feature_name = feature_name; | |
| 2832 entry->feature_state = feature_state; | |
| 2833 } | |
| 2834 | |
| 2835 void FlagsState::AddSwitchesToCommandLine( | |
| 2836 const std::set<std::string>& enabled_entries, | |
| 2837 const std::map<std::string, SwitchEntry>& name_to_switch_map, | |
| 2838 SentinelsMode sentinels, | |
| 2839 base::CommandLine* command_line) { | |
| 2840 std::map<std::string, bool> feature_switches; | |
| 2841 if (sentinels == kAddSentinels) { | |
| 2842 command_line->AppendSwitch(switches::kFlagSwitchesBegin); | |
| 2843 flags_switches_[switches::kFlagSwitchesBegin] = std::string(); | |
| 2844 } | |
| 2845 | |
| 2846 for (const std::string& entry_name : enabled_entries) { | |
| 2847 const auto& entry_it = name_to_switch_map.find(entry_name); | |
| 2848 if (entry_it == name_to_switch_map.end()) { | |
| 2849 NOTREACHED(); | |
| 2850 continue; | |
| 2851 } | |
| 2852 | |
| 2853 const SwitchEntry& entry = entry_it->second; | |
| 2854 if (!entry.feature_name.empty()) { | |
| 2855 feature_switches[entry.feature_name] = entry.feature_state; | |
| 2856 } else if (!entry.switch_name.empty()) { | |
| 2857 command_line->AppendSwitchASCII(entry.switch_name, entry.switch_value); | |
| 2858 flags_switches_[entry.switch_name] = entry.switch_value; | |
| 2859 } | |
| 2860 // If an entry doesn't match either of the above, then it is likely the | |
| 2861 // default entry for a FEATURE_VALUE entry. Safe to ignore. | |
| 2862 } | |
| 2863 | |
| 2864 if (!feature_switches.empty()) { | |
| 2865 MergeFeatureCommandLineSwitch(feature_switches, switches::kEnableFeatures, | |
| 2866 true, command_line); | |
| 2867 MergeFeatureCommandLineSwitch(feature_switches, switches::kDisableFeatures, | |
| 2868 false, command_line); | |
| 2869 } | |
| 2870 | |
| 2871 if (sentinels == kAddSentinels) { | |
| 2872 command_line->AppendSwitch(switches::kFlagSwitchesEnd); | |
| 2873 flags_switches_[switches::kFlagSwitchesEnd] = std::string(); | |
| 2874 } | |
| 2875 } | |
| 2876 | |
| 2877 void FlagsState::MergeFeatureCommandLineSwitch( | |
| 2878 const std::map<std::string, bool>& feature_switches, | |
| 2879 const char* switch_name, | |
| 2880 bool feature_state, | |
| 2881 base::CommandLine* command_line) { | |
| 2882 std::string original_switch_value = | |
| 2883 command_line->GetSwitchValueASCII(switch_name); | |
| 2884 std::vector<std::string> features = | |
| 2885 base::FeatureList::SplitFeatureListString(original_switch_value); | |
| 2886 // Only add features that don't already exist in the lists. | |
| 2887 // Note: The ContainsValue() call results in O(n^2) performance, but in | |
| 2888 // practice n should be very small. | |
| 2889 for (const auto& entry : feature_switches) { | |
| 2890 if (entry.second == feature_state && | |
| 2891 !ContainsValue(features, entry.first)) { | |
| 2892 features.push_back(entry.first); | |
| 2893 appended_switches_[switch_name].insert(entry.first); | |
| 2894 } | |
| 2895 } | |
| 2896 // Update the switch value only if it didn't change. This avoids setting an | |
| 2897 // empty list or duplicating the same list (since AppendSwitch() adds the | |
| 2898 // switch to the end but doesn't remove previous ones). | |
| 2899 std::string switch_value = base::JoinString(features, ","); | |
| 2900 if (switch_value != original_switch_value) | |
| 2901 command_line->AppendSwitchASCII(switch_name, switch_value); | |
| 2902 } | |
| 2903 | |
| 2904 } // namespace | |
| 2905 | |
| 2906 namespace testing { | 2252 namespace testing { |
| 2907 | 2253 |
| 2908 const base::HistogramBase::Sample kBadSwitchFormatHistogramId = 0; | 2254 const base::HistogramBase::Sample kBadSwitchFormatHistogramId = 0; |
| 2909 | 2255 |
| 2910 void ClearState() { | |
| 2911 FlagsState::GetInstance()->Reset(); | |
| 2912 } | |
| 2913 | |
| 2914 void SetFeatureEntries(const FeatureEntry* entries, size_t count) { | |
| 2915 if (!entries) { | |
| 2916 entries = kFeatureEntries; | |
| 2917 count = arraysize(kFeatureEntries); | |
| 2918 } | |
| 2919 FlagsState::GetInstance()->SetFeatureEntries(entries, count); | |
| 2920 } | |
| 2921 | |
| 2922 const FeatureEntry* GetFeatureEntries(size_t* count) { | 2256 const FeatureEntry* GetFeatureEntries(size_t* count) { |
| 2923 return FlagsState::GetInstance()->GetFeatureEntries(count); | 2257 *count = arraysize(kFeatureEntries); |
| 2258 return kFeatureEntries; | |
| 2924 } | 2259 } |
| 2925 | 2260 |
| 2926 } // namespace testing | 2261 } // namespace testing |
| 2927 | 2262 |
| 2928 } // namespace about_flags | 2263 } // namespace about_flags |
| OLD | NEW |