blob: fcbabe7c650754506b681221cd7803039790c155 [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]1af1dfe2010-10-19 23:49:1425enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 , kOsCrOS = 1 << 3 };
[email protected]ad2a3ded2010-08-27 13:19:0526
[email protected]1af1dfe2010-10-19 23:49:1427unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS;
[email protected]654151872010-09-13 22:43:0528
[email protected]ad2a3ded2010-08-27 13:19:0529struct Experiment {
30 // The internal name of the experiment. This is never shown to the user.
31 // It _is_ however stored in the prefs file, so you shouldn't change the
[email protected]1a47d7e2010-10-15 00:37:2432 // name of existing flags.
[email protected]ad2a3ded2010-08-27 13:19:0533 const char* internal_name;
34
35 // String id of the message containing the experiment's name.
36 int visible_name_id;
37
38 // String id of the message containing the experiment's description.
39 int visible_description_id;
40
41 // The platforms the experiment is available on
42 // Needs to be more than a compile-time #ifdef because of profile sync.
43 unsigned supported_platforms; // bitmask
44
45 // The commandline parameter that's added when this lab is active. This is
46 // different from |internal_name| so that the commandline flag can be
47 // renamed without breaking the prefs file.
48 const char* command_line;
49};
50
51const Experiment kExperiments[] = {
52 {
[email protected]232448fb2010-08-27 18:48:2453 "expose-for-tabs", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1254 IDS_FLAGS_TABPOSE_NAME,
55 IDS_FLAGS_TABPOSE_DESCRIPTION,
[email protected]ad2a3ded2010-08-27 13:19:0556 kOsMac,
57#if defined(OS_MACOSX)
58 // The switch exists only on OS X.
59 switches::kEnableExposeForTabs
60#else
61 ""
62#endif
63 },
64 {
[email protected]232448fb2010-08-27 18:48:2465 "vertical-tabs", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1266 IDS_FLAGS_SIDE_TABS_NAME,
67 IDS_FLAGS_SIDE_TABS_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:1468 // TODO(thakis): Move sidetabs to about:flags on ChromeOS
69 // http://crbug.com/57634
[email protected]ad2a3ded2010-08-27 13:19:0570 kOsWin,
71 switches::kEnableVerticalTabs
[email protected]654151872010-09-13 22:43:0572 },
73 {
74 "tabbed-options", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1275 IDS_FLAGS_TABBED_OPTIONS_NAME,
76 IDS_FLAGS_TABBED_OPTIONS_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:1477 kOsWin | kOsLinux | kOsMac, // Enabled by default on CrOS.
[email protected]654151872010-09-13 22:43:0578 switches::kEnableTabbedOptions
79 },
[email protected]bcf91672010-09-16 15:40:2180 {
[email protected]52fa2d52010-09-25 14:08:5681 "remoting", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1282 IDS_FLAGS_REMOTING_NAME,
[email protected]4fb2f1192010-09-25 14:56:3183#if defined(OS_WIN)
[email protected]52fa2d52010-09-25 14:08:5684 // Windows only supports host functionality at the moment.
[email protected]9486c1f2010-10-14 19:52:1285 IDS_FLAGS_REMOTING_HOST_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:1486#elif defined(OS_LINUX) // Also true for CrOS.
[email protected]52fa2d52010-09-25 14:08:5687 // Linux only supports client functionality at the moment.
[email protected]9486c1f2010-10-14 19:52:1288 IDS_FLAGS_REMOTING_CLIENT_DESCRIPTION,
[email protected]52fa2d52010-09-25 14:08:5689#else
[email protected]a6940852010-09-25 14:25:3290 // On other platforms, this lab isn't available at all.
91 0,
[email protected]52fa2d52010-09-25 14:08:5692#endif
[email protected]1af1dfe2010-10-19 23:49:1493 kOsWin | kOsLinux | kOsCrOS,
[email protected]52fa2d52010-09-25 14:08:5694 switches::kEnableRemoting
95 },
[email protected]a6f03652010-09-28 15:59:0796 {
[email protected]57b66d02010-09-30 11:24:5197 "disable-outdated-plugins", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1298 IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_NAME,
99 IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_DESCRIPTION,
[email protected]57b66d02010-09-30 11:24:51100 kOsAll,
101 switches::kDisableOutdatedPlugins
102 },
[email protected]b3ce30ea2010-10-01 09:33:53103 {
104 "xss-auditor", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:12105 IDS_FLAGS_XSS_AUDITOR_NAME,
106 IDS_FLAGS_XSS_AUDITOR_DESCRIPTION,
[email protected]b3ce30ea2010-10-01 09:33:53107 kOsAll,
108 switches::kEnableXSSAuditor
109 },
[email protected]aea2ff42010-10-04 18:04:19110 {
111 "background-webapps", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12112 IDS_FLAGS_BACKGROUND_WEBAPPS_NAME,
113 IDS_FLAGS_BACKGROUND_WEBAPPS_DESCRIPTION,
[email protected]aea2ff42010-10-04 18:04:19114 kOsAll,
115 switches::kEnableBackgroundMode
[email protected]7bee0b22010-10-05 17:00:47116 },
117 {
118 "cloud-print-proxy", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:12119 IDS_FLAGS_CLOUD_PRINT_PROXY_NAME,
120 IDS_FLAGS_CLOUD_PRINT_PROXY_DESCRIPTION,
[email protected]7bee0b22010-10-05 17:00:47121 kOsWin,
[email protected]7bee0b22010-10-05 17:00:47122 switches::kEnableCloudPrintProxy
[email protected]8b6588a2010-10-12 02:39:42123 },
[email protected]580939a2010-10-12 18:54:37124 {
125 "match-preview", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:12126 IDS_FLAGS_INSTANT_NAME,
127 IDS_FLAGS_INSTANT_DESCRIPTION,
[email protected]580939a2010-10-12 18:54:37128 kOsMac,
129 switches::kEnableMatchPreview
130 },
[email protected]11c4c812010-10-22 19:50:12131 // FIXME(scheib): Add Flags entry for accelerated Compositing,
132 // or pull it and the strings in generated_resources.grd by Dec 2010
133 // {
134 // "gpu-compositing", // Do not change; see above
135 // IDS_FLAGS_ACCELERATED_COMPOSITING_NAME,
136 // IDS_FLAGS_ACCELERATED_COMPOSITING_DESCRIPTION,
137 // kOsAll,
138 // switches::kDisableAcceleratedCompositing
139 // },
[email protected]8b6588a2010-10-12 02:39:42140 {
141 "gpu-canvas-2d", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12142 IDS_FLAGS_ACCELERATED_CANVAS_2D_NAME,
143 IDS_FLAGS_ACCELERATED_CANVAS_2D_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:14144 kOsWin | kOsLinux | kOsCrOS,
[email protected]8b6588a2010-10-12 02:39:42145 switches::kEnableAccelerated2dCanvas
[email protected]8d260e52010-10-13 01:03:05146 },
[email protected]11c4c812010-10-22 19:50:12147 // FIXME(scheib): Add Flags entry for WebGL,
148 // or pull it and the strings in generated_resources.grd by Dec 2010
149 // {
150 // "webgl", // Do not change; see above
151 // IDS_FLAGS_WEBGL_NAME,
152 // IDS_FLAGS_WEBGL_DESCRIPTION,
153 // kOsAll,
154 // switches::kDisableExperimentalWebGL
155 // }
[email protected]8d260e52010-10-13 01:03:05156 {
157 "print-preview", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12158 IDS_FLAGS_PRINT_PREVIEW_NAME,
159 IDS_FLAGS_PRINT_PREVIEW_DESCRIPTION,
[email protected]8d260e52010-10-13 01:03:05160 kOsAll,
161 switches::kEnablePrintPreview
[email protected]2fe15fcb2010-10-21 20:39:53162 },
163 {
164 "dns-server",
165 IDS_FLAGS_DNS_SERVER_NAME,
166 IDS_FLAGS_DNS_SERVER_DESCRIPTION,
167 kOsLinux,
168 switches::kDnsServer
169 },
[email protected]0fca4e322010-10-21 20:47:27170 {
171 "secure-infobars", // Do not change; see above
172 IDS_FLAGS_SECURE_INFOBARS_NAME,
173 IDS_FLAGS_SECURE_INFOBARS_DESCRIPTION,
174 kOsAll,
175 switches::kEnableSecureInfoBars
176 }
[email protected]ad2a3ded2010-08-27 13:19:05177};
178
[email protected]e2ddbc92010-10-15 20:02:07179// Stores and encapsulates the little state that about:flags has.
180class FlagsState {
181 public:
182 FlagsState() : needs_restart_(false) {}
183 void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line);
184 bool IsRestartNeededToCommitChanges();
185 void SetExperimentEnabled(
186 PrefService* prefs, const std::string& internal_name, bool enable);
187 void RemoveFlagsSwitches(
188 std::map<std::string, CommandLine::StringType>* switch_list);
189 void reset();
190
191 // Returns the singleton instance of this class
192 static FlagsState* instance() {
193 return Singleton<FlagsState>::get();
194 }
195
196 private:
197 bool needs_restart_;
198 std::set<std::string> flags_switches_;
199
200 DISALLOW_COPY_AND_ASSIGN(FlagsState);
201};
202
[email protected]c7b7800a2010-10-07 18:51:35203// Extracts the list of enabled lab experiments from preferences and stores them
[email protected]ad2a3ded2010-08-27 13:19:05204// in a set.
[email protected]1a47d7e2010-10-15 00:37:24205void GetEnabledFlags(const PrefService* prefs, std::set<std::string>* result) {
[email protected]ad2a3ded2010-08-27 13:19:05206 const ListValue* enabled_experiments = prefs->GetList(
207 prefs::kEnabledLabsExperiments);
208 if (!enabled_experiments)
209 return;
210
211 for (ListValue::const_iterator it = enabled_experiments->begin();
212 it != enabled_experiments->end();
213 ++it) {
214 std::string experiment_name;
215 if (!(*it)->GetAsString(&experiment_name)) {
216 LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
217 continue;
218 }
219 result->insert(experiment_name);
220 }
221}
222
223// Takes a set of enabled lab experiments
[email protected]1a47d7e2010-10-15 00:37:24224void SetEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05225 PrefService* prefs, const std::set<std::string>& enabled_experiments) {
226 ListValue* experiments_list = prefs->GetMutableList(
227 prefs::kEnabledLabsExperiments);
228 if (!experiments_list)
229 return;
230
231 experiments_list->Clear();
232 for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
233 it != enabled_experiments.end();
234 ++it) {
235 experiments_list->Append(new StringValue(*it));
236 }
237}
238
239// Removes all experiments from prefs::kEnabledLabsExperiments that are
240// unknown, to prevent this list to become very long as experiments are added
241// and removed.
242void SanitizeList(PrefService* prefs) {
243 std::set<std::string> known_experiments;
244 for (size_t i = 0; i < arraysize(kExperiments); ++i)
245 known_experiments.insert(kExperiments[i].internal_name);
246
247 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24248 GetEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05249
250 std::set<std::string> new_enabled_experiments;
251 std::set_intersection(
252 known_experiments.begin(), known_experiments.end(),
253 enabled_experiments.begin(), enabled_experiments.end(),
254 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
255
[email protected]1a47d7e2010-10-15 00:37:24256 SetEnabledFlags(prefs, new_enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05257}
258
[email protected]1a47d7e2010-10-15 00:37:24259void GetSanitizedEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05260 PrefService* prefs, std::set<std::string>* result) {
261 SanitizeList(prefs);
[email protected]1a47d7e2010-10-15 00:37:24262 GetEnabledFlags(prefs, result);
[email protected]ad2a3ded2010-08-27 13:19:05263}
264
265int GetCurrentPlatform() {
266#if defined(OS_MACOSX)
267 return kOsMac;
268#elif defined(OS_WIN)
269 return kOsWin;
[email protected]1af1dfe2010-10-19 23:49:14270#elif defined(OS_CHROMEOS) // Needs to be before the OS_LINUX check.
271 return kOsCrOS;
[email protected]ad2a3ded2010-08-27 13:19:05272#elif defined(OS_LINUX)
273 return kOsLinux;
274#else
275#error Unknown platform
276#endif
277}
278
[email protected]e2ddbc92010-10-15 20:02:07279} // namespace
280
[email protected]1a47d7e2010-10-15 00:37:24281void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line) {
[email protected]e2ddbc92010-10-15 20:02:07282 FlagsState::instance()->ConvertFlagsToSwitches(prefs, command_line);
[email protected]ad2a3ded2010-08-27 13:19:05283}
284
[email protected]1a47d7e2010-10-15 00:37:24285ListValue* GetFlagsExperimentsData(PrefService* prefs) {
[email protected]ad2a3ded2010-08-27 13:19:05286 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24287 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05288
289 int current_platform = GetCurrentPlatform();
290
291 ListValue* experiments_data = new ListValue();
292 for (size_t i = 0; i < arraysize(kExperiments); ++i) {
293 const Experiment& experiment = kExperiments[i];
294 if (!(experiment.supported_platforms & current_platform))
295 continue;
296
297 DictionaryValue* data = new DictionaryValue();
298 data->SetString("internal_name", experiment.internal_name);
299 data->SetString("name",
300 l10n_util::GetStringUTF16(experiment.visible_name_id));
301 data->SetString("description",
302 l10n_util::GetStringUTF16(
303 experiment.visible_description_id));
304 data->SetBoolean("enabled",
305 enabled_experiments.count(experiment.internal_name) > 0);
306
307 experiments_data->Append(data);
308 }
309 return experiments_data;
310}
311
[email protected]ad2a3ded2010-08-27 13:19:05312bool IsRestartNeededToCommitChanges() {
[email protected]e2ddbc92010-10-15 20:02:07313 return FlagsState::instance()->IsRestartNeededToCommitChanges();
[email protected]ad2a3ded2010-08-27 13:19:05314}
315
316void SetExperimentEnabled(
[email protected]c7b7800a2010-10-07 18:51:35317 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]e2ddbc92010-10-15 20:02:07318 FlagsState::instance()->SetExperimentEnabled(prefs, internal_name, enable);
319}
320
321void RemoveFlagsSwitches(
322 std::map<std::string, CommandLine::StringType>* switch_list) {
323 FlagsState::instance()->RemoveFlagsSwitches(switch_list);
324}
325
326//////////////////////////////////////////////////////////////////////////////
327// FlagsState implementation.
328
329namespace {
330
331void FlagsState::ConvertFlagsToSwitches(
332 PrefService* prefs, CommandLine* command_line) {
[email protected]e2ddbc92010-10-15 20:02:07333 if (command_line->HasSwitch(switches::kNoExperiments))
334 return;
335
336 std::set<std::string> enabled_experiments;
337 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
338
339 std::map<std::string, const Experiment*> experiments;
340 for (size_t i = 0; i < arraysize(kExperiments); ++i)
341 experiments[kExperiments[i].internal_name] = &kExperiments[i];
342
343 command_line->AppendSwitch(switches::kFlagSwitchesBegin);
344 flags_switches_.insert(switches::kFlagSwitchesBegin);
345 for (std::set<std::string>::iterator it = enabled_experiments.begin();
346 it != enabled_experiments.end();
347 ++it) {
348 const std::string& experiment_name = *it;
349 std::map<std::string, const Experiment*>::iterator experiment =
350 experiments.find(experiment_name);
351 DCHECK(experiment != experiments.end());
352 if (experiment == experiments.end())
353 continue;
354
355 command_line->AppendSwitch(experiment->second->command_line);
356 flags_switches_.insert(experiment->second->command_line);
357 }
358 command_line->AppendSwitch(switches::kFlagSwitchesEnd);
359 flags_switches_.insert(switches::kFlagSwitchesEnd);
360}
361
362bool FlagsState::IsRestartNeededToCommitChanges() {
363 return needs_restart_;
364}
365
366void FlagsState::SetExperimentEnabled(
367 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]ad2a3ded2010-08-27 13:19:05368 needs_restart_ = true;
369
370 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24371 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05372
373 if (enable)
374 enabled_experiments.insert(internal_name);
375 else
376 enabled_experiments.erase(internal_name);
377
[email protected]1a47d7e2010-10-15 00:37:24378 SetEnabledFlags(prefs, enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05379}
380
[email protected]e2ddbc92010-10-15 20:02:07381void FlagsState::RemoveFlagsSwitches(
382 std::map<std::string, CommandLine::StringType>* switch_list) {
383 for (std::set<std::string>::const_iterator it = flags_switches_.begin();
384 it != flags_switches_.end();
385 ++it) {
386 switch_list->erase(*it);
387 }
388}
389
390void FlagsState::reset() {
391 needs_restart_ = false;
392 flags_switches_.clear();
393}
394
395} // namespace
396
397namespace testing {
398void ClearState() {
399 FlagsState::instance()->reset();
400}
401} // namespace testing
402
[email protected]1a47d7e2010-10-15 00:37:24403} // namespace about_flags