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