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

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: Address comments. 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. 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
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
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
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
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
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
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
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