Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: chrome/browser/about_flags.cc

Issue 1408783002: Support base::Feature entries in chrome://flags. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Another win compile fix. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/about_flags.h ('k') | chrome/browser/about_flags_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/about_flags.h ('k') | chrome/browser/about_flags_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698