blob: 281c3f3f74dbbe802d66a605185407501e8751d7 [file] [log] [blame]
[email protected]9c66adc2012-01-05 02:10:161// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ad2a3ded2010-08-27 13:19:052// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]1a47d7e2010-10-15 00:37:245#include "chrome/browser/about_flags.h"
[email protected]ad2a3ded2010-08-27 13:19:056
7#include <algorithm>
8#include <iterator>
9#include <map>
10#include <set>
11
[email protected]ad2a3ded2010-08-27 13:19:0512#include "base/command_line.h"
[email protected]3b63f8f42011-03-28 01:54:1513#include "base/memory/singleton.h"
[email protected]8a6ff28d2010-12-02 16:35:1914#include "base/string_number_conversions.h"
[email protected]d208f4d82011-05-23 21:52:0315#include "base/utf_string_conversions.h"
[email protected]ad2a3ded2010-08-27 13:19:0516#include "base/values.h"
[email protected]ad2a3ded2010-08-27 13:19:0517#include "chrome/browser/prefs/pref_service.h"
[email protected]1bc78422011-03-31 08:41:3818#include "chrome/browser/prefs/scoped_user_pref_update.h"
[email protected]d208f4d82011-05-23 21:52:0319#include "chrome/common/chrome_content_client.h"
[email protected]ad2a3ded2010-08-27 13:19:0520#include "chrome/common/chrome_switches.h"
21#include "chrome/common/pref_names.h"
[email protected]7f6f44c2011-12-14 13:23:3822#include "content/public/browser/user_metrics.h"
[email protected]ad2a3ded2010-08-27 13:19:0523#include "grit/generated_resources.h"
[email protected]c051a1b2011-01-21 23:30:1724#include "ui/base/l10n/l10n_util.h"
[email protected]8ff7f342011-05-25 01:49:4725#include "ui/gfx/gl/gl_switches.h"
[email protected]ad2a3ded2010-08-27 13:19:0526
[email protected]dc04be7c2012-03-15 23:57:4927#if defined(USE_ASH)
[email protected]b65bdda2011-12-23 23:35:3128#include "ash/ash_switches.h"
[email protected]dc04be7c2012-03-15 23:57:4929#endif
30
31#if defined(USE_AURA)
[email protected]308aaa32012-03-12 13:14:5032#include "ui/aura/aura_switches.h"
[email protected]8cc10df2011-11-03 23:57:5033#endif
34
[email protected]7f6f44c2011-12-14 13:23:3835using content::UserMetricsAction;
36
[email protected]1a47d7e2010-10-15 00:37:2437namespace about_flags {
[email protected]ad2a3ded2010-08-27 13:19:0538
[email protected]8a6ff28d2010-12-02 16:35:1939// Macros to simplify specifying the type.
[email protected]a82744532011-02-11 16:15:5340#define SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \
41 Experiment::SINGLE_VALUE, command_line_switch, switch_value, NULL, 0
42#define SINGLE_VALUE_TYPE(command_line_switch) \
43 SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, "")
44#define MULTI_VALUE_TYPE(choices) \
[email protected]0e6f56d2011-02-12 23:45:1545 Experiment::MULTI_VALUE, "", "", choices, arraysize(choices)
[email protected]8a6ff28d2010-12-02 16:35:1946
[email protected]e2ddbc92010-10-15 20:02:0747namespace {
48
[email protected]9c7453d2012-01-21 00:45:4049const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid;
[email protected]ad2a3ded2010-08-27 13:19:0550
[email protected]cc3e2052011-12-20 01:01:4051// Adds a |StringValue| to |list| for each platform where |bitmask| indicates
52// whether the experiment is available on that platform.
53void AddOsStrings(unsigned bitmask, ListValue* list) {
54 struct {
55 unsigned bit;
56 const char* const name;
57 } kBitsToOs[] = {
58 {kOsMac, "Mac"},
59 {kOsWin, "Windows"},
60 {kOsLinux, "Linux"},
61 {kOsCrOS, "Chrome OS"},
62 };
63 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kBitsToOs); ++i)
64 if (bitmask & kBitsToOs[i].bit)
65 list->Append(new StringValue(kBitsToOs[i].name));
66}
67
[email protected]ba8164242010-11-16 21:31:0068// Names for former Chrome OS Labs experiments, shared with prefs migration
69// code.
70const char kMediaPlayerExperimentName[] = "media-player";
71const char kAdvancedFileSystemExperimentName[] = "advanced-file-system";
72const char kVerticalTabsExperimentName[] = "vertical-tabs";
73
[email protected]9b2c9f6a12012-01-27 21:00:0574const Experiment::Choice kOmniboxAggressiveHistoryURLChoices[] = {
75 { IDS_FLAGS_OMNIBOX_AGGRESSIVE_HISTORY_URL_SCORING_AUTOMATIC, "", "" },
76 { IDS_FLAGS_OMNIBOX_AGGRESSIVE_HISTORY_URL_SCORING_ENABLED,
77 switches::kOmniboxAggressiveHistoryURL,
78 switches::kOmniboxAggressiveHistoryURLEnabled },
79 { IDS_FLAGS_OMNIBOX_AGGRESSIVE_HISTORY_URL_SCORING_DISABLED,
80 switches::kOmniboxAggressiveHistoryURL,
81 switches::kOmniboxAggressiveHistoryURLDisabled }
82};
83
[email protected]032d5e6c2012-02-17 17:53:5584const Experiment::Choice kOmniboxInlineHistoryQuickProviderChoices[] = {
85 { IDS_FLAGS_OMNIBOX_INLINE_HISTORY_QUICK_PROVIDER_AUTOMATIC, "", "" },
86 { IDS_FLAGS_OMNIBOX_INLINE_HISTORY_QUICK_PROVIDER_ALLOWED,
87 switches::kOmniboxInlineHistoryQuickProvider,
88 switches::kOmniboxInlineHistoryQuickProviderAllowed },
89 { IDS_FLAGS_OMNIBOX_INLINE_HISTORY_QUICK_PROVIDER_PROHIBITED,
90 switches::kOmniboxInlineHistoryQuickProvider,
91 switches::kOmniboxInlineHistoryQuickProviderProhibited }
92};
93
[email protected]4bc5050c2010-11-18 17:55:5494// RECORDING USER METRICS FOR FLAGS:
95// -----------------------------------------------------------------------------
96// The first line of the experiment is the internal name. If you'd like to
97// gather statistics about the usage of your flag, you should append a marker
98// comment to the end of the feature name, like so:
99// "my-special-feature", // FLAGS:RECORD_UMA
100//
101// After doing that, run //chrome/tools/extract_actions.py (see instructions at
102// the top of that file for details) to update the chromeactions.txt file, which
103// will enable UMA to record your feature flag.
104//
105// After your feature has shipped under a flag, you can locate the metrics
106// under the action name AboutFlags_internal-action-name. Actions are recorded
107// once per startup, so you should divide this number by AboutFlags_StartupTick
108// to get a sense of usage. Note that this will not be the same as number of
109// users with a given feature enabled because users can quit and relaunch
110// the application multiple times over a given time interval.
111// TODO(rsesek): See if there's a way to count per-user, rather than
112// per-startup.
113
[email protected]8a6ff28d2010-12-02 16:35:19114// To add a new experiment add to the end of kExperiments. There are two
115// distinct types of experiments:
116// . SINGLE_VALUE: experiment is either on or off. Use the SINGLE_VALUE_TYPE
117// macro for this type supplying the command line to the macro.
[email protected]28e35af2011-02-09 12:56:22118// . MULTI_VALUE: a list of choices, the first of which should correspond to a
119// deactivated state for this lab (i.e. no command line option). To specify
120// this type of experiment use the macro MULTI_VALUE_TYPE supplying it the
121// array of choices.
[email protected]8a6ff28d2010-12-02 16:35:19122// See the documentation of Experiment for details on the fields.
123//
124// When adding a new choice, add it to the end of the list.
[email protected]ad2a3ded2010-08-27 13:19:05125const Experiment kExperiments[] = {
126 {
[email protected]aac169d2011-03-18 19:53:03127 "expose-for-tabs", // FLAGS:RECORD_UMA
128 IDS_FLAGS_TABPOSE_NAME,
129 IDS_FLAGS_TABPOSE_DESCRIPTION,
130 kOsMac,
131#if defined(OS_MACOSX)
132 // The switch exists only on OS X.
133 SINGLE_VALUE_TYPE(switches::kEnableExposeForTabs)
134#else
135 SINGLE_VALUE_TYPE("")
136#endif
137 },
138 {
[email protected]4bc5050c2010-11-18 17:55:54139 "conflicting-modules-check", // FLAGS:RECORD_UMA
[email protected]c1bbaa82010-11-08 11:17:05140 IDS_FLAGS_CONFLICTS_CHECK_NAME,
141 IDS_FLAGS_CONFLICTS_CHECK_DESCRIPTION,
142 kOsWin,
[email protected]8a6ff28d2010-12-02 16:35:19143 SINGLE_VALUE_TYPE(switches::kConflictingModulesCheck)
[email protected]c1bbaa82010-11-08 11:17:05144 },
145 {
[email protected]4bc5050c2010-11-18 17:55:54146 "cloud-print-proxy", // FLAGS:RECORD_UMA
[email protected]dae7325b2011-12-21 20:56:54147 IDS_FLAGS_CLOUD_PRINT_CONNECTOR_NAME,
148 IDS_FLAGS_CLOUD_PRINT_CONNECTOR_DESCRIPTION,
[email protected]9f8872b32011-03-04 19:44:45149 // For a Chrome build, we know we have a PDF plug-in on Windows, so it's
[email protected]4fa24bf2011-08-20 02:15:22150 // fully enabled.
[email protected]5d10d57d2011-07-22 22:16:31151 // Otherwise, where we know Windows could be working if a viable PDF
[email protected]4fa24bf2011-08-20 02:15:22152 // plug-in could be supplied, we'll keep the lab enabled. Mac and Linux
153 // always have PDF rasterization available, so no flag needed there.
154#if !defined(GOOGLE_CHROME_BUILD)
155 kOsWin,
156#else
157 0,
[email protected]fa6d2a2f2010-11-30 21:47:19158#endif
[email protected]8a6ff28d2010-12-02 16:35:19159 SINGLE_VALUE_TYPE(switches::kEnableCloudPrintProxy)
[email protected]8b6588a2010-10-12 02:39:42160 },
[email protected]580939a2010-10-12 18:54:37161 {
[email protected]bb461532010-11-26 21:50:23162 "crxless-web-apps",
163 IDS_FLAGS_CRXLESS_WEB_APPS_NAME,
164 IDS_FLAGS_CRXLESS_WEB_APPS_DESCRIPTION,
165 kOsAll,
[email protected]8a6ff28d2010-12-02 16:35:19166 SINGLE_VALUE_TYPE(switches::kEnableCrxlessWebApps)
[email protected]bb461532010-11-26 21:50:23167 },
168 {
[email protected]96c6f4c2011-05-18 19:36:22169 "ignore-gpu-blacklist",
170 IDS_FLAGS_IGNORE_GPU_BLACKLIST_NAME,
171 IDS_FLAGS_IGNORE_GPU_BLACKLIST_DESCRIPTION,
172 kOsAll,
173 SINGLE_VALUE_TYPE(switches::kIgnoreGpuBlacklist)
174 },
175 {
[email protected]0110cf112011-07-02 00:39:43176 "force-compositing-mode-2",
[email protected]96c6f4c2011-05-18 19:36:22177 IDS_FLAGS_FORCE_COMPOSITING_MODE_NAME,
178 IDS_FLAGS_FORCE_COMPOSITING_MODE_DESCRIPTION,
179 kOsAll,
180 SINGLE_VALUE_TYPE(switches::kForceCompositingMode)
181 },
182 {
[email protected]644a1072012-03-16 09:29:59183 "enable-threaded-compositing",
184 IDS_FLAGS_ENABLE_THREADED_COMPOSITING_NAME,
185 IDS_FLAGS_ENABLE_THREADED_COMPOSITING_DESCRIPTION,
186 kOsAll,
187 SINGLE_VALUE_TYPE(switches::kEnableThreadedCompositing)
188 },
189 {
190 "enable-threaded-animation",
191 IDS_FLAGS_ENABLE_THREADED_ANIMATION_NAME,
192 IDS_FLAGS_ENABLE_THREADED_ANIMATION_DESCRIPTION,
193 kOsAll,
194 SINGLE_VALUE_TYPE(switches::kEnableThreadedAnimation)
195 },
196 {
[email protected]5963b772011-02-09 22:55:38197 "composited-layer-borders",
198 IDS_FLAGS_COMPOSITED_LAYER_BORDERS,
199 IDS_FLAGS_COMPOSITED_LAYER_BORDERS_DESCRIPTION,
200 kOsAll,
201 SINGLE_VALUE_TYPE(switches::kShowCompositedLayerBorders)
202 },
203 {
[email protected]a8f1eaa2011-03-07 19:00:58204 "show-fps-counter",
205 IDS_FLAGS_SHOW_FPS_COUNTER,
206 IDS_FLAGS_SHOW_FPS_COUNTER_DESCRIPTION,
207 kOsAll,
208 SINGLE_VALUE_TYPE(switches::kShowFPSCounter)
209 },
[email protected]8ff7f342011-05-25 01:49:47210 {
[email protected]70c98a332011-12-21 20:51:52211 "accelerated-filters",
212 IDS_FLAGS_ACCELERATED_FILTERS,
213 IDS_FLAGS_ACCELERATED_FILTERS_DESCRIPTION,
214 kOsAll,
215 SINGLE_VALUE_TYPE(switches::kEnableAcceleratedFilters)
216 },
217 {
[email protected]8ff7f342011-05-25 01:49:47218 "disable-gpu-vsync",
219 IDS_FLAGS_DISABLE_GPU_VSYNC_NAME,
220 IDS_FLAGS_DISABLE_GPU_VSYNC_DESCRIPTION,
221 kOsAll,
222 SINGLE_VALUE_TYPE(switches::kDisableGpuVsync)
223 },
[email protected]deaba6d52011-09-23 14:47:12224 {
225 "disable-webgl",
226 IDS_FLAGS_DISABLE_WEBGL_NAME,
227 IDS_FLAGS_DISABLE_WEBGL_DESCRIPTION,
228 kOsAll,
229 SINGLE_VALUE_TYPE(switches::kDisableExperimentalWebGL)
230 },
[email protected]eb00a762012-01-18 07:29:28231
232#if defined(GOOGLE_CHROME_BUILD)
233 // TODO(thestig) Remove this for bug 107600.
234 {
235 "disable-print-preview", // FLAGS:RECORD_UMA
236 IDS_FLAGS_DISABLE_PRINT_PREVIEW_NAME,
237 IDS_FLAGS_DISABLE_PRINT_PREVIEW_DESCRIPTION,
238 kOsAll,
239 SINGLE_VALUE_TYPE(switches::kDisablePrintPreview)
240 },
241#else
242 // For Chromium builds where users may not have the PDF plugin.
[email protected]8d260e52010-10-13 01:03:05243 {
[email protected]4bc5050c2010-11-18 17:55:54244 "print-preview", // FLAGS:RECORD_UMA
[email protected]9486c1f2010-10-14 19:52:12245 IDS_FLAGS_PRINT_PREVIEW_NAME,
246 IDS_FLAGS_PRINT_PREVIEW_DESCRIPTION,
[email protected]b579afd2011-07-13 00:01:27247 kOsAll,
[email protected]8a6ff28d2010-12-02 16:35:19248 SINGLE_VALUE_TYPE(switches::kEnablePrintPreview)
[email protected]2fe15fcb2010-10-21 20:39:53249 },
[email protected]eb00a762012-01-18 07:29:28250#endif
251
[email protected]d208f4d82011-05-23 21:52:03252 // TODO(dspringer): When NaCl is on by default, remove this flag entry.
[email protected]2fe15fcb2010-10-21 20:39:53253 {
[email protected]e3791ce92011-08-09 01:03:32254 "enable-nacl", // FLAGS:RECORD_UMA
[email protected]4ff87d202010-11-06 01:28:40255 IDS_FLAGS_ENABLE_NACL_NAME,
256 IDS_FLAGS_ENABLE_NACL_DESCRIPTION,
257 kOsAll,
[email protected]8a6ff28d2010-12-02 16:35:19258 SINGLE_VALUE_TYPE(switches::kEnableNaCl)
[email protected]4ff87d202010-11-06 01:28:40259 },
[email protected]b39c6d92012-01-31 16:38:41260 // TODO(halyavin): When exception handling is on by default, replace this
261 // flag with disable-nacl-exception-handling.
262 {
263 "enable-nacl-exception-handling", // FLAGS:RECORD_UMA
264 IDS_FLAGS_ENABLE_NACL_EXCEPTION_HANDLING_NAME,
265 IDS_FLAGS_ENABLE_NACL_EXCEPTION_HANDLING_DESCRIPTION,
266 kOsWin,
267 SINGLE_VALUE_TYPE(switches::kEnableNaClExceptionHandling)
268 },
[email protected]4ff87d202010-11-06 01:28:40269 {
[email protected]31a665e72012-03-11 12:37:46270 "nacl-gdb", // FLAGS:RECORD_UMA
271 IDS_FLAGS_NACL_GDB_NAME,
272 IDS_FLAGS_NACL_GDB_DESCRIPTION,
273 kOsWin,
274 SINGLE_VALUE_TYPE(switches::kNaClGdb)
275 },
276 {
[email protected]4bc5050c2010-11-18 17:55:54277 "extension-apis", // FLAGS:RECORD_UMA
[email protected]11dd68cd52010-11-12 01:15:32278 IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_NAME,
279 IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION,
280 kOsAll,
[email protected]8a6ff28d2010-12-02 16:35:19281 SINGLE_VALUE_TYPE(switches::kEnableExperimentalExtensionApis)
[email protected]11dd68cd52010-11-12 01:15:32282 },
[email protected]3627b06d2010-11-12 16:36:16283 {
[email protected]cbe224d2011-08-04 22:12:49284 "apps-new-install-bubble",
285 IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_NAME,
286 IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_DESCRIPTION,
287 kOsAll,
288 SINGLE_VALUE_TYPE(switches::kAppsNewInstallBubble)
289 },
290 {
[email protected]80bd24e2010-11-30 09:34:38291 "disable-hyperlink-auditing",
292 IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_NAME,
293 IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_DESCRIPTION,
294 kOsAll,
[email protected]8a6ff28d2010-12-02 16:35:19295 SINGLE_VALUE_TYPE(switches::kNoPings)
[email protected]feb28fef2010-12-01 10:52:51296 },
297 {
298 "experimental-location-features", // FLAGS:RECORD_UMA
299 IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_NAME,
300 IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_DESCRIPTION,
301 kOsMac | kOsWin | kOsLinux, // Currently does nothing on CrOS.
[email protected]8a6ff28d2010-12-02 16:35:19302 SINGLE_VALUE_TYPE(switches::kExperimentalLocationFeatures)
303 },
304 {
[email protected]04227962011-01-20 02:03:09305 "disable-interactive-form-validation",
306 IDS_FLAGS_DISABLE_INTERACTIVE_FORM_VALIDATION_NAME,
307 IDS_FLAGS_DISABLE_INTERACTIVE_FORM_VALIDATION_DESCRIPTION,
308 kOsAll,
309 SINGLE_VALUE_TYPE(switches::kDisableInteractiveFormValidation)
310 },
[email protected]8df51192011-01-22 20:05:03311 {
[email protected]07d490bc2011-03-07 17:05:26312 "focus-existing-tab-on-open", // FLAGS:RECORD_UMA
313 IDS_FLAGS_FOCUS_EXISTING_TAB_ON_OPEN_NAME,
314 IDS_FLAGS_FOCUS_EXISTING_TAB_ON_OPEN_DESCRIPTION,
315 kOsAll,
316 SINGLE_VALUE_TYPE(switches::kFocusExistingTabOnOpen)
317 },
[email protected]d5dcfb32011-03-19 00:49:24318 {
[email protected]5aea1862011-03-23 23:55:39319 "tab-groups-context-menu",
320 IDS_FLAGS_TAB_GROUPS_CONTEXT_MENU_NAME,
321 IDS_FLAGS_TAB_GROUPS_CONTEXT_MENU_DESCRIPTION,
322 kOsWin,
323 SINGLE_VALUE_TYPE(switches::kEnableTabGroupsContextMenu)
324 },
[email protected]e9bf9d92011-03-31 20:57:15325 {
[email protected]f2557bd2011-06-01 02:33:07326 "preload-instant-search",
327 IDS_FLAGS_PRELOAD_INSTANT_SEARCH_NAME,
328 IDS_FLAGS_PRELOAD_INSTANT_SEARCH_DESCRIPTION,
329 kOsAll,
330 SINGLE_VALUE_TYPE(switches::kPreloadInstantSearch)
331 },
[email protected]354e33b2011-06-15 00:29:10332 {
333 "static-ip-config",
334 IDS_FLAGS_STATIC_IP_CONFIG_NAME,
335 IDS_FLAGS_STATIC_IP_CONFIG_DESCRIPTION,
336 kOsCrOS,
337#if defined(OS_CHROMEOS)
338 // This switch exists only on Chrome OS.
339 SINGLE_VALUE_TYPE(switches::kEnableStaticIPConfig)
340#else
341 SINGLE_VALUE_TYPE("")
342#endif
343 },
[email protected]3eb5728c2011-06-20 22:32:24344 {
345 "show-autofill-type-predictions",
346 IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_NAME,
347 IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_DESCRIPTION,
348 kOsAll,
349 SINGLE_VALUE_TYPE(switches::kShowAutofillTypePredictions)
350 },
[email protected]bff4d3e2011-06-21 23:58:52351 {
[email protected]9a6180d7d2011-09-07 01:40:33352 "sync-tabs",
353 IDS_FLAGS_SYNC_TABS_NAME,
354 IDS_FLAGS_SYNC_TABS_DESCRIPTION,
[email protected]5b0ec7f2011-08-11 02:17:17355 kOsAll,
[email protected]9a6180d7d2011-09-07 01:40:33356 SINGLE_VALUE_TYPE(switches::kEnableSyncTabs)
[email protected]5b0ec7f2011-08-11 02:17:17357 },
358 {
[email protected]aae9eeb12011-10-21 21:59:26359 "sync-app-notifications",
360 IDS_FLAGS_SYNC_APP_NOTIFICATIONS_NAME,
361 IDS_FLAGS_SYNC_APP_NOTIFICATIONS_DESCRIPTION,
362 kOsAll,
[email protected]0b6fba82011-11-18 01:31:11363 SINGLE_VALUE_TYPE(switches::kDisableSyncAppNotifications)
[email protected]aae9eeb12011-10-21 21:59:26364 },
365 {
[email protected]a22ebd812011-06-23 00:05:39366 "enable-smooth-scrolling", // FLAGS:RECORD_UMA
367 IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_NAME,
368 IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_DESCRIPTION,
369 // Can't expose the switch unless the code is compiled in.
[email protected]554b7062011-09-03 03:09:40370 // On by default for the Mac (different implementation in WebKit).
[email protected]554b7062011-09-03 03:09:40371 kOsWin | kOsLinux | kOsCrOS,
[email protected]a22ebd812011-06-23 00:05:39372 SINGLE_VALUE_TYPE(switches::kEnableSmoothScrolling)
373 },
[email protected]81a6b0b2011-06-24 17:55:40374 {
[email protected]9b2c9f6a12012-01-27 21:00:05375 "omnibox-aggressive-with-history-url",
[email protected]ed1e39502011-12-16 14:39:35376 IDS_FLAGS_OMNIBOX_AGGRESSIVE_HISTORY_URL_SCORING_NAME,
377 IDS_FLAGS_OMNIBOX_AGGRESSIVE_HISTORY_URL_SCORING_DESCRIPTION,
378 kOsAll,
[email protected]9b2c9f6a12012-01-27 21:00:05379 MULTI_VALUE_TYPE(kOmniboxAggressiveHistoryURLChoices)
[email protected]ed1e39502011-12-16 14:39:35380 },
381 {
[email protected]032d5e6c2012-02-17 17:53:55382 "omnibox-inline-history-quick-provider",
383 IDS_FLAGS_OMNIBOX_INLINE_HISTORY_QUICK_PROVIDER_NAME,
384 IDS_FLAGS_OMNIBOX_INLINE_HISTORY_QUICK_PROVIDER_DESCRIPTION,
385 kOsAll,
386 MULTI_VALUE_TYPE(kOmniboxInlineHistoryQuickProviderChoices)
387 },
388 {
[email protected]7e7a28092011-12-09 22:24:55389 "enable-panels",
390 IDS_FLAGS_ENABLE_PANELS_NAME,
391 IDS_FLAGS_ENABLE_PANELS_DESCRIPTION,
[email protected]73fb1fc52011-07-09 00:06:54392 kOsAll,
[email protected]7e7a28092011-12-09 22:24:55393 SINGLE_VALUE_TYPE(switches::kEnablePanels)
[email protected]73fb1fc52011-07-09 00:06:54394 },
[email protected]e3749d12011-07-25 22:22:12395 {
[email protected]9931875b2011-11-02 00:19:48396 "disable-shortcuts-provider",
397 IDS_FLAGS_DISABLE_SHORTCUTS_PROVIDER,
398 IDS_FLAGS_DISABLE_SHORTCUTS_PROVIDER_DESCRIPTION,
[email protected]e3749d12011-07-25 22:22:12399 kOsAll,
[email protected]9931875b2011-11-02 00:19:48400 SINGLE_VALUE_TYPE(switches::kDisableShortcutsProvider)
[email protected]e3749d12011-07-25 22:22:12401 },
[email protected]80eb4262011-08-03 16:10:41402 {
403 "memory-widget",
404 IDS_FLAGS_MEMORY_WIDGET_NAME,
405 IDS_FLAGS_MEMORY_WIDGET_DESCRIPTION,
406 kOsCrOS,
407#if defined(OS_CHROMEOS)
408 // This switch exists only on Chrome OS.
409 SINGLE_VALUE_TYPE(switches::kMemoryWidget)
410#else
411 SINGLE_VALUE_TYPE("")
412#endif
[email protected]a0e4b072011-08-17 01:47:07413 },
414 {
415 "downloads-new-ui", // FLAGS:RECORD_UMA
416 IDS_FLAGS_DOWNLOADS_NEW_UI_NAME,
417 IDS_FLAGS_DOWNLOADS_NEW_UI_DESCRIPTION,
418 kOsAll,
419 SINGLE_VALUE_TYPE(switches::kDownloadsNewUI)
420 },
[email protected]b7bb44f2011-09-01 05:17:03421 {
422 "enable-autologin",
423 IDS_FLAGS_ENABLE_AUTOLOGIN_NAME,
424 IDS_FLAGS_ENABLE_AUTOLOGIN_DESCRIPTION,
425 kOsMac | kOsWin | kOsLinux,
426 SINGLE_VALUE_TYPE(switches::kEnableAutologin)
427 },
[email protected]b9841172011-09-26 23:36:09428 {
[email protected]bbadb112011-12-12 16:55:28429 "enable-http-pipelining",
430 IDS_FLAGS_ENABLE_HTTP_PIPELINING_NAME,
431 IDS_FLAGS_ENABLE_HTTP_PIPELINING_DESCRIPTION,
432 kOsAll,
433 SINGLE_VALUE_TYPE(switches::kEnableHttpPipelining)
434 },
[email protected]d411c01d2011-10-18 16:00:27435 {
[email protected]f5da41d2011-10-08 17:40:07436 "enable-video-track",
437 IDS_FLAGS_ENABLE_VIDEO_TRACK_NAME,
438 IDS_FLAGS_ENABLE_VIDEO_TRACK_DESCRIPTION,
439 kOsAll,
440 SINGLE_VALUE_TYPE(switches::kEnableVideoTrack)
441 },
[email protected]08b83362011-10-19 05:23:17442 {
[email protected]6aa03b32011-10-27 21:44:44443 "enable-media-source",
444 IDS_FLAGS_ENABLE_MEDIA_SOURCE_NAME,
445 IDS_FLAGS_ENABLE_MEDIA_SOURCE_DESCRIPTION,
446 kOsAll,
447 SINGLE_VALUE_TYPE(switches::kEnableMediaSource)
448 },
[email protected]e4e68dbb2011-11-18 01:50:22449 {
450 "enable-pointer-lock",
451 IDS_FLAGS_ENABLE_POINTER_LOCK_NAME,
452 IDS_FLAGS_ENABLE_POINTER_LOCK_DESCRIPTION,
453 kOsAll,
454 SINGLE_VALUE_TYPE(switches::kEnablePointerLock)
455 },
[email protected]dc04be7c2012-03-15 23:57:49456#if defined(USE_ASH)
[email protected]8cc10df2011-11-03 23:57:50457 {
[email protected]57b8bb352012-01-11 05:11:46458 "aura-google-dialog-frames",
459 IDS_FLAGS_AURA_GOOGLE_DIALOG_FRAMES_NAME,
460 IDS_FLAGS_AURA_GOOGLE_DIALOG_FRAMES_DESCRIPTION,
461 kOsWin | kOsLinux | kOsCrOS,
462 SINGLE_VALUE_TYPE(ash::switches::kAuraGoogleDialogFrames)
463 },
[email protected]dc04be7c2012-03-15 23:57:49464#endif
465#if defined(USE_AURA)
[email protected]308aaa32012-03-12 13:14:50466 {
467 "aura-disable-hold-mouse-moves",
468 IDS_FLAGS_AURA_DISABLE_HOLD_MOUSE_MOVES_NAME,
469 IDS_FLAGS_AURA_DISABLE_HOLD_MOUSE_MOVES_DESCRIPTION,
470 kOsWin | kOsLinux | kOsCrOS,
471 SINGLE_VALUE_TYPE(switches::kAuraDisableHoldMouseMoves)
472 },
[email protected]eaae8b462012-01-20 22:20:39473#endif // defined(USE_AURA)
474 {
475 "enable-gamepad",
476 IDS_FLAGS_ENABLE_GAMEPAD_NAME,
477 IDS_FLAGS_ENABLE_GAMEPAD_DESCRIPTION,
478 kOsAll,
479 SINGLE_VALUE_TYPE(switches::kEnableGamepad)
480 },
[email protected]db543d322011-12-15 20:40:15481 {
482 "per-tile-painting",
483 IDS_FLAGS_PER_TILE_PAINTING_NAME,
484 IDS_FLAGS_PER_TILE_PAINTING_DESCRIPTION,
485#if defined(USE_SKIA)
[email protected]a5b1b272012-01-06 20:44:37486 kOsMac | kOsLinux | kOsCrOS,
[email protected]db543d322011-12-15 20:40:15487#else
488 0,
489#endif
490 SINGLE_VALUE_TYPE(switches::kEnablePerTilePainting)
491 },
[email protected]bf88c032011-12-22 19:05:47492 {
493 "enable-javascript-harmony",
494 IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_NAME,
495 IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_DESCRIPTION,
496 kOsAll,
497 SINGLE_VALUE_TYPE_AND_VALUE(switches::kJavaScriptFlags, "--harmony")
498 },
[email protected]7e7f378a2012-01-05 14:35:37499 {
[email protected]85646172012-01-09 22:45:54500 "enable-tab-browser-dragging",
501 IDS_FLAGS_ENABLE_TAB_BROWSER_DRAGGING_NAME,
502 IDS_FLAGS_ENABLE_TAB_BROWSER_DRAGGING_DESCRIPTION,
503 kOsWin,
504 SINGLE_VALUE_TYPE(switches::kTabBrowserDragging)
505 },
506 {
[email protected]068b7b52012-02-27 12:41:44507 "disable-restore-session-state",
508 IDS_FLAGS_DISABLE_RESTORE_SESSION_STATE_NAME,
509 IDS_FLAGS_DISABLE_RESTORE_SESSION_STATE_DESCRIPTION,
[email protected]7e7f378a2012-01-05 14:35:37510 kOsAll,
[email protected]068b7b52012-02-27 12:41:44511 SINGLE_VALUE_TYPE(switches::kDisableRestoreSessionState)
[email protected]7e7f378a2012-01-05 14:35:37512 },
[email protected]88864db2012-01-18 20:56:35513 {
514 "disable-software-rasterizer",
515 IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_NAME,
516 IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_DESCRIPTION,
517#if defined(ENABLE_SWIFTSHADER)
518 kOsAll,
519#else
520 0,
521#endif
522 SINGLE_VALUE_TYPE(switches::kDisableSoftwareRasterizer)
523 },
[email protected]15a5d722012-01-23 09:11:14524 {
525 "enable-media-stream",
526 IDS_FLAGS_MEDIA_STREAM_NAME,
527 IDS_FLAGS_MEDIA_STREAM_DESCRIPTION,
[email protected]fa82b6772012-02-20 13:19:05528 kOsAll,
[email protected]15a5d722012-01-23 09:11:14529 SINGLE_VALUE_TYPE(switches::kEnableMediaStream)
530 },
[email protected]f5ec7242012-01-27 07:15:15531 {
[email protected]fa12e2d2012-02-06 21:03:10532 "disable-uber-page",
533 IDS_FLAGS_DISABLE_UBER_PAGE_NAME,
534 IDS_FLAGS_DISABLE_UBER_PAGE_DESCRIPTION,
[email protected]f5ec7242012-01-27 07:15:15535 kOsAll,
[email protected]fa12e2d2012-02-06 21:03:10536 SINGLE_VALUE_TYPE(switches::kDisableUberPage)
[email protected]f5ec7242012-01-27 07:15:15537 },
[email protected]d2edc6702012-01-30 09:13:16538 {
539 "enable-shadow-dom",
540 IDS_FLAGS_SHADOW_DOM_NAME,
541 IDS_FLAGS_SHADOW_DOM_DESCRIPTION,
542 kOsAll,
543 SINGLE_VALUE_TYPE(switches::kEnableShadowDOM)
544 },
[email protected]9860c68b2012-02-02 01:58:09545 {
[email protected]4961218f2012-02-23 10:11:07546 "enable-style-scoped",
547 IDS_FLAGS_STYLE_SCOPED_NAME,
548 IDS_FLAGS_STYLE_SCOPED_DESCRIPTION,
549 kOsAll,
550 SINGLE_VALUE_TYPE(switches::kEnableStyleScoped)
551 },
552 {
[email protected]ca7a3d792012-03-02 15:55:49553 "enable-css-regions",
554 IDS_FLAGS_CSS_REGIONS_NAME,
555 IDS_FLAGS_CSS_REGIONS_DESCRIPTION,
556 kOsAll,
557 SINGLE_VALUE_TYPE(switches::kEnableCssRegions)
558 },
559 {
[email protected]8bed69d2012-02-02 06:46:00560 "ntp-app-install-hint",
561 IDS_FLAGS_APP_INSTALL_HINT_NAME,
562 IDS_FLAGS_APP_INSTALL_HINT_DESCRIPTION,
563 kOsAll,
564 SINGLE_VALUE_TYPE(switches::kNtpAppInstallHint)
565 },
566 {
[email protected]9860c68b2012-02-02 01:58:09567 "enable-extension-activity-ui",
568 IDS_FLAGS_ENABLE_EXTENSION_ACTIVITY_UI_NAME,
569 IDS_FLAGS_ENABLE_EXTENSION_ACTIVITY_UI_DESCRIPTION,
570 kOsAll,
571 SINGLE_VALUE_TYPE(switches::kEnableExtensionActivityUI)
[email protected]8bed69d2012-02-02 06:46:00572 },
[email protected]54ae4e92012-02-16 15:19:05573 {
574 "webui-task-manager",
575 IDS_FLAGS_WEBUI_TASK_MANAGER_NAME,
576 IDS_FLAGS_WEBUI_TASK_MANAGER_DESCRIPTION,
577 kOsAll,
578 SINGLE_VALUE_TYPE(switches::kWebUITaskManager)
579 },
[email protected]156f966332012-02-29 00:03:16580 {
[email protected]3e8befc2012-03-13 01:17:03581 "disable-ntp-other-sessions-menu",
[email protected]156f966332012-02-29 00:03:16582 IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_NAME,
583 IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_DESCRIPTION,
584 kOsAll,
[email protected]3e8befc2012-03-13 01:17:03585 SINGLE_VALUE_TYPE(switches::kDisableNTPOtherSessionsMenu)
[email protected]156f966332012-02-29 00:03:16586 },
[email protected]dc04be7c2012-03-15 23:57:49587#if defined(USE_ASH)
[email protected]31cf1c52012-02-29 20:55:01588 {
[email protected]dfc68f62012-03-17 02:09:21589 "disable-ash-uber-tray",
[email protected]26604632012-03-19 05:36:52590 IDS_FLAGS_DISABLE_ASH_UBER_TRAY_NAME,
591 IDS_FLAGS_DISABLE_ASH_UBER_TRAY_DESCRIPTION,
[email protected]31cf1c52012-02-29 20:55:01592 kOsAll,
[email protected]dfc68f62012-03-17 02:09:21593 SINGLE_VALUE_TYPE(ash::switches::kDisableAshUberTray),
[email protected]31cf1c52012-02-29 20:55:01594 },
[email protected]3cd198a22012-03-12 20:38:01595 {
596 "enable-ash-oak",
597 IDS_FLAGS_ENABLE_ASH_OAK_NAME,
598 IDS_FLAGS_ENABLE_ASH_OAK_DESCRIPTION,
599 kOsAll,
600 SINGLE_VALUE_TYPE(ash::switches::kAshEnableOak),
601 },
[email protected]31cf1c52012-02-29 20:55:01602#endif
[email protected]184ec592012-03-01 11:54:28603 {
604 "enable-devtools-experiments",
605 IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_NAME,
606 IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_DESCRIPTION,
607 kOsAll,
608 SINGLE_VALUE_TYPE(switches::kEnableDevToolsExperiments)
609 },
[email protected]76d1854e2012-03-02 23:57:44610 {
611 "enable-suggestions-ntp",
612 IDS_FLAGS_NTP_SUGGESTIONS_PAGE_NAME,
613 IDS_FLAGS_NTP_SUGGESTIONS_PAGE_DESCRIPTION,
614 kOsAll,
615 SINGLE_VALUE_TYPE(switches::kEnableSuggestionsTabPage)
616 },
[email protected]a78ef9e2012-03-21 02:49:55617 {
618 "disable-chrome-to-mobile", // FLAGS:RECORD_UMA
619 IDS_FLAGS_DISABLE_CHROME_TO_MOBILE_NAME,
620 IDS_FLAGS_DISABLE_CHROME_TO_MOBILE_DESCRIPTION,
621 kOsAll,
622 SINGLE_VALUE_TYPE(switches::kDisableChromeToMobile)
623 },
[email protected]a0e4b072011-08-17 01:47:07624};
[email protected]ad2a3ded2010-08-27 13:19:05625
[email protected]a314ee5a2010-10-26 21:23:28626const Experiment* experiments = kExperiments;
627size_t num_experiments = arraysize(kExperiments);
628
[email protected]e2ddbc92010-10-15 20:02:07629// Stores and encapsulates the little state that about:flags has.
630class FlagsState {
631 public:
632 FlagsState() : needs_restart_(false) {}
633 void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line);
634 bool IsRestartNeededToCommitChanges();
635 void SetExperimentEnabled(
[email protected]a314ee5a2010-10-26 21:23:28636 PrefService* prefs, const std::string& internal_name, bool enable);
[email protected]e2ddbc92010-10-15 20:02:07637 void RemoveFlagsSwitches(
638 std::map<std::string, CommandLine::StringType>* switch_list);
639 void reset();
640
641 // Returns the singleton instance of this class
[email protected]8e8bb6d2010-12-13 08:18:55642 static FlagsState* GetInstance() {
[email protected]e2ddbc92010-10-15 20:02:07643 return Singleton<FlagsState>::get();
644 }
645
646 private:
647 bool needs_restart_;
[email protected]a82744532011-02-11 16:15:53648 std::map<std::string, std::string> flags_switches_;
[email protected]e2ddbc92010-10-15 20:02:07649
650 DISALLOW_COPY_AND_ASSIGN(FlagsState);
651};
652
[email protected]c7b7800a2010-10-07 18:51:35653// Extracts the list of enabled lab experiments from preferences and stores them
[email protected]ad2a3ded2010-08-27 13:19:05654// in a set.
[email protected]1a47d7e2010-10-15 00:37:24655void GetEnabledFlags(const PrefService* prefs, std::set<std::string>* result) {
[email protected]ad2a3ded2010-08-27 13:19:05656 const ListValue* enabled_experiments = prefs->GetList(
657 prefs::kEnabledLabsExperiments);
658 if (!enabled_experiments)
659 return;
660
661 for (ListValue::const_iterator it = enabled_experiments->begin();
662 it != enabled_experiments->end();
663 ++it) {
664 std::string experiment_name;
665 if (!(*it)->GetAsString(&experiment_name)) {
666 LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
667 continue;
668 }
669 result->insert(experiment_name);
670 }
671}
672
673// Takes a set of enabled lab experiments
[email protected]1a47d7e2010-10-15 00:37:24674void SetEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05675 PrefService* prefs, const std::set<std::string>& enabled_experiments) {
[email protected]1bc78422011-03-31 08:41:38676 ListPrefUpdate update(prefs, prefs::kEnabledLabsExperiments);
677 ListValue* experiments_list = update.Get();
[email protected]ad2a3ded2010-08-27 13:19:05678
679 experiments_list->Clear();
680 for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
681 it != enabled_experiments.end();
682 ++it) {
683 experiments_list->Append(new StringValue(*it));
684 }
685}
686
[email protected]8a6ff28d2010-12-02 16:35:19687// Returns the name used in prefs for the choice at the specified index.
688std::string NameForChoice(const Experiment& e, int index) {
[email protected]2ce9c89752011-02-25 18:24:34689 DCHECK_EQ(Experiment::MULTI_VALUE, e.type);
690 DCHECK_LT(index, e.num_choices);
[email protected]8a6ff28d2010-12-02 16:35:19691 return std::string(e.internal_name) + about_flags::testing::kMultiSeparator +
692 base::IntToString(index);
693}
694
695// Adds the internal names for the specified experiment to |names|.
696void AddInternalName(const Experiment& e, std::set<std::string>* names) {
697 if (e.type == Experiment::SINGLE_VALUE) {
698 names->insert(e.internal_name);
699 } else {
[email protected]2ce9c89752011-02-25 18:24:34700 DCHECK_EQ(Experiment::MULTI_VALUE, e.type);
[email protected]8a6ff28d2010-12-02 16:35:19701 for (int i = 0; i < e.num_choices; ++i)
702 names->insert(NameForChoice(e, i));
703 }
704}
705
[email protected]28e35af2011-02-09 12:56:22706// Confirms that an experiment is valid, used in a DCHECK in
707// SanitizeList below.
708bool ValidateExperiment(const Experiment& e) {
709 switch (e.type) {
710 case Experiment::SINGLE_VALUE:
711 DCHECK_EQ(0, e.num_choices);
712 DCHECK(!e.choices);
713 break;
714 case Experiment::MULTI_VALUE:
715 DCHECK_GT(e.num_choices, 0);
716 DCHECK(e.choices);
[email protected]a82744532011-02-11 16:15:53717 DCHECK(e.choices[0].command_line_switch);
718 DCHECK_EQ('\0', e.choices[0].command_line_switch[0]);
[email protected]28e35af2011-02-09 12:56:22719 break;
720 default:
721 NOTREACHED();
722 }
723 return true;
724}
725
[email protected]ad2a3ded2010-08-27 13:19:05726// Removes all experiments from prefs::kEnabledLabsExperiments that are
727// unknown, to prevent this list to become very long as experiments are added
728// and removed.
729void SanitizeList(PrefService* prefs) {
730 std::set<std::string> known_experiments;
[email protected]28e35af2011-02-09 12:56:22731 for (size_t i = 0; i < num_experiments; ++i) {
732 DCHECK(ValidateExperiment(experiments[i]));
[email protected]8a6ff28d2010-12-02 16:35:19733 AddInternalName(experiments[i], &known_experiments);
[email protected]28e35af2011-02-09 12:56:22734 }
[email protected]ad2a3ded2010-08-27 13:19:05735
736 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24737 GetEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05738
739 std::set<std::string> new_enabled_experiments;
740 std::set_intersection(
741 known_experiments.begin(), known_experiments.end(),
742 enabled_experiments.begin(), enabled_experiments.end(),
743 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
744
[email protected]1a47d7e2010-10-15 00:37:24745 SetEnabledFlags(prefs, new_enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05746}
747
[email protected]1a47d7e2010-10-15 00:37:24748void GetSanitizedEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05749 PrefService* prefs, std::set<std::string>* result) {
750 SanitizeList(prefs);
[email protected]1a47d7e2010-10-15 00:37:24751 GetEnabledFlags(prefs, result);
[email protected]ad2a3ded2010-08-27 13:19:05752}
753
[email protected]a314ee5a2010-10-26 21:23:28754// Variant of GetSanitizedEnabledFlags that also removes any flags that aren't
755// enabled on the current platform.
756void GetSanitizedEnabledFlagsForCurrentPlatform(
757 PrefService* prefs, std::set<std::string>* result) {
758 GetSanitizedEnabledFlags(prefs, result);
759
760 // Filter out any experiments that aren't enabled on the current platform. We
761 // don't remove these from prefs else syncing to a platform with a different
762 // set of experiments would be lossy.
763 std::set<std::string> platform_experiments;
764 int current_platform = GetCurrentPlatform();
765 for (size_t i = 0; i < num_experiments; ++i) {
766 if (experiments[i].supported_platforms & current_platform)
[email protected]8a6ff28d2010-12-02 16:35:19767 AddInternalName(experiments[i], &platform_experiments);
[email protected]a314ee5a2010-10-26 21:23:28768 }
769
770 std::set<std::string> new_enabled_experiments;
771 std::set_intersection(
772 platform_experiments.begin(), platform_experiments.end(),
773 result->begin(), result->end(),
774 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
775
776 result->swap(new_enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05777}
778
[email protected]8a6ff28d2010-12-02 16:35:19779// Returns the Value representing the choice data in the specified experiment.
[email protected]8a6ff28d2010-12-02 16:35:19780Value* CreateChoiceData(const Experiment& experiment,
[email protected]28e35af2011-02-09 12:56:22781 const std::set<std::string>& enabled_experiments) {
[email protected]2ce9c89752011-02-25 18:24:34782 DCHECK_EQ(Experiment::MULTI_VALUE, experiment.type);
[email protected]8a6ff28d2010-12-02 16:35:19783 ListValue* result = new ListValue;
784 for (int i = 0; i < experiment.num_choices; ++i) {
785 const Experiment::Choice& choice = experiment.choices[i];
786 DictionaryValue* value = new DictionaryValue;
787 std::string name = NameForChoice(experiment, i);
788 value->SetString("description",
789 l10n_util::GetStringUTF16(choice.description_id));
790 value->SetString("internal_name", name);
[email protected]28e35af2011-02-09 12:56:22791 value->SetBoolean("selected", enabled_experiments.count(name) > 0);
[email protected]8a6ff28d2010-12-02 16:35:19792 result->Append(value);
793 }
794 return result;
795}
796
[email protected]e2ddbc92010-10-15 20:02:07797} // namespace
798
[email protected]1a47d7e2010-10-15 00:37:24799void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line) {
[email protected]8e8bb6d2010-12-13 08:18:55800 FlagsState::GetInstance()->ConvertFlagsToSwitches(prefs, command_line);
[email protected]ad2a3ded2010-08-27 13:19:05801}
802
[email protected]1a47d7e2010-10-15 00:37:24803ListValue* GetFlagsExperimentsData(PrefService* prefs) {
[email protected]ad2a3ded2010-08-27 13:19:05804 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24805 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05806
807 int current_platform = GetCurrentPlatform();
808
809 ListValue* experiments_data = new ListValue();
[email protected]a314ee5a2010-10-26 21:23:28810 for (size_t i = 0; i < num_experiments; ++i) {
811 const Experiment& experiment = experiments[i];
[email protected]ad2a3ded2010-08-27 13:19:05812
813 DictionaryValue* data = new DictionaryValue();
814 data->SetString("internal_name", experiment.internal_name);
815 data->SetString("name",
816 l10n_util::GetStringUTF16(experiment.visible_name_id));
817 data->SetString("description",
818 l10n_util::GetStringUTF16(
819 experiment.visible_description_id));
[email protected]cc3e2052011-12-20 01:01:40820 bool supported = !!(experiment.supported_platforms & current_platform);
821 data->SetBoolean("supported", supported);
822
823 ListValue* supported_platforms = new ListValue();
824 AddOsStrings(experiment.supported_platforms, supported_platforms);
825 data->Set("supported_platforms", supported_platforms);
[email protected]ad2a3ded2010-08-27 13:19:05826
[email protected]28e35af2011-02-09 12:56:22827 switch (experiment.type) {
828 case Experiment::SINGLE_VALUE:
829 data->SetBoolean(
830 "enabled",
831 enabled_experiments.count(experiment.internal_name) > 0);
832 break;
833 case Experiment::MULTI_VALUE:
834 data->Set("choices", CreateChoiceData(experiment, enabled_experiments));
835 break;
836 default:
837 NOTREACHED();
[email protected]8a6ff28d2010-12-02 16:35:19838 }
839
[email protected]ad2a3ded2010-08-27 13:19:05840 experiments_data->Append(data);
841 }
842 return experiments_data;
843}
844
[email protected]ad2a3ded2010-08-27 13:19:05845bool IsRestartNeededToCommitChanges() {
[email protected]8e8bb6d2010-12-13 08:18:55846 return FlagsState::GetInstance()->IsRestartNeededToCommitChanges();
[email protected]ad2a3ded2010-08-27 13:19:05847}
848
849void SetExperimentEnabled(
[email protected]c7b7800a2010-10-07 18:51:35850 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]8e8bb6d2010-12-13 08:18:55851 FlagsState::GetInstance()->SetExperimentEnabled(prefs, internal_name, enable);
[email protected]e2ddbc92010-10-15 20:02:07852}
853
854void RemoveFlagsSwitches(
855 std::map<std::string, CommandLine::StringType>* switch_list) {
[email protected]8e8bb6d2010-12-13 08:18:55856 FlagsState::GetInstance()->RemoveFlagsSwitches(switch_list);
[email protected]e2ddbc92010-10-15 20:02:07857}
858
[email protected]a314ee5a2010-10-26 21:23:28859int GetCurrentPlatform() {
860#if defined(OS_MACOSX)
861 return kOsMac;
862#elif defined(OS_WIN)
863 return kOsWin;
864#elif defined(OS_CHROMEOS) // Needs to be before the OS_LINUX check.
865 return kOsCrOS;
[email protected]c92f4ed2011-10-21 19:50:21866#elif defined(OS_LINUX) || defined(OS_OPENBSD)
[email protected]a314ee5a2010-10-26 21:23:28867 return kOsLinux;
[email protected]9c7453d2012-01-21 00:45:40868#elif defined(OS_ANDROID)
869 return kOsAndroid;
[email protected]a314ee5a2010-10-26 21:23:28870#else
871#error Unknown platform
872#endif
873}
874
[email protected]4bc5050c2010-11-18 17:55:54875void RecordUMAStatistics(const PrefService* prefs) {
876 std::set<std::string> flags;
877 GetEnabledFlags(prefs, &flags);
878 for (std::set<std::string>::iterator it = flags.begin(); it != flags.end();
879 ++it) {
880 std::string action("AboutFlags_");
881 action += *it;
[email protected]7f6f44c2011-12-14 13:23:38882 content::RecordComputedAction(action);
[email protected]4bc5050c2010-11-18 17:55:54883 }
884 // Since flag metrics are recorded every startup, add a tick so that the
885 // stats can be made meaningful.
886 if (flags.size())
[email protected]7f6f44c2011-12-14 13:23:38887 content::RecordAction(UserMetricsAction("AboutFlags_StartupTick"));
888 content::RecordAction(UserMetricsAction("StartupTick"));
[email protected]4bc5050c2010-11-18 17:55:54889}
890
[email protected]e2ddbc92010-10-15 20:02:07891//////////////////////////////////////////////////////////////////////////////
892// FlagsState implementation.
893
894namespace {
895
896void FlagsState::ConvertFlagsToSwitches(
897 PrefService* prefs, CommandLine* command_line) {
[email protected]e2ddbc92010-10-15 20:02:07898 if (command_line->HasSwitch(switches::kNoExperiments))
899 return;
900
901 std::set<std::string> enabled_experiments;
[email protected]ba8164242010-11-16 21:31:00902
[email protected]a314ee5a2010-10-26 21:23:28903 GetSanitizedEnabledFlagsForCurrentPlatform(prefs, &enabled_experiments);
[email protected]e2ddbc92010-10-15 20:02:07904
[email protected]a82744532011-02-11 16:15:53905 typedef std::map<std::string, std::pair<std::string, std::string> >
906 NameToSwitchAndValueMap;
907 NameToSwitchAndValueMap name_to_switch_map;
[email protected]8a6ff28d2010-12-02 16:35:19908 for (size_t i = 0; i < num_experiments; ++i) {
909 const Experiment& e = experiments[i];
910 if (e.type == Experiment::SINGLE_VALUE) {
[email protected]a82744532011-02-11 16:15:53911 name_to_switch_map[e.internal_name] =
912 std::pair<std::string, std::string>(e.command_line_switch,
913 e.command_line_value);
[email protected]8a6ff28d2010-12-02 16:35:19914 } else {
915 for (int j = 0; j < e.num_choices; ++j)
[email protected]a82744532011-02-11 16:15:53916 name_to_switch_map[NameForChoice(e, j)] =
917 std::pair<std::string, std::string>(
918 e.choices[j].command_line_switch,
919 e.choices[j].command_line_value);
[email protected]8a6ff28d2010-12-02 16:35:19920 }
921 }
[email protected]e2ddbc92010-10-15 20:02:07922
923 command_line->AppendSwitch(switches::kFlagSwitchesBegin);
[email protected]a82744532011-02-11 16:15:53924 flags_switches_.insert(
925 std::pair<std::string, std::string>(switches::kFlagSwitchesBegin,
926 std::string()));
[email protected]e2ddbc92010-10-15 20:02:07927 for (std::set<std::string>::iterator it = enabled_experiments.begin();
928 it != enabled_experiments.end();
929 ++it) {
930 const std::string& experiment_name = *it;
[email protected]a82744532011-02-11 16:15:53931 NameToSwitchAndValueMap::const_iterator name_to_switch_it =
[email protected]8a6ff28d2010-12-02 16:35:19932 name_to_switch_map.find(experiment_name);
933 if (name_to_switch_it == name_to_switch_map.end()) {
934 NOTREACHED();
[email protected]e2ddbc92010-10-15 20:02:07935 continue;
[email protected]8a6ff28d2010-12-02 16:35:19936 }
[email protected]e2ddbc92010-10-15 20:02:07937
[email protected]a82744532011-02-11 16:15:53938 const std::pair<std::string, std::string>&
939 switch_and_value_pair = name_to_switch_it->second;
940
941 command_line->AppendSwitchASCII(switch_and_value_pair.first,
942 switch_and_value_pair.second);
943 flags_switches_[switch_and_value_pair.first] = switch_and_value_pair.second;
[email protected]e2ddbc92010-10-15 20:02:07944 }
945 command_line->AppendSwitch(switches::kFlagSwitchesEnd);
[email protected]a82744532011-02-11 16:15:53946 flags_switches_.insert(
947 std::pair<std::string, std::string>(switches::kFlagSwitchesEnd,
948 std::string()));
[email protected]e2ddbc92010-10-15 20:02:07949}
950
951bool FlagsState::IsRestartNeededToCommitChanges() {
952 return needs_restart_;
953}
954
955void FlagsState::SetExperimentEnabled(
956 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]ad2a3ded2010-08-27 13:19:05957 needs_restart_ = true;
958
[email protected]8a6ff28d2010-12-02 16:35:19959 size_t at_index = internal_name.find(about_flags::testing::kMultiSeparator);
960 if (at_index != std::string::npos) {
961 DCHECK(enable);
962 // We're being asked to enable a multi-choice experiment. Disable the
963 // currently selected choice.
964 DCHECK_NE(at_index, 0u);
[email protected]28e35af2011-02-09 12:56:22965 const std::string experiment_name = internal_name.substr(0, at_index);
966 SetExperimentEnabled(prefs, experiment_name, false);
[email protected]8a6ff28d2010-12-02 16:35:19967
[email protected]28e35af2011-02-09 12:56:22968 // And enable the new choice, if it is not the default first choice.
969 if (internal_name != experiment_name + "@0") {
970 std::set<std::string> enabled_experiments;
971 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
972 enabled_experiments.insert(internal_name);
973 SetEnabledFlags(prefs, enabled_experiments);
974 }
[email protected]8a6ff28d2010-12-02 16:35:19975 return;
976 }
977
[email protected]ad2a3ded2010-08-27 13:19:05978 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24979 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05980
[email protected]8a6ff28d2010-12-02 16:35:19981 const Experiment* e = NULL;
982 for (size_t i = 0; i < num_experiments; ++i) {
983 if (experiments[i].internal_name == internal_name) {
984 e = experiments + i;
985 break;
986 }
987 }
988 DCHECK(e);
989
990 if (e->type == Experiment::SINGLE_VALUE) {
[email protected]8a2713682011-08-19 10:36:59991 if (enable)
[email protected]8a6ff28d2010-12-02 16:35:19992 enabled_experiments.insert(internal_name);
[email protected]8a2713682011-08-19 10:36:59993 else
[email protected]8a6ff28d2010-12-02 16:35:19994 enabled_experiments.erase(internal_name);
995 } else {
996 if (enable) {
997 // Enable the first choice.
998 enabled_experiments.insert(NameForChoice(*e, 0));
999 } else {
1000 // Find the currently enabled choice and disable it.
1001 for (int i = 0; i < e->num_choices; ++i) {
1002 std::string choice_name = NameForChoice(*e, i);
1003 if (enabled_experiments.find(choice_name) !=
1004 enabled_experiments.end()) {
1005 enabled_experiments.erase(choice_name);
1006 // Continue on just in case there's a bug and more than one
1007 // experiment for this choice was enabled.
1008 }
1009 }
1010 }
1011 }
[email protected]ad2a3ded2010-08-27 13:19:051012
[email protected]1a47d7e2010-10-15 00:37:241013 SetEnabledFlags(prefs, enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:051014}
1015
[email protected]e2ddbc92010-10-15 20:02:071016void FlagsState::RemoveFlagsSwitches(
1017 std::map<std::string, CommandLine::StringType>* switch_list) {
[email protected]a82744532011-02-11 16:15:531018 for (std::map<std::string, std::string>::const_iterator
1019 it = flags_switches_.begin(); it != flags_switches_.end(); ++it) {
1020 switch_list->erase(it->first);
[email protected]e2ddbc92010-10-15 20:02:071021 }
1022}
1023
1024void FlagsState::reset() {
1025 needs_restart_ = false;
1026 flags_switches_.clear();
1027}
1028
[email protected]38e46812011-05-09 20:49:221029} // namespace
[email protected]e2ddbc92010-10-15 20:02:071030
1031namespace testing {
[email protected]8a6ff28d2010-12-02 16:35:191032
1033// WARNING: '@' is also used in the html file. If you update this constant you
1034// also need to update the html file.
1035const char kMultiSeparator[] = "@";
1036
[email protected]e2ddbc92010-10-15 20:02:071037void ClearState() {
[email protected]8e8bb6d2010-12-13 08:18:551038 FlagsState::GetInstance()->reset();
[email protected]e2ddbc92010-10-15 20:02:071039}
[email protected]a314ee5a2010-10-26 21:23:281040
1041void SetExperiments(const Experiment* e, size_t count) {
1042 if (!e) {
1043 experiments = kExperiments;
1044 num_experiments = arraysize(kExperiments);
1045 } else {
1046 experiments = e;
1047 num_experiments = count;
1048 }
1049}
1050
[email protected]8a6ff28d2010-12-02 16:35:191051const Experiment* GetExperiments(size_t* count) {
1052 *count = num_experiments;
1053 return experiments;
1054}
1055
[email protected]e2ddbc92010-10-15 20:02:071056} // namespace testing
1057
[email protected]1a47d7e2010-10-15 00:37:241058} // namespace about_flags