blob: f1cebb181f5d5e0cacebd952c5aac72886345c5f [file] [log] [blame]
[email protected]ad2a3ded2010-08-27 13:19:051// Copyright (c) 2010 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
[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
12#include "app/l10n_util.h"
13#include "base/command_line.h"
[email protected]e2ddbc92010-10-15 20:02:0714#include "base/singleton.h"
[email protected]ad2a3ded2010-08-27 13:19:0515#include "base/values.h"
[email protected]ad2a3ded2010-08-27 13:19:0516#include "chrome/browser/prefs/pref_service.h"
[email protected]ad2a3ded2010-08-27 13:19:0517#include "chrome/common/chrome_switches.h"
18#include "chrome/common/pref_names.h"
19#include "grit/generated_resources.h"
20
[email protected]1a47d7e2010-10-15 00:37:2421namespace about_flags {
[email protected]ad2a3ded2010-08-27 13:19:0522
[email protected]e2ddbc92010-10-15 20:02:0723namespace {
24
[email protected]a314ee5a2010-10-26 21:23:2825const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS;
[email protected]ad2a3ded2010-08-27 13:19:0526
27const Experiment kExperiments[] = {
28 {
[email protected]232448fb2010-08-27 18:48:2429 "expose-for-tabs", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1230 IDS_FLAGS_TABPOSE_NAME,
31 IDS_FLAGS_TABPOSE_DESCRIPTION,
[email protected]ad2a3ded2010-08-27 13:19:0532 kOsMac,
33#if defined(OS_MACOSX)
34 // The switch exists only on OS X.
35 switches::kEnableExposeForTabs
36#else
37 ""
38#endif
39 },
40 {
[email protected]232448fb2010-08-27 18:48:2441 "vertical-tabs", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1242 IDS_FLAGS_SIDE_TABS_NAME,
43 IDS_FLAGS_SIDE_TABS_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:1444 // TODO(thakis): Move sidetabs to about:flags on ChromeOS
45 // http://crbug.com/57634
[email protected]ad2a3ded2010-08-27 13:19:0546 kOsWin,
47 switches::kEnableVerticalTabs
[email protected]654151872010-09-13 22:43:0548 },
49 {
50 "tabbed-options", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1251 IDS_FLAGS_TABBED_OPTIONS_NAME,
52 IDS_FLAGS_TABBED_OPTIONS_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:1453 kOsWin | kOsLinux | kOsMac, // Enabled by default on CrOS.
[email protected]654151872010-09-13 22:43:0554 switches::kEnableTabbedOptions
55 },
[email protected]bcf91672010-09-16 15:40:2156 {
[email protected]52fa2d52010-09-25 14:08:5657 "remoting", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1258 IDS_FLAGS_REMOTING_NAME,
[email protected]4fb2f1192010-09-25 14:56:3159#if defined(OS_WIN)
[email protected]52fa2d52010-09-25 14:08:5660 // Windows only supports host functionality at the moment.
[email protected]9486c1f2010-10-14 19:52:1261 IDS_FLAGS_REMOTING_HOST_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:1462#elif defined(OS_LINUX) // Also true for CrOS.
[email protected]52fa2d52010-09-25 14:08:5663 // Linux only supports client functionality at the moment.
[email protected]9486c1f2010-10-14 19:52:1264 IDS_FLAGS_REMOTING_CLIENT_DESCRIPTION,
[email protected]52fa2d52010-09-25 14:08:5665#else
[email protected]a6940852010-09-25 14:25:3266 // On other platforms, this lab isn't available at all.
67 0,
[email protected]52fa2d52010-09-25 14:08:5668#endif
[email protected]1af1dfe2010-10-19 23:49:1469 kOsWin | kOsLinux | kOsCrOS,
[email protected]52fa2d52010-09-25 14:08:5670 switches::kEnableRemoting
71 },
[email protected]a6f03652010-09-28 15:59:0772 {
[email protected]57b66d02010-09-30 11:24:5173 "disable-outdated-plugins", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1274 IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_NAME,
75 IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_DESCRIPTION,
[email protected]57b66d02010-09-30 11:24:5176 kOsAll,
77 switches::kDisableOutdatedPlugins
78 },
[email protected]b3ce30ea2010-10-01 09:33:5379 {
80 "xss-auditor", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1281 IDS_FLAGS_XSS_AUDITOR_NAME,
82 IDS_FLAGS_XSS_AUDITOR_DESCRIPTION,
[email protected]b3ce30ea2010-10-01 09:33:5383 kOsAll,
84 switches::kEnableXSSAuditor
85 },
[email protected]aea2ff42010-10-04 18:04:1986 {
87 "background-webapps", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:1288 IDS_FLAGS_BACKGROUND_WEBAPPS_NAME,
89 IDS_FLAGS_BACKGROUND_WEBAPPS_DESCRIPTION,
[email protected]aea2ff42010-10-04 18:04:1990 kOsAll,
91 switches::kEnableBackgroundMode
[email protected]7bee0b22010-10-05 17:00:4792 },
93 {
[email protected]c1bbaa82010-11-08 11:17:0594 "conflicting-modules-check", // Do not change; see above.
95 IDS_FLAGS_CONFLICTS_CHECK_NAME,
96 IDS_FLAGS_CONFLICTS_CHECK_DESCRIPTION,
97 kOsWin,
98 switches::kConflictingModulesCheck
99 },
100 {
[email protected]7bee0b22010-10-05 17:00:47101 "cloud-print-proxy", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:12102 IDS_FLAGS_CLOUD_PRINT_PROXY_NAME,
103 IDS_FLAGS_CLOUD_PRINT_PROXY_DESCRIPTION,
[email protected]7bee0b22010-10-05 17:00:47104 kOsWin,
105 switches::kEnableCloudPrintProxy
[email protected]8b6588a2010-10-12 02:39:42106 },
[email protected]580939a2010-10-12 18:54:37107 {
108 "match-preview", // Do not change; see above.
[email protected]fdf773c52010-11-01 20:58:19109 IDS_FLAGS_PREDICTIVE_INSTANT_NAME,
110 IDS_FLAGS_PREDICTIVE_INSTANT_DESCRIPTION,
[email protected]cab030772010-11-03 21:37:36111 kOsMac,
[email protected]fdf773c52010-11-01 20:58:19112 switches::kEnablePredictiveInstant
113 },
114 {
115 "verbatim-instant", // Do not change; see above.
116 IDS_FLAGS_VERBATIM_INSTANT_NAME,
117 IDS_FLAGS_VERBATIM_INSTANT_DESCRIPTION,
118 kOsMac | kOsLinux | kOsWin,
119 switches::kEnableVerbatimInstant
[email protected]580939a2010-10-12 18:54:37120 },
[email protected]11c4c812010-10-22 19:50:12121 // FIXME(scheib): Add Flags entry for accelerated Compositing,
122 // or pull it and the strings in generated_resources.grd by Dec 2010
123 // {
124 // "gpu-compositing", // Do not change; see above
125 // IDS_FLAGS_ACCELERATED_COMPOSITING_NAME,
126 // IDS_FLAGS_ACCELERATED_COMPOSITING_DESCRIPTION,
127 // kOsAll,
128 // switches::kDisableAcceleratedCompositing
129 // },
[email protected]8b6588a2010-10-12 02:39:42130 {
131 "gpu-canvas-2d", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12132 IDS_FLAGS_ACCELERATED_CANVAS_2D_NAME,
133 IDS_FLAGS_ACCELERATED_CANVAS_2D_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:14134 kOsWin | kOsLinux | kOsCrOS,
[email protected]8b6588a2010-10-12 02:39:42135 switches::kEnableAccelerated2dCanvas
[email protected]8d260e52010-10-13 01:03:05136 },
[email protected]11c4c812010-10-22 19:50:12137 // FIXME(scheib): Add Flags entry for WebGL,
138 // or pull it and the strings in generated_resources.grd by Dec 2010
139 // {
140 // "webgl", // Do not change; see above
141 // IDS_FLAGS_WEBGL_NAME,
142 // IDS_FLAGS_WEBGL_DESCRIPTION,
143 // kOsAll,
144 // switches::kDisableExperimentalWebGL
145 // }
[email protected]8d260e52010-10-13 01:03:05146 {
147 "print-preview", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12148 IDS_FLAGS_PRINT_PREVIEW_NAME,
149 IDS_FLAGS_PRINT_PREVIEW_DESCRIPTION,
[email protected]8d260e52010-10-13 01:03:05150 kOsAll,
151 switches::kEnablePrintPreview
[email protected]2fe15fcb2010-10-21 20:39:53152 },
153 {
[email protected]4ff87d202010-11-06 01:28:40154 "enable-nacl", // Do not change; see above.
155 IDS_FLAGS_ENABLE_NACL_NAME,
156 IDS_FLAGS_ENABLE_NACL_DESCRIPTION,
157 kOsAll,
158 switches::kEnableNaCl
159 },
160 {
[email protected]2fe15fcb2010-10-21 20:39:53161 "dns-server",
162 IDS_FLAGS_DNS_SERVER_NAME,
163 IDS_FLAGS_DNS_SERVER_DESCRIPTION,
164 kOsLinux,
165 switches::kDnsServer
166 },
[email protected]177aceb2010-11-03 16:17:41167 {
[email protected]83d00d92010-11-04 19:20:21168 "page-prerender",
169 IDS_FLAGS_PAGE_PRERENDER_NAME,
170 IDS_FLAGS_PAGE_PRERENDER_DESCRIPTION,
171 kOsAll,
172 switches::kEnablePagePrerender
173 },
174 {
[email protected]177aceb2010-11-03 16:17:41175 "confirm-to-quit", // Do not change; see above.
176 IDS_FLAGS_CONFIRM_TO_QUIT_NAME,
177 IDS_FLAGS_CONFIRM_TO_QUIT_DESCRIPTION,
178 kOsMac,
179 switches::kEnableConfirmToQuit
180 },
[email protected]ad2a3ded2010-08-27 13:19:05181};
182
[email protected]a314ee5a2010-10-26 21:23:28183const Experiment* experiments = kExperiments;
184size_t num_experiments = arraysize(kExperiments);
185
[email protected]e2ddbc92010-10-15 20:02:07186// Stores and encapsulates the little state that about:flags has.
187class FlagsState {
188 public:
189 FlagsState() : needs_restart_(false) {}
190 void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line);
191 bool IsRestartNeededToCommitChanges();
192 void SetExperimentEnabled(
[email protected]a314ee5a2010-10-26 21:23:28193 PrefService* prefs, const std::string& internal_name, bool enable);
[email protected]e2ddbc92010-10-15 20:02:07194 void RemoveFlagsSwitches(
195 std::map<std::string, CommandLine::StringType>* switch_list);
196 void reset();
197
198 // Returns the singleton instance of this class
199 static FlagsState* instance() {
200 return Singleton<FlagsState>::get();
201 }
202
203 private:
204 bool needs_restart_;
205 std::set<std::string> flags_switches_;
206
207 DISALLOW_COPY_AND_ASSIGN(FlagsState);
208};
209
[email protected]c7b7800a2010-10-07 18:51:35210// Extracts the list of enabled lab experiments from preferences and stores them
[email protected]ad2a3ded2010-08-27 13:19:05211// in a set.
[email protected]1a47d7e2010-10-15 00:37:24212void GetEnabledFlags(const PrefService* prefs, std::set<std::string>* result) {
[email protected]ad2a3ded2010-08-27 13:19:05213 const ListValue* enabled_experiments = prefs->GetList(
214 prefs::kEnabledLabsExperiments);
215 if (!enabled_experiments)
216 return;
217
218 for (ListValue::const_iterator it = enabled_experiments->begin();
219 it != enabled_experiments->end();
220 ++it) {
221 std::string experiment_name;
222 if (!(*it)->GetAsString(&experiment_name)) {
223 LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
224 continue;
225 }
226 result->insert(experiment_name);
227 }
228}
229
230// Takes a set of enabled lab experiments
[email protected]1a47d7e2010-10-15 00:37:24231void SetEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05232 PrefService* prefs, const std::set<std::string>& enabled_experiments) {
233 ListValue* experiments_list = prefs->GetMutableList(
234 prefs::kEnabledLabsExperiments);
235 if (!experiments_list)
236 return;
237
238 experiments_list->Clear();
239 for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
240 it != enabled_experiments.end();
241 ++it) {
242 experiments_list->Append(new StringValue(*it));
243 }
244}
245
246// Removes all experiments from prefs::kEnabledLabsExperiments that are
247// unknown, to prevent this list to become very long as experiments are added
248// and removed.
249void SanitizeList(PrefService* prefs) {
250 std::set<std::string> known_experiments;
[email protected]a314ee5a2010-10-26 21:23:28251 for (size_t i = 0; i < num_experiments; ++i)
252 known_experiments.insert(experiments[i].internal_name);
[email protected]ad2a3ded2010-08-27 13:19:05253
254 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24255 GetEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05256
257 std::set<std::string> new_enabled_experiments;
258 std::set_intersection(
259 known_experiments.begin(), known_experiments.end(),
260 enabled_experiments.begin(), enabled_experiments.end(),
261 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
262
[email protected]1a47d7e2010-10-15 00:37:24263 SetEnabledFlags(prefs, new_enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05264}
265
[email protected]1a47d7e2010-10-15 00:37:24266void GetSanitizedEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05267 PrefService* prefs, std::set<std::string>* result) {
268 SanitizeList(prefs);
[email protected]1a47d7e2010-10-15 00:37:24269 GetEnabledFlags(prefs, result);
[email protected]ad2a3ded2010-08-27 13:19:05270}
271
[email protected]a314ee5a2010-10-26 21:23:28272// Variant of GetSanitizedEnabledFlags that also removes any flags that aren't
273// enabled on the current platform.
274void GetSanitizedEnabledFlagsForCurrentPlatform(
275 PrefService* prefs, std::set<std::string>* result) {
276 GetSanitizedEnabledFlags(prefs, result);
277
278 // Filter out any experiments that aren't enabled on the current platform. We
279 // don't remove these from prefs else syncing to a platform with a different
280 // set of experiments would be lossy.
281 std::set<std::string> platform_experiments;
282 int current_platform = GetCurrentPlatform();
283 for (size_t i = 0; i < num_experiments; ++i) {
284 if (experiments[i].supported_platforms & current_platform)
285 platform_experiments.insert(experiments[i].internal_name);
286 }
287
288 std::set<std::string> new_enabled_experiments;
289 std::set_intersection(
290 platform_experiments.begin(), platform_experiments.end(),
291 result->begin(), result->end(),
292 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
293
294 result->swap(new_enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05295}
296
[email protected]e2ddbc92010-10-15 20:02:07297} // namespace
298
[email protected]1a47d7e2010-10-15 00:37:24299void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line) {
[email protected]e2ddbc92010-10-15 20:02:07300 FlagsState::instance()->ConvertFlagsToSwitches(prefs, command_line);
[email protected]ad2a3ded2010-08-27 13:19:05301}
302
[email protected]1a47d7e2010-10-15 00:37:24303ListValue* GetFlagsExperimentsData(PrefService* prefs) {
[email protected]ad2a3ded2010-08-27 13:19:05304 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24305 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05306
307 int current_platform = GetCurrentPlatform();
308
309 ListValue* experiments_data = new ListValue();
[email protected]a314ee5a2010-10-26 21:23:28310 for (size_t i = 0; i < num_experiments; ++i) {
311 const Experiment& experiment = experiments[i];
[email protected]ad2a3ded2010-08-27 13:19:05312 if (!(experiment.supported_platforms & current_platform))
313 continue;
314
315 DictionaryValue* data = new DictionaryValue();
316 data->SetString("internal_name", experiment.internal_name);
317 data->SetString("name",
318 l10n_util::GetStringUTF16(experiment.visible_name_id));
319 data->SetString("description",
320 l10n_util::GetStringUTF16(
321 experiment.visible_description_id));
322 data->SetBoolean("enabled",
323 enabled_experiments.count(experiment.internal_name) > 0);
324
325 experiments_data->Append(data);
326 }
327 return experiments_data;
328}
329
[email protected]ad2a3ded2010-08-27 13:19:05330bool IsRestartNeededToCommitChanges() {
[email protected]e2ddbc92010-10-15 20:02:07331 return FlagsState::instance()->IsRestartNeededToCommitChanges();
[email protected]ad2a3ded2010-08-27 13:19:05332}
333
334void SetExperimentEnabled(
[email protected]c7b7800a2010-10-07 18:51:35335 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]e2ddbc92010-10-15 20:02:07336 FlagsState::instance()->SetExperimentEnabled(prefs, internal_name, enable);
337}
338
339void RemoveFlagsSwitches(
340 std::map<std::string, CommandLine::StringType>* switch_list) {
341 FlagsState::instance()->RemoveFlagsSwitches(switch_list);
342}
343
[email protected]a314ee5a2010-10-26 21:23:28344int GetCurrentPlatform() {
345#if defined(OS_MACOSX)
346 return kOsMac;
347#elif defined(OS_WIN)
348 return kOsWin;
349#elif defined(OS_CHROMEOS) // Needs to be before the OS_LINUX check.
350 return kOsCrOS;
351#elif defined(OS_LINUX)
352 return kOsLinux;
353#else
354#error Unknown platform
355#endif
356}
357
[email protected]e2ddbc92010-10-15 20:02:07358//////////////////////////////////////////////////////////////////////////////
359// FlagsState implementation.
360
361namespace {
362
363void FlagsState::ConvertFlagsToSwitches(
364 PrefService* prefs, CommandLine* command_line) {
[email protected]e2ddbc92010-10-15 20:02:07365 if (command_line->HasSwitch(switches::kNoExperiments))
366 return;
367
368 std::set<std::string> enabled_experiments;
[email protected]a314ee5a2010-10-26 21:23:28369 GetSanitizedEnabledFlagsForCurrentPlatform(prefs, &enabled_experiments);
[email protected]e2ddbc92010-10-15 20:02:07370
[email protected]a314ee5a2010-10-26 21:23:28371 std::map<std::string, const Experiment*> experiment_map;
372 for (size_t i = 0; i < num_experiments; ++i)
373 experiment_map[experiments[i].internal_name] = &experiments[i];
[email protected]e2ddbc92010-10-15 20:02:07374
375 command_line->AppendSwitch(switches::kFlagSwitchesBegin);
376 flags_switches_.insert(switches::kFlagSwitchesBegin);
377 for (std::set<std::string>::iterator it = enabled_experiments.begin();
378 it != enabled_experiments.end();
379 ++it) {
380 const std::string& experiment_name = *it;
381 std::map<std::string, const Experiment*>::iterator experiment =
[email protected]a314ee5a2010-10-26 21:23:28382 experiment_map.find(experiment_name);
383 DCHECK(experiment != experiment_map.end());
384 if (experiment == experiment_map.end())
[email protected]e2ddbc92010-10-15 20:02:07385 continue;
386
387 command_line->AppendSwitch(experiment->second->command_line);
388 flags_switches_.insert(experiment->second->command_line);
389 }
390 command_line->AppendSwitch(switches::kFlagSwitchesEnd);
391 flags_switches_.insert(switches::kFlagSwitchesEnd);
392}
393
394bool FlagsState::IsRestartNeededToCommitChanges() {
395 return needs_restart_;
396}
397
398void FlagsState::SetExperimentEnabled(
399 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]ad2a3ded2010-08-27 13:19:05400 needs_restart_ = true;
401
402 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24403 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05404
405 if (enable)
406 enabled_experiments.insert(internal_name);
407 else
408 enabled_experiments.erase(internal_name);
409
[email protected]1a47d7e2010-10-15 00:37:24410 SetEnabledFlags(prefs, enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05411}
412
[email protected]e2ddbc92010-10-15 20:02:07413void FlagsState::RemoveFlagsSwitches(
414 std::map<std::string, CommandLine::StringType>* switch_list) {
415 for (std::set<std::string>::const_iterator it = flags_switches_.begin();
416 it != flags_switches_.end();
417 ++it) {
418 switch_list->erase(*it);
419 }
420}
421
422void FlagsState::reset() {
423 needs_restart_ = false;
424 flags_switches_.clear();
425}
426
427} // namespace
428
429namespace testing {
430void ClearState() {
431 FlagsState::instance()->reset();
432}
[email protected]a314ee5a2010-10-26 21:23:28433
434void SetExperiments(const Experiment* e, size_t count) {
435 if (!e) {
436 experiments = kExperiments;
437 num_experiments = arraysize(kExperiments);
438 } else {
439 experiments = e;
440 num_experiments = count;
441 }
442}
443
[email protected]e2ddbc92010-10-15 20:02:07444} // namespace testing
445
[email protected]1a47d7e2010-10-15 00:37:24446} // namespace about_flags