• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
6 
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/sha1.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/flags_storage.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/signin/signin_manager_factory.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/signin/core/browser/signin_manager.h"
20 #include "components/sync_driver/pref_names.h"
21 #include "components/variations/variations_associated_data.h"
22 #include "extensions/common/features/feature.h"
23 #include "extensions/common/features/feature_provider.h"
24 
25 namespace {
26 
27 const char kFieldTrialName[] = "EnhancedBookmarks";
28 
29 // Get extension id from Finch EnhancedBookmarks group parameters.
GetEnhancedBookmarksExtensionIdFromFinch()30 std::string GetEnhancedBookmarksExtensionIdFromFinch() {
31   return variations::GetVariationParamValue(kFieldTrialName, "id");
32 }
33 
34 // Returns true if enhanced bookmarks experiment is enabled from Finch.
IsEnhancedBookmarksExperimentEnabledFromFinch()35 bool IsEnhancedBookmarksExperimentEnabledFromFinch() {
36   const std::string ext_id = GetEnhancedBookmarksExtensionIdFromFinch();
37 #if defined(OS_ANDROID)
38   return !ext_id.empty();
39 #else
40   const extensions::FeatureProvider* feature_provider =
41       extensions::FeatureProvider::GetPermissionFeatures();
42   extensions::Feature* feature = feature_provider->GetFeature("metricsPrivate");
43   return feature && feature->IsIdInWhitelist(ext_id);
44 #endif
45 }
46 
47 };  // namespace
48 
GetBookmarksExperimentExtensionID(const PrefService * user_prefs,std::string * extension_id)49 bool GetBookmarksExperimentExtensionID(const PrefService* user_prefs,
50                                        std::string* extension_id) {
51   BookmarksExperimentState bookmarks_experiment_state =
52       static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
53           sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
54   if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH) {
55     *extension_id = GetEnhancedBookmarksExtensionIdFromFinch();
56     return !extension_id->empty();
57   }
58   if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED) {
59     *extension_id = user_prefs->GetString(
60         sync_driver::prefs::kEnhancedBookmarksExtensionId);
61     return !extension_id->empty();
62   }
63 
64   return false;
65 }
66 
UpdateBookmarksExperimentState(PrefService * user_prefs,PrefService * local_state,bool user_signed_in,BookmarksExperimentState experiment_enabled_from_sync)67 void UpdateBookmarksExperimentState(
68     PrefService* user_prefs,
69     PrefService* local_state,
70     bool user_signed_in,
71     BookmarksExperimentState experiment_enabled_from_sync) {
72  PrefService* flags_storage = local_state;
73 #if defined(OS_CHROMEOS)
74   // Chrome OS is using user prefs for flags storage.
75   flags_storage = user_prefs;
76 #endif
77 
78   BookmarksExperimentState bookmarks_experiment_state_before =
79       static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
80           sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
81   // If user signed out, clear possible previous state.
82   if (!user_signed_in) {
83     bookmarks_experiment_state_before = BOOKMARKS_EXPERIMENT_NONE;
84     ForceFinchBookmarkExperimentIfNeeded(flags_storage,
85         BOOKMARKS_EXPERIMENT_NONE);
86   }
87 
88   // kEnhancedBookmarksExperiment flag could have values "", "1" and "0".
89   // "0" - user opted out.
90   bool opt_out = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
91                      switches::kEnhancedBookmarksExperiment) == "0";
92 
93   BookmarksExperimentState bookmarks_experiment_new_state =
94       BOOKMARKS_EXPERIMENT_NONE;
95 
96   if (IsEnhancedBookmarksExperimentEnabledFromFinch() && !user_signed_in) {
97     if (opt_out) {
98       // Experiment enabled but user opted out.
99       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_OPT_OUT_FROM_FINCH;
100     } else {
101       // Experiment enabled.
102       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH;
103     }
104   } else if (experiment_enabled_from_sync == BOOKMARKS_EXPERIMENT_ENABLED) {
105     // Experiment enabled from Chrome sync.
106     if (opt_out) {
107       // Experiment enabled but user opted out.
108       bookmarks_experiment_new_state =
109           BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
110     } else {
111       // Experiment enabled.
112       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
113     }
114   } else if (experiment_enabled_from_sync == BOOKMARKS_EXPERIMENT_NONE) {
115     // Experiment is not enabled from Chrome sync.
116     bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_NONE;
117   } else if (bookmarks_experiment_state_before ==
118              BOOKMARKS_EXPERIMENT_ENABLED) {
119     if (opt_out) {
120       // Experiment enabled but user opted out.
121       bookmarks_experiment_new_state =
122           BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
123     } else {
124       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
125     }
126   } else if (bookmarks_experiment_state_before ==
127              BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT) {
128     if (opt_out) {
129       bookmarks_experiment_new_state =
130           BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
131     } else {
132       // User opted in again.
133       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
134     }
135   }
136 
137 #if defined(OS_ANDROID)
138   bool opt_in = !opt_out
139       && CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
140           switches::kEnhancedBookmarksExperiment) == "1";
141   if (opt_in && bookmarks_experiment_new_state == BOOKMARKS_EXPERIMENT_NONE)
142     bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
143 #endif
144 
145   UMA_HISTOGRAM_ENUMERATION("EnhancedBookmarks.SyncExperimentState",
146                             bookmarks_experiment_new_state,
147                             BOOKMARKS_EXPERIMENT_ENUM_SIZE);
148   user_prefs->SetInteger(
149       sync_driver::prefs::kEnhancedBookmarksExperimentEnabled,
150       bookmarks_experiment_new_state);
151   ForceFinchBookmarkExperimentIfNeeded(flags_storage,
152                                        bookmarks_experiment_new_state);
153 }
154 
InitBookmarksExperimentState(Profile * profile)155 void InitBookmarksExperimentState(Profile* profile) {
156   SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile);
157   bool is_signed_in = signin && signin->IsAuthenticated();
158   UpdateBookmarksExperimentState(
159       profile->GetPrefs(),
160       g_browser_process->local_state(),
161       is_signed_in,
162       BOOKMARKS_EXPERIMENT_ENABLED_FROM_SYNC_UNKNOWN);
163 }
164 
ForceFinchBookmarkExperimentIfNeeded(PrefService * flags_storage,BookmarksExperimentState bookmarks_experiment_state)165 void ForceFinchBookmarkExperimentIfNeeded(
166     PrefService* flags_storage,
167     BookmarksExperimentState bookmarks_experiment_state) {
168   if (!flags_storage)
169     return;
170   ListPrefUpdate update(flags_storage, prefs::kEnabledLabsExperiments);
171   base::ListValue* experiments_list = update.Get();
172   if (!experiments_list)
173     return;
174   size_t index;
175   if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_NONE) {
176     experiments_list->Remove(
177         base::StringValue(switches::kManualEnhancedBookmarks), &index);
178     experiments_list->Remove(
179         base::StringValue(switches::kManualEnhancedBookmarksOptout), &index);
180   } else if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED) {
181     experiments_list->Remove(
182         base::StringValue(switches::kManualEnhancedBookmarksOptout), &index);
183     experiments_list->AppendIfNotPresent(
184         new base::StringValue(switches::kManualEnhancedBookmarks));
185   } else if (bookmarks_experiment_state ==
186                  BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT) {
187     experiments_list->Remove(
188         base::StringValue(switches::kManualEnhancedBookmarks), &index);
189     experiments_list->AppendIfNotPresent(
190         new base::StringValue(switches::kManualEnhancedBookmarksOptout));
191   }
192 }
193 
IsEnhancedBookmarksExperimentEnabled(about_flags::FlagsStorage * flags_storage)194 bool IsEnhancedBookmarksExperimentEnabled(
195     about_flags::FlagsStorage* flags_storage) {
196 #if defined(OS_CHROMEOS)
197   // We are not setting command line flags on Chrome OS to avoid browser restart
198   // but still have flags in flags_storage. So check flags_storage instead.
199   const std::set<std::string> flags = flags_storage->GetFlags();
200   if (flags.find(switches::kManualEnhancedBookmarks) != flags.end())
201     return true;
202   if (flags.find(switches::kManualEnhancedBookmarksOptout) != flags.end())
203     return true;
204 #else
205   CommandLine* command_line = CommandLine::ForCurrentProcess();
206   if (command_line->HasSwitch(switches::kManualEnhancedBookmarks) ||
207       command_line->HasSwitch(switches::kManualEnhancedBookmarksOptout)) {
208     return true;
209   }
210 #endif
211 
212   return IsEnhancedBookmarksExperimentEnabledFromFinch();
213 }
214 
215 #if defined(OS_ANDROID)
IsEnhancedBookmarkImageFetchingEnabled(const PrefService * user_prefs)216 bool IsEnhancedBookmarkImageFetchingEnabled(const PrefService* user_prefs) {
217   if (IsEnhancedBookmarksEnabled(user_prefs))
218     return true;
219 
220   // Salient images are collected from visited bookmarked pages even if the
221   // enhanced bookmark feature is turned off. This is to have some images
222   // available so that in the future, when the feature is turned on, the user
223   // experience is not a big list of flat colors. However as a precautionary
224   // measure it is possible to disable this collection of images from finch.
225   std::string disable_fetching = variations::GetVariationParamValue(
226       kFieldTrialName, "DisableImagesFetching");
227   return disable_fetching.empty();
228 }
229 
IsEnhancedBookmarksEnabled(const PrefService * user_prefs)230 bool IsEnhancedBookmarksEnabled(const PrefService* user_prefs) {
231   BookmarksExperimentState bookmarks_experiment_state =
232       static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
233           sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
234   return bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED ||
235       bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH;
236 }
237 #endif
238 
IsEnableDomDistillerSet()239 bool IsEnableDomDistillerSet() {
240   if (CommandLine::ForCurrentProcess()->
241       HasSwitch(switches::kEnableDomDistiller)) {
242     return true;
243   }
244   if (variations::GetVariationParamValue(
245           kFieldTrialName, "enable-dom-distiller") == "1")
246     return true;
247 
248   return false;
249 }
250 
IsEnableSyncArticlesSet()251 bool IsEnableSyncArticlesSet() {
252   if (CommandLine::ForCurrentProcess()->
253       HasSwitch(switches::kEnableSyncArticles)) {
254     return true;
255   }
256   if (variations::GetVariationParamValue(
257           kFieldTrialName, "enable-sync-articles") == "1")
258     return true;
259 
260   return false;
261 }
262