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 <algorithm>
      8 #include <iterator>
      9 #include <map>
     10 #include <set>
     11 #include <utility>
     12 
     13 #include "base/command_line.h"
     14 #include "base/memory/singleton.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/flags_storage.h"
     20 #include "chrome/common/chrome_content_client.h"
     21 #include "chrome/common/chrome_switches.h"
     22 #include "components/nacl/common/nacl_switches.h"
     23 #include "content/public/browser/user_metrics.h"
     24 #include "extensions/common/switches.h"
     25 #include "grit/chromium_strings.h"
     26 #include "grit/generated_resources.h"
     27 #include "grit/google_chrome_strings.h"
     28 #include "media/base/media_switches.h"
     29 #include "ui/base/l10n/l10n_util.h"
     30 #include "ui/base/ui_base_switches.h"
     31 #include "ui/gfx/switches.h"
     32 #include "ui/gl/gl_switches.h"
     33 #include "ui/keyboard/keyboard_switches.h"
     34 #include "ui/message_center/message_center_switches.h"
     35 #include "ui/surface/surface_switches.h"
     36 
     37 #if defined(USE_ASH)
     38 #include "ash/ash_switches.h"
     39 #endif
     40 
     41 #if defined(OS_CHROMEOS)
     42 #include "chromeos/chromeos_switches.h"
     43 #include "third_party/cros_system_api/switches/chrome_switches.h"
     44 #endif
     45 
     46 using content::UserMetricsAction;
     47 
     48 namespace about_flags {
     49 
     50 // Macros to simplify specifying the type.
     51 #define SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \
     52     Experiment::SINGLE_VALUE, \
     53     command_line_switch, switch_value, NULL, NULL, NULL, 0
     54 #define SINGLE_VALUE_TYPE(command_line_switch) \
     55     SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, "")
     56 #define ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, enable_value, \
     57                                             disable_switch, disable_value) \
     58     Experiment::ENABLE_DISABLE_VALUE, enable_switch, enable_value, \
     59     disable_switch, disable_value, NULL, 3
     60 #define ENABLE_DISABLE_VALUE_TYPE(enable_switch, disable_switch) \
     61     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, "", disable_switch, "")
     62 #define MULTI_VALUE_TYPE(choices) \
     63     Experiment::MULTI_VALUE, NULL, NULL, NULL, NULL, choices, arraysize(choices)
     64 
     65 namespace {
     66 
     67 const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid;
     68 const unsigned kOsDesktop = kOsMac | kOsWin | kOsLinux | kOsCrOS;
     69 
     70 // Adds a |StringValue| to |list| for each platform where |bitmask| indicates
     71 // whether the experiment is available on that platform.
     72 void AddOsStrings(unsigned bitmask, ListValue* list) {
     73   struct {
     74     unsigned bit;
     75     const char* const name;
     76   } kBitsToOs[] = {
     77     {kOsMac, "Mac"},
     78     {kOsWin, "Windows"},
     79     {kOsLinux, "Linux"},
     80     {kOsCrOS, "Chrome OS"},
     81     {kOsAndroid, "Android"},
     82     {kOsCrOSOwnerOnly, "Chrome OS (owner only)"},
     83   };
     84   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kBitsToOs); ++i)
     85     if (bitmask & kBitsToOs[i].bit)
     86       list->Append(new StringValue(kBitsToOs[i].name));
     87 }
     88 
     89 // Convert switch constants to proper CommandLine::StringType strings.
     90 CommandLine::StringType GetSwitchString(const std::string& flag) {
     91   CommandLine cmd_line(CommandLine::NO_PROGRAM);
     92   cmd_line.AppendSwitch(flag);
     93   DCHECK(cmd_line.argv().size() == 2);
     94   return cmd_line.argv()[1];
     95 }
     96 
     97 // Scoops flags from a command line.
     98 std::set<CommandLine::StringType> ExtractFlagsFromCommandLine(
     99     const CommandLine& cmdline) {
    100   std::set<CommandLine::StringType> flags;
    101   // First do the ones between --flag-switches-begin and --flag-switches-end.
    102   CommandLine::StringVector::const_iterator first =
    103       std::find(cmdline.argv().begin(), cmdline.argv().end(),
    104                 GetSwitchString(switches::kFlagSwitchesBegin));
    105   CommandLine::StringVector::const_iterator last =
    106       std::find(cmdline.argv().begin(), cmdline.argv().end(),
    107                 GetSwitchString(switches::kFlagSwitchesEnd));
    108   if (first != cmdline.argv().end() && last != cmdline.argv().end())
    109     flags.insert(first + 1, last);
    110 #if defined(OS_CHROMEOS)
    111   // Then add those between --policy-switches-begin and --policy-switches-end.
    112   first = std::find(cmdline.argv().begin(), cmdline.argv().end(),
    113                     GetSwitchString(chromeos::switches::kPolicySwitchesBegin));
    114   last = std::find(cmdline.argv().begin(), cmdline.argv().end(),
    115                    GetSwitchString(chromeos::switches::kPolicySwitchesEnd));
    116   if (first != cmdline.argv().end() && last != cmdline.argv().end())
    117     flags.insert(first + 1, last);
    118 #endif
    119   return flags;
    120 }
    121 
    122 const Experiment::Choice kEnableCompositingForFixedPositionChoices[] = {
    123   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    124   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
    125     switches::kEnableCompositingForFixedPosition, ""},
    126   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
    127     switches::kDisableCompositingForFixedPosition, ""},
    128   { IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_HIGH_DPI,
    129     switches::kEnableHighDpiCompositingForFixedPosition, ""}
    130 };
    131 
    132 const Experiment::Choice kEnableCompositingForTransitionChoices[] = {
    133   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    134   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
    135     switches::kEnableCompositingForTransition, ""},
    136   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
    137     switches::kDisableCompositingForTransition, ""},
    138 };
    139 
    140 const Experiment::Choice kEnableAcceleratedFixedRootBackgroundChoices[] = {
    141   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    142   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
    143     switches::kEnableAcceleratedFixedRootBackground, ""},
    144   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
    145     switches::kDisableAcceleratedFixedRootBackground, ""},
    146 };
    147 
    148 const Experiment::Choice kGDIPresentChoices[] = {
    149   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    150   { IDS_FLAGS_PRESENT_WITH_GDI_FIRST_SHOW,
    151     switches::kDoFirstShowPresentWithGDI, ""},
    152   { IDS_FLAGS_PRESENT_WITH_GDI_ALL_SHOW,
    153     switches::kDoAllShowPresentWithGDI, ""}
    154 };
    155 
    156 const Experiment::Choice kTouchEventsChoices[] = {
    157   { IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC, "", "" },
    158   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
    159     switches::kTouchEvents,
    160     switches::kTouchEventsEnabled },
    161   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
    162     switches::kTouchEvents,
    163     switches::kTouchEventsDisabled }
    164 };
    165 
    166 const Experiment::Choice kTouchOptimizedUIChoices[] = {
    167   { IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC, "", "" },
    168   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
    169     switches::kTouchOptimizedUI,
    170     switches::kTouchOptimizedUIEnabled },
    171   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
    172     switches::kTouchOptimizedUI,
    173     switches::kTouchOptimizedUIDisabled }
    174 };
    175 
    176 const Experiment::Choice kNaClDebugMaskChoices[] = {
    177   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    178   // Secure shell can be used on ChromeOS for forwarding the TCP port opened by
    179   // debug stub to a remote machine. Since secure shell uses NaCl, we provide
    180   // an option to switch off its debugging.
    181   { IDS_NACL_DEBUG_MASK_CHOICE_EXCLUDE_UTILS,
    182       switches::kNaClDebugMask, "!*://*/*ssh_client.nmf" },
    183   { IDS_NACL_DEBUG_MASK_CHOICE_INCLUDE_DEBUG,
    184       switches::kNaClDebugMask, "*://*/*debug.nmf" }
    185 };
    186 
    187 #if defined(OS_CHROMEOS)
    188 
    189 const Experiment::Choice kChromeCaptivePortalDetectionChoices[] = {
    190   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    191   { IDS_FLAGS_CHROME_CAPTIVE_PORTAL_DETECTOR,
    192     chromeos::switches::kEnableChromeCaptivePortalDetector, "" },
    193   { IDS_FLAGS_SHILL_CAPTIVE_PORTAL_DETECTOR,
    194     chromeos::switches::kDisableChromeCaptivePortalDetector, "" }
    195 };
    196 
    197 #endif
    198 
    199 const Experiment::Choice kImplSidePaintingChoices[] = {
    200   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    201   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
    202     cc::switches::kEnableImplSidePainting, ""},
    203   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
    204     cc::switches::kDisableImplSidePainting, ""}
    205 };
    206 
    207 const Experiment::Choice kDelegatedRendererChoices[] = {
    208   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    209   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
    210     switches::kEnableDelegatedRenderer, ""},
    211   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
    212     switches::kDisableDelegatedRenderer, ""}
    213 };
    214 
    215 const Experiment::Choice kMaxTilesForInterestAreaChoices[] = {
    216   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    217   { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_SHORT,
    218     cc::switches::kMaxTilesForInterestArea, "64"},
    219   { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_TALL,
    220     cc::switches::kMaxTilesForInterestArea, "128"},
    221   { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_GRANDE,
    222     cc::switches::kMaxTilesForInterestArea, "256"},
    223   { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_VENTI,
    224     cc::switches::kMaxTilesForInterestArea, "512"}
    225 };
    226 
    227 const Experiment::Choice kDefaultTileWidthChoices[] = {
    228   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    229   { IDS_FLAGS_DEFAULT_TILE_WIDTH_SHORT,
    230     switches::kDefaultTileWidth, "128"},
    231   { IDS_FLAGS_DEFAULT_TILE_WIDTH_TALL,
    232     switches::kDefaultTileWidth, "256"},
    233   { IDS_FLAGS_DEFAULT_TILE_WIDTH_GRANDE,
    234     switches::kDefaultTileWidth, "512"},
    235   { IDS_FLAGS_DEFAULT_TILE_WIDTH_VENTI,
    236     switches::kDefaultTileWidth, "1024"}
    237 };
    238 
    239 const Experiment::Choice kDefaultTileHeightChoices[] = {
    240   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    241   { IDS_FLAGS_DEFAULT_TILE_HEIGHT_SHORT,
    242     switches::kDefaultTileHeight, "128"},
    243   { IDS_FLAGS_DEFAULT_TILE_HEIGHT_TALL,
    244     switches::kDefaultTileHeight, "256"},
    245   { IDS_FLAGS_DEFAULT_TILE_HEIGHT_GRANDE,
    246     switches::kDefaultTileHeight, "512"},
    247   { IDS_FLAGS_DEFAULT_TILE_HEIGHT_VENTI,
    248     switches::kDefaultTileHeight, "1024"}
    249 };
    250 
    251 const Experiment::Choice kSimpleCacheBackendChoices[] = {
    252   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    253   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
    254     switches::kUseSimpleCacheBackend, "off" },
    255   { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
    256     switches::kUseSimpleCacheBackend, "on"}
    257 };
    258 
    259 const Experiment::Choice kTabCaptureUpscaleQualityChoices[] = {
    260   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    261   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_FAST,
    262     switches::kTabCaptureUpscaleQuality, "fast" },
    263   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_GOOD,
    264     switches::kTabCaptureUpscaleQuality, "good" },
    265   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_BEST,
    266     switches::kTabCaptureUpscaleQuality, "best" },
    267 };
    268 
    269 const Experiment::Choice kTabCaptureDownscaleQualityChoices[] = {
    270   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
    271   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_FAST,
    272     switches::kTabCaptureDownscaleQuality, "fast" },
    273   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_GOOD,
    274     switches::kTabCaptureDownscaleQuality, "good" },
    275   { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_BEST,
    276     switches::kTabCaptureDownscaleQuality, "best" },
    277 };
    278 
    279 // RECORDING USER METRICS FOR FLAGS:
    280 // -----------------------------------------------------------------------------
    281 // The first line of the experiment is the internal name. If you'd like to
    282 // gather statistics about the usage of your flag, you should append a marker
    283 // comment to the end of the feature name, like so:
    284 //   "my-special-feature",  // FLAGS:RECORD_UMA
    285 //
    286 // After doing that, run //chrome/tools/extract_actions.py (see instructions at
    287 // the top of that file for details) to update the chromeactions.txt file, which
    288 // will enable UMA to record your feature flag.
    289 //
    290 // After your feature has shipped under a flag, you can locate the metrics under
    291 // the action name AboutFlags_internal-action-name. Actions are recorded once
    292 // per startup, so you should divide this number by AboutFlags_StartupTick to
    293 // get a sense of usage. Note that this will not be the same as number of users
    294 // with a given feature enabled because users can quit and relaunch the
    295 // application multiple times over a given time interval. The dashboard also
    296 // shows you how many (metrics reporting) users have enabled the flag over the
    297 // last seven days. However, note that this is not the same as the number of
    298 // users who have the flag enabled, since enabling the flag happens once,
    299 // whereas running with the flag enabled happens until the user flips the flag
    300 // again.
    301 
    302 // To add a new experiment add to the end of kExperiments. There are two
    303 // distinct types of experiments:
    304 // . SINGLE_VALUE: experiment is either on or off. Use the SINGLE_VALUE_TYPE
    305 //   macro for this type supplying the command line to the macro.
    306 // . MULTI_VALUE: a list of choices, the first of which should correspond to a
    307 //   deactivated state for this lab (i.e. no command line option).  To specify
    308 //   this type of experiment use the macro MULTI_VALUE_TYPE supplying it the
    309 //   array of choices.
    310 // See the documentation of Experiment for details on the fields.
    311 //
    312 // When adding a new choice, add it to the end of the list.
    313 const Experiment kExperiments[] = {
    314   {
    315     "expose-for-tabs",  // FLAGS:RECORD_UMA
    316     IDS_FLAGS_TABPOSE_NAME,
    317     IDS_FLAGS_TABPOSE_DESCRIPTION,
    318     kOsMac,
    319 #if defined(OS_MACOSX)
    320     // The switch exists only on OS X.
    321     SINGLE_VALUE_TYPE(switches::kEnableExposeForTabs)
    322 #else
    323     SINGLE_VALUE_TYPE("")
    324 #endif
    325   },
    326   {
    327     "conflicting-modules-check",  // FLAGS:RECORD_UMA
    328     IDS_FLAGS_CONFLICTS_CHECK_NAME,
    329     IDS_FLAGS_CONFLICTS_CHECK_DESCRIPTION,
    330     kOsWin,
    331     SINGLE_VALUE_TYPE(switches::kConflictingModulesCheck)
    332   },
    333   {
    334     "ignore-gpu-blacklist",
    335     IDS_FLAGS_IGNORE_GPU_BLACKLIST_NAME,
    336     IDS_FLAGS_IGNORE_GPU_BLACKLIST_DESCRIPTION,
    337     kOsAll,
    338     SINGLE_VALUE_TYPE(switches::kIgnoreGpuBlacklist)
    339   },
    340   {
    341     "force-compositing-mode-2",
    342     IDS_FLAGS_FORCE_COMPOSITING_MODE_NAME,
    343     IDS_FLAGS_FORCE_COMPOSITING_MODE_DESCRIPTION,
    344     kOsMac | kOsWin | kOsLinux,
    345     ENABLE_DISABLE_VALUE_TYPE(switches::kForceCompositingMode,
    346                               switches::kDisableForceCompositingMode)
    347   },
    348   {
    349     "threaded-compositing-mode",
    350     IDS_FLAGS_THREADED_COMPOSITING_MODE_NAME,
    351     IDS_FLAGS_THREADED_COMPOSITING_MODE_DESCRIPTION,
    352     kOsMac | kOsWin | kOsLinux,
    353     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableThreadedCompositing,
    354                               switches::kDisableThreadedCompositing)
    355   },
    356   {
    357     "force-accelerated-composited-scrolling",
    358      IDS_FLAGS_FORCE_ACCELERATED_OVERFLOW_SCROLL_MODE_NAME,
    359      IDS_FLAGS_FORCE_ACCELERATED_OVERFLOW_SCROLL_MODE_DESCRIPTION,
    360      kOsAll,
    361      ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAcceleratedOverflowScroll,
    362                                switches::kDisableAcceleratedOverflowScroll)
    363   },
    364   {
    365     "present-with-GDI",
    366     IDS_FLAGS_PRESENT_WITH_GDI_NAME,
    367     IDS_FLAGS_PRESENT_WITH_GDI_DESCRIPTION,
    368     kOsWin,
    369     MULTI_VALUE_TYPE(kGDIPresentChoices)
    370   },
    371   {
    372     "enable-experimental-canvas-features",
    373     IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_NAME,
    374     IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_DESCRIPTION,
    375     kOsAll,
    376     SINGLE_VALUE_TYPE(switches::kEnableExperimentalCanvasFeatures)
    377   },
    378   {
    379     "disable-accelerated-2d-canvas",
    380     IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_NAME,
    381     IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_DESCRIPTION,
    382     kOsAll,
    383     SINGLE_VALUE_TYPE(switches::kDisableAccelerated2dCanvas)
    384   },
    385   {
    386     "disable-threaded-animation",
    387     IDS_FLAGS_DISABLE_THREADED_ANIMATION_NAME,
    388     IDS_FLAGS_DISABLE_THREADED_ANIMATION_DESCRIPTION,
    389     kOsAll,
    390     SINGLE_VALUE_TYPE(cc::switches::kDisableThreadedAnimation)
    391   },
    392   {
    393     "composited-layer-borders",
    394     IDS_FLAGS_COMPOSITED_LAYER_BORDERS,
    395     IDS_FLAGS_COMPOSITED_LAYER_BORDERS_DESCRIPTION,
    396     kOsAll,
    397     SINGLE_VALUE_TYPE(cc::switches::kShowCompositedLayerBorders)
    398   },
    399   {
    400     "show-fps-counter",
    401     IDS_FLAGS_SHOW_FPS_COUNTER,
    402     IDS_FLAGS_SHOW_FPS_COUNTER_DESCRIPTION,
    403     kOsAll,
    404     SINGLE_VALUE_TYPE(cc::switches::kShowFPSCounter)
    405   },
    406   {
    407     "accelerated-filters",
    408     IDS_FLAGS_ACCELERATED_FILTERS,
    409     IDS_FLAGS_ACCELERATED_FILTERS_DESCRIPTION,
    410     kOsAll,
    411     SINGLE_VALUE_TYPE(switches::kEnableAcceleratedFilters)
    412   },
    413   {
    414     "disable-webgl",
    415     IDS_FLAGS_DISABLE_WEBGL_NAME,
    416     IDS_FLAGS_DISABLE_WEBGL_DESCRIPTION,
    417     kOsAll,
    418     SINGLE_VALUE_TYPE(switches::kDisableExperimentalWebGL)
    419   },
    420   {
    421     "disable-webrtc",
    422     IDS_FLAGS_DISABLE_WEBRTC_NAME,
    423     IDS_FLAGS_DISABLE_WEBRTC_DESCRIPTION,
    424     kOsAndroid,
    425 #if defined(OS_ANDROID)
    426     SINGLE_VALUE_TYPE(switches::kDisableWebRTC)
    427 #else
    428     SINGLE_VALUE_TYPE("")
    429 #endif
    430   },
    431 #if defined(ENABLE_WEBRTC)
    432   {
    433     "enable-sctp-data-channels",
    434     IDS_FLAGS_ENABLE_SCTP_DATA_CHANNELS_NAME,
    435     IDS_FLAGS_ENABLE_SCTP_DATA_CHANNELS_DESCRIPTION,
    436     kOsAll,
    437     SINGLE_VALUE_TYPE(switches::kEnableSCTPDataChannels)
    438   },
    439   {
    440     "disable-device-enumeration",
    441     IDS_FLAGS_DISABLE_DEVICE_ENUMERATION_NAME,
    442     IDS_FLAGS_DISABLE_DEVICE_ENUMERATION_DESCRIPTION,
    443     kOsAll,
    444     SINGLE_VALUE_TYPE(switches::kDisableDeviceEnumeration)
    445   },
    446 #endif
    447 #if defined(OS_ANDROID)
    448   {
    449     "disable-webaudio",
    450     IDS_FLAGS_DISABLE_WEBAUDIO_NAME,
    451     IDS_FLAGS_DISABLE_WEBAUDIO_DESCRIPTION,
    452     kOsAndroid,
    453     SINGLE_VALUE_TYPE(switches::kDisableWebAudio)
    454   },
    455 #endif
    456   {
    457     "fixed-position-creates-stacking-context",
    458     IDS_FLAGS_FIXED_POSITION_CREATES_STACKING_CONTEXT_NAME,
    459     IDS_FLAGS_FIXED_POSITION_CREATES_STACKING_CONTEXT_DESCRIPTION,
    460     kOsAll,
    461     ENABLE_DISABLE_VALUE_TYPE(
    462         switches::kEnableFixedPositionCreatesStackingContext,
    463         switches::kDisableFixedPositionCreatesStackingContext)
    464   },
    465   {
    466     "enable-compositing-for-fixed-position",
    467     IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_NAME,
    468     IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_DESCRIPTION,
    469     kOsAll,
    470     MULTI_VALUE_TYPE(kEnableCompositingForFixedPositionChoices)
    471   },
    472   {
    473     "enable-compositing-for-transition",
    474     IDS_FLAGS_COMPOSITING_FOR_TRANSITION_NAME,
    475     IDS_FLAGS_COMPOSITING_FOR_TRANSITION_DESCRIPTION,
    476     kOsAll,
    477     MULTI_VALUE_TYPE(kEnableCompositingForTransitionChoices)
    478   },
    479   {
    480     "enable-accelerated-fixed-root-background",
    481     IDS_FLAGS_ACCELERATED_FIXED_ROOT_BACKGROUND_NAME,
    482     IDS_FLAGS_ACCELERATED_FIXED_ROOT_BACKGROUND_DESCRIPTION,
    483     kOsAll,
    484     MULTI_VALUE_TYPE(kEnableAcceleratedFixedRootBackgroundChoices)
    485   },
    486   // TODO(bbudge): When NaCl is on by default, remove this flag entry.
    487   {
    488     "enable-nacl",  // FLAGS:RECORD_UMA
    489     IDS_FLAGS_ENABLE_NACL_NAME,
    490     IDS_FLAGS_ENABLE_NACL_DESCRIPTION,
    491     kOsDesktop,
    492     SINGLE_VALUE_TYPE(switches::kEnableNaCl)
    493   },
    494   {
    495     "enable-nacl-debug",  // FLAGS:RECORD_UMA
    496     IDS_FLAGS_ENABLE_NACL_DEBUG_NAME,
    497     IDS_FLAGS_ENABLE_NACL_DEBUG_DESCRIPTION,
    498     kOsDesktop,
    499     SINGLE_VALUE_TYPE(switches::kEnableNaClDebug)
    500   },
    501   {
    502     "nacl-debug-mask",  // FLAGS:RECORD_UMA
    503     IDS_FLAGS_NACL_DEBUG_MASK_NAME,
    504     IDS_FLAGS_NACL_DEBUG_MASK_DESCRIPTION,
    505     kOsDesktop,
    506     MULTI_VALUE_TYPE(kNaClDebugMaskChoices)
    507   },
    508   {
    509     "enable-pnacl",  // FLAGS:RECORD_UMA
    510     IDS_FLAGS_ENABLE_PNACL_NAME,
    511     IDS_FLAGS_ENABLE_PNACL_DESCRIPTION,
    512     kOsDesktop,
    513     SINGLE_VALUE_TYPE(switches::kEnablePnacl)
    514   },
    515   {
    516     "extension-apis",  // FLAGS:RECORD_UMA
    517     IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_NAME,
    518     IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION,
    519     kOsDesktop,
    520     SINGLE_VALUE_TYPE(extensions::switches::kEnableExperimentalExtensionApis)
    521   },
    522   {
    523     "extensions-on-chrome-urls",
    524     IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_NAME,
    525     IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_DESCRIPTION,
    526     kOsAll,
    527     SINGLE_VALUE_TYPE(extensions::switches::kExtensionsOnChromeURLs)
    528   },
    529   {
    530     "enable-fast-unload",
    531     IDS_FLAGS_ENABLE_FAST_UNLOAD_NAME,
    532     IDS_FLAGS_ENABLE_FAST_UNLOAD_DESCRIPTION,
    533     kOsAll,
    534     SINGLE_VALUE_TYPE(switches::kEnableFastUnload)
    535   },
    536   {
    537     "enable-adview",
    538     IDS_FLAGS_ENABLE_ADVIEW_NAME,
    539     IDS_FLAGS_ENABLE_ADVIEW_DESCRIPTION,
    540     kOsDesktop,
    541     SINGLE_VALUE_TYPE(switches::kEnableAdview)
    542   },
    543   {
    544     "enable-adview-src-attribute",
    545     IDS_FLAGS_ENABLE_ADVIEW_SRC_ATTRIBUTE_NAME,
    546     IDS_FLAGS_ENABLE_ADVIEW_SRC_ATTRIBUTE_DESCRIPTION,
    547     kOsDesktop,
    548     SINGLE_VALUE_TYPE(switches::kEnableAdviewSrcAttribute)
    549   },
    550   {
    551     "enable-app-window-controls",
    552     IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_NAME,
    553     IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_DESCRIPTION,
    554     kOsDesktop,
    555     SINGLE_VALUE_TYPE(switches::kEnableAppWindowControls)
    556   },
    557   {
    558     "script-badges",
    559     IDS_FLAGS_SCRIPT_BADGES_NAME,
    560     IDS_FLAGS_SCRIPT_BADGES_DESCRIPTION,
    561     kOsDesktop,
    562     SINGLE_VALUE_TYPE(switches::kScriptBadges)
    563   },
    564   {
    565     "script-bubble",
    566     IDS_FLAGS_SCRIPT_BUBBLE_NAME,
    567     IDS_FLAGS_SCRIPT_BUBBLE_DESCRIPTION,
    568     kOsDesktop,
    569     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kScriptBubble, "1",
    570                                         switches::kScriptBubble, "0")
    571   },
    572   {
    573     "apps-new-install-bubble",
    574     IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_NAME,
    575     IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_DESCRIPTION,
    576     kOsDesktop,
    577     SINGLE_VALUE_TYPE(switches::kAppsNewInstallBubble)
    578   },
    579   {
    580     "disable-hyperlink-auditing",
    581     IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_NAME,
    582     IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_DESCRIPTION,
    583     kOsAll,
    584     SINGLE_VALUE_TYPE(switches::kNoPings)
    585   },
    586   {
    587     "experimental-location-features",  // FLAGS:RECORD_UMA
    588     IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_NAME,
    589     IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_DESCRIPTION,
    590     kOsMac,
    591     SINGLE_VALUE_TYPE(switches::kExperimentalLocationFeatures)
    592   },
    593   {
    594     "tab-groups-context-menu",
    595     IDS_FLAGS_TAB_GROUPS_CONTEXT_MENU_NAME,
    596     IDS_FLAGS_TAB_GROUPS_CONTEXT_MENU_DESCRIPTION,
    597     kOsWin,
    598     SINGLE_VALUE_TYPE(switches::kEnableTabGroupsContextMenu)
    599   },
    600   {
    601     "enable-instant-extended-api",
    602     IDS_FLAGS_ENABLE_INSTANT_EXTENDED_API,
    603     IDS_FLAGS_ENABLE_INSTANT_EXTENDED_API_DESCRIPTION,
    604     kOsMac | kOsWin | kOsCrOS,
    605     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableInstantExtendedAPI,
    606                               switches::kDisableInstantExtendedAPI)
    607   },
    608   {
    609     "enable-local-first-load-ntp",
    610     IDS_FLAGS_ENABLE_LOCAL_FIRST_LOAD_NTP,
    611     IDS_FLAGS_ENABLE_LOCAL_FIRST_LOAD_NTP_DESCRIPTION,
    612     kOsMac | kOsWin | kOsCrOS,
    613     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableLocalFirstLoadNTP,
    614                               switches::kDisableLocalFirstLoadNTP)
    615   },
    616 #if defined(OS_ANDROID)
    617   {
    618     "enable-new-ntp",
    619     IDS_FLAGS_ENABLE_NEW_NTP,
    620     IDS_FLAGS_ENABLE_NEW_NTP_DESCRIPTION,
    621     kOsAndroid,
    622     SINGLE_VALUE_TYPE(switches::kEnableNewNTP)
    623   },
    624 #endif
    625   {
    626     "static-ip-config",
    627     IDS_FLAGS_STATIC_IP_CONFIG_NAME,
    628     IDS_FLAGS_STATIC_IP_CONFIG_DESCRIPTION,
    629     kOsCrOS,
    630 #if defined(OS_CHROMEOS)
    631     // This switch exists only on Chrome OS.
    632     SINGLE_VALUE_TYPE(chromeos::switches::kEnableStaticIPConfig)
    633 #else
    634     SINGLE_VALUE_TYPE("")
    635 #endif
    636   },
    637   {
    638     "show-autofill-type-predictions",
    639     IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_NAME,
    640     IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_DESCRIPTION,
    641     kOsAll,
    642     SINGLE_VALUE_TYPE(autofill::switches::kShowAutofillTypePredictions)
    643   },
    644   {
    645     "enable-gesture-tap-highlight",
    646     IDS_FLAGS_ENABLE_GESTURE_TAP_HIGHLIGHTING_NAME,
    647     IDS_FLAGS_ENABLE_GESTURE_TAP_HIGHLIGHTING_DESCRIPTION,
    648     kOsLinux | kOsCrOS,
    649     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableGestureTapHighlight,
    650                               switches::kDisableGestureTapHighlight)
    651   },
    652   {
    653     "enable-smooth-scrolling",  // FLAGS:RECORD_UMA
    654     IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_NAME,
    655     IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_DESCRIPTION,
    656     // Can't expose the switch unless the code is compiled in.
    657     // On by default for the Mac (different implementation in WebKit).
    658     kOsWin | kOsLinux,
    659     SINGLE_VALUE_TYPE(switches::kEnableSmoothScrolling)
    660   },
    661   {
    662     "enable-panels",
    663     IDS_FLAGS_ENABLE_PANELS_NAME,
    664     IDS_FLAGS_ENABLE_PANELS_DESCRIPTION,
    665     kOsDesktop,
    666     SINGLE_VALUE_TYPE(switches::kEnablePanels)
    667   },
    668   {
    669     // See http://crbug.com/120416 for how to remove this flag.
    670     "save-page-as-mhtml",  // FLAGS:RECORD_UMA
    671     IDS_FLAGS_SAVE_PAGE_AS_MHTML_NAME,
    672     IDS_FLAGS_SAVE_PAGE_AS_MHTML_DESCRIPTION,
    673     kOsMac | kOsWin | kOsLinux,
    674     SINGLE_VALUE_TYPE(switches::kSavePageAsMHTML)
    675   },
    676   {
    677     "enable-autologin",
    678     IDS_FLAGS_ENABLE_AUTOLOGIN_NAME,
    679     IDS_FLAGS_ENABLE_AUTOLOGIN_DESCRIPTION,
    680     kOsMac | kOsWin | kOsLinux,
    681     SINGLE_VALUE_TYPE(switches::kEnableAutologin)
    682   },
    683   {
    684     "enable-quic",
    685     IDS_FLAGS_ENABLE_QUIC_NAME,
    686     IDS_FLAGS_ENABLE_QUIC_DESCRIPTION,
    687     kOsAll,
    688     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableQuic,
    689                               switches::kDisableQuic)
    690   },
    691   {
    692     "enable-quic-https",
    693     IDS_FLAGS_ENABLE_QUIC_HTTPS_NAME,
    694     IDS_FLAGS_ENABLE_QUIC_HTTPS_DESCRIPTION,
    695     kOsAll,
    696     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableQuicHttps,
    697                               switches::kDisableQuicHttps)
    698   },
    699   {
    700     "enable-spdy4a2",
    701     IDS_FLAGS_ENABLE_SPDY4A2_NAME,
    702     IDS_FLAGS_ENABLE_SPDY4A2_DESCRIPTION,
    703     kOsAll,
    704     SINGLE_VALUE_TYPE(switches::kEnableSpdy4a2)
    705   },
    706   {
    707     "enable-http2-draft-04",
    708     IDS_FLAGS_ENABLE_HTTP2_DRAFT_04_NAME,
    709     IDS_FLAGS_ENABLE_HTTP2_DRAFT_04_DESCRIPTION,
    710     kOsAll,
    711     SINGLE_VALUE_TYPE(switches::kEnableHttp2Draft04)
    712   },
    713   {
    714     "enable-async-dns",
    715     IDS_FLAGS_ENABLE_ASYNC_DNS_NAME,
    716     IDS_FLAGS_ENABLE_ASYNC_DNS_DESCRIPTION,
    717     kOsWin | kOsMac | kOsLinux | kOsCrOS,
    718     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAsyncDns,
    719                               switches::kDisableAsyncDns)
    720   },
    721   {
    722     "disable-media-source",
    723     IDS_FLAGS_DISABLE_WEBKIT_MEDIA_SOURCE_NAME,
    724     IDS_FLAGS_DISABLE_WEBKIT_MEDIA_SOURCE_DESCRIPTION,
    725     kOsAll,
    726     SINGLE_VALUE_TYPE(switches::kDisableWebKitMediaSource)
    727   },
    728   {
    729     "enable-encrypted-media",
    730     IDS_FLAGS_ENABLE_ENCRYPTED_MEDIA_NAME,
    731     IDS_FLAGS_ENABLE_ENCRYPTED_MEDIA_DESCRIPTION,
    732     kOsAll,
    733     SINGLE_VALUE_TYPE(switches::kEnableEncryptedMedia)
    734   },
    735   {
    736     "disable-encrypted-media",
    737     IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_NAME,
    738     IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_DESCRIPTION,
    739     kOsAll,
    740     SINGLE_VALUE_TYPE(switches::kDisableLegacyEncryptedMedia)
    741   },
    742   {
    743     "override-encrypted-media-canplaytype",
    744     IDS_FLAGS_ENCRYPTED_MEDIA_CANPLAYTYPE_OVERRIDE_NAME,
    745     IDS_FLAGS_ENCRYPTED_MEDIA_CANPLAYTYPE_OVERRIDE_DESCRIPTION,
    746     kOsMac | kOsWin,
    747     SINGLE_VALUE_TYPE(switches::kOverrideEncryptedMediaCanPlayType)
    748   },
    749   {
    750     "enable-opus-playback",
    751     IDS_FLAGS_ENABLE_OPUS_PLAYBACK_NAME,
    752     IDS_FLAGS_ENABLE_OPUS_PLAYBACK_DESCRIPTION,
    753     kOsDesktop,
    754     SINGLE_VALUE_TYPE(switches::kEnableOpusPlayback)
    755   },
    756  {
    757     "enable-vp8-alpha-playback",
    758     IDS_FLAGS_ENABLE_VP8_ALPHA_PLAYBACK_NAME,
    759     IDS_FLAGS_ENABLE_VP8_ALPHA_PLAYBACK_DESCRIPTION,
    760     kOsDesktop,
    761     SINGLE_VALUE_TYPE(switches::kEnableVp8AlphaPlayback)
    762   },
    763   {
    764     "enable-managed-users",
    765     IDS_FLAGS_ENABLE_LOCALLY_MANAGED_USERS_NAME,
    766     IDS_FLAGS_ENABLE_LOCALLY_MANAGED_USERS_DESCRIPTION,
    767     kOsMac | kOsWin | kOsLinux | kOsCrOSOwnerOnly,
    768     SINGLE_VALUE_TYPE(switches::kEnableManagedUsers)
    769   },
    770 #if defined(USE_ASH)
    771   {
    772     "ash-disable-auto-maximizing",
    773     IDS_FLAGS_ASH_AUTO_MAXIMIZING_NAME,
    774     IDS_FLAGS_ASH_AUTO_MAXIMIZING_DESCRIPTION,
    775     kOsWin | kOsLinux | kOsCrOS,
    776     SINGLE_VALUE_TYPE(ash::switches::kAshDisableAutoMaximizing)
    777   },
    778   {
    779     "ash-disable-auto-window-placement",
    780     IDS_FLAGS_ASH_AUTO_WINDOW_PLACEMENT_NAME,
    781     IDS_FLAGS_ASH_AUTO_WINDOW_PLACEMENT_DESCRIPTION,
    782     kOsWin | kOsLinux | kOsCrOS,
    783     SINGLE_VALUE_TYPE(ash::switches::kAshDisableAutoWindowPlacement)
    784   },
    785   {
    786     "ash-disable-per-app-launcher",
    787     IDS_FLAGS_ASH_DISABLE_PER_APP_LAUNCHER_NAME,
    788     IDS_FLAGS_ASH_DISABLE_PER_APP_LAUNCHER_DESCRIPTION,
    789     kOsWin | kOsLinux | kOsCrOS,
    790     SINGLE_VALUE_TYPE(ash::switches::kAshDisablePerAppLauncher)
    791   },
    792 #endif
    793   {
    794     "per-tile-painting",
    795     IDS_FLAGS_PER_TILE_PAINTING_NAME,
    796     IDS_FLAGS_PER_TILE_PAINTING_DESCRIPTION,
    797     kOsMac | kOsLinux | kOsCrOS,
    798     SINGLE_VALUE_TYPE(cc::switches::kEnablePerTilePainting)
    799   },
    800   {
    801     "enable-javascript-harmony",
    802     IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_NAME,
    803     IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_DESCRIPTION,
    804     kOsAll,
    805     SINGLE_VALUE_TYPE_AND_VALUE(switches::kJavaScriptFlags, "--harmony")
    806   },
    807   {
    808     "enable-tab-browser-dragging",
    809     IDS_FLAGS_ENABLE_TAB_BROWSER_DRAGGING_NAME,
    810     IDS_FLAGS_ENABLE_TAB_BROWSER_DRAGGING_DESCRIPTION,
    811     kOsWin,
    812     SINGLE_VALUE_TYPE(switches::kTabBrowserDragging)
    813   },
    814   {
    815     "disable-restore-session-state",
    816     IDS_FLAGS_DISABLE_RESTORE_SESSION_STATE_NAME,
    817     IDS_FLAGS_DISABLE_RESTORE_SESSION_STATE_DESCRIPTION,
    818     kOsAll,
    819     SINGLE_VALUE_TYPE(switches::kDisableRestoreSessionState)
    820   },
    821   {
    822     "disable-software-rasterizer",
    823     IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_NAME,
    824     IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_DESCRIPTION,
    825 #if defined(ENABLE_SWIFTSHADER)
    826     kOsAll,
    827 #else
    828     0,
    829 #endif
    830     SINGLE_VALUE_TYPE(switches::kDisableSoftwareRasterizer)
    831   },
    832   {
    833     "enable-experimental-web-platform-features",
    834     IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_NAME,
    835     IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_DESCRIPTION,
    836     kOsAll,
    837     SINGLE_VALUE_TYPE(switches::kEnableExperimentalWebPlatformFeatures)
    838   },
    839   {
    840     "enable-css-shaders",
    841     IDS_FLAGS_CSS_SHADERS_NAME,
    842     IDS_FLAGS_CSS_SHADERS_DESCRIPTION,
    843     kOsAll,
    844     SINGLE_VALUE_TYPE(switches::kEnableCssShaders)
    845   },
    846   {
    847     "disable-ntp-other-sessions-menu",
    848     IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_NAME,
    849     IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_DESCRIPTION,
    850     kOsDesktop,
    851     SINGLE_VALUE_TYPE(switches::kDisableNTPOtherSessionsMenu)
    852   },
    853 #if defined(USE_ASH)
    854   {
    855     "enable-ash-oak",
    856     IDS_FLAGS_ENABLE_ASH_OAK_NAME,
    857     IDS_FLAGS_ENABLE_ASH_OAK_DESCRIPTION,
    858     kOsAll,
    859     SINGLE_VALUE_TYPE(ash::switches::kAshEnableOak),
    860   },
    861 #endif
    862   {
    863     "enable-devtools-experiments",
    864     IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_NAME,
    865     IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_DESCRIPTION,
    866     kOsDesktop,
    867     SINGLE_VALUE_TYPE(switches::kEnableDevToolsExperiments)
    868   },
    869   {
    870     "remote-debugging-raw-usb",
    871     IDS_FLAGS_REMOTE_DEBUGGING_RAW_USB_NAME,
    872     IDS_FLAGS_REMOTE_DEBUGGING_RAW_USB_DESCRIPTION,
    873     kOsDesktop,
    874     SINGLE_VALUE_TYPE(switches::kRemoteDebuggingRawUSB)
    875   },
    876   {
    877     "silent-debugger-extension-api",
    878     IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_NAME,
    879     IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_DESCRIPTION,
    880     kOsDesktop,
    881     SINGLE_VALUE_TYPE(switches::kSilentDebuggerExtensionAPI)
    882   },
    883   {
    884     "enable-suggestions-ntp",
    885     IDS_FLAGS_NTP_SUGGESTIONS_PAGE_NAME,
    886     IDS_FLAGS_NTP_SUGGESTIONS_PAGE_DESCRIPTION,
    887     kOsDesktop,
    888     SINGLE_VALUE_TYPE(switches::kEnableSuggestionsTabPage)
    889   },
    890   {
    891     "spellcheck-autocorrect",
    892     IDS_FLAGS_SPELLCHECK_AUTOCORRECT,
    893     IDS_FLAGS_SPELLCHECK_AUTOCORRECT_DESCRIPTION,
    894     kOsWin | kOsLinux | kOsCrOS,
    895     SINGLE_VALUE_TYPE(switches::kEnableSpellingAutoCorrect)
    896   },
    897   {
    898     "enable-scroll-prediction",
    899     IDS_FLAGS_ENABLE_SCROLL_PREDICTION_NAME,
    900     IDS_FLAGS_ENABLE_SCROLL_PREDICTION_DESCRIPTION,
    901     kOsDesktop,
    902     SINGLE_VALUE_TYPE(switches::kEnableScrollPrediction)
    903   },
    904   {
    905     "touch-events",
    906     IDS_TOUCH_EVENTS_NAME,
    907     IDS_TOUCH_EVENTS_DESCRIPTION,
    908     kOsDesktop,
    909     MULTI_VALUE_TYPE(kTouchEventsChoices)
    910   },
    911   {
    912     "touch-optimized-ui",
    913     IDS_FLAGS_TOUCH_OPTIMIZED_UI_NAME,
    914     IDS_FLAGS_TOUCH_OPTIMIZED_UI_DESCRIPTION,
    915     kOsWin,
    916     MULTI_VALUE_TYPE(kTouchOptimizedUIChoices)
    917   },
    918   {
    919     "disable-touch-adjustment",
    920     IDS_DISABLE_TOUCH_ADJUSTMENT_NAME,
    921     IDS_DISABLE_TOUCH_ADJUSTMENT_DESCRIPTION,
    922     kOsWin | kOsLinux | kOsCrOS,
    923     SINGLE_VALUE_TYPE(switches::kDisableTouchAdjustment)
    924   },
    925 #if defined(OS_CHROMEOS)
    926   {
    927       "ash-use-alternate-shelf",
    928       IDS_FLAGS_ALTERNATE_SHELF_LAYOUT_NAME,
    929       IDS_FLAGS_ALTERNATE_SHELF_LAYOUT_DESCRIPTION,
    930       kOsCrOS,
    931       SINGLE_VALUE_TYPE(ash::switches::kAshUseAlternateShelfLayout)
    932   },
    933   {
    934     "enable-background-loader",
    935     IDS_ENABLE_BACKLOADER_NAME,
    936     IDS_ENABLE_BACKLOADER_DESCRIPTION,
    937     kOsCrOS,
    938     SINGLE_VALUE_TYPE(chromeos::switches::kEnableBackgroundLoader)
    939   },
    940   {
    941     "enable-screensaver-extension",
    942     IDS_ENABLE_SCREENSAVER_EXTENSION_NAME,
    943     IDS_ENABLE_SCREENSAVER_EXTENSION_DESCRIPTION,
    944     kOsCrOS,
    945     SINGLE_VALUE_TYPE(chromeos::switches::kEnableScreensaverExtensions)
    946   },
    947   {
    948     "no-discard-tabs",
    949     IDS_FLAGS_NO_DISCARD_TABS_NAME,
    950     IDS_FLAGS_NO_DISCARD_TABS_DESCRIPTION,
    951     kOsCrOS,
    952     SINGLE_VALUE_TYPE(chromeos::switches::kNoDiscardTabs)
    953   },
    954   {
    955     "ash-enable-docked-windows",
    956     IDS_FLAGS_DOCKED_WINDOWS_NAME,
    957     IDS_FLAGS_DOCKED_WINDOWS_DESCRIPTION,
    958     kOsCrOS,
    959     SINGLE_VALUE_TYPE(ash::switches::kAshEnableDockedWindows)
    960   },
    961 #endif
    962   {
    963     "enable-download-resumption",
    964     IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_NAME,
    965     IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_DESCRIPTION,
    966     kOsDesktop,
    967     SINGLE_VALUE_TYPE(switches::kEnableDownloadResumption)
    968   },
    969   {
    970     "allow-nacl-socket-api",
    971     IDS_FLAGS_ALLOW_NACL_SOCKET_API_NAME,
    972     IDS_FLAGS_ALLOW_NACL_SOCKET_API_DESCRIPTION,
    973     kOsDesktop,
    974     SINGLE_VALUE_TYPE_AND_VALUE(switches::kAllowNaClSocketAPI, "*")
    975   },
    976   {
    977     "stacked-tab-strip",
    978     IDS_FLAGS_STACKED_TAB_STRIP_NAME,
    979     IDS_FLAGS_STACKED_TAB_STRIP_DESCRIPTION,
    980     kOsWin,
    981     SINGLE_VALUE_TYPE(switches::kEnableStackedTabStrip)
    982   },
    983   {
    984     "force-device-scale-factor",
    985     IDS_FLAGS_FORCE_HIGH_DPI_NAME,
    986     IDS_FLAGS_FORCE_HIGH_DPI_DESCRIPTION,
    987     kOsCrOS,
    988     SINGLE_VALUE_TYPE_AND_VALUE(switches::kForceDeviceScaleFactor, "2")
    989   },
    990 #if defined(OS_CHROMEOS)
    991   {
    992     "allow-touchpad-three-finger-click",
    993     IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_NAME,
    994     IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_DESCRIPTION,
    995     kOsCrOS,
    996     SINGLE_VALUE_TYPE(chromeos::switches::kEnableTouchpadThreeFingerClick)
    997   },
    998 #endif
    999 #if defined(USE_ASH)
   1000   {
   1001     "show-launcher-alignment-menu",
   1002     IDS_FLAGS_SHOW_SHELF_ALIGNMENT_MENU_NAME,
   1003     IDS_FLAGS_SHOW_SHELF_ALIGNMENT_MENU_DESCRIPTION,
   1004     kOsAll,
   1005     SINGLE_VALUE_TYPE(switches::kShowShelfAlignmentMenu)
   1006   },
   1007   {
   1008     "disable-minimize-on-second-launcher-item-click",
   1009     IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_NAME,
   1010     IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_DESCRIPTION,
   1011     kOsAll,
   1012     SINGLE_VALUE_TYPE(switches::kDisableMinimizeOnSecondLauncherItemClick)
   1013   },
   1014   {
   1015     "enable-overview-mode",
   1016     IDS_FLAGS_OVERVIEW_MODE_NAME,
   1017     IDS_FLAGS_OVERVIEW_MODE_DESCRIPTION,
   1018     kOsCrOS,
   1019     SINGLE_VALUE_TYPE(ash::switches::kAshEnableOverviewMode)
   1020   },
   1021   {
   1022     "show-touch-hud",
   1023     IDS_FLAGS_SHOW_TOUCH_HUD_NAME,
   1024     IDS_FLAGS_SHOW_TOUCH_HUD_DESCRIPTION,
   1025     kOsAll,
   1026     SINGLE_VALUE_TYPE(ash::switches::kAshTouchHud)
   1027   },
   1028   {
   1029     "enable-pinch",
   1030     IDS_FLAGS_ENABLE_PINCH_SCALE_NAME,
   1031     IDS_FLAGS_ENABLE_PINCH_SCALE_DESCRIPTION,
   1032     kOsLinux | kOsWin | kOsCrOS,
   1033     ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePinch, switches::kDisablePinch),
   1034   },
   1035   {
   1036     "enable-pinch-virtual-viewport",
   1037     IDS_FLAGS_ENABLE_PINCH_VIRTUAL_VIEWPORT_NAME,
   1038     IDS_FLAGS_ENABLE_PINCH_VIRTUAL_VIEWPORT_DESCRIPTION,
   1039     kOsLinux | kOsWin | kOsCrOS,
   1040     SINGLE_VALUE_TYPE(cc::switches::kEnablePinchVirtualViewport),
   1041   },
   1042   {
   1043     "forced-maximize-mode",
   1044     IDS_FLAGS_FORCE_MAXIMIZE_MODE_NAME,
   1045     IDS_FLAGS_FORCE_MAXIMIZE_MODE_DESCRIPTION,
   1046     kOsLinux | kOsWin | kOsCrOS,
   1047     SINGLE_VALUE_TYPE(ash::switches::kForcedMaximizeMode),
   1048   },
   1049 #endif  // defined(USE_ASH)
   1050 #if defined(OS_CHROMEOS)
   1051   {
   1052     "disable-boot-animation",
   1053     IDS_FLAGS_DISABLE_BOOT_ANIMATION,
   1054     IDS_FLAGS_DISABLE_BOOT_ANIMATION_DESCRIPTION,
   1055     kOsCrOSOwnerOnly,
   1056     SINGLE_VALUE_TYPE(chromeos::switches::kDisableBootAnimation),
   1057   },
   1058   {
   1059     "captive-portal-detector",
   1060     IDS_FLAGS_CAPTIVE_PORTAL_DETECTOR_NAME,
   1061     IDS_FLAGS_CAPTIVE_PORTAL_DETECTOR_DESCRIPTION,
   1062     kOsCrOSOwnerOnly,
   1063     MULTI_VALUE_TYPE(kChromeCaptivePortalDetectionChoices),
   1064   },
   1065   {
   1066     "disable-new-lock-animations",
   1067     IDS_FLAGS_ASH_NEW_LOCK_ANIMATIONS,
   1068     IDS_FLAGS_ASH_NEW_LOCK_ANIMATIONS_DESCRIPTION,
   1069     kOsCrOS,
   1070     SINGLE_VALUE_TYPE(ash::switches::kAshDisableNewLockAnimations),
   1071   },
   1072   {
   1073     "file-manager-show-checkboxes",
   1074     IDS_FLAGS_FILE_MANAGER_SHOW_CHECKBOXES_NAME,
   1075     IDS_FLAGS_FILE_MANAGER_SHOW_CHECKBOXES_DESCRIPTION,
   1076     kOsCrOS,
   1077     SINGLE_VALUE_TYPE(chromeos::switches::kFileManagerShowCheckboxes)
   1078   },
   1079   {
   1080     "file-manager-enable-webstore-integration",
   1081     IDS_FLAGS_FILE_MANAGER_ENABLE_WEBSTORE_INTEGRATION,
   1082     IDS_FLAGS_FILE_MANAGER_ENABLE_WEBSTORE_INTEGRATION_DESCRIPTION,
   1083     kOsCrOS,
   1084     SINGLE_VALUE_TYPE(chromeos::switches::kFileManagerEnableWebstoreIntegration)
   1085   },
   1086   {
   1087     "disable-quickoffice-component-app",
   1088     IDS_FLAGS_DISABLE_QUICKOFFICE_COMPONENT_APP_NAME,
   1089     IDS_FLAGS_DISABLE_QUICKOFFICE_COMPONENT_APP_DESCRIPTION,
   1090     kOsCrOS,
   1091     SINGLE_VALUE_TYPE(chromeos::switches::kDisableQuickofficeComponentApp),
   1092   },
   1093 #endif  // defined(OS_CHROMEOS)
   1094   {
   1095     "views-textfield",
   1096     IDS_FLAGS_VIEWS_TEXTFIELD_NAME,
   1097     IDS_FLAGS_VIEWS_TEXTFIELD_DESCRIPTION,
   1098     kOsWin,
   1099     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableViewsTextfield,
   1100                               switches::kDisableViewsTextfield),
   1101   },
   1102   {
   1103     "new-dialog-style",
   1104     IDS_FLAGS_NEW_DIALOG_STYLE_NAME,
   1105     IDS_FLAGS_NEW_DIALOG_STYLE_DESCRIPTION,
   1106     kOsWin | kOsCrOS,
   1107     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableNewDialogStyle,
   1108                               switches::kDisableNewDialogStyle),
   1109   },
   1110   { "disable-accelerated-video-decode",
   1111     IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_NAME,
   1112     IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_DESCRIPTION,
   1113     kOsWin | kOsCrOS,
   1114     SINGLE_VALUE_TYPE(switches::kDisableAcceleratedVideoDecode),
   1115   },
   1116 #if defined(USE_ASH)
   1117   {
   1118     "ash-debug-shortcuts",
   1119     IDS_FLAGS_DEBUG_SHORTCUTS_NAME,
   1120     IDS_FLAGS_DEBUG_SHORTCUTS_DESCRIPTION,
   1121     kOsAll,
   1122     SINGLE_VALUE_TYPE(ash::switches::kAshDebugShortcuts),
   1123   },
   1124 #endif
   1125   {
   1126     "enable-contacts",
   1127     IDS_FLAGS_ENABLE_CONTACTS_NAME,
   1128     IDS_FLAGS_ENABLE_CONTACTS_DESCRIPTION,
   1129     kOsCrOS,
   1130     SINGLE_VALUE_TYPE(switches::kEnableContacts)
   1131   },
   1132 #if defined(USE_ASH)
   1133   { "ash-enable-advanced-gestures",
   1134     IDS_FLAGS_ENABLE_ADVANCED_GESTURES_NAME,
   1135     IDS_FLAGS_ENABLE_ADVANCED_GESTURES_DESCRIPTION,
   1136     kOsCrOS,
   1137     SINGLE_VALUE_TYPE(ash::switches::kAshEnableAdvancedGestures),
   1138   },
   1139   { "ash-disable-tab-scrubbing",
   1140     IDS_FLAGS_DISABLE_TAB_SCRUBBING_NAME,
   1141     IDS_FLAGS_DISABLE_TAB_SCRUBBING_DESCRIPTION,
   1142     kOsCrOS,
   1143     SINGLE_VALUE_TYPE(switches::kAshDisableTabScrubbing),
   1144   },
   1145   { "ash-disable-drag-and-drop-applist-to-launcher",
   1146     IDS_FLAGS_DND_APPLIST_TO_LAUNCHER_NAME,
   1147     IDS_FLAGS_DND_APPLIST_TO_LAUNCHER_DESCRIPTION,
   1148     kOsCrOS,
   1149     SINGLE_VALUE_TYPE(ash::switches::kAshDisableDragAndDropAppListToLauncher),
   1150   },
   1151   { "ash-immersive-fullscreen-2",
   1152     IDS_FLAGS_ASH_IMMERSIVE_FULLSCREEN_NAME,
   1153     IDS_FLAGS_ASH_IMMERSIVE_FULLSCREEN_DESCRIPTION,
   1154     kOsCrOS,
   1155     ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshEnableImmersiveFullscreen,
   1156                               ash::switches::kAshDisableImmersiveFullscreen),
   1157   },
   1158 #if defined(OS_LINUX)
   1159   { "ash-enable-memory-monitor",
   1160       IDS_FLAGS_ENABLE_MEMORY_MONITOR_NAME,
   1161       IDS_FLAGS_ENABLE_MEMORY_MONITOR_DESCRIPTION,
   1162       kOsCrOS,
   1163       SINGLE_VALUE_TYPE(ash::switches::kAshEnableMemoryMonitor),
   1164   },
   1165 #endif
   1166 #endif
   1167 #if defined(OS_CHROMEOS)
   1168   { "use-new-network-configuration-handlers",
   1169     IDS_FLAGS_CHROMEOS_USE_NEW_NETWORK_CONFIGURATION_HANDLERS_NAME,
   1170     IDS_FLAGS_CHROMEOS_USE_NEW_NETWORK_CONFIGURATION_HANDLERS_DESCRIPTION,
   1171     kOsCrOS,
   1172     SINGLE_VALUE_TYPE(chromeos::switches::kUseNewNetworkConfigurationHandlers),
   1173   },
   1174   {
   1175     "ash-audio-device-menu",
   1176     IDS_FLAGS_ASH_AUDIO_DEVICE_MENU_NAME,
   1177     IDS_FLAGS_ASH_AUDIO_DEVICE_MENU_DESCRIPTION,
   1178     kOsCrOS,
   1179     ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshEnableAudioDeviceMenu,
   1180                               ash::switches::kAshDisableAudioDeviceMenu)
   1181   },
   1182   {
   1183     "enable-carrier-switching",
   1184     IDS_FLAGS_ENABLE_CARRIER_SWITCHING,
   1185     IDS_FLAGS_ENABLE_CARRIER_SWITCHING_DESCRIPTION,
   1186     kOsCrOS,
   1187     SINGLE_VALUE_TYPE(chromeos::switches::kEnableCarrierSwitching)
   1188   },
   1189   {
   1190     "enable-request-tablet-site",
   1191     IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_NAME,
   1192     IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_DESCRIPTION,
   1193     kOsCrOS,
   1194     SINGLE_VALUE_TYPE(chromeos::switches::kEnableRequestTabletSite)
   1195   },
   1196 #endif
   1197   {
   1198     "debug-packed-apps",
   1199     IDS_FLAGS_DEBUG_PACKED_APP_NAME,
   1200     IDS_FLAGS_DEBUG_PACKED_APP_DESCRIPTION,
   1201     kOsDesktop,
   1202     SINGLE_VALUE_TYPE(switches::kDebugPackedApps)
   1203   },
   1204   {
   1205     "enable-password-generation",
   1206     IDS_FLAGS_ENABLE_PASSWORD_GENERATION_NAME,
   1207     IDS_FLAGS_ENABLE_PASSWORD_GENERATION_DESCRIPTION,
   1208     kOsDesktop,
   1209     SINGLE_VALUE_TYPE(switches::kEnablePasswordGeneration)
   1210   },
   1211   {
   1212     "password-autofill-public-suffix-domain-matching",
   1213     IDS_FLAGS_PASSWORD_AUTOFILL_PUBLIC_SUFFIX_DOMAIN_MATCHING_NAME,
   1214     IDS_FLAGS_PASSWORD_AUTOFILL_PUBLIC_SUFFIX_DOMAIN_MATCHING_DESCRIPTION,
   1215     kOsAndroid,
   1216     ENABLE_DISABLE_VALUE_TYPE(
   1217         switches::kEnablePasswordAutofillPublicSuffixDomainMatching,
   1218         switches::kDisablePasswordAutofillPublicSuffixDomainMatching)
   1219   },
   1220   {
   1221     "enable-deferred-image-decoding",
   1222     IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_NAME,
   1223     IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_DESCRIPTION,
   1224     kOsMac | kOsLinux | kOsCrOS,
   1225     SINGLE_VALUE_TYPE(switches::kEnableDeferredImageDecoding)
   1226   },
   1227   {
   1228     "performance-monitor-gathering",
   1229     IDS_FLAGS_PERFORMANCE_MONITOR_GATHERING_NAME,
   1230     IDS_FLAGS_PERFORMANCE_MONITOR_GATHERING_DESCRIPTION,
   1231     kOsAll,
   1232     SINGLE_VALUE_TYPE(switches::kPerformanceMonitorGathering)
   1233   },
   1234   {
   1235     "enable-experimental-form-filling",
   1236     IDS_FLAGS_ENABLE_EXPERIMENTAL_FORM_FILLING_NAME,
   1237     IDS_FLAGS_ENABLE_EXPERIMENTAL_FORM_FILLING_DESCRIPTION,
   1238     kOsWin | kOsCrOS,
   1239     SINGLE_VALUE_TYPE(autofill::switches::kEnableExperimentalFormFilling)
   1240   },
   1241   {
   1242     "wallet-service-use-prod",
   1243     IDS_FLAGS_ENABLE_WALLET_PRODUCTION_SERVICE_NAME,
   1244     IDS_FLAGS_ENABLE_WALLET_PRODUCTION_SERVICE_DESCRIPTION,
   1245     kOsCrOS | kOsWin,
   1246     SINGLE_VALUE_TYPE(autofill::switches::kWalletServiceUseProd)
   1247   },
   1248   {
   1249     "enable-interactive-autocomplete",
   1250     IDS_FLAGS_ENABLE_INTERACTIVE_AUTOCOMPLETE_NAME,
   1251     IDS_FLAGS_ENABLE_INTERACTIVE_AUTOCOMPLETE_DESCRIPTION,
   1252     kOsWin | kOsCrOS | kOsMac,
   1253     ENABLE_DISABLE_VALUE_TYPE(
   1254         autofill::switches::kEnableInteractiveAutocomplete,
   1255         autofill::switches::kDisableInteractiveAutocomplete)
   1256   },
   1257 #if defined(USE_AURA)
   1258   {
   1259     "overscroll-history-navigation",
   1260     IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_NAME,
   1261     IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_DESCRIPTION,
   1262     kOsAll,
   1263     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
   1264         switches::kOverscrollHistoryNavigation, "1",
   1265         switches::kOverscrollHistoryNavigation, "0")
   1266   },
   1267 #endif
   1268   {
   1269     "scroll-end-effect",
   1270     IDS_FLAGS_SCROLL_END_EFFECT_NAME,
   1271     IDS_FLAGS_SCROLL_END_EFFECT_DESCRIPTION,
   1272     kOsCrOS,
   1273     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
   1274         switches::kScrollEndEffect, "1",
   1275         switches::kScrollEndEffect, "0")
   1276   },
   1277   {
   1278     "enable-touch-side-bezels",
   1279     IDS_FLAGS_ENABLE_TOUCH_SIDE_BEZELS_NAME,
   1280     IDS_FLAGS_ENABLE_TOUCH_SIDE_BEZELS_DESCRIPTION,
   1281     kOsCrOS,
   1282     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
   1283         switches::kTouchSideBezels, "1",
   1284         switches::kTouchSideBezels, "0")
   1285   },
   1286   {
   1287     "enable-touch-drag-drop",
   1288     IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_NAME,
   1289     IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_DESCRIPTION,
   1290     kOsWin | kOsCrOS,
   1291     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchDragDrop,
   1292                               switches::kDisableTouchDragDrop)
   1293   },
   1294   {
   1295     "enable-touch-editing",
   1296     IDS_FLAGS_ENABLE_TOUCH_EDITING_NAME,
   1297     IDS_FLAGS_ENABLE_TOUCH_EDITING_DESCRIPTION,
   1298     kOsCrOS,
   1299     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchEditing,
   1300                               switches::kDisableTouchEditing)
   1301   },
   1302   {
   1303     "enable-rich-notifications",
   1304     IDS_FLAGS_ENABLE_RICH_NOTIFICATIONS_NAME,
   1305     IDS_FLAGS_ENABLE_RICH_NOTIFICATIONS_DESCRIPTION,
   1306     kOsWin | kOsMac,
   1307     ENABLE_DISABLE_VALUE_TYPE(
   1308         message_center::switches::kEnableRichNotifications,
   1309         message_center::switches::kDisableRichNotifications)
   1310   },
   1311   {
   1312     "enable-sync-synced-notifications",
   1313     IDS_FLAGS_ENABLE_SYNCED_NOTIFICATIONS_NAME,
   1314     IDS_FLAGS_ENABLE_SYNCED_NOTIFICATIONS_DESCRIPTION,
   1315     kOsDesktop,
   1316     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSyncSyncedNotifications,
   1317                               switches::kDisableSyncSyncedNotifications)
   1318   },
   1319   {
   1320     "disable-full-history-sync",
   1321     IDS_FLAGS_FULL_HISTORY_SYNC_NAME,
   1322     IDS_FLAGS_FULL_HISTORY_SYNC_DESCRIPTION,
   1323     kOsAll,
   1324     SINGLE_VALUE_TYPE(switches::kHistoryDisableFullHistorySync)
   1325   },
   1326   {
   1327     "enable-usermedia-screen-capture",
   1328     IDS_FLAGS_ENABLE_SCREEN_CAPTURE_NAME,
   1329     IDS_FLAGS_ENABLE_SCREEN_CAPTURE_DESCRIPTION,
   1330     kOsDesktop,
   1331     SINGLE_VALUE_TYPE(switches::kEnableUserMediaScreenCapturing)
   1332   },
   1333   {
   1334     "enable-apps-devtool-app",
   1335     IDS_FLAGS_ENABLE_APPS_DEVTOOL_APP_NAME,
   1336     IDS_FLAGS_ENABLE_APPS_DEVTOOL_APP_DESCRIPTION,
   1337     kOsDesktop,
   1338     SINGLE_VALUE_TYPE(switches::kAppsDevtool)
   1339   },
   1340   {
   1341     "impl-side-painting",
   1342     IDS_FLAGS_IMPL_SIDE_PAINTING_NAME,
   1343     IDS_FLAGS_IMPL_SIDE_PAINTING_DESCRIPTION,
   1344     kOsAndroid | kOsLinux | kOsCrOS,
   1345     MULTI_VALUE_TYPE(kImplSidePaintingChoices)
   1346   },
   1347   {
   1348     "delegated-renderer",
   1349     IDS_FLAGS_DELEGATED_RENDERER_NAME,
   1350     IDS_FLAGS_DELEGATED_RENDERER_DESCRIPTION,
   1351 #ifdef USE_AURA
   1352     kOsWin | kOsLinux |
   1353 #endif
   1354     kOsAndroid | kOsCrOS,
   1355     MULTI_VALUE_TYPE(kDelegatedRendererChoices)
   1356   },
   1357   {
   1358     "enable-websocket-experimental-implementation",
   1359     IDS_FLAGS_ENABLE_EXPERIMENTAL_WEBSOCKET_NAME,
   1360     IDS_FLAGS_ENABLE_EXPERIMENTAL_WEBSOCKET_DESCRIPTION,
   1361     kOsAll,
   1362     SINGLE_VALUE_TYPE(switches::kEnableExperimentalWebSocket)
   1363   },
   1364   {
   1365     "max-tiles-for-interest-area",
   1366     IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_NAME,
   1367     IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_DESCRIPTION,
   1368     kOsAndroid | kOsLinux | kOsCrOS,
   1369     MULTI_VALUE_TYPE(kMaxTilesForInterestAreaChoices)
   1370   },
   1371   {
   1372     "enable-offline-mode",
   1373     IDS_FLAGS_ENABLE_OFFLINE_MODE_NAME,
   1374     IDS_FLAGS_ENABLE_OFFLINE_MODE_DESCRIPTION,
   1375     kOsAll,
   1376     SINGLE_VALUE_TYPE(switches::kEnableOfflineCacheAccess)
   1377   },
   1378   {
   1379     "default-tile-width",
   1380     IDS_FLAGS_DEFAULT_TILE_WIDTH_NAME,
   1381     IDS_FLAGS_DEFAULT_TILE_WIDTH_DESCRIPTION,
   1382     kOsAll,
   1383     MULTI_VALUE_TYPE(kDefaultTileWidthChoices)
   1384   },
   1385   {
   1386     "default-tile-height",
   1387     IDS_FLAGS_DEFAULT_TILE_HEIGHT_NAME,
   1388     IDS_FLAGS_DEFAULT_TILE_HEIGHT_DESCRIPTION,
   1389     kOsAll,
   1390     MULTI_VALUE_TYPE(kDefaultTileHeightChoices)
   1391   },
   1392   // TODO(sky): ifdef needed until focus sorted out in DesktopNativeWidgetAura.
   1393 #if !defined(USE_AURA)
   1394   {
   1395     "track-active-visit-time",
   1396     IDS_FLAGS_TRACK_ACTIVE_VISIT_TIME_NAME,
   1397     IDS_FLAGS_TRACK_ACTIVE_VISIT_TIME_DESCRIPTION,
   1398     kOsWin,
   1399     SINGLE_VALUE_TYPE(switches::kTrackActiveVisitTime)
   1400   },
   1401 #endif
   1402 #if defined(OS_ANDROID)
   1403   {
   1404     "disable-gesture-requirement-for-media-playback",
   1405     IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_NAME,
   1406     IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_DESCRIPTION,
   1407     kOsAndroid,
   1408     SINGLE_VALUE_TYPE(switches::kDisableGestureRequirementForMediaPlayback)
   1409   },
   1410 #endif
   1411 #if defined(ENABLE_GOOGLE_NOW)
   1412   {
   1413     "enable-google-now",
   1414     IDS_FLAGS_ENABLE_GOOGLE_NOW_INTEGRATION_NAME,
   1415     IDS_FLAGS_ENABLE_GOOGLE_NOW_INTEGRATION_DESCRIPTION,
   1416     kOsWin | kOsCrOS | kOsMac,
   1417     SINGLE_VALUE_TYPE(switches::kEnableGoogleNowIntegration)
   1418   },
   1419 #endif
   1420 #if defined(OS_CHROMEOS)
   1421   {
   1422     "enable-virtual-keyboard",
   1423     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_NAME,
   1424     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_DESCRIPTION,
   1425     kOsCrOS,
   1426     SINGLE_VALUE_TYPE(keyboard::switches::kEnableVirtualKeyboard)
   1427   },
   1428 #endif
   1429   {
   1430     "enable-simple-cache-backend",
   1431     IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_NAME,
   1432     IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_DESCRIPTION,
   1433     kOsAll,
   1434     MULTI_VALUE_TYPE(kSimpleCacheBackendChoices)
   1435   },
   1436   {
   1437     "enable-tcp-fast-open",
   1438     IDS_FLAGS_ENABLE_TCP_FAST_OPEN_NAME,
   1439     IDS_FLAGS_ENABLE_TCP_FAST_OPEN_DESCRIPTION,
   1440     kOsLinux | kOsCrOS | kOsAndroid,
   1441     SINGLE_VALUE_TYPE(switches::kEnableTcpFastOpen)
   1442   },
   1443   {
   1444     "apps-use-native-frame",
   1445     IDS_FLAGS_ENABLE_NATIVE_FRAMES_FOR_APPS_NAME,
   1446     IDS_FLAGS_ENABLE_NATIVE_FRAMES_FOR_APPS_DESCRIPTION,
   1447     kOsMac | kOsWin,
   1448     SINGLE_VALUE_TYPE(switches::kAppsUseNativeFrame)
   1449   },
   1450   {
   1451     "enable-syncfs-directory-operation",
   1452     IDS_FLAGS_ENABLE_SYNC_DIRECTORY_OPERATION_NAME,
   1453     IDS_FLAGS_ENABLE_SYNC_DIRECTORY_OPERATION_DESCRIPTION,
   1454     kOsAll,
   1455     SINGLE_VALUE_TYPE(switches::kSyncfsEnableDirectoryOperation),
   1456   },
   1457   {
   1458     "enable-reset-profile-settings",
   1459     IDS_FLAGS_ENABLE_RESET_PROFILE_SETTINGS_NAME,
   1460     IDS_FLAGS_ENABLE_RESET_PROFILE_SETTINGS_DESCRIPTION,
   1461     kOsAll,
   1462     SINGLE_VALUE_TYPE(switches::kEnableResetProfileSettings)
   1463   },
   1464   {
   1465     "enable-device-discovery",
   1466     IDS_FLAGS_ENABLE_DEVICE_DISCOVERY_NAME,
   1467     IDS_FLAGS_ENABLE_DEVICE_DISCOVERY_DESCRIPTION,
   1468     kOsDesktop,
   1469     SINGLE_VALUE_TYPE(switches::kEnableDeviceDiscovery)
   1470   },
   1471 #if defined(OS_MACOSX)
   1472   {
   1473     "enable-app-list-shim",
   1474     IDS_FLAGS_ENABLE_APP_LIST_SHIM_NAME,
   1475     IDS_FLAGS_ENABLE_APP_LIST_SHIM_DESCRIPTION,
   1476     kOsMac,
   1477     SINGLE_VALUE_TYPE(switches::kEnableAppListShim)
   1478   },
   1479   {
   1480     "enable-app-shims",
   1481     IDS_FLAGS_ENABLE_APP_SHIMS_NAME,
   1482     IDS_FLAGS_ENABLE_APP_SHIMS_DESCRIPTION,
   1483     kOsMac,
   1484     SINGLE_VALUE_TYPE(switches::kEnableAppShims)
   1485   },
   1486   {
   1487     "enable-simplified-fullscreen",
   1488     IDS_FLAGS_ENABLE_SIMPLIFIED_FULLSCREEN_NAME,
   1489     IDS_FLAGS_ENABLE_SIMPLIFIED_FULLSCREEN_DESCRIPTION,
   1490     kOsMac,
   1491     SINGLE_VALUE_TYPE(switches::kEnableSimplifiedFullscreen)
   1492   },
   1493 #endif
   1494 #if defined(OS_CHROMEOS) || defined(OS_WIN)
   1495   {
   1496     "omnibox-auto-completion-for-ime",
   1497     IDS_FLAGS_ENABLE_OMNIBOX_AUTO_COMPLETION_FOR_IME_NAME,
   1498     IDS_FLAGS_ENABLE_OMNIBOX_AUTO_COMPLETION_FOR_IME_DESCRIPTION,
   1499     kOsCrOS | kOsWin,
   1500     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOmniboxAutoCompletionForIme,
   1501                               switches::kDisableOmniboxAutoCompletionForIme)
   1502   },
   1503 #endif
   1504 #if defined(USE_AURA)
   1505   {
   1506     "tab-capture-upscale-quality",
   1507     IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_NAME,
   1508     IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_DESCRIPTION,
   1509     kOsAll,
   1510     MULTI_VALUE_TYPE(kTabCaptureUpscaleQualityChoices)
   1511   },
   1512   {
   1513     "tab-capture-downscale-quality",
   1514     IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_NAME,
   1515     IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_DESCRIPTION,
   1516     kOsAll,
   1517     MULTI_VALUE_TYPE(kTabCaptureDownscaleQualityChoices)
   1518   },
   1519 #endif
   1520   {
   1521     "enable-spelling-service-feedback",
   1522     IDS_FLAGS_ENABLE_SPELLING_SERVICE_FEEDBACK_NAME,
   1523     IDS_FLAGS_ENABLE_SPELLING_SERVICE_FEEDBACK_DESCRIPTION,
   1524     kOsAll,
   1525     SINGLE_VALUE_TYPE(switches::kEnableSpellingServiceFeedback)
   1526   },
   1527   {
   1528     "enable-webgl-draft-extensions",
   1529     IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_NAME,
   1530     IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_DESCRIPTION,
   1531     kOsAll,
   1532     SINGLE_VALUE_TYPE(switches::kEnableWebGLDraftExtensions)
   1533   },
   1534   {
   1535     "enable-html-imports",
   1536     IDS_FLAGS_ENABLE_HTML_IMPORTS_NAME,
   1537     IDS_FLAGS_ENABLE_HTML_IMPORTS_DESCRIPTION,
   1538     kOsAll,
   1539     SINGLE_VALUE_TYPE(switches::kEnableHTMLImports)
   1540   },
   1541   {
   1542     "high-dpi-support",
   1543     IDS_FLAGS_HIDPI_NAME,
   1544     IDS_FLAGS_HIDPI_DESCRIPTION,
   1545     kOsWin,
   1546     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kHighDPISupport,"1",
   1547         switches::kHighDPISupport,"0")
   1548   },
   1549 #if defined(OS_CHROMEOS)
   1550   {
   1551     "enable-quickoffice-viewing",
   1552     IDS_FLAGS_ENABLE_QUICKOFFICE_DESKTOP_VIEWING_NAME,
   1553     IDS_FLAGS_ENABLE_QUICKOFFICE_DESKTOP_VIEWING_DESCRIPTION,
   1554     kOsCrOS,
   1555     SINGLE_VALUE_TYPE(switches::kEnableQuickofficeViewing),
   1556   },
   1557   {
   1558     "enable-sticky-keys",
   1559     IDS_FLAGS_ENABLE_STICKY_KEYS_NAME,
   1560     IDS_FLAGS_ENABLE_STICKY_KEYS_DESCRIPTION,
   1561     kOsCrOS,
   1562     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableStickyKeys,
   1563                               switches::kDisableStickyKeys)
   1564   },
   1565 #endif
   1566   {
   1567     "enable-translate-settings",
   1568     IDS_FLAGS_ENABLE_TRANSLATE_SETTINGS_NAME,
   1569     IDS_FLAGS_ENABLE_TRANSLATE_SETTINGS_DESCRIPTION,
   1570     kOsAll,
   1571     SINGLE_VALUE_TYPE(switches::kEnableTranslateSettings)
   1572   },
   1573   {
   1574     "enable-web-midi",
   1575     IDS_FLAGS_ENABLE_WEB_MIDI_NAME,
   1576     IDS_FLAGS_ENABLE_WEB_MIDI_DESCRIPTION,
   1577     kOsMac,
   1578     SINGLE_VALUE_TYPE(switches::kEnableWebMIDI)
   1579   },
   1580   {
   1581     "enable-new-profile-management",
   1582     IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_NAME,
   1583     IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_DESCRIPTION,
   1584     kOsWin,
   1585     SINGLE_VALUE_TYPE(switches::kNewProfileManagement)
   1586   },
   1587   {
   1588     "enable-gaia-profile-info",
   1589     IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_NAME,
   1590     IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_DESCRIPTION,
   1591     kOsMac | kOsWin | kOsLinux,
   1592     SINGLE_VALUE_TYPE(switches::kGaiaProfileInfo)
   1593   },
   1594 #if defined(OS_WIN)
   1595   {
   1596     "disable-app-launcher",
   1597     IDS_FLAGS_DISABLE_APP_LIST_NAME,
   1598     IDS_FLAGS_DISABLE_APP_LIST_DESCRIPTION,
   1599     kOsAll,
   1600     SINGLE_VALUE_TYPE(switches::kDisableAppList)
   1601   },
   1602 #endif
   1603   {
   1604     "disable-compositor-touch-hit-testing",
   1605     IDS_FLAGS_DISABLE_COMPOSITOR_TOUCH_HIT_TESTING_NAME,
   1606     IDS_FLAGS_DISABLE_COMPOSITOR_TOUCH_HIT_TESTING_DESCRIPTION,
   1607     kOsAll,
   1608     SINGLE_VALUE_TYPE(cc::switches::kDisableCompositorTouchHitTesting),
   1609   },
   1610 };
   1611 
   1612 const Experiment* experiments = kExperiments;
   1613 size_t num_experiments = arraysize(kExperiments);
   1614 
   1615 // Stores and encapsulates the little state that about:flags has.
   1616 class FlagsState {
   1617  public:
   1618   FlagsState() : needs_restart_(false) {}
   1619   void ConvertFlagsToSwitches(FlagsStorage* flags_storage,
   1620                               CommandLine* command_line);
   1621   bool IsRestartNeededToCommitChanges();
   1622   void SetExperimentEnabled(
   1623       FlagsStorage* flags_storage,
   1624       const std::string& internal_name,
   1625       bool enable);
   1626   void RemoveFlagsSwitches(
   1627       std::map<std::string, CommandLine::StringType>* switch_list);
   1628   void ResetAllFlags(FlagsStorage* flags_storage);
   1629   void reset();
   1630 
   1631   // Returns the singleton instance of this class
   1632   static FlagsState* GetInstance() {
   1633     return Singleton<FlagsState>::get();
   1634   }
   1635 
   1636  private:
   1637   bool needs_restart_;
   1638   std::map<std::string, std::string> flags_switches_;
   1639 
   1640   DISALLOW_COPY_AND_ASSIGN(FlagsState);
   1641 };
   1642 
   1643 // Adds the internal names for the specified experiment to |names|.
   1644 void AddInternalName(const Experiment& e, std::set<std::string>* names) {
   1645   if (e.type == Experiment::SINGLE_VALUE) {
   1646     names->insert(e.internal_name);
   1647   } else {
   1648     DCHECK(e.type == Experiment::MULTI_VALUE ||
   1649            e.type == Experiment::ENABLE_DISABLE_VALUE);
   1650     for (int i = 0; i < e.num_choices; ++i)
   1651       names->insert(e.NameForChoice(i));
   1652   }
   1653 }
   1654 
   1655 // Confirms that an experiment is valid, used in a DCHECK in
   1656 // SanitizeList below.
   1657 bool ValidateExperiment(const Experiment& e) {
   1658   switch (e.type) {
   1659     case Experiment::SINGLE_VALUE:
   1660       DCHECK_EQ(0, e.num_choices);
   1661       DCHECK(!e.choices);
   1662       break;
   1663     case Experiment::MULTI_VALUE:
   1664       DCHECK_GT(e.num_choices, 0);
   1665       DCHECK(e.choices);
   1666       DCHECK(e.choices[0].command_line_switch);
   1667       DCHECK_EQ('\0', e.choices[0].command_line_switch[0]);
   1668       break;
   1669     case Experiment::ENABLE_DISABLE_VALUE:
   1670       DCHECK_EQ(3, e.num_choices);
   1671       DCHECK(!e.choices);
   1672       DCHECK(e.command_line_switch);
   1673       DCHECK(e.command_line_value);
   1674       DCHECK(e.disable_command_line_switch);
   1675       DCHECK(e.disable_command_line_value);
   1676       break;
   1677     default:
   1678       NOTREACHED();
   1679   }
   1680   return true;
   1681 }
   1682 
   1683 // Removes all experiments from prefs::kEnabledLabsExperiments that are
   1684 // unknown, to prevent this list to become very long as experiments are added
   1685 // and removed.
   1686 void SanitizeList(FlagsStorage* flags_storage) {
   1687   std::set<std::string> known_experiments;
   1688   for (size_t i = 0; i < num_experiments; ++i) {
   1689     DCHECK(ValidateExperiment(experiments[i]));
   1690     AddInternalName(experiments[i], &known_experiments);
   1691   }
   1692 
   1693   std::set<std::string> enabled_experiments = flags_storage->GetFlags();
   1694 
   1695   std::set<std::string> new_enabled_experiments;
   1696   std::set_intersection(
   1697       known_experiments.begin(), known_experiments.end(),
   1698       enabled_experiments.begin(), enabled_experiments.end(),
   1699       std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
   1700 
   1701   if (new_enabled_experiments != enabled_experiments)
   1702     flags_storage->SetFlags(new_enabled_experiments);
   1703 }
   1704 
   1705 void GetSanitizedEnabledFlags(
   1706     FlagsStorage* flags_storage, std::set<std::string>* result) {
   1707   SanitizeList(flags_storage);
   1708   *result = flags_storage->GetFlags();
   1709 }
   1710 
   1711 // Variant of GetSanitizedEnabledFlags that also removes any flags that aren't
   1712 // enabled on the current platform.
   1713 void GetSanitizedEnabledFlagsForCurrentPlatform(
   1714     FlagsStorage* flags_storage, std::set<std::string>* result) {
   1715   GetSanitizedEnabledFlags(flags_storage, result);
   1716 
   1717   // Filter out any experiments that aren't enabled on the current platform.  We
   1718   // don't remove these from prefs else syncing to a platform with a different
   1719   // set of experiments would be lossy.
   1720   std::set<std::string> platform_experiments;
   1721   int current_platform = GetCurrentPlatform();
   1722   for (size_t i = 0; i < num_experiments; ++i) {
   1723     if (experiments[i].supported_platforms & current_platform)
   1724       AddInternalName(experiments[i], &platform_experiments);
   1725 #if defined(OS_CHROMEOS)
   1726     if (experiments[i].supported_platforms & kOsCrOSOwnerOnly)
   1727       AddInternalName(experiments[i], &platform_experiments);
   1728 #endif
   1729   }
   1730 
   1731   std::set<std::string> new_enabled_experiments;
   1732   std::set_intersection(
   1733       platform_experiments.begin(), platform_experiments.end(),
   1734       result->begin(), result->end(),
   1735       std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
   1736 
   1737   result->swap(new_enabled_experiments);
   1738 }
   1739 
   1740 // Returns the Value representing the choice data in the specified experiment.
   1741 Value* CreateChoiceData(const Experiment& experiment,
   1742                         const std::set<std::string>& enabled_experiments) {
   1743   DCHECK(experiment.type == Experiment::MULTI_VALUE ||
   1744          experiment.type == Experiment::ENABLE_DISABLE_VALUE);
   1745   ListValue* result = new ListValue;
   1746   for (int i = 0; i < experiment.num_choices; ++i) {
   1747     DictionaryValue* value = new DictionaryValue;
   1748     const std::string name = experiment.NameForChoice(i);
   1749     value->SetString("internal_name", name);
   1750     value->SetString("description", experiment.DescriptionForChoice(i));
   1751     value->SetBoolean("selected", enabled_experiments.count(name) > 0);
   1752     result->Append(value);
   1753   }
   1754   return result;
   1755 }
   1756 
   1757 }  // namespace
   1758 
   1759 std::string Experiment::NameForChoice(int index) const {
   1760   DCHECK(type == Experiment::MULTI_VALUE ||
   1761          type == Experiment::ENABLE_DISABLE_VALUE);
   1762   DCHECK_LT(index, num_choices);
   1763   return std::string(internal_name) + testing::kMultiSeparator +
   1764          base::IntToString(index);
   1765 }
   1766 
   1767 string16 Experiment::DescriptionForChoice(int index) const {
   1768   DCHECK(type == Experiment::MULTI_VALUE ||
   1769          type == Experiment::ENABLE_DISABLE_VALUE);
   1770   DCHECK_LT(index, num_choices);
   1771   int description_id;
   1772   if (type == Experiment::ENABLE_DISABLE_VALUE) {
   1773     const int kEnableDisableDescriptionIds[] = {
   1774       IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT,
   1775       IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
   1776       IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
   1777     };
   1778     description_id = kEnableDisableDescriptionIds[index];
   1779   } else {
   1780     description_id = choices[index].description_id;
   1781   }
   1782   return l10n_util::GetStringUTF16(description_id);
   1783 }
   1784 
   1785 void ConvertFlagsToSwitches(FlagsStorage* flags_storage,
   1786                             CommandLine* command_line) {
   1787   FlagsState::GetInstance()->ConvertFlagsToSwitches(flags_storage,
   1788                                                     command_line);
   1789 }
   1790 
   1791 bool AreSwitchesIdenticalToCurrentCommandLine(
   1792     const CommandLine& new_cmdline, const CommandLine& active_cmdline) {
   1793   std::set<CommandLine::StringType> new_flags =
   1794       ExtractFlagsFromCommandLine(new_cmdline);
   1795   std::set<CommandLine::StringType> active_flags =
   1796       ExtractFlagsFromCommandLine(active_cmdline);
   1797 
   1798   // Needed because std::equal doesn't check if the 2nd set is empty.
   1799   if (new_flags.size() != active_flags.size())
   1800     return false;
   1801 
   1802   return std::equal(new_flags.begin(), new_flags.end(), active_flags.begin());
   1803 }
   1804 
   1805 void GetFlagsExperimentsData(FlagsStorage* flags_storage,
   1806                              FlagAccess access,
   1807                              base::ListValue* supported_experiments,
   1808                              base::ListValue* unsupported_experiments) {
   1809   std::set<std::string> enabled_experiments;
   1810   GetSanitizedEnabledFlags(flags_storage, &enabled_experiments);
   1811 
   1812   int current_platform = GetCurrentPlatform();
   1813 
   1814   for (size_t i = 0; i < num_experiments; ++i) {
   1815     const Experiment& experiment = experiments[i];
   1816 
   1817     DictionaryValue* data = new DictionaryValue();
   1818     data->SetString("internal_name", experiment.internal_name);
   1819     data->SetString("name",
   1820                     l10n_util::GetStringUTF16(experiment.visible_name_id));
   1821     data->SetString("description",
   1822                     l10n_util::GetStringUTF16(
   1823                         experiment.visible_description_id));
   1824 
   1825     ListValue* supported_platforms = new ListValue();
   1826     AddOsStrings(experiment.supported_platforms, supported_platforms);
   1827     data->Set("supported_platforms", supported_platforms);
   1828 
   1829     switch (experiment.type) {
   1830       case Experiment::SINGLE_VALUE:
   1831         data->SetBoolean(
   1832             "enabled",
   1833             enabled_experiments.count(experiment.internal_name) > 0);
   1834         break;
   1835       case Experiment::MULTI_VALUE:
   1836       case Experiment::ENABLE_DISABLE_VALUE:
   1837         data->Set("choices", CreateChoiceData(experiment, enabled_experiments));
   1838         break;
   1839       default:
   1840         NOTREACHED();
   1841     }
   1842 
   1843     bool supported = (experiment.supported_platforms & current_platform) != 0;
   1844 #if defined(OS_CHROMEOS)
   1845     if (access == kOwnerAccessToFlags &&
   1846         (experiment.supported_platforms & kOsCrOSOwnerOnly) != 0) {
   1847       supported = true;
   1848     }
   1849 #endif
   1850     if (supported)
   1851       supported_experiments->Append(data);
   1852     else
   1853       unsupported_experiments->Append(data);
   1854   }
   1855 }
   1856 
   1857 bool IsRestartNeededToCommitChanges() {
   1858   return FlagsState::GetInstance()->IsRestartNeededToCommitChanges();
   1859 }
   1860 
   1861 void SetExperimentEnabled(FlagsStorage* flags_storage,
   1862                           const std::string& internal_name,
   1863                           bool enable) {
   1864   FlagsState::GetInstance()->SetExperimentEnabled(flags_storage,
   1865                                                   internal_name, enable);
   1866 }
   1867 
   1868 void RemoveFlagsSwitches(
   1869     std::map<std::string, CommandLine::StringType>* switch_list) {
   1870   FlagsState::GetInstance()->RemoveFlagsSwitches(switch_list);
   1871 }
   1872 
   1873 void ResetAllFlags(FlagsStorage* flags_storage) {
   1874   FlagsState::GetInstance()->ResetAllFlags(flags_storage);
   1875 }
   1876 
   1877 int GetCurrentPlatform() {
   1878 #if defined(OS_MACOSX)
   1879   return kOsMac;
   1880 #elif defined(OS_WIN)
   1881   return kOsWin;
   1882 #elif defined(OS_CHROMEOS)  // Needs to be before the OS_LINUX check.
   1883   return kOsCrOS;
   1884 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
   1885   return kOsLinux;
   1886 #elif defined(OS_ANDROID)
   1887   return kOsAndroid;
   1888 #else
   1889 #error Unknown platform
   1890 #endif
   1891 }
   1892 
   1893 void RecordUMAStatistics(FlagsStorage* flags_storage) {
   1894   std::set<std::string> flags = flags_storage->GetFlags();
   1895   for (std::set<std::string>::iterator it = flags.begin(); it != flags.end();
   1896        ++it) {
   1897     std::string action("AboutFlags_");
   1898     action += *it;
   1899     content::RecordComputedAction(action);
   1900   }
   1901   // Since flag metrics are recorded every startup, add a tick so that the
   1902   // stats can be made meaningful.
   1903   if (flags.size())
   1904     content::RecordAction(UserMetricsAction("AboutFlags_StartupTick"));
   1905   content::RecordAction(UserMetricsAction("StartupTick"));
   1906 }
   1907 
   1908 //////////////////////////////////////////////////////////////////////////////
   1909 // FlagsState implementation.
   1910 
   1911 namespace {
   1912 
   1913 typedef std::map<std::string, std::pair<std::string, std::string> >
   1914     NameToSwitchAndValueMap;
   1915 
   1916 void SetFlagToSwitchMapping(const std::string& key,
   1917                             const std::string& switch_name,
   1918                             const std::string& switch_value,
   1919                             NameToSwitchAndValueMap* name_to_switch_map) {
   1920   DCHECK(name_to_switch_map->end() == name_to_switch_map->find(key));
   1921   (*name_to_switch_map)[key] = std::make_pair(switch_name, switch_value);
   1922 }
   1923 
   1924 void FlagsState::ConvertFlagsToSwitches(
   1925     FlagsStorage* flags_storage, CommandLine* command_line) {
   1926   if (command_line->HasSwitch(switches::kNoExperiments))
   1927     return;
   1928 
   1929   std::set<std::string> enabled_experiments;
   1930 
   1931   GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage,
   1932                                              &enabled_experiments);
   1933 
   1934   NameToSwitchAndValueMap name_to_switch_map;
   1935   for (size_t i = 0; i < num_experiments; ++i) {
   1936     const Experiment& e = experiments[i];
   1937     if (e.type == Experiment::SINGLE_VALUE) {
   1938       SetFlagToSwitchMapping(e.internal_name, e.command_line_switch,
   1939                              e.command_line_value, &name_to_switch_map);
   1940     } else if (e.type == Experiment::MULTI_VALUE) {
   1941       for (int j = 0; j < e.num_choices; ++j) {
   1942         SetFlagToSwitchMapping(e.NameForChoice(j),
   1943                                e.choices[j].command_line_switch,
   1944                                e.choices[j].command_line_value,
   1945                                &name_to_switch_map);
   1946       }
   1947     } else {
   1948       DCHECK_EQ(e.type, Experiment::ENABLE_DISABLE_VALUE);
   1949       SetFlagToSwitchMapping(e.NameForChoice(0), std::string(), std::string(),
   1950                              &name_to_switch_map);
   1951       SetFlagToSwitchMapping(e.NameForChoice(1), e.command_line_switch,
   1952                              e.command_line_value, &name_to_switch_map);
   1953       SetFlagToSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch,
   1954                              e.disable_command_line_value, &name_to_switch_map);
   1955     }
   1956   }
   1957 
   1958   command_line->AppendSwitch(switches::kFlagSwitchesBegin);
   1959   flags_switches_.insert(
   1960       std::pair<std::string, std::string>(switches::kFlagSwitchesBegin,
   1961                                           std::string()));
   1962   for (std::set<std::string>::iterator it = enabled_experiments.begin();
   1963        it != enabled_experiments.end();
   1964        ++it) {
   1965     const std::string& experiment_name = *it;
   1966     NameToSwitchAndValueMap::const_iterator name_to_switch_it =
   1967         name_to_switch_map.find(experiment_name);
   1968     if (name_to_switch_it == name_to_switch_map.end()) {
   1969       NOTREACHED();
   1970       continue;
   1971     }
   1972 
   1973     const std::pair<std::string, std::string>&
   1974         switch_and_value_pair = name_to_switch_it->second;
   1975 
   1976     command_line->AppendSwitchASCII(switch_and_value_pair.first,
   1977                                     switch_and_value_pair.second);
   1978     flags_switches_[switch_and_value_pair.first] = switch_and_value_pair.second;
   1979   }
   1980   command_line->AppendSwitch(switches::kFlagSwitchesEnd);
   1981   flags_switches_.insert(
   1982       std::pair<std::string, std::string>(switches::kFlagSwitchesEnd,
   1983                                           std::string()));
   1984 }
   1985 
   1986 bool FlagsState::IsRestartNeededToCommitChanges() {
   1987   return needs_restart_;
   1988 }
   1989 
   1990 void FlagsState::SetExperimentEnabled(FlagsStorage* flags_storage,
   1991                                       const std::string& internal_name,
   1992                                       bool enable) {
   1993   size_t at_index = internal_name.find(testing::kMultiSeparator);
   1994   if (at_index != std::string::npos) {
   1995     DCHECK(enable);
   1996     // We're being asked to enable a multi-choice experiment. Disable the
   1997     // currently selected choice.
   1998     DCHECK_NE(at_index, 0u);
   1999     const std::string experiment_name = internal_name.substr(0, at_index);
   2000     SetExperimentEnabled(flags_storage, experiment_name, false);
   2001 
   2002     // And enable the new choice, if it is not the default first choice.
   2003     if (internal_name != experiment_name + "@0") {
   2004       std::set<std::string> enabled_experiments;
   2005       GetSanitizedEnabledFlags(flags_storage, &enabled_experiments);
   2006       needs_restart_ |= enabled_experiments.insert(internal_name).second;
   2007       flags_storage->SetFlags(enabled_experiments);
   2008     }
   2009     return;
   2010   }
   2011 
   2012   std::set<std::string> enabled_experiments;
   2013   GetSanitizedEnabledFlags(flags_storage, &enabled_experiments);
   2014 
   2015   const Experiment* e = NULL;
   2016   for (size_t i = 0; i < num_experiments; ++i) {
   2017     if (experiments[i].internal_name == internal_name) {
   2018       e = experiments + i;
   2019       break;
   2020     }
   2021   }
   2022   DCHECK(e);
   2023 
   2024   if (e->type == Experiment::SINGLE_VALUE) {
   2025     if (enable)
   2026       needs_restart_ |= enabled_experiments.insert(internal_name).second;
   2027     else
   2028       needs_restart_ |= (enabled_experiments.erase(internal_name) > 0);
   2029   } else {
   2030     if (enable) {
   2031       // Enable the first choice.
   2032       needs_restart_ |= enabled_experiments.insert(e->NameForChoice(0)).second;
   2033     } else {
   2034       // Find the currently enabled choice and disable it.
   2035       for (int i = 0; i < e->num_choices; ++i) {
   2036         std::string choice_name = e->NameForChoice(i);
   2037         if (enabled_experiments.find(choice_name) !=
   2038             enabled_experiments.end()) {
   2039           needs_restart_ = true;
   2040           enabled_experiments.erase(choice_name);
   2041           // Continue on just in case there's a bug and more than one
   2042           // experiment for this choice was enabled.
   2043         }
   2044       }
   2045     }
   2046   }
   2047 
   2048   flags_storage->SetFlags(enabled_experiments);
   2049 }
   2050 
   2051 void FlagsState::RemoveFlagsSwitches(
   2052     std::map<std::string, CommandLine::StringType>* switch_list) {
   2053   for (std::map<std::string, std::string>::const_iterator
   2054            it = flags_switches_.begin(); it != flags_switches_.end(); ++it) {
   2055     switch_list->erase(it->first);
   2056   }
   2057 }
   2058 
   2059 void FlagsState::ResetAllFlags(FlagsStorage* flags_storage) {
   2060   needs_restart_ = true;
   2061 
   2062   std::set<std::string> no_experiments;
   2063   flags_storage->SetFlags(no_experiments);
   2064 }
   2065 
   2066 void FlagsState::reset() {
   2067   needs_restart_ = false;
   2068   flags_switches_.clear();
   2069 }
   2070 
   2071 }  // namespace
   2072 
   2073 namespace testing {
   2074 
   2075 // WARNING: '@' is also used in the html file. If you update this constant you
   2076 // also need to update the html file.
   2077 const char kMultiSeparator[] = "@";
   2078 
   2079 void ClearState() {
   2080   FlagsState::GetInstance()->reset();
   2081 }
   2082 
   2083 void SetExperiments(const Experiment* e, size_t count) {
   2084   if (!e) {
   2085     experiments = kExperiments;
   2086     num_experiments = arraysize(kExperiments);
   2087   } else {
   2088     experiments = e;
   2089     num_experiments = count;
   2090   }
   2091 }
   2092 
   2093 const Experiment* GetExperiments(size_t* count) {
   2094   *count = num_experiments;
   2095   return experiments;
   2096 }
   2097 
   2098 }  // namespace testing
   2099 
   2100 }  // namespace about_flags
   2101