blob: 4caeec90d994bdaef231be257709ab990867ad7e [file] [log] [blame]
sdefresne14900ee2015-11-27 14:43:211// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Implementation of about_flags for iOS that sets flags based on experimental
6// settings.
7
8#include "ios/chrome/browser/about_flags.h"
9
avi571943672015-12-22 02:12:4910#include <stddef.h>
11#include <stdint.h>
sdefresne14900ee2015-11-27 14:43:2112#import <UIKit/UIKit.h>
13
14#include "base/bind.h"
15#include "base/command_line.h"
16#include "base/logging.h"
avi571943672015-12-22 02:12:4917#include "base/macros.h"
sdefresne14900ee2015-11-27 14:43:2118#include "base/memory/singleton.h"
19#include "base/strings/stringprintf.h"
20#include "base/strings/sys_string_conversions.h"
21#include "base/sys_info.h"
robliao59eed1a2016-10-28 17:12:1622#include "base/task_scheduler/switches.h"
sdefresne14900ee2015-11-27 14:43:2123#include "components/dom_distiller/core/dom_distiller_switches.h"
Cooper Knaak1e026562017-07-26 05:22:2824#include "components/feature_engagement_tracker/public/feature_constants.h"
25#include "components/feature_engagement_tracker/public/feature_list.h"
sdefresne14900ee2015-11-27 14:43:2126#include "components/flags_ui/feature_entry.h"
27#include "components/flags_ui/feature_entry_macros.h"
28#include "components/flags_ui/flags_storage.h"
29#include "components/flags_ui/flags_ui_switches.h"
noyau4cfb1332016-10-25 17:05:4230#include "components/ntp_tiles/switches.h"
mathp9b4c11d2017-07-06 20:24:1331#include "components/payments/core/features.h"
elawrence816f6790e2017-06-16 18:19:2832#include "components/security_state/core/switches.h"
jlebel2cf54d72017-03-29 13:51:4033#include "components/signin/core/common/signin_switches.h"
sdefresne36579782016-02-05 11:08:2534#include "components/strings/grit/components_strings.h"
sdefresne14900ee2015-11-27 14:43:2135#include "ios/chrome/browser/chrome_switches.h"
vabr0215a8e2017-03-28 12:47:3436#include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
sdefresne14900ee2015-11-27 14:43:2137#include "ios/chrome/grit/ios_strings.h"
Mike Dougherty929e2482017-07-19 18:38:2538#include "ios/components/captive_portal/features.h"
msardafc76f662017-02-24 12:46:2839#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
sdefresne14900ee2015-11-27 14:43:2140#include "ios/web/public/user_agent.h"
41#include "ios/web/public/web_view_creation_util.h"
42
43#if !defined(OFFICIAL_BUILD)
44#include "components/variations/variations_switches.h"
vitaliii489217aa2017-01-30 14:50:2245#endif
stkhapuginc1be1792016-12-13 14:30:5346
47#if !defined(__has_feature) || !__has_feature(objc_arc)
48#error "This file requires ARC support."
49#endif
sdefresne14900ee2015-11-27 14:43:2150
elawrence816f6790e2017-06-16 18:19:2851using flags_ui::FeatureEntry;
52
sdefresne14900ee2015-11-27 14:43:2153namespace {
elawrence816f6790e2017-06-16 18:19:2854const FeatureEntry::Choice kMarkHttpAsChoices[] = {
55 {flags_ui::kGenericExperimentChoiceDefault, "", ""},
56 {flag_descriptions::kMarkHttpAsNonSecureAfterEditing,
57 security_state::switches::kMarkHttpAs,
58 security_state::switches::kMarkHttpAsNonSecureAfterEditing},
59 {flag_descriptions::kMarkHttpAsNonSecureWhileIncognito,
60 security_state::switches::kMarkHttpAs,
61 security_state::switches::kMarkHttpAsNonSecureWhileIncognito},
62 {flag_descriptions::kMarkHttpAsNonSecureWhileIncognitoOrEditing,
63 security_state::switches::kMarkHttpAs,
64 security_state::switches::kMarkHttpAsNonSecureWhileIncognitoOrEditing},
65 {flag_descriptions::kMarkHttpAsDangerous,
66 security_state::switches::kMarkHttpAs,
67 security_state::switches::kMarkHttpAsDangerous}};
68
Cooper Knaak1e026562017-07-26 05:22:2869// To add a new entry, add to the end of kFeatureEntries. There are four
sdefresne14900ee2015-11-27 14:43:2170// distinct types of entries:
Cooper Knaak1e026562017-07-26 05:22:2871// . ENABLE_DISABLE_VALUE: entry is either enabled, disabled, or uses the
72// default value for this feature. Use the ENABLE_DISABLE_VALUE_TYPE
sdefresne14900ee2015-11-27 14:43:2173// macro for this type supplying the command line to the macro.
74// . MULTI_VALUE: a list of choices, the first of which should correspond to a
75// deactivated state for this lab (i.e. no command line option). To specify
76// this type of entry use the macro MULTI_VALUE_TYPE supplying it the
77// array of choices.
Cooper Knaak1e026562017-07-26 05:22:2878// . FEATURE_VALUE: entry is associated with a base::Feature instance. Entry is
79// either enabled, disabled, or uses the default value of the associated
80// base::Feature instance. To specify this type of entry use the macro
81// FEATURE_VALUE_TYPE supplying it the base::Feature instance.
82// . FEATURE_WITH_PARAM_VALUES: a list of choices associated with a
83// base::Feature instance. Choices corresponding to the default state, a
84// universally enabled state, and a universally disabled state are
85// automatically included. To specify this type of entry use the macro
86// FEATURE_WITH_PARAMS_VALUE_TYPE supplying it the base::Feature instance and
87// the array of choices.
88//
sdefresne14900ee2015-11-27 14:43:2189// See the documentation of FeatureEntry for details on the fields.
90//
91// When adding a new choice, add it to the end of the list.
92const flags_ui::FeatureEntry kFeatureEntries[] = {
vabr0215a8e2017-03-28 12:47:3493 {"contextual-search", flag_descriptions::kContextualSearch,
94 flag_descriptions::kContextualSearchDescription, flags_ui::kOsIos,
sdefresne14900ee2015-11-27 14:43:2195 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableContextualSearch,
96 switches::kDisableContextualSearch)},
vabr0215a8e2017-03-28 12:47:3497 {"ios-physical-web", flag_descriptions::kPhysicalWeb,
98 flag_descriptions::kPhysicalWebDescription, flags_ui::kOsIos,
mattreynolds1a4181f2016-10-05 23:50:0099 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableIOSPhysicalWeb,
100 switches::kDisableIOSPhysicalWeb)},
vabr0215a8e2017-03-28 12:47:34101 {"browser-task-scheduler", flag_descriptions::kBrowserTaskScheduler,
102 flag_descriptions::kBrowserTaskSchedulerDescription, flags_ui::kOsIos,
robliao59eed1a2016-10-28 17:12:16103 ENABLE_DISABLE_VALUE_TYPE(switches::kEnableBrowserTaskScheduler,
104 switches::kDisableBrowserTaskScheduler)},
elawrence816f6790e2017-06-16 18:19:28105 {"mark-non-secure-as", flag_descriptions::kMarkHttpAsName,
106 flag_descriptions::kMarkHttpAsDescription, flags_ui::kOsIos,
107 MULTI_VALUE_TYPE(kMarkHttpAsChoices)},
mathp9b4c11d2017-07-06 20:24:13108 {"web-payments", flag_descriptions::kWebPaymentsName,
109 flag_descriptions::kWebPaymentsDescription, flags_ui::kOsIos,
110 FEATURE_VALUE_TYPE(payments::features::kWebPayments)},
Mike Dougherty929e2482017-07-19 18:38:25111 {"ios-captive-portal", flag_descriptions::kIosCaptivePortalName,
112 flag_descriptions::kIosCaptivePortalDescription, flags_ui::kOsIos,
113 FEATURE_VALUE_TYPE(captive_portal::kIosCaptivePortal)},
Cooper Knaak1e026562017-07-26 05:22:28114 {"in-product-help-demo-mode-choice",
115 flag_descriptions::kInProductHelpDemoModeName,
116 flag_descriptions::kInProductHelpDemoModeDescription, flags_ui::kOsIos,
117 FEATURE_WITH_PARAMS_VALUE_TYPE(
118 feature_engagement_tracker::kIPHDemoMode,
119 feature_engagement_tracker::kIPHDemoModeChoiceVariations,
120 "IPH_DemoMode")}};
sdefresne14900ee2015-11-27 14:43:21121
122// Add all switches from experimental flags to |command_line|.
123void AppendSwitchesFromExperimentalSettings(base::CommandLine* command_line) {
124 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
125
liaoyukedf4f7e42017-01-07 00:21:10126 // Populate command line flag for the tab strip auto scroll new tabs
127 // experiment from the configuration plist.
128 if ([defaults boolForKey:@"TabStripAutoScrollNewTabsDisabled"])
129 command_line->AppendSwitch(switches::kDisableTabStripAutoScrollNewTabs);
130
sdefresne14900ee2015-11-27 14:43:21131 // Populate command line flag for the SnapshotLRUCache experiment from the
132 // configuration plist.
133 NSString* enableLRUSnapshotCache =
134 [defaults stringForKey:@"SnapshotLRUCache"];
135 if ([enableLRUSnapshotCache isEqualToString:@"Enabled"]) {
136 command_line->AppendSwitch(switches::kEnableLRUSnapshotCache);
137 } else if ([enableLRUSnapshotCache isEqualToString:@"Disabled"]) {
138 command_line->AppendSwitch(switches::kDisableLRUSnapshotCache);
139 }
140
sdefresne14900ee2015-11-27 14:43:21141 // Populate command line flags from PasswordGenerationEnabled.
142 NSString* enablePasswordGenerationValue =
143 [defaults stringForKey:@"PasswordGenerationEnabled"];
144 if ([enablePasswordGenerationValue isEqualToString:@"Enabled"]) {
145 command_line->AppendSwitch(switches::kEnableIOSPasswordGeneration);
146 } else if ([enablePasswordGenerationValue isEqualToString:@"Disabled"]) {
147 command_line->AppendSwitch(switches::kDisableIOSPasswordGeneration);
148 }
149
mattreynoldsc9f1df52016-06-29 08:30:04150 // Populate command line flags from PhysicalWebEnabled.
151 NSString* enablePhysicalWebValue =
152 [defaults stringForKey:@"PhysicalWebEnabled"];
153 if ([enablePhysicalWebValue isEqualToString:@"Enabled"]) {
154 command_line->AppendSwitch(switches::kEnableIOSPhysicalWeb);
155 } else if ([enablePhysicalWebValue isEqualToString:@"Disabled"]) {
156 command_line->AppendSwitch(switches::kDisableIOSPhysicalWeb);
157 }
158
sdefresne14900ee2015-11-27 14:43:21159 // Web page replay flags.
160 BOOL webPageReplayEnabled = [defaults boolForKey:@"WebPageReplayEnabled"];
161 NSString* webPageReplayProxy =
162 [defaults stringForKey:@"WebPageReplayProxyAddress"];
163 if (webPageReplayEnabled && [webPageReplayProxy length]) {
164 command_line->AppendSwitch(switches::kIOSIgnoreCertificateErrors);
165 // 80 and 443 are the default ports from web page replay.
166 command_line->AppendSwitchASCII(switches::kIOSTestingFixedHttpPort, "80");
167 command_line->AppendSwitchASCII(switches::kIOSTestingFixedHttpsPort, "443");
168 command_line->AppendSwitchASCII(
169 switches::kIOSHostResolverRules,
170 "MAP * " + base::SysNSStringToUTF8(webPageReplayProxy));
171 }
172
sdefresne14900ee2015-11-27 14:43:21173 NSString* autoReloadEnabledValue =
174 [defaults stringForKey:@"AutoReloadEnabled"];
175 if ([autoReloadEnabledValue isEqualToString:@"Enabled"]) {
176 command_line->AppendSwitch(switches::kEnableOfflineAutoReload);
177 } else if ([autoReloadEnabledValue isEqualToString:@"Disabled"]) {
178 command_line->AppendSwitch(switches::kDisableOfflineAutoReload);
179 }
180
181 // Populate command line flags from EnableFastWebScrollViewInsets.
182 NSString* enableFastWebScrollViewInsets =
183 [defaults stringForKey:@"EnableFastWebScrollViewInsets"];
184 if ([enableFastWebScrollViewInsets isEqualToString:@"Enabled"]) {
185 command_line->AppendSwitch(switches::kEnableIOSFastWebScrollViewInsets);
186 } else if ([enableFastWebScrollViewInsets isEqualToString:@"Disabled"]) {
187 command_line->AppendSwitch(switches::kDisableIOSFastWebScrollViewInsets);
188 }
189
190 // Populate command line flags from ReaderModeEnabled.
191 if ([defaults boolForKey:@"ReaderModeEnabled"]) {
192 command_line->AppendSwitch(switches::kEnableReaderModeToolbarIcon);
193
194 // Populate command line from ReaderMode Heuristics detection.
195 NSString* readerModeDetectionHeuristics =
196 [defaults stringForKey:@"ReaderModeDetectionHeuristics"];
197 if (!readerModeDetectionHeuristics) {
noyaudb4a2d62016-09-26 11:04:45198 command_line->AppendSwitchASCII(
199 switches::kReaderModeHeuristics,
200 switches::reader_mode_heuristics::kOGArticle);
sdefresne14900ee2015-11-27 14:43:21201 } else if ([readerModeDetectionHeuristics isEqualToString:@"AdaBoost"]) {
noyaudb4a2d62016-09-26 11:04:45202 command_line->AppendSwitchASCII(
203 switches::kReaderModeHeuristics,
204 switches::reader_mode_heuristics::kAdaBoost);
sdefresne14900ee2015-11-27 14:43:21205 } else {
206 DCHECK([readerModeDetectionHeuristics isEqualToString:@"Off"]);
noyaudb4a2d62016-09-26 11:04:45207 command_line->AppendSwitchASCII(switches::kReaderModeHeuristics,
208 switches::reader_mode_heuristics::kNone);
sdefresne14900ee2015-11-27 14:43:21209 }
210 }
211
sdefresne14900ee2015-11-27 14:43:21212 // Set the UA flag if UseMobileSafariUA is enabled.
213 if ([defaults boolForKey:@"UseMobileSafariUA"]) {
214 // Safari uses "Vesion/", followed by the OS version excluding bugfix, where
215 // Chrome puts its product token.
avi571943672015-12-22 02:12:49216 int32_t major = 0;
217 int32_t minor = 0;
218 int32_t bugfix = 0;
sdefresne14900ee2015-11-27 14:43:21219 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
220 std::string product = base::StringPrintf("Version/%d.%d", major, minor);
221
222 command_line->AppendSwitchASCII(switches::kUserAgent,
223 web::BuildUserAgentFromProduct(product));
224 }
225
gambardd2e44fb2017-01-25 09:14:21226 // Populate command line flag for Suggestions UI display.
227 NSString* enableSuggestions = [defaults stringForKey:@"EnableSuggestions"];
228 if ([enableSuggestions isEqualToString:@"Enabled"]) {
229 command_line->AppendSwitch(switches::kEnableSuggestionsUI);
230 } else if ([enableSuggestions isEqualToString:@"Disabled"]) {
231 command_line->AppendSwitch(switches::kDisableSuggestionsUI);
232 }
233
jkrcal7d79de52017-05-05 18:13:10234 // Populate command line flag for fetching missing favicons for NTP tiles.
235 NSString* enableMostLikelyFaviconsFromServer =
236 [defaults stringForKey:@"EnableNtpMostLikelyFaviconsFromServer"];
237 if ([enableMostLikelyFaviconsFromServer isEqualToString:@"Enabled"]) {
238 command_line->AppendSwitch(
239 ntp_tiles::switches::kEnableNtpMostLikelyFaviconsFromServer);
240 } else if ([enableMostLikelyFaviconsFromServer isEqualToString:@"Disabled"]) {
241 command_line->AppendSwitch(
242 ntp_tiles::switches::kDisableNtpMostLikelyFaviconsFromServer);
243 }
244
Danyao Wang6ab20f72017-06-20 14:13:41245 // Populate command line flag for the native to WKBackForwardList based
246 // navigation manager experiment.
247 NSString* enableSlimNavigationManager =
248 [defaults stringForKey:@"EnableSlimNavigationManager"];
249 if ([enableSlimNavigationManager isEqualToString:@"Enabled"]) {
250 command_line->AppendSwitch(switches::kEnableSlimNavigationManager);
251 } else if ([enableSlimNavigationManager isEqualToString:@"Disabled"]) {
252 command_line->AppendSwitch(switches::kDisableSlimNavigationManager);
253 }
254
sdefresne14900ee2015-11-27 14:43:21255 // Freeform commandline flags. These are added last, so that any flags added
256 // earlier in this function take precedence.
257 if ([defaults boolForKey:@"EnableFreeformCommandLineFlags"]) {
258 base::CommandLine::StringVector flags;
259 // Append an empty "program" argument.
260 flags.push_back("");
261
262 // The number of flags corresponds to the number of text fields in
263 // Experimental.plist.
264 const int kNumFreeformFlags = 5;
265 for (int i = 1; i <= kNumFreeformFlags; ++i) {
266 NSString* key =
267 [NSString stringWithFormat:@"FreeformCommandLineFlag%d", i];
268 NSString* flag = [defaults stringForKey:key];
269 if ([flag length]) {
270 flags.push_back(base::SysNSStringToUTF8(flag));
271 }
272 }
273
274 base::CommandLine temp_command_line(flags);
275 command_line->AppendArguments(temp_command_line, false);
276 }
msardafc76f662017-02-24 12:46:28277
jlebel2cf54d72017-03-29 13:51:40278 // Populate command line flag for Sign-in promo.
279 NSString* enableSigninPromo = [defaults stringForKey:@"EnableSigninPromo"];
280 if ([enableSigninPromo isEqualToString:@"Enabled"]) {
281 command_line->AppendSwitch(switches::kEnableSigninPromo);
282 } else if ([enableSigninPromo isEqualToString:@"Disabled"]) {
283 command_line->AppendSwitch(switches::kDisableSigninPromo);
284 }
285
martiwed82d452017-06-19 00:10:26286 // Populate command line flag for Bookmark reordering.
287 NSString* enableBookmarkReordering =
288 [defaults stringForKey:@"EnableBookmarkReordering"];
289 if ([enableBookmarkReordering isEqualToString:@"Enabled"]) {
290 command_line->AppendSwitch(switches::kEnableBookmarkReordering);
291 } else if ([enableBookmarkReordering isEqualToString:@"Disabled"]) {
292 command_line->AppendSwitch(switches::kDisableBookmarkReordering);
293 }
294
Yuke Liao705611d2017-06-01 18:03:06295 // Populate command line flag for the request mobile site experiment from the
296 // configuration plist.
297 if ([defaults boolForKey:@"RequestMobileSiteDisabled"])
298 command_line->AppendSwitch(switches::kDisableRequestMobileSite);
299
justincohendacc85d2017-06-28 23:34:10300 // Populate command line flag for 3rd party keyboard omnibox workaround.
301 NSString* enableThirdPartyKeyboardWorkaround =
302 [defaults stringForKey:@"EnableThirdPartyKeyboardWorkaround"];
303 if ([enableThirdPartyKeyboardWorkaround isEqualToString:@"Enabled"]) {
304 command_line->AppendSwitch(switches::kEnableThirdPartyKeyboardWorkaround);
305 } else if ([enableThirdPartyKeyboardWorkaround isEqualToString:@"Disabled"]) {
306 command_line->AppendSwitch(switches::kDisableThirdPartyKeyboardWorkaround);
307 }
308
msardafc76f662017-02-24 12:46:28309 ios::GetChromeBrowserProvider()->AppendSwitchesFromExperimentalSettings(
310 defaults, command_line);
sdefresne14900ee2015-11-27 14:43:21311}
312
313bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
314 return false;
315}
316
317class FlagsStateSingleton {
318 public:
319 FlagsStateSingleton()
320 : flags_state_(kFeatureEntries, arraysize(kFeatureEntries)) {}
321 ~FlagsStateSingleton() {}
322
323 static FlagsStateSingleton* GetInstance() {
324 return base::Singleton<FlagsStateSingleton>::get();
325 }
326
327 static flags_ui::FlagsState* GetFlagsState() {
328 return &GetInstance()->flags_state_;
329 }
330
331 private:
332 flags_ui::FlagsState flags_state_;
333
334 DISALLOW_COPY_AND_ASSIGN(FlagsStateSingleton);
335};
336} // namespace
337
338void ConvertFlagsToSwitches(flags_ui::FlagsStorage* flags_storage,
339 base::CommandLine* command_line) {
340 FlagsStateSingleton::GetFlagsState()->ConvertFlagsToSwitches(
sdefresnec9763902015-12-02 10:30:11341 flags_storage, command_line, flags_ui::kAddSentinels,
342 switches::kEnableIOSFeatures, switches::kDisableIOSFeatures);
sdefresne14900ee2015-11-27 14:43:21343 AppendSwitchesFromExperimentalSettings(command_line);
344}
345
jkrcalbf073372016-07-29 07:21:31346std::vector<std::string> RegisterAllFeatureVariationParameters(
347 flags_ui::FlagsStorage* flags_storage,
348 base::FeatureList* feature_list) {
349 return FlagsStateSingleton::GetFlagsState()
350 ->RegisterAllFeatureVariationParameters(flags_storage, feature_list);
351}
352
sdefresne14900ee2015-11-27 14:43:21353void GetFlagFeatureEntries(flags_ui::FlagsStorage* flags_storage,
354 flags_ui::FlagAccess access,
355 base::ListValue* supported_entries,
356 base::ListValue* unsupported_entries) {
357 FlagsStateSingleton::GetFlagsState()->GetFlagFeatureEntries(
358 flags_storage, access, supported_entries, unsupported_entries,
359 base::Bind(&SkipConditionalFeatureEntry));
360}
361
362void SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage,
363 const std::string& internal_name,
364 bool enable) {
365 FlagsStateSingleton::GetFlagsState()->SetFeatureEntryEnabled(
366 flags_storage, internal_name, enable);
367}
368
369void ResetAllFlags(flags_ui::FlagsStorage* flags_storage) {
370 FlagsStateSingleton::GetFlagsState()->ResetAllFlags(flags_storage);
371}
372
373namespace testing {
374
375const flags_ui::FeatureEntry* GetFeatureEntries(size_t* count) {
376 *count = arraysize(kFeatureEntries);
377 return kFeatureEntries;
378}
379
380} // namespace testing