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/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/feature_list.h" | |
13 #include "base/memory/singleton.h" | 14 #include "base/memory/singleton.h" |
14 #include "base/metrics/sparse_histogram.h" | 15 #include "base/metrics/sparse_histogram.h" |
15 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
16 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
17 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
18 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
19 #include "base/values.h" | 20 #include "base/values.h" |
20 #include "cc/base/switches.h" | 21 #include "cc/base/switches.h" |
21 #include "chrome/common/channel_info.h" | 22 #include "chrome/common/channel_info.h" |
22 #include "chrome/common/chrome_content_client.h" | 23 #include "chrome/common/chrome_content_client.h" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
76 #if defined(ENABLE_EXTENSIONS) | 77 #if defined(ENABLE_EXTENSIONS) |
77 #include "extensions/common/switches.h" | 78 #include "extensions/common/switches.h" |
78 #endif | 79 #endif |
79 | 80 |
80 #if defined(USE_OZONE) | 81 #if defined(USE_OZONE) |
81 #include "ui/ozone/public/ozone_switches.h" | 82 #include "ui/ozone/public/ozone_switches.h" |
82 #endif | 83 #endif |
83 | 84 |
84 namespace about_flags { | 85 namespace about_flags { |
85 | 86 |
86 // Macros to simplify specifying the type. | 87 // Macros to simplify specifying the type. |
Nico
2015/10/21 20:45:35
That's a lot of macros by now. Maybe this should h
Alexei Svitkine (slow)
2015/10/21 21:37:00
The comments in the header file on the enum are ac
| |
87 #define SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \ | 88 #define SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \ |
88 FeatureEntry::SINGLE_VALUE, \ | 89 FeatureEntry::SINGLE_VALUE, command_line_switch, switch_value, nullptr, \ |
89 command_line_switch, switch_value, NULL, NULL, NULL, 0 | 90 nullptr, nullptr, nullptr, 0 |
90 #define SINGLE_VALUE_TYPE(command_line_switch) \ | 91 #define SINGLE_VALUE_TYPE(command_line_switch) \ |
91 SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, "") | 92 SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, "") |
92 #define SINGLE_DISABLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \ | 93 #define SINGLE_DISABLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \ |
93 FeatureEntry::SINGLE_DISABLE_VALUE, \ | 94 FeatureEntry::SINGLE_DISABLE_VALUE, command_line_switch, switch_value, \ |
94 command_line_switch, switch_value, NULL, NULL, NULL, 0 | 95 nullptr, nullptr, nullptr, nullptr, 0 |
95 #define SINGLE_DISABLE_VALUE_TYPE(command_line_switch) \ | 96 #define SINGLE_DISABLE_VALUE_TYPE(command_line_switch) \ |
96 SINGLE_DISABLE_VALUE_TYPE_AND_VALUE(command_line_switch, "") | 97 SINGLE_DISABLE_VALUE_TYPE_AND_VALUE(command_line_switch, "") |
97 #define ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, enable_value, \ | 98 #define ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, enable_value, \ |
98 disable_switch, disable_value) \ | 99 disable_switch, disable_value) \ |
99 FeatureEntry::ENABLE_DISABLE_VALUE, enable_switch, enable_value, \ | 100 FeatureEntry::ENABLE_DISABLE_VALUE, enable_switch, enable_value, \ |
100 disable_switch, disable_value, NULL, 3 | 101 disable_switch, disable_value, nullptr, nullptr, 3 |
101 #define ENABLE_DISABLE_VALUE_TYPE(enable_switch, disable_switch) \ | 102 #define ENABLE_DISABLE_VALUE_TYPE(enable_switch, disable_switch) \ |
102 ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, "", disable_switch, "") | 103 ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, "", disable_switch, "") |
103 #define MULTI_VALUE_TYPE(choices) \ | 104 #define MULTI_VALUE_TYPE(choices) \ |
104 FeatureEntry::MULTI_VALUE, NULL, NULL, NULL, NULL, choices, \ | 105 FeatureEntry::MULTI_VALUE, nullptr, nullptr, nullptr, nullptr, nullptr, \ |
105 arraysize(choices) | 106 choices, arraysize(choices) |
107 #define FEATURE_VALUE_TYPE(feature) \ | |
Nico
2015/10/21 20:45:35
Do you have some feature that you want to add to t
Alexei Svitkine (slow)
2015/10/21 21:37:00
Not yet, but I expect a few to be added soon once
| |
108 FeatureEntry::FEATURE_VALUE, nullptr, nullptr, nullptr, nullptr, \ | |
109 feature.name, nullptr, 3 | |
106 | 110 |
107 namespace { | 111 namespace { |
108 | 112 |
109 // Enumeration of OSs. | 113 // Enumeration of OSs. |
110 enum { | 114 enum { |
111 kOsMac = 1 << 0, | 115 kOsMac = 1 << 0, |
112 kOsWin = 1 << 1, | 116 kOsWin = 1 << 1, |
113 kOsLinux = 1 << 2, | 117 kOsLinux = 1 << 2, |
114 kOsCrOS = 1 << 3, | 118 kOsCrOS = 1 << 3, |
115 kOsAndroid = 1 << 4, | 119 kOsAndroid = 1 << 4, |
(...skipping 2037 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2153 | 2157 |
2154 void SetFeatureEntries(const FeatureEntry* entries, size_t count); | 2158 void SetFeatureEntries(const FeatureEntry* entries, size_t count); |
2155 const FeatureEntry* GetFeatureEntries(size_t* count); | 2159 const FeatureEntry* GetFeatureEntries(size_t* count); |
2156 | 2160 |
2157 // Returns the singleton instance of this class | 2161 // Returns the singleton instance of this class |
2158 static FlagsState* GetInstance() { | 2162 static FlagsState* GetInstance() { |
2159 return base::Singleton<FlagsState>::get(); | 2163 return base::Singleton<FlagsState>::get(); |
2160 } | 2164 } |
2161 | 2165 |
2162 private: | 2166 private: |
2167 // Keeps track of affected switches for each FeatureEntry, based on which | |
2168 // choice is selected for it. | |
2169 struct SwitchEntry { | |
2170 // Corresponding base::Feature to toggle. | |
2171 std::string feature_name; | |
2172 | |
2173 // If |feature_name| is not empty, the state (enable/disabled) to set. | |
2174 bool feature_state; | |
Nico
2015/10/21 20:45:35
Will this need to be a tri-state (force on, force
Alexei Svitkine (slow)
2015/10/21 21:37:00
Correct, it doesn't need to be tri-state. See line
| |
2175 | |
2176 // The name of the switch to add. | |
2177 std::string switch_name; | |
2178 | |
2179 // If |switch_name| is not empty, the value of the switch to set. | |
2180 std::string switch_value; | |
2181 | |
2182 SwitchEntry() : feature_state(false) {} | |
2183 }; | |
2184 | |
2185 // Adds mapping to |name_to_switch_map| to set the given switch name/value. | |
2186 void AddSwitchMapping(const std::string& key, | |
2187 const std::string& switch_name, | |
2188 const std::string& switch_value, | |
2189 std::map<std::string, SwitchEntry>* name_to_switch_map); | |
2190 | |
2191 // Adds mapping to |name_to_switch_map| to toggle base::Feature |feature_name| | |
2192 // to state |feature_state|. | |
2193 void AddFeatureMapping( | |
2194 const std::string& key, | |
2195 const std::string& feature_name, | |
2196 bool feature_state, | |
2197 std::map<std::string, SwitchEntry>* name_to_switch_map); | |
2198 | |
2199 // Updates the switches in |command_line| by applying the modifications | |
2200 // specified in |name_to_switch_map| for each entry in |enabled_entries|. | |
2201 void AddSwitchesToCommandLine( | |
2202 const std::set<std::string>& enabled_entries, | |
2203 const std::map<std::string, SwitchEntry>& name_to_switch_map, | |
2204 SentinelsMode sentinels, | |
2205 base::CommandLine* command_line); | |
2206 | |
2207 // Updates |command_line| by merging the value of the --enable-features= or | |
2208 // --disable-features= list (per the |switch_name| param) with corresponding | |
2209 // entries in |feature_switches| that have value |feature_state|. Keeps track | |
2210 // of the changes by updating |appended_switches|. | |
2211 void MergeFeatureCommandLineSwitch( | |
2212 const std::map<std::string, bool>& feature_switches, | |
2213 const char* switch_name, | |
2214 bool feature_state, | |
2215 base::CommandLine* command_line); | |
2216 | |
2163 // Removes all entries from prefs::kEnabledLabsExperiments that are unknown, | 2217 // Removes all entries from prefs::kEnabledLabsExperiments that are unknown, |
2164 // to prevent this list to become very long as entries are added and removed. | 2218 // to prevent this list to become very long as entries are added and removed. |
2165 void SanitizeList(flags_ui::FlagsStorage* flags_storage); | 2219 void SanitizeList(flags_ui::FlagsStorage* flags_storage); |
2166 | 2220 |
2167 void GetSanitizedEnabledFlags(flags_ui::FlagsStorage* flags_storage, | 2221 void GetSanitizedEnabledFlags(flags_ui::FlagsStorage* flags_storage, |
2168 std::set<std::string>* result); | 2222 std::set<std::string>* result); |
2169 | 2223 |
2170 // Variant of GetSanitizedEnabledFlags that also removes any flags that aren't | 2224 // Variant of GetSanitizedEnabledFlags that also removes any flags that aren't |
2171 // enabled on the current platform. | 2225 // enabled on the current platform. |
2172 void GetSanitizedEnabledFlagsForCurrentPlatform( | 2226 void GetSanitizedEnabledFlagsForCurrentPlatform( |
2173 flags_ui::FlagsStorage* flags_storage, | 2227 flags_ui::FlagsStorage* flags_storage, |
2174 std::set<std::string>* result); | 2228 std::set<std::string>* result); |
2175 | 2229 |
2176 const FeatureEntry* feature_entries; | 2230 const FeatureEntry* feature_entries; |
2177 size_t num_feature_entries; | 2231 size_t num_feature_entries; |
2178 | 2232 |
2179 bool needs_restart_; | 2233 bool needs_restart_; |
2180 std::map<std::string, std::string> flags_switches_; | 2234 std::map<std::string, std::string> flags_switches_; |
2181 | 2235 |
2236 // Map from switch name to a set of string, that keeps track which strings | |
2237 // were appended to existing (list value) switches. | |
2238 std::map<std::string, std::set<std::string>> appended_switches_; | |
2239 | |
2182 DISALLOW_COPY_AND_ASSIGN(FlagsState); | 2240 DISALLOW_COPY_AND_ASSIGN(FlagsState); |
2183 }; | 2241 }; |
2184 | 2242 |
2185 // Adds the internal names for the specified entry to |names|. | 2243 // Adds the internal names for the specified entry to |names|. |
2186 void AddInternalName(const FeatureEntry& e, std::set<std::string>* names) { | 2244 void AddInternalName(const FeatureEntry& e, std::set<std::string>* names) { |
2187 if (e.type == FeatureEntry::SINGLE_VALUE || | 2245 switch (e.type) { |
2188 e.type == FeatureEntry::SINGLE_DISABLE_VALUE) { | 2246 case FeatureEntry::SINGLE_VALUE: |
2189 names->insert(e.internal_name); | 2247 case FeatureEntry::SINGLE_DISABLE_VALUE: |
2190 } else { | 2248 names->insert(e.internal_name); |
2191 DCHECK(e.type == FeatureEntry::MULTI_VALUE || | 2249 break; |
2192 e.type == FeatureEntry::ENABLE_DISABLE_VALUE); | 2250 case FeatureEntry::MULTI_VALUE: |
2193 for (int i = 0; i < e.num_choices; ++i) | 2251 case FeatureEntry::ENABLE_DISABLE_VALUE: |
2194 names->insert(e.NameForChoice(i)); | 2252 case FeatureEntry::FEATURE_VALUE: |
2253 for (int i = 0; i < e.num_choices; ++i) | |
2254 names->insert(e.NameForChoice(i)); | |
2255 break; | |
2195 } | 2256 } |
2196 } | 2257 } |
2197 | 2258 |
2198 // Confirms that an entry is valid, used in a DCHECK in | 2259 // Confirms that an entry is valid, used in a DCHECK in |
2199 // SanitizeList below. | 2260 // SanitizeList below. |
2200 bool ValidateFeatureEntry(const FeatureEntry& e) { | 2261 bool ValidateFeatureEntry(const FeatureEntry& e) { |
2201 switch (e.type) { | 2262 switch (e.type) { |
2202 case FeatureEntry::SINGLE_VALUE: | 2263 case FeatureEntry::SINGLE_VALUE: |
2203 case FeatureEntry::SINGLE_DISABLE_VALUE: | 2264 case FeatureEntry::SINGLE_DISABLE_VALUE: |
2204 DCHECK_EQ(0, e.num_choices); | 2265 DCHECK_EQ(0, e.num_choices); |
2205 DCHECK(!e.choices); | 2266 DCHECK(!e.choices); |
2206 break; | 2267 return true; |
2207 case FeatureEntry::MULTI_VALUE: | 2268 case FeatureEntry::MULTI_VALUE: |
2208 DCHECK_GT(e.num_choices, 0); | 2269 DCHECK_GT(e.num_choices, 0); |
2209 DCHECK(e.choices); | 2270 DCHECK(e.choices); |
2210 DCHECK(e.choices[0].command_line_switch); | 2271 DCHECK(e.choices[0].command_line_switch); |
2211 DCHECK_EQ('\0', e.choices[0].command_line_switch[0]); | 2272 DCHECK_EQ('\0', e.choices[0].command_line_switch[0]); |
2212 break; | 2273 return true; |
2213 case FeatureEntry::ENABLE_DISABLE_VALUE: | 2274 case FeatureEntry::ENABLE_DISABLE_VALUE: |
2214 DCHECK_EQ(3, e.num_choices); | 2275 DCHECK_EQ(3, e.num_choices); |
2215 DCHECK(!e.choices); | 2276 DCHECK(!e.choices); |
2216 DCHECK(e.command_line_switch); | 2277 DCHECK(e.command_line_switch); |
2217 DCHECK(e.command_line_value); | 2278 DCHECK(e.command_line_value); |
2218 DCHECK(e.disable_command_line_switch); | 2279 DCHECK(e.disable_command_line_switch); |
2219 DCHECK(e.disable_command_line_value); | 2280 DCHECK(e.disable_command_line_value); |
2220 break; | 2281 return true; |
2221 default: | 2282 case FeatureEntry::FEATURE_VALUE: |
2222 NOTREACHED(); | 2283 DCHECK_EQ(3, e.num_choices); |
2284 DCHECK(!e.choices); | |
2285 DCHECK(e.feature_name); | |
2286 return true; | |
2223 } | 2287 } |
2224 return true; | 2288 NOTREACHED(); |
2289 return false; | |
2225 } | 2290 } |
2226 | 2291 |
2227 void FlagsState::SanitizeList(flags_ui::FlagsStorage* flags_storage) { | 2292 void FlagsState::SanitizeList(flags_ui::FlagsStorage* flags_storage) { |
2228 std::set<std::string> known_entries; | 2293 std::set<std::string> known_entries; |
2229 for (size_t i = 0; i < num_feature_entries; ++i) { | 2294 for (size_t i = 0; i < num_feature_entries; ++i) { |
2230 DCHECK(ValidateFeatureEntry(feature_entries[i])); | 2295 DCHECK(ValidateFeatureEntry(feature_entries[i])); |
2231 AddInternalName(feature_entries[i], &known_entries); | 2296 AddInternalName(feature_entries[i], &known_entries); |
2232 } | 2297 } |
2233 | 2298 |
2234 std::set<std::string> enabled_entries = flags_storage->GetFlags(); | 2299 std::set<std::string> enabled_entries = flags_storage->GetFlags(); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2338 // Returns true if none of this entry's options have been enabled. | 2403 // Returns true if none of this entry's options have been enabled. |
2339 bool IsDefaultValue( | 2404 bool IsDefaultValue( |
2340 const FeatureEntry& entry, | 2405 const FeatureEntry& entry, |
2341 const std::set<std::string>& enabled_entries) { | 2406 const std::set<std::string>& enabled_entries) { |
2342 switch (entry.type) { | 2407 switch (entry.type) { |
2343 case FeatureEntry::SINGLE_VALUE: | 2408 case FeatureEntry::SINGLE_VALUE: |
2344 case FeatureEntry::SINGLE_DISABLE_VALUE: | 2409 case FeatureEntry::SINGLE_DISABLE_VALUE: |
2345 return enabled_entries.count(entry.internal_name) == 0; | 2410 return enabled_entries.count(entry.internal_name) == 0; |
2346 case FeatureEntry::MULTI_VALUE: | 2411 case FeatureEntry::MULTI_VALUE: |
2347 case FeatureEntry::ENABLE_DISABLE_VALUE: | 2412 case FeatureEntry::ENABLE_DISABLE_VALUE: |
2413 case FeatureEntry::FEATURE_VALUE: | |
2348 for (int i = 0; i < entry.num_choices; ++i) { | 2414 for (int i = 0; i < entry.num_choices; ++i) { |
2349 if (enabled_entries.count(entry.NameForChoice(i)) > 0) | 2415 if (enabled_entries.count(entry.NameForChoice(i)) > 0) |
2350 return false; | 2416 return false; |
2351 } | 2417 } |
2352 break; | 2418 return true; |
2353 default: | |
2354 NOTREACHED(); | |
2355 } | 2419 } |
2420 NOTREACHED(); | |
2356 return true; | 2421 return true; |
2357 } | 2422 } |
2358 | 2423 |
2359 // Returns the Value representing the choice data in the specified entry. | 2424 // Returns the Value representing the choice data in the specified entry. |
2360 base::Value* CreateChoiceData( | 2425 base::Value* CreateChoiceData( |
2361 const FeatureEntry& entry, | 2426 const FeatureEntry& entry, |
2362 const std::set<std::string>& enabled_entries) { | 2427 const std::set<std::string>& enabled_entries) { |
2363 DCHECK(entry.type == FeatureEntry::MULTI_VALUE || | 2428 DCHECK(entry.type == FeatureEntry::MULTI_VALUE || |
2364 entry.type == FeatureEntry::ENABLE_DISABLE_VALUE); | 2429 entry.type == FeatureEntry::ENABLE_DISABLE_VALUE || |
2430 entry.type == FeatureEntry::FEATURE_VALUE); | |
2365 base::ListValue* result = new base::ListValue; | 2431 base::ListValue* result = new base::ListValue; |
2366 for (int i = 0; i < entry.num_choices; ++i) { | 2432 for (int i = 0; i < entry.num_choices; ++i) { |
2367 base::DictionaryValue* value = new base::DictionaryValue; | 2433 base::DictionaryValue* value = new base::DictionaryValue; |
2368 const std::string name = entry.NameForChoice(i); | 2434 const std::string name = entry.NameForChoice(i); |
2369 value->SetString("internal_name", name); | 2435 value->SetString("internal_name", name); |
2370 value->SetString("description", entry.DescriptionForChoice(i)); | 2436 value->SetString("description", entry.DescriptionForChoice(i)); |
2371 value->SetBoolean("selected", enabled_entries.count(name) > 0); | 2437 value->SetBoolean("selected", enabled_entries.count(name) > 0); |
2372 result->Append(value); | 2438 result->Append(value); |
2373 } | 2439 } |
2374 return result; | 2440 return result; |
2375 } | 2441 } |
2376 | 2442 |
2377 } // namespace | 2443 } // namespace |
2378 | 2444 |
2379 std::string FeatureEntry::NameForChoice(int index) const { | 2445 std::string FeatureEntry::NameForChoice(int index) const { |
2380 DCHECK(type == FeatureEntry::MULTI_VALUE || | 2446 DCHECK(type == FeatureEntry::MULTI_VALUE || |
2381 type == FeatureEntry::ENABLE_DISABLE_VALUE); | 2447 type == FeatureEntry::ENABLE_DISABLE_VALUE || |
2448 type == FeatureEntry::FEATURE_VALUE); | |
2382 DCHECK_LT(index, num_choices); | 2449 DCHECK_LT(index, num_choices); |
2383 return std::string(internal_name) + testing::kMultiSeparator + | 2450 return std::string(internal_name) + testing::kMultiSeparator + |
2384 base::IntToString(index); | 2451 base::IntToString(index); |
2385 } | 2452 } |
2386 | 2453 |
2387 base::string16 FeatureEntry::DescriptionForChoice(int index) const { | 2454 base::string16 FeatureEntry::DescriptionForChoice(int index) const { |
2388 DCHECK(type == FeatureEntry::MULTI_VALUE || | 2455 DCHECK(type == FeatureEntry::MULTI_VALUE || |
2389 type == FeatureEntry::ENABLE_DISABLE_VALUE); | 2456 type == FeatureEntry::ENABLE_DISABLE_VALUE || |
2457 type == FeatureEntry::FEATURE_VALUE); | |
2390 DCHECK_LT(index, num_choices); | 2458 DCHECK_LT(index, num_choices); |
2391 int description_id; | 2459 int description_id; |
2392 if (type == FeatureEntry::ENABLE_DISABLE_VALUE) { | 2460 if (type == FeatureEntry::ENABLE_DISABLE_VALUE || |
2461 type == FeatureEntry::FEATURE_VALUE) { | |
2393 const int kEnableDisableDescriptionIds[] = { | 2462 const int kEnableDisableDescriptionIds[] = { |
2394 IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, | 2463 IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, |
2395 IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, | 2464 IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, |
2396 IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED, | 2465 IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED, |
2397 }; | 2466 }; |
2398 description_id = kEnableDisableDescriptionIds[index]; | 2467 description_id = kEnableDisableDescriptionIds[index]; |
2399 } else { | 2468 } else { |
2400 description_id = choices[index].description_id; | 2469 description_id = choices[index].description_id; |
2401 } | 2470 } |
2402 return l10n_util::GetStringUTF16(description_id); | 2471 return l10n_util::GetStringUTF16(description_id); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2506 FlagsState::GetInstance()->GetFlagFeatureEntries(flags_storage, access, | 2575 FlagsState::GetInstance()->GetFlagFeatureEntries(flags_storage, access, |
2507 supported_entries, | 2576 supported_entries, |
2508 unsupported_entries); | 2577 unsupported_entries); |
2509 } | 2578 } |
2510 | 2579 |
2511 bool IsRestartNeededToCommitChanges() { | 2580 bool IsRestartNeededToCommitChanges() { |
2512 return FlagsState::GetInstance()->IsRestartNeededToCommitChanges(); | 2581 return FlagsState::GetInstance()->IsRestartNeededToCommitChanges(); |
2513 } | 2582 } |
2514 | 2583 |
2515 void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, | 2584 void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, |
2516 const std::string& internal_name, | 2585 const std::string& internal_name, |
2517 bool enable) { | 2586 bool enable) { |
2518 FlagsState::GetInstance()->SetFeatureEntryEnabled(flags_storage, | 2587 FlagsState::GetInstance()->SetFeatureEntryEnabled(flags_storage, |
2519 internal_name, enable); | 2588 internal_name, enable); |
2520 } | 2589 } |
2521 | 2590 |
2522 void RemoveFlagsSwitches( | 2591 void RemoveFlagsSwitches( |
2523 std::map<std::string, base::CommandLine::StringType>* switch_list) { | 2592 std::map<std::string, base::CommandLine::StringType>* switch_list) { |
2524 FlagsState::GetInstance()->RemoveFlagsSwitches(switch_list); | 2593 FlagsState::GetInstance()->RemoveFlagsSwitches(switch_list); |
2525 } | 2594 } |
2526 | 2595 |
2527 void ResetAllFlags(flags_ui::FlagsStorage* flags_storage) { | 2596 void ResetAllFlags(flags_ui::FlagsStorage* flags_storage) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2588 // to use macro with non-static histogram name here. | 2657 // to use macro with non-static histogram name here. |
2589 UMA_HISTOGRAM_SPARSE_SLOWLY(uma_histogram_hame, uma_id); | 2658 UMA_HISTOGRAM_SPARSE_SLOWLY(uma_histogram_hame, uma_id); |
2590 } | 2659 } |
2591 } | 2660 } |
2592 | 2661 |
2593 ////////////////////////////////////////////////////////////////////////////// | 2662 ////////////////////////////////////////////////////////////////////////////// |
2594 // FlagsState implementation. | 2663 // FlagsState implementation. |
2595 | 2664 |
2596 namespace { | 2665 namespace { |
2597 | 2666 |
2598 typedef std::map<std::string, std::pair<std::string, std::string> > | |
2599 NameToSwitchAndValueMap; | |
2600 | |
2601 void SetFlagToSwitchMapping(const std::string& key, | |
2602 const std::string& switch_name, | |
2603 const std::string& switch_value, | |
2604 NameToSwitchAndValueMap* name_to_switch_map) { | |
2605 DCHECK(name_to_switch_map->end() == name_to_switch_map->find(key)); | |
2606 (*name_to_switch_map)[key] = std::make_pair(switch_name, switch_value); | |
2607 } | |
2608 | |
2609 void FlagsState::ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage, | 2667 void FlagsState::ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage, |
2610 base::CommandLine* command_line, | 2668 base::CommandLine* command_line, |
2611 SentinelsMode sentinels) { | 2669 SentinelsMode sentinels) { |
2612 if (command_line->HasSwitch(switches::kNoExperiments)) | 2670 if (command_line->HasSwitch(switches::kNoExperiments)) |
2613 return; | 2671 return; |
2614 | 2672 |
2615 std::set<std::string> enabled_entries; | 2673 std::set<std::string> enabled_entries; |
2616 | 2674 |
2617 GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, | 2675 GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries); |
2618 &enabled_entries); | |
2619 | 2676 |
2620 NameToSwitchAndValueMap name_to_switch_map; | 2677 std::map<std::string, SwitchEntry> name_to_switch_map; |
2621 for (size_t i = 0; i < num_feature_entries; ++i) { | 2678 for (size_t i = 0; i < num_feature_entries; ++i) { |
2622 const FeatureEntry& e = feature_entries[i]; | 2679 const FeatureEntry& e = feature_entries[i]; |
2623 if (e.type == FeatureEntry::SINGLE_VALUE || | 2680 switch (e.type) { |
2624 e.type == FeatureEntry::SINGLE_DISABLE_VALUE) { | 2681 case FeatureEntry::SINGLE_VALUE: |
2625 SetFlagToSwitchMapping(e.internal_name, e.command_line_switch, | 2682 case FeatureEntry::SINGLE_DISABLE_VALUE: |
2626 e.command_line_value, &name_to_switch_map); | 2683 AddSwitchMapping(e.internal_name, e.command_line_switch, |
2627 } else if (e.type == FeatureEntry::MULTI_VALUE) { | 2684 e.command_line_value, &name_to_switch_map); |
2628 for (int j = 0; j < e.num_choices; ++j) { | 2685 break; |
2629 SetFlagToSwitchMapping(e.NameForChoice(j), | 2686 case FeatureEntry::MULTI_VALUE: |
2630 e.choices[j].command_line_switch, | 2687 for (int j = 0; j < e.num_choices; ++j) { |
2631 e.choices[j].command_line_value, | 2688 AddSwitchMapping(e.NameForChoice(j), e.choices[j].command_line_switch, |
2632 &name_to_switch_map); | 2689 e.choices[j].command_line_value, |
2633 } | 2690 &name_to_switch_map); |
2634 } else { | 2691 } |
2635 DCHECK_EQ(e.type, FeatureEntry::ENABLE_DISABLE_VALUE); | 2692 break; |
2636 SetFlagToSwitchMapping(e.NameForChoice(0), std::string(), std::string(), | 2693 case FeatureEntry::ENABLE_DISABLE_VALUE: |
2637 &name_to_switch_map); | 2694 AddSwitchMapping(e.NameForChoice(0), std::string(), std::string(), |
2638 SetFlagToSwitchMapping(e.NameForChoice(1), e.command_line_switch, | 2695 &name_to_switch_map); |
2639 e.command_line_value, &name_to_switch_map); | 2696 AddSwitchMapping(e.NameForChoice(1), e.command_line_switch, |
2640 SetFlagToSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch, | 2697 e.command_line_value, &name_to_switch_map); |
2641 e.disable_command_line_value, &name_to_switch_map); | 2698 AddSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch, |
2699 e.disable_command_line_value, &name_to_switch_map); | |
2700 break; | |
2701 case FeatureEntry::FEATURE_VALUE: | |
2702 AddFeatureMapping(e.NameForChoice(0), std::string(), false, | |
2703 &name_to_switch_map); | |
2704 AddFeatureMapping(e.NameForChoice(1), e.feature_name, true, | |
2705 &name_to_switch_map); | |
2706 AddFeatureMapping(e.NameForChoice(2), e.feature_name, false, | |
2707 &name_to_switch_map); | |
2708 break; | |
2642 } | 2709 } |
2643 } | 2710 } |
2644 | 2711 |
2645 if (sentinels == kAddSentinels) { | 2712 AddSwitchesToCommandLine(enabled_entries, name_to_switch_map, sentinels, |
2646 command_line->AppendSwitch(switches::kFlagSwitchesBegin); | 2713 command_line); |
2647 flags_switches_.insert( | |
2648 std::pair<std::string, std::string>(switches::kFlagSwitchesBegin, | |
2649 std::string())); | |
2650 } | |
2651 for (const std::string& entry_name : enabled_entries) { | |
2652 NameToSwitchAndValueMap::const_iterator name_to_switch_it = | |
2653 name_to_switch_map.find(entry_name); | |
2654 if (name_to_switch_it == name_to_switch_map.end()) { | |
2655 NOTREACHED(); | |
2656 continue; | |
2657 } | |
2658 | |
2659 const std::pair<std::string, std::string>& | |
2660 switch_and_value_pair = name_to_switch_it->second; | |
2661 | |
2662 CHECK(!switch_and_value_pair.first.empty()); | |
2663 command_line->AppendSwitchASCII(switch_and_value_pair.first, | |
2664 switch_and_value_pair.second); | |
2665 flags_switches_[switch_and_value_pair.first] = switch_and_value_pair.second; | |
2666 } | |
2667 if (sentinels == kAddSentinels) { | |
2668 command_line->AppendSwitch(switches::kFlagSwitchesEnd); | |
2669 flags_switches_.insert( | |
2670 std::pair<std::string, std::string>(switches::kFlagSwitchesEnd, | |
2671 std::string())); | |
2672 } | |
2673 } | 2714 } |
2674 | 2715 |
2675 bool FlagsState::IsRestartNeededToCommitChanges() { | 2716 bool FlagsState::IsRestartNeededToCommitChanges() { |
2676 return needs_restart_; | 2717 return needs_restart_; |
2677 } | 2718 } |
2678 | 2719 |
2679 void FlagsState::SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, | 2720 void FlagsState::SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage, |
2680 const std::string& internal_name, | 2721 const std::string& internal_name, |
2681 bool enable) { | 2722 bool enable) { |
2682 size_t at_index = internal_name.find(testing::kMultiSeparator); | 2723 size_t at_index = internal_name.find(testing::kMultiSeparator); |
(...skipping 11 matching lines...) Expand all Loading... | |
2694 GetSanitizedEnabledFlags(flags_storage, &enabled_entries); | 2735 GetSanitizedEnabledFlags(flags_storage, &enabled_entries); |
2695 needs_restart_ |= enabled_entries.insert(internal_name).second; | 2736 needs_restart_ |= enabled_entries.insert(internal_name).second; |
2696 flags_storage->SetFlags(enabled_entries); | 2737 flags_storage->SetFlags(enabled_entries); |
2697 } | 2738 } |
2698 return; | 2739 return; |
2699 } | 2740 } |
2700 | 2741 |
2701 std::set<std::string> enabled_entries; | 2742 std::set<std::string> enabled_entries; |
2702 GetSanitizedEnabledFlags(flags_storage, &enabled_entries); | 2743 GetSanitizedEnabledFlags(flags_storage, &enabled_entries); |
2703 | 2744 |
2704 const FeatureEntry* e = NULL; | 2745 const FeatureEntry* e = nullptr; |
2705 for (size_t i = 0; i < num_feature_entries; ++i) { | 2746 for (size_t i = 0; i < num_feature_entries; ++i) { |
2706 if (feature_entries[i].internal_name == internal_name) { | 2747 if (feature_entries[i].internal_name == internal_name) { |
2707 e = feature_entries + i; | 2748 e = feature_entries + i; |
2708 break; | 2749 break; |
2709 } | 2750 } |
2710 } | 2751 } |
2711 DCHECK(e); | 2752 DCHECK(e); |
2712 | 2753 |
2713 if (e->type == FeatureEntry::SINGLE_VALUE) { | 2754 if (e->type == FeatureEntry::SINGLE_VALUE) { |
2714 if (enable) | 2755 if (enable) |
(...skipping 24 matching lines...) Expand all Loading... | |
2739 } | 2780 } |
2740 } | 2781 } |
2741 | 2782 |
2742 flags_storage->SetFlags(enabled_entries); | 2783 flags_storage->SetFlags(enabled_entries); |
2743 } | 2784 } |
2744 | 2785 |
2745 void FlagsState::RemoveFlagsSwitches( | 2786 void FlagsState::RemoveFlagsSwitches( |
2746 std::map<std::string, base::CommandLine::StringType>* switch_list) { | 2787 std::map<std::string, base::CommandLine::StringType>* switch_list) { |
2747 for (const auto& entry : flags_switches_) | 2788 for (const auto& entry : flags_switches_) |
2748 switch_list->erase(entry.first); | 2789 switch_list->erase(entry.first); |
2790 | |
2791 // If feature entries were added to --enable-features= or --disable-features= | |
2792 // lists, remove them here while preserving existing values. | |
2793 for (const auto& entry : appended_switches_) { | |
2794 const auto& switch_name = entry.first; | |
2795 const auto& switch_added_values = entry.second; | |
2796 | |
2797 const auto& existing_value = (*switch_list)[switch_name]; | |
Nico
2015/10/21 20:45:35
nit: i'd use std::string instead of auto in the pr
Alexei Svitkine (slow)
2015/10/21 21:37:00
It's different between platforms. The actual type
| |
2798 #if defined(OS_WIN) | |
2799 const std::string existing_value_utf8 = base::UTF16ToUTF8(existing_value); | |
2800 #else | |
2801 const std::string& existing_value_utf8 = existing_value; | |
2802 #endif | |
2803 | |
2804 std::vector<std::string> features = | |
2805 base::FeatureList::SplitFeatureListString(existing_value_utf8); | |
2806 std::vector<std::string> remaining_features; | |
2807 // For any featrue name in |features| that is not in |switch_added_values| - | |
2808 // i.e. it wasn't added by about_flags code, add it to |remaining_features|. | |
2809 for (const std::string& feature : features) { | |
2810 if (!ContainsKey(switch_added_values, feature)) | |
2811 remaining_features.push_back(feature); | |
2812 } | |
2813 | |
2814 // Either remove the flag entirely if |remaining_features| is empty, or set | |
2815 // the new list. | |
2816 if (remaining_features.empty()) { | |
2817 switch_list->erase(switch_name); | |
2818 } else { | |
2819 std::string switch_value = base::JoinString(remaining_features, ","); | |
2820 #if defined(OS_WIN) | |
2821 (*switch_list)[switch_name] = base::UTF8ToUTF16(switch_value); | |
2822 #else | |
2823 (*switch_list)[switch_name] = switch_value; | |
2824 #endif | |
2825 } | |
2826 } | |
2749 } | 2827 } |
2750 | 2828 |
2751 void FlagsState::ResetAllFlags(flags_ui::FlagsStorage* flags_storage) { | 2829 void FlagsState::ResetAllFlags(flags_ui::FlagsStorage* flags_storage) { |
2752 needs_restart_ = true; | 2830 needs_restart_ = true; |
2753 | 2831 |
2754 std::set<std::string> no_entries; | 2832 std::set<std::string> no_entries; |
2755 flags_storage->SetFlags(no_entries); | 2833 flags_storage->SetFlags(no_entries); |
2756 } | 2834 } |
2757 | 2835 |
2758 void FlagsState::Reset() { | 2836 void FlagsState::Reset() { |
2759 needs_restart_ = false; | 2837 needs_restart_ = false; |
2760 flags_switches_.clear(); | 2838 flags_switches_.clear(); |
2839 appended_switches_.clear(); | |
2761 } | 2840 } |
2762 | 2841 |
2763 void FlagsState::SetFeatureEntries(const FeatureEntry* entries, size_t count) { | 2842 void FlagsState::SetFeatureEntries(const FeatureEntry* entries, size_t count) { |
2764 feature_entries = entries; | 2843 feature_entries = entries; |
2765 num_feature_entries = count; | 2844 num_feature_entries = count; |
2766 } | 2845 } |
2767 | 2846 |
2768 const FeatureEntry* FlagsState::GetFeatureEntries(size_t* count) { | 2847 const FeatureEntry* FlagsState::GetFeatureEntries(size_t* count) { |
2769 *count = num_feature_entries; | 2848 *count = num_feature_entries; |
2770 return feature_entries; | 2849 return feature_entries; |
2771 } | 2850 } |
2772 | 2851 |
2852 void FlagsState::AddSwitchMapping( | |
2853 const std::string& key, | |
2854 const std::string& switch_name, | |
2855 const std::string& switch_value, | |
2856 std::map<std::string, SwitchEntry>* name_to_switch_map) { | |
2857 DCHECK(!ContainsKey(*name_to_switch_map, key)); | |
2858 | |
2859 SwitchEntry* entry = &(*name_to_switch_map)[key]; | |
2860 entry->switch_name = switch_name; | |
2861 entry->switch_value = switch_value; | |
2862 } | |
2863 | |
2864 void FlagsState::AddFeatureMapping( | |
2865 const std::string& key, | |
2866 const std::string& feature_name, | |
2867 bool feature_state, | |
2868 std::map<std::string, SwitchEntry>* name_to_switch_map) { | |
2869 DCHECK(!ContainsKey(*name_to_switch_map, key)); | |
2870 | |
2871 SwitchEntry* entry = &(*name_to_switch_map)[key]; | |
2872 entry->feature_name = feature_name; | |
2873 entry->feature_state = feature_state; | |
2874 } | |
2875 | |
2876 void FlagsState::AddSwitchesToCommandLine( | |
2877 const std::set<std::string>& enabled_entries, | |
2878 const std::map<std::string, SwitchEntry>& name_to_switch_map, | |
2879 SentinelsMode sentinels, | |
2880 base::CommandLine* command_line) { | |
2881 std::map<std::string, bool> feature_switches; | |
2882 if (sentinels == kAddSentinels) { | |
2883 command_line->AppendSwitch(switches::kFlagSwitchesBegin); | |
2884 flags_switches_[switches::kFlagSwitchesBegin] = std::string(); | |
2885 } | |
2886 | |
2887 for (const std::string& entry_name : enabled_entries) { | |
2888 const auto& entry_it = name_to_switch_map.find(entry_name); | |
2889 if (entry_it == name_to_switch_map.end()) { | |
2890 NOTREACHED(); | |
2891 continue; | |
2892 } | |
2893 | |
2894 const SwitchEntry& entry = entry_it->second; | |
2895 if (!entry.feature_name.empty()) { | |
2896 feature_switches[entry.feature_name] = entry.feature_state; | |
2897 } else if (!entry.switch_name.empty()) { | |
2898 command_line->AppendSwitchASCII(entry.switch_name, entry.switch_value); | |
2899 flags_switches_[entry.switch_name] = entry.switch_value; | |
2900 } | |
2901 // If an entry doesn't match either of the above, then it is likely the | |
2902 // default entry for a FEATURE_VALUE entry. Safe to ignore. | |
2903 } | |
2904 | |
2905 if (!feature_switches.empty()) { | |
2906 MergeFeatureCommandLineSwitch(feature_switches, switches::kEnableFeatures, | |
2907 true, command_line); | |
2908 MergeFeatureCommandLineSwitch(feature_switches, switches::kDisableFeatures, | |
2909 false, command_line); | |
2910 } | |
2911 | |
2912 if (sentinels == kAddSentinels) { | |
2913 command_line->AppendSwitch(switches::kFlagSwitchesEnd); | |
2914 flags_switches_[switches::kFlagSwitchesEnd] = std::string(); | |
2915 } | |
2916 } | |
2917 | |
2918 void FlagsState::MergeFeatureCommandLineSwitch( | |
2919 const std::map<std::string, bool>& feature_switches, | |
2920 const char* switch_name, | |
2921 bool feature_state, | |
2922 base::CommandLine* command_line) { | |
2923 std::string original_switch_value = | |
2924 command_line->GetSwitchValueASCII(switch_name); | |
2925 std::vector<std::string> features = | |
2926 base::FeatureList::SplitFeatureListString(original_switch_value); | |
2927 // Only add features that don't already exist in the lists. | |
2928 // Note: The ContainsValue() call results in O(n^2) performance, but in | |
2929 // practice n should be very small. | |
Nico
2015/10/21 20:45:35
how many base::Feature entries are there today? (i
Alexei Svitkine (slow)
2015/10/21 21:37:00
Currently, none - as I haven't announced the base:
| |
2930 for (const auto& entry : feature_switches) { | |
2931 if (entry.second == feature_state && | |
2932 !ContainsValue(features, entry.first)) { | |
2933 features.push_back(entry.first); | |
2934 appended_switches_[switch_name].insert(entry.first); | |
2935 } | |
2936 } | |
2937 // Update the switch value only if it didn't change. This avoids setting an | |
2938 // empty list or duplicating the same list (since AppendSwitch() adds the | |
2939 // switch to the end but doesn't remove previous ones). | |
2940 std::string switch_value = base::JoinString(features, ","); | |
2941 if (switch_value != original_switch_value) | |
2942 command_line->AppendSwitchASCII(switch_name, switch_value); | |
2943 } | |
2944 | |
2773 } // namespace | 2945 } // namespace |
2774 | 2946 |
2775 namespace testing { | 2947 namespace testing { |
2776 | 2948 |
2777 // WARNING: '@' is also used in the html file. If you update this constant you | 2949 // WARNING: '@' is also used in the html file. If you update this constant you |
2778 // also need to update the html file. | 2950 // also need to update the html file. |
2779 const char kMultiSeparator[] = "@"; | 2951 const char kMultiSeparator[] = "@"; |
2780 | 2952 |
2781 const base::HistogramBase::Sample kBadSwitchFormatHistogramId = 0; | 2953 const base::HistogramBase::Sample kBadSwitchFormatHistogramId = 0; |
2782 | 2954 |
2783 void ClearState() { | 2955 void ClearState() { |
2784 FlagsState::GetInstance()->Reset(); | 2956 FlagsState::GetInstance()->Reset(); |
2785 } | 2957 } |
2786 | 2958 |
2787 void SetFeatureEntries(const FeatureEntry* entries, size_t count) { | 2959 void SetFeatureEntries(const FeatureEntry* entries, size_t count) { |
2788 if (!entries) { | 2960 if (!entries) { |
2789 entries = kFeatureEntries; | 2961 entries = kFeatureEntries; |
2790 count = arraysize(kFeatureEntries); | 2962 count = arraysize(kFeatureEntries); |
2791 } | 2963 } |
2792 FlagsState::GetInstance()->SetFeatureEntries(entries, count); | 2964 FlagsState::GetInstance()->SetFeatureEntries(entries, count); |
2793 } | 2965 } |
2794 | 2966 |
2795 const FeatureEntry* GetFeatureEntries(size_t* count) { | 2967 const FeatureEntry* GetFeatureEntries(size_t* count) { |
2796 return FlagsState::GetInstance()->GetFeatureEntries(count); | 2968 return FlagsState::GetInstance()->GetFeatureEntries(count); |
2797 } | 2969 } |
2798 | 2970 |
2799 } // namespace testing | 2971 } // namespace testing |
2800 | 2972 |
2801 } // namespace about_flags | 2973 } // namespace about_flags |
OLD | NEW |