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