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