Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / about_flags.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/about_flags.h"
6
7 #include <iterator>
8 #include <map>
9 #include <set>
10 #include <utility>
11
12 #include "base/command_line.h"
13 #include "base/memory/singleton.h"
14 #include "base/metrics/sparse_histogram.h"
15 #include "base/numerics/safe_conversions.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/values.h"
21 #include "cc/base/switches.h"
22 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
23 #include "chrome/browser/flags_storage.h"
24 #include "chrome/common/chrome_content_client.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/grit/generated_resources.h"
27 #include "components/autofill/core/common/autofill_switches.h"
28 #include "components/cloud_devices/common/cloud_devices_switches.h"
29 #include "components/metrics/metrics_hashes.h"
30 #include "components/nacl/common/nacl_switches.h"
31 #include "components/proximity_auth/switches.h"
32 #include "components/search/search_switches.h"
33 #include "content/public/browser/user_metrics.h"
34 #include "media/base/media_switches.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "ui/base/ui_base_switches.h"
37 #include "ui/display/display_switches.h"
38 #include "ui/events/event_switches.h"
39 #include "ui/gfx/switches.h"
40 #include "ui/gl/gl_switches.h"
41 #include "ui/keyboard/keyboard_switches.h"
42 #include "ui/native_theme/native_theme_switches.h"
43 #include "ui/views/views_switches.h"
44
45 #if defined(OS_ANDROID)
46 #include "chrome/common/chrome_version_info.h"
47 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
48 #include "components/omnibox/omnibox_switches.h"
49 #else
50 #include "ui/message_center/message_center_switches.h"
51 #endif
52
53 #if defined(USE_ASH)
54 #include "ash/ash_switches.h"
55 #endif
56
57 #if defined(OS_CHROMEOS)
58 #include "chromeos/chromeos_switches.h"
59 #include "third_party/cros_system_api/switches/chrome_switches.h"
60 #endif
61
62 #if defined(ENABLE_APP_LIST)
63 #include "ui/app_list/app_list_switches.h"
64 #endif
65
66 #if defined(ENABLE_EXTENSIONS)
67 #include "extensions/common/switches.h"
68 #endif
69
70 using base::UserMetricsAction;
71
72 namespace about_flags {
73
74 const base::HistogramBase::Sample kBadSwitchFormatHistogramId = 0;
75
76 // Macros to simplify specifying the type.
77 #define SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \
78     Experiment::SINGLE_VALUE, \
79     command_line_switch, switch_value, NULL, NULL, NULL, 0
80 #define SINGLE_VALUE_TYPE(command_line_switch) \
81     SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, "")
82 #define ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, enable_value, \
83                                             disable_switch, disable_value) \
84     Experiment::ENABLE_DISABLE_VALUE, enable_switch, enable_value, \
85     disable_switch, disable_value, NULL, 3
86 #define ENABLE_DISABLE_VALUE_TYPE(enable_switch, disable_switch) \
87     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, "", disable_switch, "")
88 #define MULTI_VALUE_TYPE(choices) \
89     Experiment::MULTI_VALUE, NULL, NULL, NULL, NULL, choices, arraysize(choices)
90
91 namespace {
92
93 const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid;
94 const unsigned kOsDesktop = kOsMac | kOsWin | kOsLinux | kOsCrOS;
95
96 // Adds a |StringValue| to |list| for each platform where |bitmask| indicates
97 // whether the experiment is available on that platform.
98 void AddOsStrings(unsigned bitmask, base::ListValue* list) {
99   struct {
100     unsigned bit;
101     const char* const name;
102   } kBitsToOs[] = {
103     {kOsMac, "Mac"},
104     {kOsWin, "Windows"},
105     {kOsLinux, "Linux"},
106     {kOsCrOS, "Chrome OS"},
107     {kOsAndroid, "Android"},
108     {kOsCrOSOwnerOnly, "Chrome OS (owner only)"},
109   };
110   for (size_t i = 0; i < arraysize(kBitsToOs); ++i)
111     if (bitmask & kBitsToOs[i].bit)
112       list->Append(new base::StringValue(kBitsToOs[i].name));
113 }
114
115 // Convert switch constants to proper CommandLine::StringType strings.
116 CommandLine::StringType GetSwitchString(const std::string& flag) {
117   CommandLine cmd_line(CommandLine::NO_PROGRAM);
118   cmd_line.AppendSwitch(flag);
119   DCHECK_EQ(2U, cmd_line.argv().size());
120   return cmd_line.argv()[1];
121 }
122
123 // Scoops flags from a command line.
124 std::set<CommandLine::StringType> ExtractFlagsFromCommandLine(
125     const CommandLine& cmdline) {
126   std::set<CommandLine::StringType> flags;
127   // First do the ones between --flag-switches-begin and --flag-switches-end.
128   CommandLine::StringVector::const_iterator first =
129       std::find(cmdline.argv().begin(), cmdline.argv().end(),
130                 GetSwitchString(switches::kFlagSwitchesBegin));
131   CommandLine::StringVector::const_iterator last =
132       std::find(cmdline.argv().begin(), cmdline.argv().end(),
133                 GetSwitchString(switches::kFlagSwitchesEnd));
134   if (first != cmdline.argv().end() && last != cmdline.argv().end())
135     flags.insert(first + 1, last);
136 #if defined(OS_CHROMEOS)
137   // Then add those between --policy-switches-begin and --policy-switches-end.
138   first = std::find(cmdline.argv().begin(), cmdline.argv().end(),
139                     GetSwitchString(chromeos::switches::kPolicySwitchesBegin));
140   last = std::find(cmdline.argv().begin(), cmdline.argv().end(),
141                    GetSwitchString(chromeos::switches::kPolicySwitchesEnd));
142   if (first != cmdline.argv().end() && last != cmdline.argv().end())
143     flags.insert(first + 1, last);
144 #endif
145   return flags;
146 }
147
148 const Experiment::Choice kEnableDisplayList2DcanvasChoices[] = {
149   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
150   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
151     switches::kEnableDisplayList2dCanvas, ""},
152   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
153     switches::kDisableDisplayList2dCanvas, ""},
154 };
155
156 const Experiment::Choice kEnableCompositingForTransitionChoices[] = {
157   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
158   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
159     switches::kEnableCompositingForTransition, ""},
160   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
161     switches::kDisableCompositingForTransition, ""},
162 };
163
164 const Experiment::Choice kTouchEventsChoices[] = {
165   { IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC, "", "" },
166   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
167     switches::kTouchEvents,
168     switches::kTouchEventsEnabled },
169   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
170     switches::kTouchEvents,
171     switches::kTouchEventsDisabled }
172 };
173
174 #if defined(USE_AURA)
175 const Experiment::Choice kOverscrollHistoryNavigationChoices[] = {
176   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, "", "" },
177   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
178     switches::kOverscrollHistoryNavigation,
179     "0" },
180   { IDS_OVERSCROLL_HISTORY_NAVIGATION_SIMPLE_UI,
181     switches::kOverscrollHistoryNavigation,
182     "2" }
183 };
184 #endif
185
186 #if !defined(DISABLE_NACL)
187 const Experiment::Choice kNaClDebugMaskChoices[] = {
188   // Secure shell can be used on ChromeOS for forwarding the TCP port opened by
189   // debug stub to a remote machine. Since secure shell uses NaCl, we usually
190   // want to avoid debugging that. The PNaCl translator is also a NaCl module,
191   // so by default we want to avoid debugging that.
192   // NOTE: As the default value must be the empty string, the mask excluding
193   // the PNaCl translator and secure shell is substituted elsewhere.
194   { IDS_NACL_DEBUG_MASK_CHOICE_EXCLUDE_UTILS_PNACL, "", "" },
195   { IDS_NACL_DEBUG_MASK_CHOICE_DEBUG_ALL, switches::kNaClDebugMask, "*://*" },
196   { IDS_NACL_DEBUG_MASK_CHOICE_INCLUDE_DEBUG,
197       switches::kNaClDebugMask, "*://*/*debug.nmf" }
198 };
199 #endif
200
201 const Experiment::Choice kImplSidePaintingChoices[] = {
202   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
203   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
204     switches::kEnableImplSidePainting, ""},
205   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
206     switches::kDisableImplSidePainting, ""}
207 };
208
209 const Experiment::Choice kLCDTextChoices[] = {
210   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
211   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, switches::kEnableLCDText, ""},
212   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED, switches::kDisableLCDText, ""}
213 };
214
215 const Experiment::Choice kDistanceFieldTextChoices[] = {
216   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
217   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
218     switches::kEnableDistanceFieldText, "" },
219   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
220     switches::kDisableDistanceFieldText, "" }
221 };
222
223 #ifndef USE_AURA
224 const Experiment::Choice kDelegatedRendererChoices[] = {
225   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
226   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
227     switches::kEnableDelegatedRenderer, ""},
228   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
229     switches::kDisableDelegatedRenderer, ""}
230 };
231 #endif
232
233 const Experiment::Choice kMaxTilesForInterestAreaChoices[] = {
234   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
235   { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_SHORT,
236     cc::switches::kMaxTilesForInterestArea, "64"},
237   { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_TALL,
238     cc::switches::kMaxTilesForInterestArea, "128"},
239   { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_GRANDE,
240     cc::switches::kMaxTilesForInterestArea, "256"},
241   { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_VENTI,
242     cc::switches::kMaxTilesForInterestArea, "512"}
243 };
244
245 const Experiment::Choice kDefaultTileWidthChoices[] = {
246   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
247   { IDS_FLAGS_DEFAULT_TILE_WIDTH_SHORT,
248     switches::kDefaultTileWidth, "128"},
249   { IDS_FLAGS_DEFAULT_TILE_WIDTH_TALL,
250     switches::kDefaultTileWidth, "256"},
251   { IDS_FLAGS_DEFAULT_TILE_WIDTH_GRANDE,
252     switches::kDefaultTileWidth, "512"},
253   { IDS_FLAGS_DEFAULT_TILE_WIDTH_VENTI,
254     switches::kDefaultTileWidth, "1024"}
255 };
256
257 const Experiment::Choice kDefaultTileHeightChoices[] = {
258   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
259   { IDS_FLAGS_DEFAULT_TILE_HEIGHT_SHORT,
260     switches::kDefaultTileHeight, "128"},
261   { IDS_FLAGS_DEFAULT_TILE_HEIGHT_TALL,
262     switches::kDefaultTileHeight, "256"},
263   { IDS_FLAGS_DEFAULT_TILE_HEIGHT_GRANDE,
264     switches::kDefaultTileHeight, "512"},
265   { IDS_FLAGS_DEFAULT_TILE_HEIGHT_VENTI,
266     switches::kDefaultTileHeight, "1024"}
267 };
268
269 const Experiment::Choice kSimpleCacheBackendChoices[] = {
270   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
271   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
272     switches::kUseSimpleCacheBackend, "off" },
273   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
274     switches::kUseSimpleCacheBackend, "on"}
275 };
276
277 #if defined(USE_AURA)
278 const Experiment::Choice kTabCaptureUpscaleQualityChoices[] = {
279   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
280   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_FAST,
281     switches::kTabCaptureUpscaleQuality, "fast" },
282   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_GOOD,
283     switches::kTabCaptureUpscaleQuality, "good" },
284   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_BEST,
285     switches::kTabCaptureUpscaleQuality, "best" },
286 };
287
288 const Experiment::Choice kTabCaptureDownscaleQualityChoices[] = {
289   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
290   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_FAST,
291     switches::kTabCaptureDownscaleQuality, "fast" },
292   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_GOOD,
293     switches::kTabCaptureDownscaleQuality, "good" },
294   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_BEST,
295     switches::kTabCaptureDownscaleQuality, "best" },
296 };
297 #endif
298
299 #if defined(USE_AURA) || defined(OS_LINUX)
300 const Experiment::Choice kOverlayScrollbarChoices[] = {
301   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
302   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
303     switches::kEnableOverlayScrollbar, ""},
304   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
305     switches::kDisableOverlayScrollbar, ""}
306 };
307 #endif
308
309 const Experiment::Choice kOneCopyChoices[] = {
310   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
311   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
312     switches::kEnableOneCopy, ""},
313   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
314     switches::kDisableOneCopy, ""}
315 };
316
317 #if defined(OS_ANDROID)
318 const Experiment::Choice kZeroSuggestExperimentsChoices[] = {
319   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
320   { IDS_FLAGS_ZERO_SUGGEST_MOST_VISITED,
321     switches::kEnableZeroSuggestMostVisited, ""},
322   { IDS_FLAGS_ZERO_SUGGEST_MOST_VISITED_WITHOUT_SERP,
323     switches::kEnableZeroSuggestMostVisitedWithoutSerp, ""},
324   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
325     switches::kDisableZeroSuggest, ""}
326 };
327 #endif
328
329 const Experiment::Choice kNumRasterThreadsChoices[] = {
330   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
331   { IDS_FLAGS_NUM_RASTER_THREADS_ONE, switches::kNumRasterThreads, "1" },
332   { IDS_FLAGS_NUM_RASTER_THREADS_TWO, switches::kNumRasterThreads, "2" },
333   { IDS_FLAGS_NUM_RASTER_THREADS_THREE, switches::kNumRasterThreads, "3" },
334   { IDS_FLAGS_NUM_RASTER_THREADS_FOUR, switches::kNumRasterThreads, "4" }
335 };
336
337 const Experiment::Choice kEnableGpuRasterizationChoices[] = {
338   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
339   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
340     switches::kEnableGpuRasterization, "" },
341   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
342     switches::kDisableGpuRasterization, "" },
343   { IDS_FLAGS_FORCE_GPU_RASTERIZATION,
344     switches::kForceGpuRasterization, "" },
345 };
346
347 // We're using independent flags here (as opposed to a common flag with
348 // different values) to be able to enable/disable the entire experience
349 // associated with this feature server-side from the FieldTrial (the complete
350 // experience includes other flag changes as well). It is not currently possible
351 // to do that with "flag=value" flags.
352 const Experiment::Choice kSearchButtonInOmniboxChoices[] = {
353   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
354   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
355     switches::kDisableSearchButtonInOmnibox, ""},
356   { IDS_FLAGS_SEARCH_BUTTON_IN_OMNIBOX_ENABLE_FOR_STR,
357     switches::kEnableSearchButtonInOmniboxForStr, ""},
358   { IDS_FLAGS_SEARCH_BUTTON_IN_OMNIBOX_ENABLE_FOR_STR_OR_IIP,
359     switches::kEnableSearchButtonInOmniboxForStrOrIip, ""},
360   { IDS_FLAGS_SEARCH_BUTTON_IN_OMNIBOX_ENABLED,
361     switches::kEnableSearchButtonInOmniboxAlways, ""}
362 };
363
364 // See comment above for kSearchButtonInOmniboxChoices. The same reasoning
365 // applies here.
366 const Experiment::Choice kOriginChipChoices[] = {
367   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
368   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED, switches::kDisableOriginChip, ""},
369   { IDS_FLAGS_ORIGIN_CHIP_ALWAYS, switches::kEnableOriginChipAlways, ""},
370   { IDS_FLAGS_ORIGIN_CHIP_ON_SRP, switches::kEnableOriginChipOnSrp, ""}
371 };
372
373 const Experiment::Choice kTouchScrollingModeChoices[] = {
374   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
375   { IDS_FLAGS_TOUCH_SCROLLING_MODE_TOUCHCANCEL,
376     switches::kTouchScrollingMode,
377     switches::kTouchScrollingModeTouchcancel },
378   { IDS_FLAGS_TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE,
379     switches::kTouchScrollingMode,
380     switches::kTouchScrollingModeAsyncTouchmove },
381   { IDS_FLAGS_TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE,
382     switches::kTouchScrollingMode,
383     switches::kTouchScrollingModeSyncTouchmove },
384 };
385
386 #if defined(ENABLE_APP_LIST)
387 const Experiment::Choice kEnableSyncAppListChoices[] = {
388   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
389   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
390     app_list::switches::kEnableSyncAppList, "" },
391   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
392     app_list::switches::kDisableSyncAppList, "" },
393 };
394 #endif
395
396 const Experiment::Choice kExtensionContentVerificationChoices[] = {
397   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
398   { IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_BOOTSTRAP,
399     switches::kExtensionContentVerification,
400     switches::kExtensionContentVerificationBootstrap },
401   { IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_ENFORCE,
402     switches::kExtensionContentVerification,
403     switches::kExtensionContentVerificationEnforce },
404   { IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_ENFORCE_STRICT,
405     switches::kExtensionContentVerification,
406     switches::kExtensionContentVerificationEnforceStrict },
407 };
408
409 #if defined(OS_ANDROID)
410 const Experiment::Choice kAnswersInSuggestChoices[] = {
411   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
412   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
413     switches::kEnableAnswersInSuggest, ""},
414   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
415     switches::kDisableAnswersInSuggest, ""}
416 };
417 #endif
418
419 const Experiment::Choice kEnableSettingsWindowChoices[] = {
420   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
421   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
422     ::switches::kEnableSettingsWindow, "" },
423   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
424     ::switches::kDisableSettingsWindow, "" },
425 };
426
427 // Note that the value is specified in seconds (where 0 is equivalent to
428 // disabled).
429 const Experiment::Choice kRememberCertificateErrorDecisionsChoices[] = {
430   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
431   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
432     switches::kRememberCertErrorDecisions,
433     "-1" },
434   { IDS_REMEMBER_CERTIFICATE_ERROR_DECISION_CHOICE_ONE_DAY,
435     switches::kRememberCertErrorDecisions,
436     "86400" },
437   { IDS_REMEMBER_CERTIFICATE_ERROR_DECISION_CHOICE_THREE_DAYS,
438     switches::kRememberCertErrorDecisions,
439     "259200" },
440   { IDS_REMEMBER_CERTIFICATE_ERROR_DECISION_CHOICE_ONE_WEEK,
441     switches::kRememberCertErrorDecisions,
442     "604800" },
443   { IDS_REMEMBER_CERTIFICATE_ERROR_DECISION_CHOICE_ONE_MONTH,
444     switches::kRememberCertErrorDecisions,
445     "2592000" },
446   { IDS_REMEMBER_CERTIFICATE_ERROR_DECISION_CHOICE_THREE_MONTHS,
447     switches::kRememberCertErrorDecisions,
448     "7776000" },
449 };
450
451 const Experiment::Choice kEnableDropSyncCredentialChoices[] = {
452   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", ""},
453   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
454     password_manager::switches::kEnableDropSyncCredential, "" },
455   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
456     password_manager::switches::kDisableDropSyncCredential, "" },
457 };
458
459 #if defined(OS_MACOSX)
460 const Experiment::Choice kEnableAVFoundationChoices[] = {
461   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
462   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, switches::kEnableAVFoundation, ""},
463   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED, switches::kForceQTKit, ""}
464 };
465 #endif
466
467 const Experiment::Choice kAutofillSyncCredentialChoices[] = {
468   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", ""},
469   { IDS_ALLOW_AUTOFILL_SYNC_CREDENTIAL,
470     password_manager::switches::kAllowAutofillSyncCredential, ""},
471   { IDS_DISALLOW_AUTOFILL_SYNC_CREDENTIAL_FOR_REAUTH,
472     password_manager::switches::kDisallowAutofillSyncCredentialForReauth, ""},
473   { IDS_DISALLOW_AUTOFILL_SYNC_CREDENTIAL,
474     password_manager::switches::kDisallowAutofillSyncCredential, ""},
475 };
476
477 const Experiment::Choice kSSLVersionMinChoices[] = {
478   { IDS_FLAGS_SSL_VERSION_DEFAULT, "", "" },
479   { IDS_FLAGS_SSL_VERSION_SSLV3, switches::kSSLVersionMin,
480     switches::kSSLVersionSSLv3 },
481   { IDS_FLAGS_SSL_VERSION_TLSV1, switches::kSSLVersionMin,
482     switches::kSSLVersionTLSv1 },
483   { IDS_FLAGS_SSL_VERSION_TLSV11, switches::kSSLVersionMin,
484     switches::kSSLVersionTLSv11 },
485   { IDS_FLAGS_SSL_VERSION_TLSV12, switches::kSSLVersionMin,
486     switches::kSSLVersionTLSv12 },
487 };
488
489 // RECORDING USER METRICS FOR FLAGS:
490 // -----------------------------------------------------------------------------
491 // The first line of the experiment is the internal name. If you'd like to
492 // gather statistics about the usage of your flag, you should append a marker
493 // comment to the end of the feature name, like so:
494 //   "my-special-feature",  // FLAGS:RECORD_UMA
495 //
496 // After doing that, run
497 //   tools/metrics/actions/extract_actions.py
498 // to add the metric to actions.xml (which will enable UMA to record your
499 // feature flag), then update the <owner>s and <description> sections. Make sure
500 // to include the actions.xml file when you upload your code for review!
501 //
502 // After your feature has shipped under a flag, you can locate the metrics under
503 // the action name AboutFlags_internal-action-name. Actions are recorded once
504 // per startup, so you should divide this number by AboutFlags_StartupTick to
505 // get a sense of usage. Note that this will not be the same as number of users
506 // with a given feature enabled because users can quit and relaunch the
507 // application multiple times over a given time interval. The dashboard also
508 // shows you how many (metrics reporting) users have enabled the flag over the
509 // last seven days. However, note that this is not the same as the number of
510 // users who have the flag enabled, since enabling the flag happens once,
511 // whereas running with the flag enabled happens until the user flips the flag
512 // again.
513
514 // To add a new experiment add to the end of kExperiments. There are two
515 // distinct types of experiments:
516 // . SINGLE_VALUE: experiment is either on or off. Use the SINGLE_VALUE_TYPE
517 //   macro for this type supplying the command line to the macro.
518 // . MULTI_VALUE: a list of choices, the first of which should correspond to a
519 //   deactivated state for this lab (i.e. no command line option).  To specify
520 //   this type of experiment use the macro MULTI_VALUE_TYPE supplying it the
521 //   array of choices.
522 // See the documentation of Experiment for details on the fields.
523 //
524 // Command-line switches must have entries in enum "LoginCustomFlags" in
525 // histograms.xml. See note in histograms.xml and don't forget to run
526 // AboutFlagsHistogramTest unit test to calculate and verify checksum.
527 //
528 // When adding a new choice, add it to the end of the list.
529 const Experiment kExperiments[] = {
530   {
531     "ignore-gpu-blacklist",
532     IDS_FLAGS_IGNORE_GPU_BLACKLIST_NAME,
533     IDS_FLAGS_IGNORE_GPU_BLACKLIST_DESCRIPTION,
534     kOsAll,
535     SINGLE_VALUE_TYPE(switches::kIgnoreGpuBlacklist)
536   },
537   {
538     "disable_layer_squashing",
539     IDS_FLAGS_DISABLE_LAYER_SQUASHING_NAME,
540     IDS_FLAGS_DISABLE_LAYER_SQUASHING_DESCRIPTION,
541     kOsAll,
542     SINGLE_VALUE_TYPE(switches::kDisableLayerSquashing)
543   },
544 #if defined(OS_WIN)
545   {
546     "disable-direct-write",
547     IDS_FLAGS_DISABLE_DIRECT_WRITE_NAME,
548     IDS_FLAGS_DISABLE_DIRECT_WRITE_DESCRIPTION,
549     kOsWin,
550     SINGLE_VALUE_TYPE(switches::kDisableDirectWrite)
551   },
552 #endif
553   {
554     "enable-experimental-canvas-features",
555     IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_NAME,
556     IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_DESCRIPTION,
557     kOsAll,
558     SINGLE_VALUE_TYPE(switches::kEnableExperimentalCanvasFeatures)
559   },
560   {
561     "disable-accelerated-2d-canvas",
562     IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_NAME,
563     IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_DESCRIPTION,
564     kOsAll,
565     SINGLE_VALUE_TYPE(switches::kDisableAccelerated2dCanvas)
566   },
567   {
568     "enable-display-list-2d-canvas",
569     IDS_FLAGS_ENABLE_DISPLAY_LIST_2D_CANVAS_NAME,
570     IDS_FLAGS_ENABLE_DISPLAY_LIST_2D_CANVAS_DESCRIPTION,
571     kOsAll,
572     MULTI_VALUE_TYPE(kEnableDisplayList2DcanvasChoices)
573   },
574   {
575     "composited-layer-borders",
576     IDS_FLAGS_COMPOSITED_LAYER_BORDERS,
577     IDS_FLAGS_COMPOSITED_LAYER_BORDERS_DESCRIPTION,
578     kOsAll,
579     SINGLE_VALUE_TYPE(cc::switches::kShowCompositedLayerBorders)
580   },
581   {
582     "show-fps-counter",
583     IDS_FLAGS_SHOW_FPS_COUNTER,
584     IDS_FLAGS_SHOW_FPS_COUNTER_DESCRIPTION,
585     kOsAll,
586     SINGLE_VALUE_TYPE(cc::switches::kShowFPSCounter)
587   },
588   {
589     "disable-webgl",
590     IDS_FLAGS_DISABLE_WEBGL_NAME,
591     IDS_FLAGS_DISABLE_WEBGL_DESCRIPTION,
592     kOsAll,
593     SINGLE_VALUE_TYPE(switches::kDisableExperimentalWebGL)
594   },
595   {
596     "disable-webrtc",
597     IDS_FLAGS_DISABLE_WEBRTC_NAME,
598     IDS_FLAGS_DISABLE_WEBRTC_DESCRIPTION,
599     kOsAndroid,
600 #if defined(OS_ANDROID)
601     SINGLE_VALUE_TYPE(switches::kDisableWebRTC)
602 #else
603     SINGLE_VALUE_TYPE("")
604 #endif
605   },
606 #if defined(ENABLE_WEBRTC)
607   {
608     "disable-webrtc-hw-decoding",
609     IDS_FLAGS_DISABLE_WEBRTC_HW_DECODING_NAME,
610     IDS_FLAGS_DISABLE_WEBRTC_HW_DECODING_DESCRIPTION,
611     kOsAndroid | kOsCrOS,
612     SINGLE_VALUE_TYPE(switches::kDisableWebRtcHWDecoding)
613   },
614   {
615     "disable-webrtc-hw-encoding",
616     IDS_FLAGS_DISABLE_WEBRTC_HW_ENCODING_NAME,
617     IDS_FLAGS_DISABLE_WEBRTC_HW_ENCODING_DESCRIPTION,
618     kOsAndroid | kOsCrOS,
619     SINGLE_VALUE_TYPE(switches::kDisableWebRtcHWEncoding)
620   },
621 #endif
622 #if defined(OS_ANDROID)
623   {
624     "disable-webaudio",
625     IDS_FLAGS_DISABLE_WEBAUDIO_NAME,
626     IDS_FLAGS_DISABLE_WEBAUDIO_DESCRIPTION,
627     kOsAndroid,
628     SINGLE_VALUE_TYPE(switches::kDisableWebAudio)
629   },
630 #endif
631   {
632     "enable-compositing-for-transition",
633     IDS_FLAGS_COMPOSITING_FOR_TRANSITION_NAME,
634     IDS_FLAGS_COMPOSITING_FOR_TRANSITION_DESCRIPTION,
635     kOsAll,
636     MULTI_VALUE_TYPE(kEnableCompositingForTransitionChoices)
637   },
638   // Native client is compiled out when DISABLE_NACL is defined.
639 #if !defined(DISABLE_NACL)
640   {
641     "enable-nacl",  // FLAGS:RECORD_UMA
642     IDS_FLAGS_ENABLE_NACL_NAME,
643     IDS_FLAGS_ENABLE_NACL_DESCRIPTION,
644     kOsAll,
645     SINGLE_VALUE_TYPE(switches::kEnableNaCl)
646   },
647   {
648     "enable-nacl-debug",  // FLAGS:RECORD_UMA
649     IDS_FLAGS_ENABLE_NACL_DEBUG_NAME,
650     IDS_FLAGS_ENABLE_NACL_DEBUG_DESCRIPTION,
651     kOsDesktop,
652     SINGLE_VALUE_TYPE(switches::kEnableNaClDebug)
653   },
654   {
655     "nacl-debug-mask",  // FLAGS:RECORD_UMA
656     IDS_FLAGS_NACL_DEBUG_MASK_NAME,
657     IDS_FLAGS_NACL_DEBUG_MASK_DESCRIPTION,
658     kOsDesktop,
659     MULTI_VALUE_TYPE(kNaClDebugMaskChoices)
660   },
661 #endif
662 #if defined(ENABLE_EXTENSIONS)
663   {
664     "extension-apis",  // FLAGS:RECORD_UMA
665     IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_NAME,
666     IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION,
667     kOsDesktop,
668     SINGLE_VALUE_TYPE(extensions::switches::kEnableExperimentalExtensionApis)
669   },
670   {
671     "extensions-on-chrome-urls",
672     IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_NAME,
673     IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_DESCRIPTION,
674     kOsAll,
675     SINGLE_VALUE_TYPE(extensions::switches::kExtensionsOnChromeURLs)
676   },
677 #endif
678   {
679     "enable-fast-unload",
680     IDS_FLAGS_ENABLE_FAST_UNLOAD_NAME,
681     IDS_FLAGS_ENABLE_FAST_UNLOAD_DESCRIPTION,
682     kOsAll,
683     SINGLE_VALUE_TYPE(switches::kEnableFastUnload)
684   },
685 #if defined(ENABLE_EXTENSIONS)
686   {
687     "enable-app-window-controls",
688     IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_NAME,
689     IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_DESCRIPTION,
690     kOsDesktop,
691     SINGLE_VALUE_TYPE(extensions::switches::kEnableAppWindowControls)
692   },
693 #endif
694   {
695     "disable-hyperlink-auditing",
696     IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_NAME,
697     IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_DESCRIPTION,
698     kOsAll,
699     SINGLE_VALUE_TYPE(switches::kNoPings)
700   },
701 #if defined(OS_ANDROID)
702   {
703     "contextual-search",
704     IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH,
705     IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH_DESCRIPTION,
706     kOsAndroid,
707     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableContextualSearch,
708                               switches::kDisableContextualSearch)
709   },
710 #endif
711   {
712     "show-autofill-type-predictions",
713     IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_NAME,
714     IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_DESCRIPTION,
715     kOsAll,
716     SINGLE_VALUE_TYPE(autofill::switches::kShowAutofillTypePredictions)
717   },
718   {
719     "enable-smooth-scrolling",  // FLAGS:RECORD_UMA
720     IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_NAME,
721     IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_DESCRIPTION,
722     // Can't expose the switch unless the code is compiled in.
723     // On by default for the Mac (different implementation in WebKit).
724     kOsLinux,
725     SINGLE_VALUE_TYPE(switches::kEnableSmoothScrolling)
726   },
727 #if defined(USE_AURA) || defined(OS_LINUX)
728   {
729     "overlay-scrollbars",
730     IDS_FLAGS_ENABLE_OVERLAY_SCROLLBARS_NAME,
731     IDS_FLAGS_ENABLE_OVERLAY_SCROLLBARS_DESCRIPTION,
732     // Uses the system preference on Mac (a different implementation).
733     // On Android, this is always enabled.
734     kOsLinux | kOsCrOS | kOsWin,
735     MULTI_VALUE_TYPE(kOverlayScrollbarChoices)
736   },
737 #endif
738   {
739     "enable-panels",
740     IDS_FLAGS_ENABLE_PANELS_NAME,
741     IDS_FLAGS_ENABLE_PANELS_DESCRIPTION,
742     kOsDesktop,
743     SINGLE_VALUE_TYPE(switches::kEnablePanels)
744   },
745   {
746     // See http://crbug.com/120416 for how to remove this flag.
747     "save-page-as-mhtml",  // FLAGS:RECORD_UMA
748     IDS_FLAGS_SAVE_PAGE_AS_MHTML_NAME,
749     IDS_FLAGS_SAVE_PAGE_AS_MHTML_DESCRIPTION,
750     kOsMac | kOsWin | kOsLinux,
751     SINGLE_VALUE_TYPE(switches::kSavePageAsMHTML)
752   },
753   {
754     "enable-quic",
755     IDS_FLAGS_ENABLE_QUIC_NAME,
756     IDS_FLAGS_ENABLE_QUIC_DESCRIPTION,
757     kOsAll,
758     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableQuic,
759                               switches::kDisableQuic)
760   },
761   {
762     "enable-spdy4",
763     IDS_FLAGS_ENABLE_SPDY4_NAME,
764     IDS_FLAGS_ENABLE_SPDY4_DESCRIPTION,
765     kOsAll,
766     SINGLE_VALUE_TYPE(switches::kEnableSpdy4)
767   },
768   {
769     "enable-async-dns",
770     IDS_FLAGS_ENABLE_ASYNC_DNS_NAME,
771     IDS_FLAGS_ENABLE_ASYNC_DNS_DESCRIPTION,
772     kOsWin | kOsMac | kOsLinux | kOsCrOS,
773     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAsyncDns,
774                               switches::kDisableAsyncDns)
775   },
776   {
777     "disable-media-source",
778     IDS_FLAGS_DISABLE_MEDIA_SOURCE_NAME,
779     IDS_FLAGS_DISABLE_MEDIA_SOURCE_DESCRIPTION,
780     kOsAll,
781     SINGLE_VALUE_TYPE(switches::kDisableMediaSource)
782   },
783   {
784     "enable-encrypted-media",
785     IDS_FLAGS_ENABLE_ENCRYPTED_MEDIA_NAME,
786     IDS_FLAGS_ENABLE_ENCRYPTED_MEDIA_DESCRIPTION,
787     kOsAll,
788     SINGLE_VALUE_TYPE(switches::kEnableEncryptedMedia)
789   },
790   {
791     "disable-prefixed-encrypted-media",
792     IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_NAME,
793     IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_DESCRIPTION,
794     kOsAll,
795     SINGLE_VALUE_TYPE(switches::kDisablePrefixedEncryptedMedia)
796   },
797 #if defined(OS_ANDROID)
798   {
799     "disable-infobar-for-protected-media-identifier",
800     IDS_FLAGS_DISABLE_INFOBAR_FOR_PROTECTED_MEDIA_IDENTIFIER_NAME,
801     IDS_FLAGS_DISABLE_INFOBAR_FOR_PROTECTED_MEDIA_IDENTIFIER_DESCRIPTION,
802     kOsAndroid,
803     SINGLE_VALUE_TYPE(switches::kDisableInfobarForProtectedMediaIdentifier)
804   },
805   {
806     "mediadrm-enable-non-compositing",
807     IDS_FLAGS_MEDIADRM_ENABLE_NON_COMPOSITING_NAME,
808     IDS_FLAGS_MEDIADRM_ENABLE_NON_COMPOSITING_DESCRIPTION,
809     kOsAndroid,
810     SINGLE_VALUE_TYPE(switches::kMediaDrmEnableNonCompositing)
811   },
812 #endif  // defined(OS_ANDROID)
813   {
814     "enable-javascript-harmony",
815     IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_NAME,
816     IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_DESCRIPTION,
817     kOsAll,
818     SINGLE_VALUE_TYPE(switches::kJavaScriptHarmony)
819   },
820   {
821     "disable-software-rasterizer",
822     IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_NAME,
823     IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_DESCRIPTION,
824 #if defined(ENABLE_SWIFTSHADER)
825     kOsAll,
826 #else
827     0,
828 #endif
829     SINGLE_VALUE_TYPE(switches::kDisableSoftwareRasterizer)
830   },
831   {
832     "enable-gpu-rasterization",
833     IDS_FLAGS_ENABLE_GPU_RASTERIZATION_NAME,
834     IDS_FLAGS_ENABLE_GPU_RASTERIZATION_DESCRIPTION,
835     kOsAndroid,
836     MULTI_VALUE_TYPE(kEnableGpuRasterizationChoices)
837   },
838   {
839     "enable-experimental-web-platform-features",
840     IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_NAME,
841     IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_DESCRIPTION,
842     kOsAll,
843     SINGLE_VALUE_TYPE(switches::kEnableExperimentalWebPlatformFeatures)
844   },
845   {
846     "disable-ntp-other-sessions-menu",
847     IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_NAME,
848     IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_DESCRIPTION,
849     kOsDesktop,
850     SINGLE_VALUE_TYPE(switches::kDisableNTPOtherSessionsMenu)
851   },
852   {
853     "enable-material-design-ntp",
854     IDS_FLAGS_ENABLE_MATERIAL_DESIGN_NTP_NAME,
855     IDS_FLAGS_ENABLE_MATERIAL_DESIGN_NTP_DESCRIPTION,
856     kOsDesktop,
857     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableMaterialDesignNTP,
858                               switches::kDisableMaterialDesignNTP)
859   },
860   {
861     "enable-devtools-experiments",
862     IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_NAME,
863     IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_DESCRIPTION,
864     kOsDesktop,
865     SINGLE_VALUE_TYPE(switches::kEnableDevToolsExperiments)
866   },
867   {
868     "silent-debugger-extension-api",
869     IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_NAME,
870     IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_DESCRIPTION,
871     kOsDesktop,
872     SINGLE_VALUE_TYPE(switches::kSilentDebuggerExtensionAPI)
873   },
874 #if defined(ENABLE_SPELLCHECK)
875   {
876     "spellcheck-autocorrect",
877     IDS_FLAGS_SPELLCHECK_AUTOCORRECT,
878     IDS_FLAGS_SPELLCHECK_AUTOCORRECT_DESCRIPTION,
879     kOsWin | kOsLinux | kOsCrOS,
880     SINGLE_VALUE_TYPE(switches::kEnableSpellingAutoCorrect)
881   },
882 #endif
883   {
884     "enable-scroll-prediction",
885     IDS_FLAGS_ENABLE_SCROLL_PREDICTION_NAME,
886     IDS_FLAGS_ENABLE_SCROLL_PREDICTION_DESCRIPTION,
887     kOsDesktop,
888     SINGLE_VALUE_TYPE(switches::kEnableScrollPrediction)
889   },
890   {
891     "touch-events",
892     IDS_TOUCH_EVENTS_NAME,
893     IDS_TOUCH_EVENTS_DESCRIPTION,
894     kOsDesktop,
895     MULTI_VALUE_TYPE(kTouchEventsChoices)
896   },
897   {
898     "disable-touch-adjustment",
899     IDS_DISABLE_TOUCH_ADJUSTMENT_NAME,
900     IDS_DISABLE_TOUCH_ADJUSTMENT_DESCRIPTION,
901     kOsWin | kOsLinux | kOsCrOS | kOsAndroid,
902     SINGLE_VALUE_TYPE(switches::kDisableTouchAdjustment)
903   },
904 #if defined(OS_CHROMEOS)
905   {
906     "network-portal-notification",
907     IDS_FLAGS_NETWORK_PORTAL_NOTIFICATION_NAME,
908     IDS_FLAGS_NETWORK_PORTAL_NOTIFICATION_DESCRIPTION,
909     kOsCrOS,
910     ENABLE_DISABLE_VALUE_TYPE(
911         chromeos::switches::kEnableNetworkPortalNotification,
912         chromeos::switches::kDisableNetworkPortalNotification)
913   },
914 #endif
915   {
916     "enable-download-resumption",
917     IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_NAME,
918     IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_DESCRIPTION,
919     kOsDesktop,
920     SINGLE_VALUE_TYPE(switches::kEnableDownloadResumption)
921   },
922 #if defined(ENABLE_PLUGINS)
923   {
924     "allow-nacl-socket-api",
925     IDS_FLAGS_ALLOW_NACL_SOCKET_API_NAME,
926     IDS_FLAGS_ALLOW_NACL_SOCKET_API_DESCRIPTION,
927     kOsDesktop,
928     SINGLE_VALUE_TYPE_AND_VALUE(switches::kAllowNaClSocketAPI, "*")
929   },
930 #endif
931 #if defined(OS_CHROMEOS)
932   {
933     "allow-touchpad-three-finger-click",
934     IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_NAME,
935     IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_DESCRIPTION,
936     kOsCrOS,
937     SINGLE_VALUE_TYPE(chromeos::switches::kEnableTouchpadThreeFingerClick)
938   },
939   {
940     "disable-easy-signin",
941     IDS_FLAGS_DISABLE_EASY_SIGNIN_NAME,
942     IDS_FLAGS_DISABLE_EASY_SIGNIN_DESCRIPTION,
943     kOsCrOSOwnerOnly,
944     SINGLE_VALUE_TYPE(chromeos::switches::kDisableEasySignin),
945   },
946   {
947     "enable-easy-unlock-proximity-detection",
948     IDS_FLAGS_ENABLE_EASY_UNLOCK_PROXIMITY_DETECTION_NAME,
949     IDS_FLAGS_ENABLE_EASY_UNLOCK_PROXIMITY_DETECTION_DESCRIPTION,
950     kOsCrOS,
951     SINGLE_VALUE_TYPE(proximity_auth::switches::kEnableProximityDetection)
952   },
953 #endif
954 #if defined(USE_ASH)
955   {
956     "disable-minimize-on-second-launcher-item-click",
957     IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_NAME,
958     IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_DESCRIPTION,
959     kOsAll,
960     SINGLE_VALUE_TYPE(switches::kDisableMinimizeOnSecondLauncherItemClick)
961   },
962   {
963     "show-touch-hud",
964     IDS_FLAGS_SHOW_TOUCH_HUD_NAME,
965     IDS_FLAGS_SHOW_TOUCH_HUD_DESCRIPTION,
966     kOsAll,
967     SINGLE_VALUE_TYPE(ash::switches::kAshTouchHud)
968   },
969   {
970     "enable-pinch",
971     IDS_FLAGS_ENABLE_PINCH_SCALE_NAME,
972     IDS_FLAGS_ENABLE_PINCH_SCALE_DESCRIPTION,
973     kOsLinux | kOsWin | kOsCrOS,
974     ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePinch, switches::kDisablePinch),
975   },
976 #endif  // defined(USE_ASH)
977   {
978     "enable-pinch-virtual-viewport",
979     IDS_FLAGS_ENABLE_PINCH_VIRTUAL_VIEWPORT_NAME,
980     IDS_FLAGS_ENABLE_PINCH_VIRTUAL_VIEWPORT_DESCRIPTION,
981     kOsLinux | kOsWin | kOsCrOS | kOsAndroid,
982     ENABLE_DISABLE_VALUE_TYPE(
983         cc::switches::kEnablePinchVirtualViewport,
984         cc::switches::kDisablePinchVirtualViewport),
985   },
986   {
987     "enable-viewport-meta",
988     IDS_FLAGS_ENABLE_VIEWPORT_META_NAME,
989     IDS_FLAGS_ENABLE_VIEWPORT_META_DESCRIPTION,
990     kOsLinux | kOsWin | kOsCrOS | kOsMac,
991     SINGLE_VALUE_TYPE(switches::kEnableViewportMeta),
992   },
993 #if defined(OS_CHROMEOS)
994   {
995     "disable-boot-animation",
996     IDS_FLAGS_DISABLE_BOOT_ANIMATION,
997     IDS_FLAGS_DISABLE_BOOT_ANIMATION_DESCRIPTION,
998     kOsCrOSOwnerOnly,
999     SINGLE_VALUE_TYPE(chromeos::switches::kDisableBootAnimation),
1000   },
1001   {
1002     "enable-video-player-chromecast-support",
1003     IDS_FLAGS_ENABLE_VIDEO_PLAYER_CHROMECAST_SUPPORT_NAME,
1004     IDS_FLAGS_ENABLE_VIDEO_PLAYER_CHROMECAST_SUPPORT_DESCRIPTION,
1005     kOsCrOS,
1006     SINGLE_VALUE_TYPE(chromeos::switches::kEnableVideoPlayerChromecastSupport)
1007   },
1008   {
1009     "disable-office-editing-component-app",
1010     IDS_FLAGS_DISABLE_OFFICE_EDITING_COMPONENT_APP_NAME,
1011     IDS_FLAGS_DISABLE_OFFICE_EDITING_COMPONENT_APP_DESCRIPTION,
1012     kOsCrOS,
1013     SINGLE_VALUE_TYPE(chromeos::switches::kDisableOfficeEditingComponentApp),
1014   },
1015   {
1016     "disable-display-color-calibration",
1017     IDS_FLAGS_DISABLE_DISPLAY_COLOR_CALIBRATION_NAME,
1018     IDS_FLAGS_DISABLE_DISPLAY_COLOR_CALIBRATION_DESCRIPTION,
1019     kOsCrOS,
1020     SINGLE_VALUE_TYPE(ui::switches::kDisableDisplayColorCalibration),
1021   },
1022 #endif  // defined(OS_CHROMEOS)
1023   { "disable-accelerated-video-decode",
1024     IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_NAME,
1025     IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_DESCRIPTION,
1026     kOsWin | kOsCrOS,
1027     SINGLE_VALUE_TYPE(switches::kDisableAcceleratedVideoDecode),
1028   },
1029 #if defined(USE_ASH)
1030   {
1031     "ash-debug-shortcuts",
1032     IDS_FLAGS_DEBUG_SHORTCUTS_NAME,
1033     IDS_FLAGS_DEBUG_SHORTCUTS_DESCRIPTION,
1034     kOsAll,
1035     SINGLE_VALUE_TYPE(ash::switches::kAshDebugShortcuts),
1036   },
1037   { "ash-enable-touch-view-testing",
1038     IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_NAME,
1039     IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_DESCRIPTION,
1040     kOsCrOS,
1041     SINGLE_VALUE_TYPE(ash::switches::kAshEnableTouchViewTesting),
1042   },
1043   {
1044     "enable-touch-feedback",
1045     IDS_FLAGS_ENABLE_TOUCH_FEEDBACK_NAME,
1046     IDS_FLAGS_ENABLE_TOUCH_FEEDBACK_DESCRIPTION,
1047     kOsCrOS,
1048     SINGLE_VALUE_TYPE(switches::kEnableTouchFeedback),
1049   },
1050   { "ash-disable-text-filtering-in-overview-mode",
1051     IDS_FLAGS_ASH_DISABLE_TEXT_FILTERING_IN_OVERVIEW_MODE_NAME,
1052     IDS_FLAGS_ASH_DISABLE_TEXT_FILTERING_IN_OVERVIEW_MODE_DESCRIPTION,
1053     kOsCrOS,
1054     SINGLE_VALUE_TYPE(ash::switches::kAshDisableTextFilteringInOverviewMode),
1055   },
1056 #endif  // defined(USE_ASH)
1057 #if defined(OS_CHROMEOS)
1058   {
1059     "enable-carrier-switching",
1060     IDS_FLAGS_ENABLE_CARRIER_SWITCHING,
1061     IDS_FLAGS_ENABLE_CARRIER_SWITCHING_DESCRIPTION,
1062     kOsCrOS,
1063     SINGLE_VALUE_TYPE(chromeos::switches::kEnableCarrierSwitching)
1064   },
1065   {
1066     "enable-cloud-backup",
1067     IDS_FLAGS_ENABLE_CLOUD_BACKUP,
1068     IDS_FLAGS_ENABLE_CLOUD_BACKUP_DESCRIPTION,
1069     kOsCrOS,
1070     SINGLE_VALUE_TYPE(chromeos::switches::kEnableCloudBackup)
1071   },
1072   {
1073     "enable-request-tablet-site",
1074     IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_NAME,
1075     IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_DESCRIPTION,
1076     kOsCrOS,
1077     SINGLE_VALUE_TYPE(chromeos::switches::kEnableRequestTabletSite)
1078   },
1079 #endif
1080   {
1081     "debug-packed-apps",
1082     IDS_FLAGS_DEBUG_PACKED_APP_NAME,
1083     IDS_FLAGS_DEBUG_PACKED_APP_DESCRIPTION,
1084     kOsDesktop,
1085     SINGLE_VALUE_TYPE(switches::kDebugPackedApps)
1086   },
1087   {
1088     "enable-password-generation",
1089     IDS_FLAGS_ENABLE_PASSWORD_GENERATION_NAME,
1090     IDS_FLAGS_ENABLE_PASSWORD_GENERATION_DESCRIPTION,
1091     kOsWin | kOsLinux | kOsCrOS | kOsMac | kOsAndroid,
1092     ENABLE_DISABLE_VALUE_TYPE(autofill::switches::kEnablePasswordGeneration,
1093                               autofill::switches::kDisablePasswordGeneration)
1094   },
1095   {
1096     "enable-automatic-password-saving",
1097     IDS_FLAGS_ENABLE_AUTOMATIC_PASSWORD_SAVING_NAME,
1098     IDS_FLAGS_ENABLE_AUTOMATIC_PASSWORD_SAVING_DESCRIPTION,
1099     kOsDesktop,
1100     SINGLE_VALUE_TYPE(
1101         password_manager::switches::kEnableAutomaticPasswordSaving)
1102   },
1103   {
1104     "password-manager-reauthentication",
1105     IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_NAME,
1106     IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_DESCRIPTION,
1107     kOsMac | kOsWin,
1108     SINGLE_VALUE_TYPE(switches::kDisablePasswordManagerReauthentication)
1109   },
1110   {
1111     "enable-password-link",
1112     IDS_FLAGS_PASSWORD_MANAGER_LINK_NAME,
1113     IDS_FLAGS_PASSWORD_MANAGER_LINK_DESCRIPTION,
1114     kOsAndroid | kOsDesktop,
1115     ENABLE_DISABLE_VALUE_TYPE(
1116         password_manager::switches::kEnablePasswordLink,
1117         password_manager::switches::kDisablePasswordLink)
1118   },
1119   {
1120     "enable-deferred-image-decoding",
1121     IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_NAME,
1122     IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_DESCRIPTION,
1123     kOsMac | kOsLinux | kOsCrOS,
1124     SINGLE_VALUE_TYPE(switches::kEnableDeferredImageDecoding)
1125   },
1126   {
1127     "wallet-service-use-sandbox",
1128     IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_NAME,
1129     IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_DESCRIPTION,
1130     kOsAndroid | kOsDesktop,
1131     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
1132         autofill::switches::kWalletServiceUseSandbox, "1",
1133         autofill::switches::kWalletServiceUseSandbox, "0")
1134   },
1135 #if defined(USE_AURA)
1136   {
1137     "overscroll-history-navigation",
1138     IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_NAME,
1139     IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_DESCRIPTION,
1140     kOsAll,
1141     MULTI_VALUE_TYPE(kOverscrollHistoryNavigationChoices)
1142   },
1143 #endif
1144   {
1145     "scroll-end-effect",
1146     IDS_FLAGS_SCROLL_END_EFFECT_NAME,
1147     IDS_FLAGS_SCROLL_END_EFFECT_DESCRIPTION,
1148     kOsCrOS,
1149     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
1150         switches::kScrollEndEffect, "1",
1151         switches::kScrollEndEffect, "0")
1152   },
1153   {
1154     "enable-renderer-mojo-channel",
1155     IDS_FLAGS_ENABLE_RENDERER_MOJO_CHANNEL_NAME,
1156     IDS_FLAGS_ENABLE_RENDERER_MOJO_CHANNEL_DESCRIPTION,
1157     kOsAll,
1158     SINGLE_VALUE_TYPE(switches::kEnableRendererMojoChannel)
1159   },
1160   {
1161     "enable-touch-drag-drop",
1162     IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_NAME,
1163     IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_DESCRIPTION,
1164     kOsWin | kOsCrOS,
1165     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchDragDrop,
1166                               switches::kDisableTouchDragDrop)
1167   },
1168   {
1169     "enable-touch-editing",
1170     IDS_FLAGS_ENABLE_TOUCH_EDITING_NAME,
1171     IDS_FLAGS_ENABLE_TOUCH_EDITING_DESCRIPTION,
1172     kOsCrOS | kOsWin | kOsLinux,
1173     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchEditing,
1174                               switches::kDisableTouchEditing)
1175   },
1176   {
1177     "enable-stale-while-revalidate",
1178     IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_NAME,
1179     IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_DESCRIPTION,
1180     kOsAll,
1181     SINGLE_VALUE_TYPE(switches::kEnableStaleWhileRevalidate)
1182   },
1183   {
1184     "enable-suggestions-service",
1185     IDS_FLAGS_ENABLE_SUGGESTIONS_SERVICE_NAME,
1186     IDS_FLAGS_ENABLE_SUGGESTIONS_SERVICE_DESCRIPTION,
1187     kOsAndroid | kOsCrOS,
1188     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSuggestionsService,
1189                               switches::kDisableSuggestionsService)
1190   },
1191   {
1192     "enable-supervised-user-blacklist",
1193     IDS_FLAGS_ENABLE_SUPERVISED_USER_BLACKLIST_NAME,
1194     IDS_FLAGS_ENABLE_SUPERVISED_USER_BLACKLIST_DESCRIPTION,
1195     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
1196     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSupervisedUserBlacklist,
1197                               switches::kDisableSupervisedUserBlacklist)
1198   },
1199   {
1200     "enable-supervised-user-safesites",
1201     IDS_FLAGS_ENABLE_SUPERVISED_USER_SAFESITES_NAME,
1202     IDS_FLAGS_ENABLE_SUPERVISED_USER_SAFESITES_DESCRIPTION,
1203     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
1204     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSupervisedUserSafeSites,
1205                               switches::kDisableSupervisedUserSafeSites)
1206   },
1207   {
1208     "enable-sync-synced-notifications",
1209     IDS_FLAGS_ENABLE_SYNCED_NOTIFICATIONS_NAME,
1210     IDS_FLAGS_ENABLE_SYNCED_NOTIFICATIONS_DESCRIPTION,
1211     kOsDesktop,
1212     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSyncSyncedNotifications,
1213                               switches::kDisableSyncSyncedNotifications)
1214   },
1215 #if defined(ENABLE_APP_LIST)
1216   {
1217     "enable-sync-app-list",
1218     IDS_FLAGS_ENABLE_SYNC_APP_LIST_NAME,
1219     IDS_FLAGS_ENABLE_SYNC_APP_LIST_DESCRIPTION,
1220     kOsDesktop,
1221     MULTI_VALUE_TYPE(kEnableSyncAppListChoices)
1222   },
1223 #endif
1224 #if defined(OS_MACOSX)
1225   {
1226     "enable-avfoundation",
1227     IDS_FLAGS_ENABLE_AVFOUNDATION_NAME,
1228     IDS_FLAGS_ENABLE_AVFOUNDATION_DESCRIPTION,
1229     kOsMac,
1230     MULTI_VALUE_TYPE(kEnableAVFoundationChoices)
1231   },
1232 #endif
1233   {
1234     "impl-side-painting",
1235     IDS_FLAGS_IMPL_SIDE_PAINTING_NAME,
1236     IDS_FLAGS_IMPL_SIDE_PAINTING_DESCRIPTION,
1237     kOsAll,
1238     MULTI_VALUE_TYPE(kImplSidePaintingChoices)
1239   },
1240   {
1241     "lcd-text-aa",
1242     IDS_FLAGS_LCD_TEXT_NAME,
1243     IDS_FLAGS_LCD_TEXT_DESCRIPTION,
1244     kOsDesktop,
1245     MULTI_VALUE_TYPE(kLCDTextChoices)
1246   },
1247 #if defined(OS_ANDROID) || defined(OS_MACOSX)
1248   {
1249     "delegated-renderer",
1250     IDS_FLAGS_DELEGATED_RENDERER_NAME,
1251     IDS_FLAGS_DELEGATED_RENDERER_DESCRIPTION,
1252     kOsAndroid,  // TODO(ccameron) Add mac support soon.
1253     MULTI_VALUE_TYPE(kDelegatedRendererChoices)
1254   },
1255 #endif
1256   {
1257     "max-tiles-for-interest-area",
1258     IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_NAME,
1259     IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_DESCRIPTION,
1260     kOsAll,
1261     MULTI_VALUE_TYPE(kMaxTilesForInterestAreaChoices)
1262   },
1263   {
1264     "enable-offline-auto-reload",
1265     IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_NAME,
1266     IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_DESCRIPTION,
1267     kOsAll,
1268     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOfflineAutoReload,
1269                               switches::kDisableOfflineAutoReload)
1270   },
1271   {
1272     "enable-offline-auto-reload-visible-only",
1273     IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_VISIBLE_ONLY_NAME,
1274     IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_VISIBLE_ONLY_DESCRIPTION,
1275     kOsAll,
1276     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOfflineAutoReloadVisibleOnly,
1277                               switches::kDisableOfflineAutoReloadVisibleOnly)
1278   },
1279   {
1280     "enable-offline-load-stale-cache",
1281     IDS_FLAGS_ENABLE_OFFLINE_LOAD_STALE_NAME,
1282     IDS_FLAGS_ENABLE_OFFLINE_LOAD_STALE_DESCRIPTION,
1283     kOsLinux | kOsMac | kOsWin | kOsAndroid,
1284     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOfflineLoadStaleCache,
1285                               switches::kDisableOfflineLoadStaleCache)
1286   },
1287   {
1288     "default-tile-width",
1289     IDS_FLAGS_DEFAULT_TILE_WIDTH_NAME,
1290     IDS_FLAGS_DEFAULT_TILE_WIDTH_DESCRIPTION,
1291     kOsAll,
1292     MULTI_VALUE_TYPE(kDefaultTileWidthChoices)
1293   },
1294   {
1295     "default-tile-height",
1296     IDS_FLAGS_DEFAULT_TILE_HEIGHT_NAME,
1297     IDS_FLAGS_DEFAULT_TILE_HEIGHT_DESCRIPTION,
1298     kOsAll,
1299     MULTI_VALUE_TYPE(kDefaultTileHeightChoices)
1300   },
1301 #if defined(OS_ANDROID)
1302   {
1303     "disable-gesture-requirement-for-media-playback",
1304     IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_NAME,
1305     IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_DESCRIPTION,
1306     kOsAndroid,
1307     SINGLE_VALUE_TYPE(switches::kDisableGestureRequirementForMediaPlayback)
1308   },
1309 #endif
1310 #if defined(ENABLE_EXTENSIONS)
1311   {
1312     "disable-extension-info-dialog",
1313     IDS_FLAGS_DISABLE_EXTENSION_INFO_DIALOG_NAME,
1314     IDS_FLAGS_DISABLE_EXTENSION_INFO_DIALOG_DESCRIPTION,
1315     kOsWin | kOsLinux | kOsCrOS,
1316     SINGLE_VALUE_TYPE(extensions::switches::kDisableExtensionInfoDialog)
1317   },
1318 #endif
1319 #if defined(OS_CHROMEOS)
1320   {
1321     "enable-virtual-keyboard",
1322     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_NAME,
1323     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_DESCRIPTION,
1324     kOsCrOS,
1325     SINGLE_VALUE_TYPE(keyboard::switches::kEnableVirtualKeyboard)
1326   },
1327   {
1328     "enable-virtual-keyboard-overscroll",
1329     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_OVERSCROLL_NAME,
1330     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_OVERSCROLL_DESCRIPTION,
1331     kOsCrOS,
1332     ENABLE_DISABLE_VALUE_TYPE(
1333         keyboard::switches::kEnableVirtualKeyboardOverscroll,
1334         keyboard::switches::kDisableVirtualKeyboardOverscroll)
1335   },
1336   {
1337     "enable-swipe-selection",
1338     IDS_FLAGS_ENABLE_SWIPE_SELECTION_NAME,
1339     IDS_FLAGS_ENABLE_SWIPE_SELECTION_DESCRIPTION,
1340     kOsCrOS,
1341     SINGLE_VALUE_TYPE(keyboard::switches::kEnableSwipeSelection)
1342   },
1343   {
1344     "enable-input-view",
1345     IDS_FLAGS_ENABLE_INPUT_VIEW_NAME,
1346     IDS_FLAGS_ENABLE_INPUT_VIEW_DESCRIPTION,
1347     kOsCrOS,
1348     ENABLE_DISABLE_VALUE_TYPE(keyboard::switches::kEnableInputView,
1349                               keyboard::switches::kDisableInputView)
1350   },
1351   {
1352     "enable-new-korean-ime",
1353     IDS_FLAGS_ENABLE_NEW_KOREAN_IME_NAME,
1354     IDS_FLAGS_ENABLE_NEW_KOREAN_IME_DESCRIPTION,
1355     kOsCrOS,
1356     SINGLE_VALUE_TYPE(chromeos::switches::kEnableNewKoreanIme)
1357   },
1358   {
1359     "enable-physical-keyboard-autocorrect",
1360     IDS_FLAGS_ENABLE_PHYSICAL_KEYBOARD_AUTOCORRECT_NAME,
1361     IDS_FLAGS_ENABLE_PHYSICAL_KEYBOARD_AUTOCORRECT_DESCRIPTION,
1362     kOsCrOS,
1363     SINGLE_VALUE_TYPE(chromeos::switches::kEnablePhysicalKeyboardAutocorrect)
1364   },
1365   {
1366     "enable-experimental-input-view-features",
1367     IDS_FLAGS_ENABLE_EXPERIMENTAL_INPUT_VIEW_FEATURES_NAME,
1368     IDS_FLAGS_ENABLE_EXPERIMENTAL_INPUT_VIEW_FEATURES_DESCRIPTION,
1369     kOsCrOS,
1370     SINGLE_VALUE_TYPE(keyboard::switches::kEnableExperimentalInputViewFeatures)
1371   },
1372   {
1373     "auto-virtual-keyboard",
1374     IDS_FLAGS_AUTO_VIRTUAL_KEYBOARD_NAME,
1375     IDS_FLAGS_AUTO_VIRTUAL_KEYBOARD_DESCRIPTION,
1376     kOsCrOS,
1377     SINGLE_VALUE_TYPE(keyboard::switches::kAutoVirtualKeyboard)
1378   },
1379 #endif
1380   {
1381     "enable-simple-cache-backend",
1382     IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_NAME,
1383     IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_DESCRIPTION,
1384     kOsWin | kOsMac | kOsLinux | kOsCrOS,
1385     MULTI_VALUE_TYPE(kSimpleCacheBackendChoices)
1386   },
1387   {
1388     "enable-tcp-fast-open",
1389     IDS_FLAGS_ENABLE_TCP_FAST_OPEN_NAME,
1390     IDS_FLAGS_ENABLE_TCP_FAST_OPEN_DESCRIPTION,
1391     kOsLinux | kOsCrOS | kOsAndroid,
1392     SINGLE_VALUE_TYPE(switches::kEnableTcpFastOpen)
1393   },
1394 #if defined(ENABLE_SERVICE_DISCOVERY)
1395   {
1396     "device-discovery-notifications",
1397     IDS_FLAGS_DEVICE_DISCOVERY_NOTIFICATIONS_NAME,
1398     IDS_FLAGS_DEVICE_DISCOVERY_NOTIFICATIONS_DESCRIPTION,
1399     kOsDesktop,
1400     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDeviceDiscoveryNotifications,
1401                               switches::kDisableDeviceDiscoveryNotifications)
1402   },
1403   {
1404     "enable-cloud-devices",
1405     IDS_FLAGS_ENABLE_CLOUD_DEVICES_NAME,
1406     IDS_FLAGS_ENABLE_CLOUD_DEVICES_DESCRIPTION,
1407     kOsDesktop,
1408     SINGLE_VALUE_TYPE(switches::kEnableCloudDevices)
1409   },
1410   {
1411     "enable-print-preview-register-promos",
1412     IDS_FLAGS_ENABLE_PRINT_PREVIEW_REGISTER_PROMOS_NAME,
1413     IDS_FLAGS_ENABLE_PRINT_PREVIEW_REGISTER_PROMOS_DESCRIPTION,
1414     kOsDesktop,
1415     SINGLE_VALUE_TYPE(switches::kEnablePrintPreviewRegisterPromos)
1416   },
1417 #endif  // ENABLE_SERVICE_DISCOVERY
1418 #if defined(OS_WIN)
1419   {
1420     "enable-cloud-print-xps",
1421     IDS_FLAGS_ENABLE_CLOUD_PRINT_XPS_NAME,
1422     IDS_FLAGS_ENABLE_CLOUD_PRINT_XPS_DESCRIPTION,
1423     kOsWin,
1424     SINGLE_VALUE_TYPE(switches::kEnableCloudPrintXps)
1425   },
1426 #endif
1427 #if defined(USE_AURA)
1428   {
1429     "tab-capture-upscale-quality",
1430     IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_NAME,
1431     IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_DESCRIPTION,
1432     kOsAll,
1433     MULTI_VALUE_TYPE(kTabCaptureUpscaleQualityChoices)
1434   },
1435   {
1436     "tab-capture-downscale-quality",
1437     IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_NAME,
1438     IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_DESCRIPTION,
1439     kOsAll,
1440     MULTI_VALUE_TYPE(kTabCaptureDownscaleQualityChoices)
1441   },
1442 #endif
1443 #if defined(ENABLE_SPELLCHECK)
1444   {
1445     "enable-spelling-feedback-field-trial",
1446     IDS_FLAGS_ENABLE_SPELLING_FEEDBACK_FIELD_TRIAL_NAME,
1447     IDS_FLAGS_ENABLE_SPELLING_FEEDBACK_FIELD_TRIAL_DESCRIPTION,
1448     kOsAll,
1449     SINGLE_VALUE_TYPE(switches::kEnableSpellingFeedbackFieldTrial)
1450   },
1451 #endif
1452   {
1453     "enable-webgl-draft-extensions",
1454     IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_NAME,
1455     IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_DESCRIPTION,
1456     kOsAll,
1457     SINGLE_VALUE_TYPE(switches::kEnableWebGLDraftExtensions)
1458   },
1459   {
1460     "enable-web-midi",
1461     IDS_FLAGS_ENABLE_WEB_MIDI_NAME,
1462     IDS_FLAGS_ENABLE_WEB_MIDI_DESCRIPTION,
1463     kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid,
1464     SINGLE_VALUE_TYPE(switches::kEnableWebMIDI)
1465   },
1466   {
1467     "enable-new-profile-management",
1468     IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_NAME,
1469     IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_DESCRIPTION,
1470     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
1471     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableNewProfileManagement,
1472                               switches::kDisableNewProfileManagement)
1473   },
1474   {
1475     "enable-account-consistency",
1476     IDS_FLAGS_ENABLE_ACCOUNT_CONSISTENCY_NAME,
1477     IDS_FLAGS_ENABLE_ACCOUNT_CONSISTENCY_DESCRIPTION,
1478     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
1479     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAccountConsistency,
1480                               switches::kDisableAccountConsistency)
1481   },
1482   {
1483     "enable-fast-user-switching",
1484     IDS_FLAGS_ENABLE_FAST_USER_SWITCHING_NAME,
1485     IDS_FLAGS_ENABLE_FAST_USER_SWITCHING_DESCRIPTION,
1486     kOsMac | kOsWin | kOsLinux,
1487     SINGLE_VALUE_TYPE(switches::kFastUserSwitching)
1488   },
1489   {
1490     "enable-new-avatar-menu",
1491     IDS_FLAGS_ENABLE_NEW_AVATAR_MENU_NAME,
1492     IDS_FLAGS_ENABLE_NEW_AVATAR_MENU_DESCRIPTION,
1493     kOsMac | kOsWin | kOsLinux,
1494     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableNewAvatarMenu,
1495                               switches::kDisableNewAvatarMenu)
1496   },
1497   {
1498     "enable-web-based-signin",
1499     IDS_FLAGS_ENABLE_WEB_BASED_SIGNIN_NAME,
1500     IDS_FLAGS_ENABLE_WEB_BASED_SIGNIN_DESCRIPTION,
1501     kOsMac | kOsWin | kOsLinux,
1502     SINGLE_VALUE_TYPE(switches::kEnableWebBasedSignin)
1503   },
1504   {
1505     "enable-webview-based-signin",
1506     IDS_FLAGS_ENABLE_WEBVIEW_BASED_SIGNIN_NAME,
1507     IDS_FLAGS_ENABLE_WEBVIEW_BASED_SIGNIN_DESCRIPTION,
1508     kOsMac | kOsWin | kOsLinux,
1509     SINGLE_VALUE_TYPE(switches::kEnableWebviewBasedSignin)
1510   },
1511   {
1512     "enable-google-profile-info",
1513     IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_NAME,
1514     IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_DESCRIPTION,
1515     kOsMac | kOsWin | kOsLinux,
1516     SINGLE_VALUE_TYPE(switches::kGoogleProfileInfo)
1517   },
1518   {
1519     "reset-app-list-install-state",
1520     IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_NAME,
1521     IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_DESCRIPTION,
1522     kOsMac | kOsWin | kOsLinux,
1523     SINGLE_VALUE_TYPE(switches::kResetAppListInstallState)
1524   },
1525 #if defined(ENABLE_APP_LIST)
1526 #if defined(OS_LINUX)
1527   {
1528     // This is compiled out on non-Linux platforms because otherwise it would be
1529     // visible on Win/Mac/CrOS but not on Linux GTK, which would be confusing.
1530     // TODO(mgiuca): Remove the #if when Aura is the default on Linux.
1531     "enable-app-list",
1532     IDS_FLAGS_ENABLE_APP_LIST_NAME,
1533     IDS_FLAGS_ENABLE_APP_LIST_DESCRIPTION,
1534     kOsLinux,
1535     SINGLE_VALUE_TYPE(switches::kEnableAppList)
1536   },
1537 #endif
1538   {
1539     "disable-app-list-app-info",
1540     IDS_FLAGS_DISABLE_APP_INFO_IN_APP_LIST,
1541     IDS_FLAGS_DISABLE_APP_INFO_IN_APP_LIST_DESCRIPTION,
1542     kOsLinux | kOsWin | kOsCrOS,
1543     SINGLE_VALUE_TYPE(app_list::switches::kDisableAppInfo)
1544   },
1545   {
1546     "disable-drive-apps-in-app-list",
1547     IDS_FLAGS_DISABLE_DRIVE_APPS_IN_APP_LIST_NAME,
1548     IDS_FLAGS_DISABLE_DRIVE_APPS_IN_APP_LIST_DESCRIPTION,
1549     kOsCrOS,
1550     SINGLE_VALUE_TYPE(app_list::switches::kDisableDriveAppsInAppList)
1551   },
1552 #endif
1553 #if defined(OS_ANDROID)
1554   {
1555     "enable-accessibility-tab-switcher",
1556     IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_NAME,
1557     IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_DESCRIPTION,
1558     kOsAndroid,
1559     SINGLE_VALUE_TYPE(switches::kEnableAccessibilityTabSwitcher)
1560   },
1561   {
1562     // TODO(dmazzoni): remove this flag when native android accessibility
1563     // ships in the stable channel. http://crbug.com/356775
1564     "enable-accessibility-script-injection",
1565     IDS_FLAGS_ENABLE_ACCESSIBILITY_SCRIPT_INJECTION_NAME,
1566     IDS_FLAGS_ENABLE_ACCESSIBILITY_SCRIPT_INJECTION_DESCRIPTION,
1567     kOsAndroid,
1568     // Java-only switch: ContentSwitches.ENABLE_ACCESSIBILITY_SCRIPT_INJECTION.
1569     SINGLE_VALUE_TYPE("enable-accessibility-script-injection")
1570   },
1571 #endif
1572   {
1573     "enable-one-copy",
1574     IDS_FLAGS_ONE_COPY_NAME,
1575     IDS_FLAGS_ONE_COPY_DESCRIPTION,
1576     kOsAll,
1577     MULTI_VALUE_TYPE(kOneCopyChoices)
1578   },
1579   {
1580     "enable-zero-copy",
1581     IDS_FLAGS_ZERO_COPY_NAME,
1582     IDS_FLAGS_ZERO_COPY_DESCRIPTION,
1583     kOsAll,
1584     SINGLE_VALUE_TYPE(switches::kEnableZeroCopy)
1585   },
1586 #if defined(OS_CHROMEOS)
1587   {
1588     "enable-first-run-ui-transitions",
1589     IDS_FLAGS_ENABLE_FIRST_RUN_UI_TRANSITIONS_NAME,
1590     IDS_FLAGS_ENABLE_FIRST_RUN_UI_TRANSITIONS_DESCRIPTION,
1591     kOsCrOS,
1592     SINGLE_VALUE_TYPE(chromeos::switches::kEnableFirstRunUITransitions)
1593   },
1594 #endif
1595   {
1596     "enable-streamlined-hosted-apps",
1597     IDS_FLAGS_ENABLE_STREAMLINED_HOSTED_APPS_NAME,
1598     IDS_FLAGS_ENABLE_STREAMLINED_HOSTED_APPS_DESCRIPTION,
1599     kOsWin | kOsCrOS | kOsLinux,
1600     SINGLE_VALUE_TYPE(switches::kEnableStreamlinedHostedApps)
1601   },
1602   {
1603     "enable-ephemeral-apps",
1604     IDS_FLAGS_ENABLE_EPHEMERAL_APPS_NAME,
1605     IDS_FLAGS_ENABLE_EPHEMERAL_APPS_DESCRIPTION,
1606     kOsAll,
1607     SINGLE_VALUE_TYPE(switches::kEnableEphemeralApps)
1608   },
1609   {
1610     "enable-linkable-ephemeral-apps",
1611     IDS_FLAGS_ENABLE_LINKABLE_EPHEMERAL_APPS_NAME,
1612     IDS_FLAGS_ENABLE_LINKABLE_EPHEMERAL_APPS_DESCRIPTION,
1613     kOsAll,
1614     SINGLE_VALUE_TYPE(switches::kEnableLinkableEphemeralApps)
1615   },
1616   {
1617     "enable-service-worker-sync",
1618     IDS_FLAGS_ENABLE_SERVICE_WORKER_SYNC_NAME,
1619     IDS_FLAGS_ENABLE_SERVICE_WORKER_SYNC_DESCRIPTION,
1620     kOsAll,
1621     SINGLE_VALUE_TYPE(switches::kEnableServiceWorkerSync)
1622   },
1623 #if defined(OS_ANDROID)
1624   {
1625     "disable-click-delay",
1626     IDS_FLAGS_DISABLE_CLICK_DELAY_NAME,
1627     IDS_FLAGS_DISABLE_CLICK_DELAY_DESCRIPTION,
1628     kOsAndroid,
1629     // Java-only switch: CommandLine.DISABLE_CLICK_DELAY
1630     SINGLE_VALUE_TYPE("disable-click-delay")
1631   },
1632 #endif
1633 #if defined(OS_MACOSX)
1634   {
1635     "enable-translate-new-ux",
1636     IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_NAME,
1637     IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_DESCRIPTION,
1638     kOsMac,
1639     SINGLE_VALUE_TYPE(switches::kEnableTranslateNewUX)
1640   },
1641 #endif
1642 #if defined(TOOLKIT_VIEWS)
1643   {
1644     "disable-views-rect-based-targeting",  // FLAGS:RECORD_UMA
1645     IDS_FLAGS_DISABLE_VIEWS_RECT_BASED_TARGETING_NAME,
1646     IDS_FLAGS_DISABLE_VIEWS_RECT_BASED_TARGETING_DESCRIPTION,
1647     kOsCrOS | kOsWin | kOsLinux,
1648     SINGLE_VALUE_TYPE(views::switches::kDisableViewsRectBasedTargeting)
1649   },
1650   {
1651     "enable-link-disambiguation-popup",
1652     IDS_FLAGS_ENABLE_LINK_DISAMBIGUATION_POPUP_NAME,
1653     IDS_FLAGS_ENABLE_LINK_DISAMBIGUATION_POPUP_DESCRIPTION,
1654     kOsCrOS | kOsWin,
1655     SINGLE_VALUE_TYPE(switches::kEnableLinkDisambiguationPopup)
1656   },
1657 #endif
1658 #if defined(ENABLE_EXTENSIONS)
1659   {
1660     "enable-apps-show-on-first-paint",
1661     IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_NAME,
1662     IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_DESCRIPTION,
1663     kOsDesktop,
1664     SINGLE_VALUE_TYPE(extensions::switches::kEnableAppsShowOnFirstPaint)
1665   },
1666 #endif
1667   {
1668     "enhanced-bookmarks-experiment",
1669     IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_NAME,
1670     IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_DESCRIPTION,
1671     kOsDesktop | kOsAndroid,
1672     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
1673         switches::kEnhancedBookmarksExperiment, "1",
1674         switches::kEnhancedBookmarksExperiment, "0")
1675   },
1676   {
1677     "manual-enhanced-bookmarks",
1678     IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_NAME,
1679     IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_DESCRIPTION,
1680     kOsDesktop | kOsAndroid,
1681     SINGLE_VALUE_TYPE(switches::kManualEnhancedBookmarks)
1682   },
1683   {
1684     "manual-enhanced-bookmarks-optout",
1685     IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_NAME,
1686     IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_DESCRIPTION,
1687     kOsDesktop | kOsAndroid,
1688     SINGLE_VALUE_TYPE(switches::kManualEnhancedBookmarksOptout)
1689   },
1690 #if defined(OS_ANDROID)
1691   {
1692     "enable-zero-suggest-experiment",
1693     IDS_FLAGS_ZERO_SUGGEST_EXPERIMENT_NAME,
1694     IDS_FLAGS_ZERO_SUGGEST_EXPERIMENT_DESCRIPTION,
1695     kOsAndroid,
1696     MULTI_VALUE_TYPE(kZeroSuggestExperimentsChoices)
1697   },
1698   {
1699     "enable-reader-mode-toolbar-icon",
1700     IDS_FLAGS_READER_MODE_EXPERIMENT_NAME,
1701     IDS_FLAGS_READER_MODE_EXPERIMENT_DESCRIPTION,
1702     kOsAndroid,
1703     SINGLE_VALUE_TYPE(switches::kEnableReaderModeToolbarIcon)
1704   },
1705 #endif
1706   {
1707     "num-raster-threads",
1708     IDS_FLAGS_NUM_RASTER_THREADS_NAME,
1709     IDS_FLAGS_NUM_RASTER_THREADS_DESCRIPTION,
1710     kOsAll,
1711     MULTI_VALUE_TYPE(kNumRasterThreadsChoices)
1712   },
1713   {
1714     "origin-chip-in-omnibox",
1715     IDS_FLAGS_ORIGIN_CHIP_NAME,
1716     IDS_FLAGS_ORIGIN_CHIP_DESCRIPTION,
1717     kOsCrOS | kOsMac | kOsWin | kOsLinux,
1718     MULTI_VALUE_TYPE(kOriginChipChoices)
1719   },
1720   {
1721     "search-button-in-omnibox",
1722     IDS_FLAGS_SEARCH_BUTTON_IN_OMNIBOX_NAME,
1723     IDS_FLAGS_SEARCH_BUTTON_IN_OMNIBOX_DESCRIPTION,
1724     kOsCrOS | kOsMac | kOsWin | kOsLinux,
1725     MULTI_VALUE_TYPE(kSearchButtonInOmniboxChoices)
1726   },
1727   {
1728     "ignore-autocomplete-off-autofill",
1729     IDS_FLAGS_IGNORE_AUTOCOMPLETE_OFF_AUTOFILL_NAME,
1730     IDS_FLAGS_IGNORE_AUTOCOMPLETE_OFF_AUTOFILL_DESCRIPTION,
1731     kOsCrOS | kOsMac | kOsWin | kOsLinux,
1732     SINGLE_VALUE_TYPE(autofill::switches::kIgnoreAutocompleteOffForAutofill)
1733   },
1734   {
1735     "enable-permissions-bubbles",
1736     IDS_FLAGS_ENABLE_PERMISSIONS_BUBBLES_NAME,
1737     IDS_FLAGS_ENABLE_PERMISSIONS_BUBBLES_DESCRIPTION,
1738     kOsCrOS | kOsMac | kOsWin | kOsLinux,
1739     ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePermissionsBubbles,
1740                               switches::kDisablePermissionsBubbles)
1741   },
1742   {
1743     "enable-session-crashed-bubble",
1744     IDS_FLAGS_ENABLE_SESSION_CRASHED_BUBBLE_NAME,
1745     IDS_FLAGS_ENABLE_SESSION_CRASHED_BUBBLE_DESCRIPTION,
1746     kOsWin | kOsLinux,
1747     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSessionCrashedBubble,
1748                               switches::kDisableSessionCrashedBubble)
1749   },
1750   {
1751     "out-of-process-pdf",
1752     IDS_FLAGS_OUT_OF_PROCESS_PDF_NAME,
1753     IDS_FLAGS_OUT_OF_PROCESS_PDF_DESCRIPTION,
1754     kOsDesktop,
1755     SINGLE_VALUE_TYPE(switches::kOutOfProcessPdf)
1756   },
1757   {
1758     "disable-cast-streaming-hw-encoding",
1759     IDS_FLAGS_DISABLE_CAST_STREAMING_HW_ENCODING_NAME,
1760     IDS_FLAGS_DISABLE_CAST_STREAMING_HW_ENCODING_DESCRIPTION,
1761     kOsAll,
1762     SINGLE_VALUE_TYPE(switches::kDisableCastStreamingHWEncoding)
1763   },
1764 #if defined(OS_ANDROID)
1765   {
1766     "disable-cast",
1767     IDS_FLAGS_DISABLE_CAST_NAME,
1768     IDS_FLAGS_DISABLE_CAST_DESCRIPTION,
1769     kOsAndroid,
1770     SINGLE_VALUE_TYPE(switches::kDisableCast)
1771   },
1772   {
1773     "prefetch-search-results",
1774     IDS_FLAGS_PREFETCH_SEARCH_RESULTS_NAME,
1775     IDS_FLAGS_PREFETCH_SEARCH_RESULTS_DESCRIPTION,
1776     kOsAndroid,
1777     SINGLE_VALUE_TYPE(switches::kPrefetchSearchResults)
1778   },
1779 #endif
1780 #if defined(ENABLE_APP_LIST)
1781   {
1782     "enable-experimental-app-list",
1783     IDS_FLAGS_ENABLE_EXPERIMENTAL_APP_LIST_NAME,
1784     IDS_FLAGS_ENABLE_EXPERIMENTAL_APP_LIST_DESCRIPTION,
1785     kOsWin | kOsLinux | kOsCrOS,
1786     SINGLE_VALUE_TYPE(app_list::switches::kEnableExperimentalAppList)
1787   },
1788   {
1789     "enable-centered-app-list",
1790     IDS_FLAGS_ENABLE_CENTERED_APP_LIST_NAME,
1791     IDS_FLAGS_ENABLE_CENTERED_APP_LIST_DESCRIPTION,
1792     kOsWin | kOsLinux | kOsCrOS,
1793     SINGLE_VALUE_TYPE(app_list::switches::kEnableCenteredAppList)
1794   },
1795 #endif
1796   {
1797     "touch-scrolling-mode",
1798     IDS_FLAGS_TOUCH_SCROLLING_MODE_NAME,
1799     IDS_FLAGS_TOUCH_SCROLLING_MODE_DESCRIPTION,
1800     kOsWin | kOsLinux | kOsCrOS | kOsAndroid,
1801     MULTI_VALUE_TYPE(kTouchScrollingModeChoices)
1802   },
1803   {
1804     "disable-threaded-scrolling",
1805     IDS_FLAGS_DISABLE_THREADED_SCROLLING_NAME,
1806     IDS_FLAGS_DISABLE_THREADED_SCROLLING_DESCRIPTION,
1807     kOsWin | kOsLinux | kOsCrOS | kOsAndroid,
1808     SINGLE_VALUE_TYPE(switches::kDisableThreadedScrolling)
1809   },
1810   {
1811     "bleeding-edge-renderer-mode",
1812     IDS_FLAGS_BLEEDING_RENDERER_NAME,
1813     IDS_FLAGS_BLEEDING_RENDERER_DESCRIPTION,
1814     kOsAndroid,
1815     SINGLE_VALUE_TYPE(switches::kEnableBleedingEdgeRenderingFastPaths)
1816   },
1817   {
1818     "enable-settings-window",
1819     IDS_FLAGS_ENABLE_SETTINGS_WINDOW_NAME,
1820     IDS_FLAGS_ENABLE_SETTINGS_WINDOW_DESCRIPTION,
1821     kOsDesktop,
1822     MULTI_VALUE_TYPE(kEnableSettingsWindowChoices)
1823   },
1824 #if defined(OS_ANDROID)
1825   {
1826     "enable-instant-search-clicks",
1827     IDS_FLAGS_ENABLE_INSTANT_SEARCH_CLICKS_NAME,
1828     IDS_FLAGS_ENABLE_INSTANT_SEARCH_CLICKS_DESCRIPTION,
1829     kOsAndroid,
1830     SINGLE_VALUE_TYPE(switches::kEnableInstantSearchClicks)
1831   },
1832 #endif
1833   {
1834     "enable-save-password-bubble",
1835     IDS_FLAGS_ENABLE_SAVE_PASSWORD_BUBBLE_NAME,
1836     IDS_FLAGS_ENABLE_SAVE_PASSWORD_BUBBLE_DESCRIPTION,
1837     kOsWin | kOsLinux | kOsCrOS | kOsMac,
1838     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSavePasswordBubble,
1839                               switches::kDisableSavePasswordBubble)
1840   },
1841   // TODO(tyoshino): Remove this temporary flag and command line switch. See
1842   // crbug.com/366483 for the target milestone.
1843   {
1844     "allow-insecure-websocket-from-https-origin",
1845     IDS_FLAGS_ALLOW_INSECURE_WEBSOCKET_FROM_HTTPS_ORIGIN_NAME,
1846     IDS_FLAGS_ALLOW_INSECURE_WEBSOCKET_FROM_HTTPS_ORIGIN_DESCRIPTION,
1847     kOsAll,
1848     SINGLE_VALUE_TYPE(switches::kAllowInsecureWebSocketFromHttpsOrigin)
1849   },
1850   {
1851     "enable-apps-file-associations",
1852     IDS_FLAGS_ENABLE_APPS_FILE_ASSOCIATIONS_NAME,
1853     IDS_FLAGS_ENABLE_APPS_FILE_ASSOCIATIONS_DESCRIPTION,
1854     kOsMac,
1855     SINGLE_VALUE_TYPE(switches::kEnableAppsFileAssociations)
1856   },
1857 #if defined(OS_ANDROID)
1858   {
1859     "enable-embeddedsearch-api",
1860     IDS_FLAGS_ENABLE_EMBEDDEDSEARCH_API_NAME,
1861     IDS_FLAGS_ENABLE_EMBEDDEDSEARCH_API_DESCRIPTION,
1862     kOsAndroid,
1863     SINGLE_VALUE_TYPE(switches::kEnableEmbeddedSearchAPI)
1864   },
1865   {
1866     "enable-app-install-alerts",
1867     IDS_FLAGS_ENABLE_APP_INSTALL_ALERTS_NAME,
1868     IDS_FLAGS_ENABLE_APP_INSTALL_ALERTS_DESCRIPTION,
1869     kOsAndroid,
1870     SINGLE_VALUE_TYPE(switches::kEnableAppInstallAlerts)
1871   },
1872 #endif
1873   {
1874     "distance-field-text",
1875     IDS_FLAGS_DISTANCE_FIELD_TEXT_NAME,
1876     IDS_FLAGS_DISTANCE_FIELD_TEXT_DESCRIPTION,
1877     kOsAll,
1878     MULTI_VALUE_TYPE(kDistanceFieldTextChoices)
1879   },
1880   {
1881     "extension-content-verification",
1882     IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_NAME,
1883     IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_DESCRIPTION,
1884     kOsDesktop,
1885     MULTI_VALUE_TYPE(kExtensionContentVerificationChoices)
1886   },
1887 #if defined(USE_AURA)
1888   {
1889     "text-input-focus-manager",
1890     IDS_FLAGS_TEXT_INPUT_FOCUS_MANAGER_NAME,
1891     IDS_FLAGS_TEXT_INPUT_FOCUS_MANAGER_DESCRIPTION,
1892     kOsCrOS | kOsLinux | kOsWin,
1893     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTextInputFocusManager,
1894                               switches::kDisableTextInputFocusManager)
1895   },
1896 #endif
1897 #if defined(ENABLE_EXTENSIONS)
1898   {
1899     "extension-active-script-permission",
1900     IDS_FLAGS_USER_CONSENT_FOR_EXTENSION_SCRIPTS_NAME,
1901     IDS_FLAGS_USER_CONSENT_FOR_EXTENSION_SCRIPTS_DESCRIPTION,
1902     kOsAll,
1903     SINGLE_VALUE_TYPE(extensions::switches::kEnableScriptsRequireAction)
1904   },
1905 #endif
1906   {
1907     "harfbuzz-rendertext",
1908     IDS_FLAGS_HARFBUZZ_RENDERTEXT_NAME,
1909     IDS_FLAGS_HARFBUZZ_RENDERTEXT_DESCRIPTION,
1910     kOsDesktop,
1911     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableHarfBuzzRenderText,
1912                               switches::kDisableHarfBuzzRenderText)
1913   },
1914 #if defined(OS_ANDROID)
1915   {
1916     "answers-in-suggest",
1917     IDS_FLAGS_ENABLE_ANSWERS_IN_SUGGEST_NAME,
1918     IDS_FLAGS_ENABLE_ANSWERS_IN_SUGGEST_DESCRIPTION,
1919     kOsAndroid,
1920     MULTI_VALUE_TYPE(kAnswersInSuggestChoices)
1921   },
1922 #endif
1923 #if defined(OS_ANDROID)
1924   {
1925     "enable-data-reduction-proxy-dev",
1926     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_DEV_NAME,
1927     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_DEV_DESCRIPTION,
1928     kOsAndroid,
1929     ENABLE_DISABLE_VALUE_TYPE(
1930         data_reduction_proxy::switches::kEnableDataReductionProxyDev,
1931         data_reduction_proxy::switches::kDisableDataReductionProxyDev)
1932   },
1933   {
1934     "enable-data-reduction-proxy-alt",
1935     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_ALTERNATIVE_NAME,
1936     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_ALTERNATIVE_DESCRIPTION,
1937     kOsAndroid,
1938     SINGLE_VALUE_TYPE(
1939         data_reduction_proxy::switches::kEnableDataReductionProxyAlt)
1940   },
1941 #endif
1942   {
1943     "enable-experimental-hotwording",
1944     IDS_FLAGS_ENABLE_EXPERIMENTAL_HOTWORDING_NAME,
1945     IDS_FLAGS_ENABLE_EXPERIMENTAL_HOTWORDING_DESCRIPTION,
1946     kOsDesktop,
1947     SINGLE_VALUE_TYPE(switches::kEnableExperimentalHotwording)
1948   },
1949 #if defined(ENABLE_EXTENSIONS)
1950   {
1951     "enable-embedded-extension-options",
1952     IDS_FLAGS_ENABLE_EMBEDDED_EXTENSION_OPTIONS_NAME,
1953     IDS_FLAGS_ENABLE_EMBEDDED_EXTENSION_OPTIONS_DESCRIPTION,
1954     kOsDesktop,
1955     SINGLE_VALUE_TYPE(extensions::switches::kEnableEmbeddedExtensionOptions)
1956   },
1957 #endif
1958   {
1959     "enable-website-settings-manager",
1960     IDS_FLAGS_ENABLE_WEBSITE_SETTINGS_NAME,
1961     IDS_FLAGS_ENABLE_WEBSITE_SETTINGS_DESCRIPTION,
1962     kOsDesktop,
1963     SINGLE_VALUE_TYPE(switches::kEnableWebsiteSettingsManager)
1964   },
1965   {
1966     "remember-cert-error-decisions",
1967     IDS_FLAGS_REMEMBER_CERTIFICATE_ERROR_DECISIONS_NAME,
1968     IDS_FLAGS_REMEMBER_CERTIFICATE_ERROR_DECISIONS_DESCRIPTION,
1969     kOsAll,
1970     MULTI_VALUE_TYPE(kRememberCertificateErrorDecisionsChoices)
1971   },
1972   {
1973     "enable-drop-sync-credential",
1974     IDS_FLAGS_ENABLE_DROP_SYNC_CREDENTIAL_NAME,
1975     IDS_FLAGS_ENABLE_DROP_SYNC_CREDENTIAL_DESCRIPTION,
1976     kOsAll,
1977     MULTI_VALUE_TYPE(kEnableDropSyncCredentialChoices)
1978   },
1979 #if defined(ENABLE_EXTENSIONS)
1980   {
1981     "enable-extension-action-redesign",
1982     IDS_FLAGS_ENABLE_EXTENSION_ACTION_REDESIGN_NAME,
1983     IDS_FLAGS_ENABLE_EXTENSION_ACTION_REDESIGN_DESCRIPTION,
1984     kOsWin | kOsLinux | kOsCrOS,
1985     SINGLE_VALUE_TYPE(extensions::switches::kEnableExtensionActionRedesign)
1986   },
1987 #endif
1988   {
1989     "autofill-sync-credential",
1990     IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_NAME,
1991     IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_DESCRIPTION,
1992     kOsAll,
1993     MULTI_VALUE_TYPE(kAutofillSyncCredentialChoices)
1994   },
1995 #if !defined(OS_ANDROID)
1996   {
1997     "enable-message-center-always-scroll-up-upon-notification-removal",
1998     IDS_FLAGS_ENABLE_MESSAGE_CENTER_ALWAYS_SCROLL_UP_UPON_REMOVAL_NAME,
1999     IDS_FLAGS_ENABLE_MESSAGE_CENTER_ALWAYS_SCROLL_UP_UPON_REMOVAL_DESCRIPTION,
2000     kOsDesktop,
2001     SINGLE_VALUE_TYPE(
2002         switches::kEnableMessageCenterAlwaysScrollUpUponNotificationRemoval)
2003   },
2004 #endif
2005 #if defined(OS_CHROMEOS)
2006   {
2007     "wake-on-packets",
2008     IDS_FLAGS_WAKE_ON_PACKETS_NAME,
2009     IDS_FLAGS_WAKE_ON_PACKETS_DESCRIPTION,
2010     kOsCrOSOwnerOnly,
2011     SINGLE_VALUE_TYPE(chromeos::switches::kWakeOnPackets)
2012   },
2013 #endif  // OS_CHROMEOS
2014   {
2015     "enable-tab-audio-muting",
2016     IDS_FLAGS_ENABLE_TAB_AUDIO_MUTING_NAME,
2017     IDS_FLAGS_ENABLE_TAB_AUDIO_MUTING_DESCRIPTION,
2018     kOsDesktop,
2019     SINGLE_VALUE_TYPE(switches::kEnableTabAudioMuting)
2020   },
2021   {
2022     "enable-credential-manager-api",
2023     IDS_FLAGS_CREDENTIAL_MANAGER_API_NAME,
2024     IDS_FLAGS_CREDENTIAL_MANAGER_API_DESCRIPTION,
2025     kOsAll,
2026     SINGLE_VALUE_TYPE(switches::kEnableCredentialManagerAPI)
2027   },
2028 #if defined(ENABLE_PLUGINS)
2029   {
2030     "enable-plugin-power-saver",
2031     IDS_FLAGS_ENABLE_PLUGIN_POWER_SAVER_NAME,
2032     IDS_FLAGS_ENABLE_PLUGIN_POWER_SAVER_DESCRIPTION,
2033     kOsDesktop,
2034     SINGLE_VALUE_TYPE(switches::kEnablePluginPowerSaver)
2035   },
2036 #endif
2037 #if defined(OS_CHROMEOS)
2038   {
2039     "enable-remote-assistance",
2040     IDS_FLAGS_ENABLE_REMOTE_ASSISTANCE_NAME,
2041     IDS_FLAGS_ENABLE_REMOTE_ASSISTANCE_DESCRIPTION,
2042     kOsCrOS,
2043     SINGLE_VALUE_TYPE(extensions::switches::kEnableRemoteAssistance)
2044   },
2045   {
2046     "disable-new-zip-unpacker",
2047     IDS_FLAGS_DISABLE_NEW_ZIP_UNPACKER_NAME,
2048     IDS_FLAGS_DISABLE_NEW_ZIP_UNPACKER_DESCRIPTION,
2049     kOsCrOS,
2050     SINGLE_VALUE_TYPE(chromeos::switches::kDisableNewZIPUnpacker)
2051   },
2052 #endif  // defined(OS_CHROMEOS)
2053   {
2054     "ssl-version-min",
2055     IDS_FLAGS_SSL_VERSION_MIN_NAME,
2056     IDS_FLAGS_SSL_VERSION_MIN_DESCRIPTION,
2057     kOsAll,
2058     MULTI_VALUE_TYPE(kSSLVersionMinChoices)
2059   },
2060   // NOTE: Adding new command-line switches requires adding corresponding
2061   // entries to enum "LoginCustomFlags" in histograms.xml. See note in
2062   // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
2063 };
2064
2065 const Experiment* experiments = kExperiments;
2066 size_t num_experiments = arraysize(kExperiments);
2067
2068 // Stores and encapsulates the little state that about:flags has.
2069 class FlagsState {
2070  public:
2071   FlagsState() : needs_restart_(false) {}
2072   void ConvertFlagsToSwitches(FlagsStorage* flags_storage,
2073                               CommandLine* command_line,
2074                               SentinelsMode sentinels);
2075   bool IsRestartNeededToCommitChanges();
2076   void SetExperimentEnabled(
2077       FlagsStorage* flags_storage,
2078       const std::string& internal_name,
2079       bool enable);
2080   void RemoveFlagsSwitches(
2081       std::map<std::string, CommandLine::StringType>* switch_list);
2082   void ResetAllFlags(FlagsStorage* flags_storage);
2083   void reset();
2084
2085   // Returns the singleton instance of this class
2086   static FlagsState* GetInstance() {
2087     return Singleton<FlagsState>::get();
2088   }
2089
2090  private:
2091   bool needs_restart_;
2092   std::map<std::string, std::string> flags_switches_;
2093
2094   DISALLOW_COPY_AND_ASSIGN(FlagsState);
2095 };
2096
2097 // Adds the internal names for the specified experiment to |names|.
2098 void AddInternalName(const Experiment& e, std::set<std::string>* names) {
2099   if (e.type == Experiment::SINGLE_VALUE) {
2100     names->insert(e.internal_name);
2101   } else {
2102     DCHECK(e.type == Experiment::MULTI_VALUE ||
2103            e.type == Experiment::ENABLE_DISABLE_VALUE);
2104     for (int i = 0; i < e.num_choices; ++i)
2105       names->insert(e.NameForChoice(i));
2106   }
2107 }
2108
2109 // Confirms that an experiment is valid, used in a DCHECK in
2110 // SanitizeList below.
2111 bool ValidateExperiment(const Experiment& e) {
2112   switch (e.type) {
2113     case Experiment::SINGLE_VALUE:
2114       DCHECK_EQ(0, e.num_choices);
2115       DCHECK(!e.choices);
2116       break;
2117     case Experiment::MULTI_VALUE:
2118       DCHECK_GT(e.num_choices, 0);
2119       DCHECK(e.choices);
2120       DCHECK(e.choices[0].command_line_switch);
2121       DCHECK_EQ('\0', e.choices[0].command_line_switch[0]);
2122       break;
2123     case Experiment::ENABLE_DISABLE_VALUE:
2124       DCHECK_EQ(3, e.num_choices);
2125       DCHECK(!e.choices);
2126       DCHECK(e.command_line_switch);
2127       DCHECK(e.command_line_value);
2128       DCHECK(e.disable_command_line_switch);
2129       DCHECK(e.disable_command_line_value);
2130       break;
2131     default:
2132       NOTREACHED();
2133   }
2134   return true;
2135 }
2136
2137 // Removes all experiments from prefs::kEnabledLabsExperiments that are
2138 // unknown, to prevent this list to become very long as experiments are added
2139 // and removed.
2140 void SanitizeList(FlagsStorage* flags_storage) {
2141   std::set<std::string> known_experiments;
2142   for (size_t i = 0; i < num_experiments; ++i) {
2143     DCHECK(ValidateExperiment(experiments[i]));
2144     AddInternalName(experiments[i], &known_experiments);
2145   }
2146
2147   std::set<std::string> enabled_experiments = flags_storage->GetFlags();
2148
2149   std::set<std::string> new_enabled_experiments =
2150       base::STLSetIntersection<std::set<std::string> >(
2151           known_experiments, enabled_experiments);
2152
2153   if (new_enabled_experiments != enabled_experiments)
2154     flags_storage->SetFlags(new_enabled_experiments);
2155 }
2156
2157 void GetSanitizedEnabledFlags(
2158     FlagsStorage* flags_storage, std::set<std::string>* result) {
2159   SanitizeList(flags_storage);
2160   *result = flags_storage->GetFlags();
2161 }
2162
2163 bool SkipConditionalExperiment(const Experiment& experiment,
2164                                FlagsStorage* flags_storage) {
2165   if ((experiment.internal_name == std::string("manual-enhanced-bookmarks")) ||
2166       (experiment.internal_name ==
2167            std::string("manual-enhanced-bookmarks-optout"))) {
2168     return true;
2169   }
2170
2171 #if defined(OS_ANDROID)
2172   // enable-data-reduction-proxy-dev is only available for the Dev/Beta channel.
2173   if (!strcmp("enable-data-reduction-proxy-dev", experiment.internal_name) &&
2174       chrome::VersionInfo::GetChannel() != chrome::VersionInfo::CHANNEL_BETA &&
2175       chrome::VersionInfo::GetChannel() != chrome::VersionInfo::CHANNEL_DEV) {
2176     return true;
2177   }
2178   // enable-data-reduction-proxy-alt is only available for the Dev channel.
2179   if (!strcmp("enable-data-reduction-proxy-alt", experiment.internal_name) &&
2180       chrome::VersionInfo::GetChannel() != chrome::VersionInfo::CHANNEL_DEV) {
2181     return true;
2182   }
2183 #endif
2184
2185   return false;
2186 }
2187
2188
2189 // Variant of GetSanitizedEnabledFlags that also removes any flags that aren't
2190 // enabled on the current platform.
2191 void GetSanitizedEnabledFlagsForCurrentPlatform(
2192     FlagsStorage* flags_storage, std::set<std::string>* result) {
2193   GetSanitizedEnabledFlags(flags_storage, result);
2194
2195   // Filter out any experiments that aren't enabled on the current platform.  We
2196   // don't remove these from prefs else syncing to a platform with a different
2197   // set of experiments would be lossy.
2198   std::set<std::string> platform_experiments;
2199   int current_platform = GetCurrentPlatform();
2200   for (size_t i = 0; i < num_experiments; ++i) {
2201     if (experiments[i].supported_platforms & current_platform)
2202       AddInternalName(experiments[i], &platform_experiments);
2203 #if defined(OS_CHROMEOS)
2204     if (experiments[i].supported_platforms & kOsCrOSOwnerOnly)
2205       AddInternalName(experiments[i], &platform_experiments);
2206 #endif
2207   }
2208
2209   std::set<std::string> new_enabled_experiments =
2210       base::STLSetIntersection<std::set<std::string> >(
2211           platform_experiments, *result);
2212
2213   result->swap(new_enabled_experiments);
2214 }
2215
2216 // Returns the Value representing the choice data in the specified experiment.
2217 base::Value* CreateChoiceData(
2218     const Experiment& experiment,
2219     const std::set<std::string>& enabled_experiments) {
2220   DCHECK(experiment.type == Experiment::MULTI_VALUE ||
2221          experiment.type == Experiment::ENABLE_DISABLE_VALUE);
2222   base::ListValue* result = new base::ListValue;
2223   for (int i = 0; i < experiment.num_choices; ++i) {
2224     base::DictionaryValue* value = new base::DictionaryValue;
2225     const std::string name = experiment.NameForChoice(i);
2226     value->SetString("internal_name", name);
2227     value->SetString("description", experiment.DescriptionForChoice(i));
2228     value->SetBoolean("selected", enabled_experiments.count(name) > 0);
2229     result->Append(value);
2230   }
2231   return result;
2232 }
2233
2234 }  // namespace
2235
2236 std::string Experiment::NameForChoice(int index) const {
2237   DCHECK(type == Experiment::MULTI_VALUE ||
2238          type == Experiment::ENABLE_DISABLE_VALUE);
2239   DCHECK_LT(index, num_choices);
2240   return std::string(internal_name) + testing::kMultiSeparator +
2241          base::IntToString(index);
2242 }
2243
2244 base::string16 Experiment::DescriptionForChoice(int index) const {
2245   DCHECK(type == Experiment::MULTI_VALUE ||
2246          type == Experiment::ENABLE_DISABLE_VALUE);
2247   DCHECK_LT(index, num_choices);
2248   int description_id;
2249   if (type == Experiment::ENABLE_DISABLE_VALUE) {
2250     const int kEnableDisableDescriptionIds[] = {
2251       IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT,
2252       IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
2253       IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
2254     };
2255     description_id = kEnableDisableDescriptionIds[index];
2256   } else {
2257     description_id = choices[index].description_id;
2258   }
2259   return l10n_util::GetStringUTF16(description_id);
2260 }
2261
2262 void ConvertFlagsToSwitches(FlagsStorage* flags_storage,
2263                             CommandLine* command_line,
2264                             SentinelsMode sentinels) {
2265   FlagsState::GetInstance()->ConvertFlagsToSwitches(flags_storage,
2266                                                     command_line,
2267                                                     sentinels);
2268 }
2269
2270 bool AreSwitchesIdenticalToCurrentCommandLine(
2271     const CommandLine& new_cmdline,
2272     const CommandLine& active_cmdline,
2273     std::set<CommandLine::StringType>* out_difference) {
2274   std::set<CommandLine::StringType> new_flags =
2275       ExtractFlagsFromCommandLine(new_cmdline);
2276   std::set<CommandLine::StringType> active_flags =
2277       ExtractFlagsFromCommandLine(active_cmdline);
2278
2279   bool result = false;
2280   // Needed because std::equal doesn't check if the 2nd set is empty.
2281   if (new_flags.size() == active_flags.size()) {
2282     result =
2283         std::equal(new_flags.begin(), new_flags.end(), active_flags.begin());
2284   }
2285
2286   if (out_difference && !result) {
2287     std::set_symmetric_difference(
2288         new_flags.begin(),
2289         new_flags.end(),
2290         active_flags.begin(),
2291         active_flags.end(),
2292         std::inserter(*out_difference, out_difference->begin()));
2293   }
2294
2295   return result;
2296 }
2297
2298 void GetFlagsExperimentsData(FlagsStorage* flags_storage,
2299                              FlagAccess access,
2300                              base::ListValue* supported_experiments,
2301                              base::ListValue* unsupported_experiments) {
2302   std::set<std::string> enabled_experiments;
2303   GetSanitizedEnabledFlags(flags_storage, &enabled_experiments);
2304
2305   int current_platform = GetCurrentPlatform();
2306
2307   for (size_t i = 0; i < num_experiments; ++i) {
2308     const Experiment& experiment = experiments[i];
2309     if (SkipConditionalExperiment(experiment, flags_storage))
2310       continue;
2311
2312     base::DictionaryValue* data = new base::DictionaryValue();
2313     data->SetString("internal_name", experiment.internal_name);
2314     data->SetString("name",
2315                     l10n_util::GetStringUTF16(experiment.visible_name_id));
2316     data->SetString("description",
2317                     l10n_util::GetStringUTF16(
2318                         experiment.visible_description_id));
2319
2320     base::ListValue* supported_platforms = new base::ListValue();
2321     AddOsStrings(experiment.supported_platforms, supported_platforms);
2322     data->Set("supported_platforms", supported_platforms);
2323
2324     switch (experiment.type) {
2325       case Experiment::SINGLE_VALUE:
2326         data->SetBoolean(
2327             "enabled",
2328             enabled_experiments.count(experiment.internal_name) > 0);
2329         break;
2330       case Experiment::MULTI_VALUE:
2331       case Experiment::ENABLE_DISABLE_VALUE:
2332         data->Set("choices", CreateChoiceData(experiment, enabled_experiments));
2333         break;
2334       default:
2335         NOTREACHED();
2336     }
2337
2338     bool supported = (experiment.supported_platforms & current_platform) != 0;
2339 #if defined(OS_CHROMEOS)
2340     if (access == kOwnerAccessToFlags &&
2341         (experiment.supported_platforms & kOsCrOSOwnerOnly) != 0) {
2342       supported = true;
2343     }
2344 #endif
2345     if (supported)
2346       supported_experiments->Append(data);
2347     else
2348       unsupported_experiments->Append(data);
2349   }
2350 }
2351
2352 bool IsRestartNeededToCommitChanges() {
2353   return FlagsState::GetInstance()->IsRestartNeededToCommitChanges();
2354 }
2355
2356 void SetExperimentEnabled(FlagsStorage* flags_storage,
2357                           const std::string& internal_name,
2358                           bool enable) {
2359   FlagsState::GetInstance()->SetExperimentEnabled(flags_storage,
2360                                                   internal_name, enable);
2361 }
2362
2363 void RemoveFlagsSwitches(
2364     std::map<std::string, CommandLine::StringType>* switch_list) {
2365   FlagsState::GetInstance()->RemoveFlagsSwitches(switch_list);
2366 }
2367
2368 void ResetAllFlags(FlagsStorage* flags_storage) {
2369   FlagsState::GetInstance()->ResetAllFlags(flags_storage);
2370 }
2371
2372 int GetCurrentPlatform() {
2373 #if defined(OS_MACOSX)
2374   return kOsMac;
2375 #elif defined(OS_WIN)
2376   return kOsWin;
2377 #elif defined(OS_CHROMEOS)  // Needs to be before the OS_LINUX check.
2378   return kOsCrOS;
2379 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
2380   return kOsLinux;
2381 #elif defined(OS_ANDROID)
2382   return kOsAndroid;
2383 #else
2384 #error Unknown platform
2385 #endif
2386 }
2387
2388 void RecordUMAStatistics(FlagsStorage* flags_storage) {
2389   std::set<std::string> flags = flags_storage->GetFlags();
2390   for (std::set<std::string>::iterator it = flags.begin(); it != flags.end();
2391        ++it) {
2392     std::string action("AboutFlags_");
2393     action += *it;
2394     content::RecordComputedAction(action);
2395   }
2396   // Since flag metrics are recorded every startup, add a tick so that the
2397   // stats can be made meaningful.
2398   if (flags.size())
2399     content::RecordAction(UserMetricsAction("AboutFlags_StartupTick"));
2400   content::RecordAction(UserMetricsAction("StartupTick"));
2401 }
2402
2403 base::HistogramBase::Sample GetSwitchUMAId(const std::string& switch_name) {
2404   return static_cast<base::HistogramBase::Sample>(
2405       metrics::HashMetricName(switch_name));
2406 }
2407
2408 void ReportCustomFlags(const std::string& uma_histogram_hame,
2409                        const std::set<std::string>& command_line_difference) {
2410   for (std::set<std::string>::const_iterator it =
2411            command_line_difference.begin();
2412        it != command_line_difference.end();
2413        ++it) {
2414     int uma_id = about_flags::kBadSwitchFormatHistogramId;
2415     if (StartsWithASCII(*it, "--", true /* case_sensitive */)) {
2416       // Skip '--' before switch name.
2417       std::string switch_name(it->substr(2));
2418
2419       // Kill value, if any.
2420       const size_t value_pos = switch_name.find('=');
2421       if (value_pos != std::string::npos)
2422         switch_name.resize(value_pos);
2423
2424       uma_id = GetSwitchUMAId(switch_name);
2425     } else {
2426       NOTREACHED() << "ReportCustomFlags(): flag '" << *it
2427                    << "' has incorrect format.";
2428     }
2429     DVLOG(1) << "ReportCustomFlags(): histogram='" << uma_histogram_hame
2430              << "' '" << *it << "', uma_id=" << uma_id;
2431
2432     // Sparse histogram macro does not cache the histogram, so it's safe
2433     // to use macro with non-static histogram name here.
2434     UMA_HISTOGRAM_SPARSE_SLOWLY(uma_histogram_hame, uma_id);
2435   }
2436 }
2437
2438 //////////////////////////////////////////////////////////////////////////////
2439 // FlagsState implementation.
2440
2441 namespace {
2442
2443 typedef std::map<std::string, std::pair<std::string, std::string> >
2444     NameToSwitchAndValueMap;
2445
2446 void SetFlagToSwitchMapping(const std::string& key,
2447                             const std::string& switch_name,
2448                             const std::string& switch_value,
2449                             NameToSwitchAndValueMap* name_to_switch_map) {
2450   DCHECK(name_to_switch_map->end() == name_to_switch_map->find(key));
2451   (*name_to_switch_map)[key] = std::make_pair(switch_name, switch_value);
2452 }
2453
2454 void FlagsState::ConvertFlagsToSwitches(FlagsStorage* flags_storage,
2455                                         CommandLine* command_line,
2456                                         SentinelsMode sentinels) {
2457   if (command_line->HasSwitch(switches::kNoExperiments))
2458     return;
2459
2460   std::set<std::string> enabled_experiments;
2461
2462   GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage,
2463                                              &enabled_experiments);
2464
2465   NameToSwitchAndValueMap name_to_switch_map;
2466   for (size_t i = 0; i < num_experiments; ++i) {
2467     const Experiment& e = experiments[i];
2468     if (e.type == Experiment::SINGLE_VALUE) {
2469       SetFlagToSwitchMapping(e.internal_name, e.command_line_switch,
2470                              e.command_line_value, &name_to_switch_map);
2471     } else if (e.type == Experiment::MULTI_VALUE) {
2472       for (int j = 0; j < e.num_choices; ++j) {
2473         SetFlagToSwitchMapping(e.NameForChoice(j),
2474                                e.choices[j].command_line_switch,
2475                                e.choices[j].command_line_value,
2476                                &name_to_switch_map);
2477       }
2478     } else {
2479       DCHECK_EQ(e.type, Experiment::ENABLE_DISABLE_VALUE);
2480       SetFlagToSwitchMapping(e.NameForChoice(0), std::string(), std::string(),
2481                              &name_to_switch_map);
2482       SetFlagToSwitchMapping(e.NameForChoice(1), e.command_line_switch,
2483                              e.command_line_value, &name_to_switch_map);
2484       SetFlagToSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch,
2485                              e.disable_command_line_value, &name_to_switch_map);
2486     }
2487   }
2488
2489   if (sentinels == kAddSentinels) {
2490     command_line->AppendSwitch(switches::kFlagSwitchesBegin);
2491     flags_switches_.insert(
2492         std::pair<std::string, std::string>(switches::kFlagSwitchesBegin,
2493                                             std::string()));
2494   }
2495   for (std::set<std::string>::iterator it = enabled_experiments.begin();
2496        it != enabled_experiments.end();
2497        ++it) {
2498     const std::string& experiment_name = *it;
2499     NameToSwitchAndValueMap::const_iterator name_to_switch_it =
2500         name_to_switch_map.find(experiment_name);
2501     if (name_to_switch_it == name_to_switch_map.end()) {
2502       NOTREACHED();
2503       continue;
2504     }
2505
2506 #if defined(OS_CHROMEOS)
2507     // On Chrome OS setting command line flag may make browser to restart on
2508     // user login. As this flag eventually will be set to a significant number
2509     // of users skip manual-enhanced-bookmarks to avoid restart.
2510     if (experiment_name == "manual-enhanced-bookmarks")
2511       continue;
2512 #endif
2513
2514     const std::pair<std::string, std::string>&
2515         switch_and_value_pair = name_to_switch_it->second;
2516
2517     CHECK(!switch_and_value_pair.first.empty());
2518     command_line->AppendSwitchASCII(switch_and_value_pair.first,
2519                                     switch_and_value_pair.second);
2520     flags_switches_[switch_and_value_pair.first] = switch_and_value_pair.second;
2521   }
2522   if (sentinels == kAddSentinels) {
2523     command_line->AppendSwitch(switches::kFlagSwitchesEnd);
2524     flags_switches_.insert(
2525         std::pair<std::string, std::string>(switches::kFlagSwitchesEnd,
2526                                             std::string()));
2527   }
2528 }
2529
2530 bool FlagsState::IsRestartNeededToCommitChanges() {
2531   return needs_restart_;
2532 }
2533
2534 void FlagsState::SetExperimentEnabled(FlagsStorage* flags_storage,
2535                                       const std::string& internal_name,
2536                                       bool enable) {
2537   size_t at_index = internal_name.find(testing::kMultiSeparator);
2538   if (at_index != std::string::npos) {
2539     DCHECK(enable);
2540     // We're being asked to enable a multi-choice experiment. Disable the
2541     // currently selected choice.
2542     DCHECK_NE(at_index, 0u);
2543     const std::string experiment_name = internal_name.substr(0, at_index);
2544     SetExperimentEnabled(flags_storage, experiment_name, false);
2545
2546     // And enable the new choice, if it is not the default first choice.
2547     if (internal_name != experiment_name + "@0") {
2548       std::set<std::string> enabled_experiments;
2549       GetSanitizedEnabledFlags(flags_storage, &enabled_experiments);
2550       needs_restart_ |= enabled_experiments.insert(internal_name).second;
2551       flags_storage->SetFlags(enabled_experiments);
2552     }
2553     return;
2554   }
2555
2556   std::set<std::string> enabled_experiments;
2557   GetSanitizedEnabledFlags(flags_storage, &enabled_experiments);
2558
2559   const Experiment* e = NULL;
2560   for (size_t i = 0; i < num_experiments; ++i) {
2561     if (experiments[i].internal_name == internal_name) {
2562       e = experiments + i;
2563       break;
2564     }
2565   }
2566   DCHECK(e);
2567
2568   if (e->type == Experiment::SINGLE_VALUE) {
2569     if (enable)
2570       needs_restart_ |= enabled_experiments.insert(internal_name).second;
2571     else
2572       needs_restart_ |= (enabled_experiments.erase(internal_name) > 0);
2573   } else {
2574     if (enable) {
2575       // Enable the first choice.
2576       needs_restart_ |= enabled_experiments.insert(e->NameForChoice(0)).second;
2577     } else {
2578       // Find the currently enabled choice and disable it.
2579       for (int i = 0; i < e->num_choices; ++i) {
2580         std::string choice_name = e->NameForChoice(i);
2581         if (enabled_experiments.find(choice_name) !=
2582             enabled_experiments.end()) {
2583           needs_restart_ = true;
2584           enabled_experiments.erase(choice_name);
2585           // Continue on just in case there's a bug and more than one
2586           // experiment for this choice was enabled.
2587         }
2588       }
2589     }
2590   }
2591
2592   flags_storage->SetFlags(enabled_experiments);
2593 }
2594
2595 void FlagsState::RemoveFlagsSwitches(
2596     std::map<std::string, CommandLine::StringType>* switch_list) {
2597   for (std::map<std::string, std::string>::const_iterator
2598            it = flags_switches_.begin(); it != flags_switches_.end(); ++it) {
2599     switch_list->erase(it->first);
2600   }
2601 }
2602
2603 void FlagsState::ResetAllFlags(FlagsStorage* flags_storage) {
2604   needs_restart_ = true;
2605
2606   std::set<std::string> no_experiments;
2607   flags_storage->SetFlags(no_experiments);
2608 }
2609
2610 void FlagsState::reset() {
2611   needs_restart_ = false;
2612   flags_switches_.clear();
2613 }
2614
2615 }  // namespace
2616
2617 namespace testing {
2618
2619 // WARNING: '@' is also used in the html file. If you update this constant you
2620 // also need to update the html file.
2621 const char kMultiSeparator[] = "@";
2622
2623 void ClearState() {
2624   FlagsState::GetInstance()->reset();
2625 }
2626
2627 void SetExperiments(const Experiment* e, size_t count) {
2628   if (!e) {
2629     experiments = kExperiments;
2630     num_experiments = arraysize(kExperiments);
2631   } else {
2632     experiments = e;
2633     num_experiments = count;
2634   }
2635 }
2636
2637 const Experiment* GetExperiments(size_t* count) {
2638   *count = num_experiments;
2639   return experiments;
2640 }
2641
2642 }  // namespace testing
2643
2644 }  // namespace about_flags