blob: 6cfd84c865cc7f81664ea3b4622152149d4693dc [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]1a47d7e2010-10-15 00:37:24131 // FIXME(scheib): Add Flags entry for accelerated Compositing,
[email protected]8b6588a2010-10-12 02:39:42132 // or pull it and the strings in generated_resources.grd by Dec 2010
133 //{
134 // "gpu-compositing", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12135 // IDS_FLAGS_ACCELERATED_COMPOSITING_NAME,
136 // IDS_FLAGS_ACCELERATED_COMPOSITING_DESCRIPTION,
[email protected]8b6588a2010-10-12 02:39:42137 // kOsAll,
138 // switches::kDisableAcceleratedCompositing
139 //},
140 {
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]1a47d7e2010-10-15 00:37:24147 // FIXME(scheib): Add Flags entry for WebGL,
[email protected]8b6588a2010-10-12 02:39:42148 // or pull it and the strings in generated_resources.grd by Dec 2010
149 //{
150 // "webgl", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12151 // IDS_FLAGS_WEBGL_NAME,
152 // IDS_FLAGS_WEBGL_DESCRIPTION,
[email protected]8b6588a2010-10-12 02:39:42153 // 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]ad2a3ded2010-08-27 13:19:05170};
171
[email protected]e2ddbc92010-10-15 20:02:07172// Stores and encapsulates the little state that about:flags has.
173class FlagsState {
174 public:
175 FlagsState() : needs_restart_(false) {}
176 void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line);
177 bool IsRestartNeededToCommitChanges();
178 void SetExperimentEnabled(
179 PrefService* prefs, const std::string& internal_name, bool enable);
180 void RemoveFlagsSwitches(
181 std::map<std::string, CommandLine::StringType>* switch_list);
182 void reset();
183
184 // Returns the singleton instance of this class
185 static FlagsState* instance() {
186 return Singleton<FlagsState>::get();
187 }
188
189 private:
190 bool needs_restart_;
191 std::set<std::string> flags_switches_;
192
193 DISALLOW_COPY_AND_ASSIGN(FlagsState);
194};
195
[email protected]c7b7800a2010-10-07 18:51:35196// Extracts the list of enabled lab experiments from preferences and stores them
[email protected]ad2a3ded2010-08-27 13:19:05197// in a set.
[email protected]1a47d7e2010-10-15 00:37:24198void GetEnabledFlags(const PrefService* prefs, std::set<std::string>* result) {
[email protected]ad2a3ded2010-08-27 13:19:05199 const ListValue* enabled_experiments = prefs->GetList(
200 prefs::kEnabledLabsExperiments);
201 if (!enabled_experiments)
202 return;
203
204 for (ListValue::const_iterator it = enabled_experiments->begin();
205 it != enabled_experiments->end();
206 ++it) {
207 std::string experiment_name;
208 if (!(*it)->GetAsString(&experiment_name)) {
209 LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
210 continue;
211 }
212 result->insert(experiment_name);
213 }
214}
215
216// Takes a set of enabled lab experiments
[email protected]1a47d7e2010-10-15 00:37:24217void SetEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05218 PrefService* prefs, const std::set<std::string>& enabled_experiments) {
219 ListValue* experiments_list = prefs->GetMutableList(
220 prefs::kEnabledLabsExperiments);
221 if (!experiments_list)
222 return;
223
224 experiments_list->Clear();
225 for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
226 it != enabled_experiments.end();
227 ++it) {
228 experiments_list->Append(new StringValue(*it));
229 }
230}
231
232// Removes all experiments from prefs::kEnabledLabsExperiments that are
233// unknown, to prevent this list to become very long as experiments are added
234// and removed.
235void SanitizeList(PrefService* prefs) {
236 std::set<std::string> known_experiments;
237 for (size_t i = 0; i < arraysize(kExperiments); ++i)
238 known_experiments.insert(kExperiments[i].internal_name);
239
240 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24241 GetEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05242
243 std::set<std::string> new_enabled_experiments;
244 std::set_intersection(
245 known_experiments.begin(), known_experiments.end(),
246 enabled_experiments.begin(), enabled_experiments.end(),
247 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
248
[email protected]1a47d7e2010-10-15 00:37:24249 SetEnabledFlags(prefs, new_enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05250}
251
[email protected]1a47d7e2010-10-15 00:37:24252void GetSanitizedEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05253 PrefService* prefs, std::set<std::string>* result) {
254 SanitizeList(prefs);
[email protected]1a47d7e2010-10-15 00:37:24255 GetEnabledFlags(prefs, result);
[email protected]ad2a3ded2010-08-27 13:19:05256}
257
258int GetCurrentPlatform() {
259#if defined(OS_MACOSX)
260 return kOsMac;
261#elif defined(OS_WIN)
262 return kOsWin;
[email protected]1af1dfe2010-10-19 23:49:14263#elif defined(OS_CHROMEOS) // Needs to be before the OS_LINUX check.
264 return kOsCrOS;
[email protected]ad2a3ded2010-08-27 13:19:05265#elif defined(OS_LINUX)
266 return kOsLinux;
267#else
268#error Unknown platform
269#endif
270}
271
[email protected]e2ddbc92010-10-15 20:02:07272} // namespace
273
[email protected]1a47d7e2010-10-15 00:37:24274void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line) {
[email protected]e2ddbc92010-10-15 20:02:07275 FlagsState::instance()->ConvertFlagsToSwitches(prefs, command_line);
[email protected]ad2a3ded2010-08-27 13:19:05276}
277
[email protected]1a47d7e2010-10-15 00:37:24278ListValue* GetFlagsExperimentsData(PrefService* prefs) {
[email protected]ad2a3ded2010-08-27 13:19:05279 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24280 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05281
282 int current_platform = GetCurrentPlatform();
283
284 ListValue* experiments_data = new ListValue();
285 for (size_t i = 0; i < arraysize(kExperiments); ++i) {
286 const Experiment& experiment = kExperiments[i];
287 if (!(experiment.supported_platforms & current_platform))
288 continue;
289
290 DictionaryValue* data = new DictionaryValue();
291 data->SetString("internal_name", experiment.internal_name);
292 data->SetString("name",
293 l10n_util::GetStringUTF16(experiment.visible_name_id));
294 data->SetString("description",
295 l10n_util::GetStringUTF16(
296 experiment.visible_description_id));
297 data->SetBoolean("enabled",
298 enabled_experiments.count(experiment.internal_name) > 0);
299
300 experiments_data->Append(data);
301 }
302 return experiments_data;
303}
304
[email protected]ad2a3ded2010-08-27 13:19:05305bool IsRestartNeededToCommitChanges() {
[email protected]e2ddbc92010-10-15 20:02:07306 return FlagsState::instance()->IsRestartNeededToCommitChanges();
[email protected]ad2a3ded2010-08-27 13:19:05307}
308
309void SetExperimentEnabled(
[email protected]c7b7800a2010-10-07 18:51:35310 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]e2ddbc92010-10-15 20:02:07311 FlagsState::instance()->SetExperimentEnabled(prefs, internal_name, enable);
312}
313
314void RemoveFlagsSwitches(
315 std::map<std::string, CommandLine::StringType>* switch_list) {
316 FlagsState::instance()->RemoveFlagsSwitches(switch_list);
317}
318
319//////////////////////////////////////////////////////////////////////////////
320// FlagsState implementation.
321
322namespace {
323
324void FlagsState::ConvertFlagsToSwitches(
325 PrefService* prefs, CommandLine* command_line) {
[email protected]e2ddbc92010-10-15 20:02:07326 if (command_line->HasSwitch(switches::kNoExperiments))
327 return;
328
329 std::set<std::string> enabled_experiments;
330 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
331
332 std::map<std::string, const Experiment*> experiments;
333 for (size_t i = 0; i < arraysize(kExperiments); ++i)
334 experiments[kExperiments[i].internal_name] = &kExperiments[i];
335
336 command_line->AppendSwitch(switches::kFlagSwitchesBegin);
337 flags_switches_.insert(switches::kFlagSwitchesBegin);
338 for (std::set<std::string>::iterator it = enabled_experiments.begin();
339 it != enabled_experiments.end();
340 ++it) {
341 const std::string& experiment_name = *it;
342 std::map<std::string, const Experiment*>::iterator experiment =
343 experiments.find(experiment_name);
344 DCHECK(experiment != experiments.end());
345 if (experiment == experiments.end())
346 continue;
347
348 command_line->AppendSwitch(experiment->second->command_line);
349 flags_switches_.insert(experiment->second->command_line);
350 }
351 command_line->AppendSwitch(switches::kFlagSwitchesEnd);
352 flags_switches_.insert(switches::kFlagSwitchesEnd);
353}
354
355bool FlagsState::IsRestartNeededToCommitChanges() {
356 return needs_restart_;
357}
358
359void FlagsState::SetExperimentEnabled(
360 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]ad2a3ded2010-08-27 13:19:05361 needs_restart_ = true;
362
363 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24364 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05365
366 if (enable)
367 enabled_experiments.insert(internal_name);
368 else
369 enabled_experiments.erase(internal_name);
370
[email protected]1a47d7e2010-10-15 00:37:24371 SetEnabledFlags(prefs, enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05372}
373
[email protected]e2ddbc92010-10-15 20:02:07374void FlagsState::RemoveFlagsSwitches(
375 std::map<std::string, CommandLine::StringType>* switch_list) {
376 for (std::set<std::string>::const_iterator it = flags_switches_.begin();
377 it != flags_switches_.end();
378 ++it) {
379 switch_list->erase(*it);
380 }
381}
382
383void FlagsState::reset() {
384 needs_restart_ = false;
385 flags_switches_.clear();
386}
387
388} // namespace
389
390namespace testing {
391void ClearState() {
392 FlagsState::instance()->reset();
393}
394} // namespace testing
395
[email protected]1a47d7e2010-10-15 00:37:24396} // namespace about_flags