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