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