7163870f2378c737cef66cd42eb61387ad1fe289
[platform/framework/web/crosswalk.git] / src / chrome / browser / prefs / chrome_pref_service_factory.cc
1 // Copyright (c) 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 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/debug/trace_event.h"
13 #include "base/files/file_path.h"
14 #include "base/metrics/field_trial.h"
15 #include "base/metrics/histogram.h"
16 #include "base/prefs/default_pref_store.h"
17 #include "base/prefs/json_pref_store.h"
18 #include "base/prefs/pref_filter.h"
19 #include "base/prefs/pref_notifier_impl.h"
20 #include "base/prefs/pref_registry.h"
21 #include "base/prefs/pref_registry_simple.h"
22 #include "base/prefs/pref_service.h"
23 #include "base/prefs/pref_store.h"
24 #include "base/prefs/pref_value_store.h"
25 #include "base/threading/sequenced_worker_pool.h"
26 #include "base/time/time.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/prefs/command_line_pref_store.h"
29 #include "chrome/browser/prefs/pref_hash_filter.h"
30 #include "chrome/browser/prefs/pref_model_associator.h"
31 #include "chrome/browser/prefs/pref_service_syncable.h"
32 #include "chrome/browser/prefs/pref_service_syncable_factory.h"
33 #include "chrome/browser/prefs/profile_pref_store_manager.h"
34 #include "chrome/browser/profiles/file_path_verifier_win.h"
35 #include "chrome/browser/profiles/profile_info_cache.h"
36 #include "chrome/browser/profiles/profile_manager.h"
37 #include "chrome/browser/ui/profile_error_dialog.h"
38 #include "chrome/common/chrome_constants.h"
39 #include "chrome/common/pref_names.h"
40 #include "components/user_prefs/pref_registry_syncable.h"
41 #include "content/public/browser/browser_context.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "extensions/browser/pref_names.h"
44 #include "grit/browser_resources.h"
45 #include "grit/chromium_strings.h"
46 #include "grit/generated_resources.h"
47 #include "ui/base/resource/resource_bundle.h"
48
49 #if defined(ENABLE_CONFIGURATION_POLICY)
50 #include "components/policy/core/browser/browser_policy_connector.h"
51 #include "components/policy/core/browser/configuration_policy_pref_store.h"
52 #include "components/policy/core/common/policy_types.h"
53 #endif
54
55 #if defined(ENABLE_MANAGED_USERS)
56 #include "chrome/browser/managed_mode/supervised_user_pref_store.h"
57 #endif
58
59 #if defined(OS_WIN)
60 #include "base/win/win_util.h"
61 #if defined(ENABLE_RLZ)
62 #include "rlz/lib/machine_id.h"
63 #endif  // defined(ENABLE_RLZ)
64 #endif  // defined(OS_WIN)
65
66 using content::BrowserContext;
67 using content::BrowserThread;
68
69 namespace {
70
71 // Whether we are in testing mode; can be enabled via
72 // DisableDelaysAndDomainCheckForTesting(). Forces startup checks to occur
73 // with no delay and ignores the presence of a domain when determining the
74 // active SettingsEnforcement group.
75 bool g_disable_delays_and_domain_check_for_testing = false;
76
77 // These preferences must be kept in sync with the TrackedPreference enum in
78 // tools/metrics/histograms/histograms.xml. To add a new preference, append it
79 // to the array and add a corresponding value to the histogram enum. Each
80 // tracked preference must be given a unique reporting ID.
81 const PrefHashFilter::TrackedPreferenceMetadata kTrackedPrefs[] = {
82   {
83     0, prefs::kShowHomeButton,
84     PrefHashFilter::ENFORCE_ON_LOAD,
85     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
86   },
87   {
88     1, prefs::kHomePageIsNewTabPage,
89     PrefHashFilter::ENFORCE_ON_LOAD,
90     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
91   },
92   {
93     2, prefs::kHomePage,
94     PrefHashFilter::ENFORCE_ON_LOAD,
95     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
96   },
97   {
98     3, prefs::kRestoreOnStartup,
99     PrefHashFilter::ENFORCE_ON_LOAD,
100     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
101   },
102   {
103     4, prefs::kURLsToRestoreOnStartup,
104     PrefHashFilter::ENFORCE_ON_LOAD,
105     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
106   },
107   {
108     5, extensions::pref_names::kExtensions,
109     PrefHashFilter::NO_ENFORCEMENT,
110     PrefHashFilter::TRACKING_STRATEGY_SPLIT
111   },
112   {
113     6, prefs::kGoogleServicesLastUsername,
114     PrefHashFilter::ENFORCE_ON_LOAD,
115     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
116   },
117   {
118     7, prefs::kSearchProviderOverrides,
119     PrefHashFilter::ENFORCE_ON_LOAD,
120     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
121   },
122   {
123     8, prefs::kDefaultSearchProviderSearchURL,
124     PrefHashFilter::ENFORCE_ON_LOAD,
125     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
126   },
127   {
128     9, prefs::kDefaultSearchProviderKeyword,
129     PrefHashFilter::ENFORCE_ON_LOAD,
130     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
131   },
132   {
133     10, prefs::kDefaultSearchProviderName,
134     PrefHashFilter::ENFORCE_ON_LOAD,
135     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
136   },
137 #if !defined(OS_ANDROID)
138   {
139     11, prefs::kPinnedTabs,
140     PrefHashFilter::ENFORCE_ON_LOAD,
141     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
142   },
143 #endif
144   {
145     12, extensions::pref_names::kKnownDisabled,
146     PrefHashFilter::NO_ENFORCEMENT,
147     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
148   },
149   {
150     13, prefs::kProfileResetPromptMemento,
151     PrefHashFilter::ENFORCE_ON_LOAD,
152     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
153   },
154 };
155
156 // The count of tracked preferences IDs across all platforms.
157 const size_t kTrackedPrefsReportingIDsCount = 14;
158 COMPILE_ASSERT(kTrackedPrefsReportingIDsCount >= arraysize(kTrackedPrefs),
159                need_to_increment_ids_count);
160
161 enum SettingsEnforcementGroup {
162   GROUP_NO_ENFORCEMENT,
163   // Only enforce settings on profile loads; still allow seeding of unloaded
164   // profiles.
165   GROUP_ENFORCE_ON_LOAD,
166   GROUP_ENFORCE_ALWAYS
167 };
168
169 SettingsEnforcementGroup GetSettingsEnforcementGroup() {
170 # if defined(OS_WIN)
171   if (!g_disable_delays_and_domain_check_for_testing) {
172     static bool first_call = true;
173     static const bool is_enrolled_to_domain = base::win::IsEnrolledToDomain();
174     if (first_call) {
175       UMA_HISTOGRAM_BOOLEAN("Settings.TrackedPreferencesNoEnforcementOnDomain",
176                             is_enrolled_to_domain);
177       first_call = false;
178     }
179     if (is_enrolled_to_domain)
180       return GROUP_NO_ENFORCEMENT;
181   }
182 #endif
183
184   struct {
185     const char* group_name;
186     SettingsEnforcementGroup group;
187   } static const kEnforcementLevelMap[] = {
188     { chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement,
189       GROUP_NO_ENFORCEMENT },
190     { chrome_prefs::internals::kSettingsEnforcementGroupEnforceOnload,
191       GROUP_ENFORCE_ON_LOAD },
192     { chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways,
193       GROUP_ENFORCE_ALWAYS },
194   };
195
196   // Use the strongest enforcement setting in the absence of a field trial
197   // config.
198   SettingsEnforcementGroup enforcement_group = GROUP_ENFORCE_ALWAYS;
199   bool group_determined_from_trial = false;
200   base::FieldTrial* trial =
201       base::FieldTrialList::Find(
202           chrome_prefs::internals::kSettingsEnforcementTrialName);
203   if (trial) {
204     const std::string& group_name = trial->group_name();
205     // ARRAYSIZE_UNSAFE must be used since the array is declared locally; it is
206     // only unsafe because it could not trigger a compile error on some
207     // non-array pointer types; this is fine since kEnforcementLevelMap is
208     // clearly an array.
209     for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kEnforcementLevelMap); ++i) {
210       if (kEnforcementLevelMap[i].group_name == group_name) {
211         enforcement_group = kEnforcementLevelMap[i].group;
212         group_determined_from_trial = true;
213         break;
214       }
215     }
216   }
217   UMA_HISTOGRAM_BOOLEAN("Settings.EnforcementGroupDeterminedFromTrial",
218                         group_determined_from_trial);
219   return enforcement_group;
220 }
221
222 // Returns the effective preference tracking configuration.
223 std::vector<PrefHashFilter::TrackedPreferenceMetadata>
224 GetTrackingConfiguration() {
225   const PrefHashFilter::EnforcementLevel maximum_level =
226       GetSettingsEnforcementGroup() == GROUP_NO_ENFORCEMENT
227           ? PrefHashFilter::NO_ENFORCEMENT
228           : PrefHashFilter::ENFORCE_ON_LOAD;
229
230   std::vector<PrefHashFilter::TrackedPreferenceMetadata> result;
231   for (size_t i = 0; i < arraysize(kTrackedPrefs); ++i) {
232     PrefHashFilter::TrackedPreferenceMetadata data = kTrackedPrefs[i];
233     if (data.enforcement_level > maximum_level)
234       data.enforcement_level = maximum_level;
235     result.push_back(data);
236   }
237   return result;
238 }
239
240
241 // Shows notifications which correspond to PersistentPrefStore's reading errors.
242 void HandleReadError(PersistentPrefStore::PrefReadError error) {
243   // Sample the histogram also for the successful case in order to get a
244   // baseline on the success rate in addition to the error distribution.
245   UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error,
246                             PersistentPrefStore::PREF_READ_ERROR_MAX_ENUM);
247
248   if (error != PersistentPrefStore::PREF_READ_ERROR_NONE) {
249 #if !defined(OS_CHROMEOS)
250     // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
251     // an example problem that this can cause.
252     // Do some diagnosis and try to avoid losing data.
253     int message_id = 0;
254     if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE) {
255       message_id = IDS_PREFERENCES_CORRUPT_ERROR;
256     } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) {
257       message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
258     }
259
260     if (message_id) {
261       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
262                               base::Bind(&ShowProfileErrorDialog,
263                                          PROFILE_ERROR_PREFERENCES,
264                                          message_id));
265     }
266 #else
267     // On ChromeOS error screen with message about broken local state
268     // will be displayed.
269 #endif
270   }
271 }
272
273 scoped_ptr<ProfilePrefStoreManager> CreateProfilePrefStoreManager(
274     const base::FilePath& profile_path) {
275   std::string device_id;
276 #if defined(OS_WIN) && defined(ENABLE_RLZ)
277   // This is used by
278   // chrome/browser/extensions/api/music_manager_private/device_id_win.cc
279   // but that API is private (http://crbug.com/276485) and other platforms are
280   // not available synchronously.
281   // As part of improving pref metrics on other platforms we may want to find
282   // ways to defer preference loading until the device ID can be used.
283   rlz_lib::GetMachineId(&device_id);
284 #endif
285   return make_scoped_ptr(new ProfilePrefStoreManager(
286       profile_path,
287       GetTrackingConfiguration(),
288       kTrackedPrefsReportingIDsCount,
289       ResourceBundle::GetSharedInstance()
290           .GetRawDataResource(IDR_PREF_HASH_SEED_BIN)
291           .as_string(),
292       device_id,
293       g_browser_process->local_state()));
294 }
295
296 void PrepareFactory(
297     PrefServiceSyncableFactory* factory,
298     policy::PolicyService* policy_service,
299     ManagedUserSettingsService* managed_user_settings,
300     scoped_refptr<PersistentPrefStore> user_pref_store,
301     const scoped_refptr<PrefStore>& extension_prefs,
302     bool async) {
303 #if defined(ENABLE_CONFIGURATION_POLICY)
304   using policy::ConfigurationPolicyPrefStore;
305   factory->set_managed_prefs(
306       make_scoped_refptr(new ConfigurationPolicyPrefStore(
307           policy_service,
308           g_browser_process->browser_policy_connector()->GetHandlerList(),
309           policy::POLICY_LEVEL_MANDATORY)));
310   factory->set_recommended_prefs(
311       make_scoped_refptr(new ConfigurationPolicyPrefStore(
312           policy_service,
313           g_browser_process->browser_policy_connector()->GetHandlerList(),
314           policy::POLICY_LEVEL_RECOMMENDED)));
315 #endif  // ENABLE_CONFIGURATION_POLICY
316
317 #if defined(ENABLE_MANAGED_USERS)
318   if (managed_user_settings) {
319     factory->set_supervised_user_prefs(
320         make_scoped_refptr(new SupervisedUserPrefStore(managed_user_settings)));
321   }
322 #endif
323
324   factory->set_async(async);
325   factory->set_extension_prefs(extension_prefs);
326   factory->set_command_line_prefs(
327       make_scoped_refptr(
328           new CommandLinePrefStore(CommandLine::ForCurrentProcess())));
329   factory->set_read_error_callback(base::Bind(&HandleReadError));
330   factory->set_user_prefs(user_pref_store);
331 }
332
333 // Initialize/update preference hash stores for all profiles but the one whose
334 // path matches |ignored_profile_path|.
335 void UpdateAllPrefHashStoresIfRequired(
336     const base::FilePath& ignored_profile_path) {
337   if (GetSettingsEnforcementGroup() >= GROUP_ENFORCE_ALWAYS)
338     return;
339   const ProfileInfoCache& profile_info_cache =
340       g_browser_process->profile_manager()->GetProfileInfoCache();
341   const size_t n_profiles = profile_info_cache.GetNumberOfProfiles();
342   for (size_t i = 0; i < n_profiles; ++i) {
343     const base::FilePath profile_path =
344         profile_info_cache.GetPathOfProfileAtIndex(i);
345     if (profile_path != ignored_profile_path) {
346       CreateProfilePrefStoreManager(profile_path)
347           ->UpdateProfileHashStoreIfRequired(
348               JsonPrefStore::GetTaskRunnerForFile(
349                   profile_path, BrowserThread::GetBlockingPool()));
350     }
351   }
352 }
353
354 }  // namespace
355
356 namespace chrome_prefs {
357
358 namespace internals {
359
360 const char kSettingsEnforcementTrialName[] = "SettingsEnforcement";
361 const char kSettingsEnforcementGroupNoEnforcement[] = "no_enforcement";
362 const char kSettingsEnforcementGroupEnforceOnload[] = "enforce_on_load";
363 const char kSettingsEnforcementGroupEnforceAlways[] = "enforce_always";
364
365 }  // namespace internals
366
367 scoped_ptr<PrefService> CreateLocalState(
368     const base::FilePath& pref_filename,
369     base::SequencedTaskRunner* pref_io_task_runner,
370     policy::PolicyService* policy_service,
371     const scoped_refptr<PrefRegistry>& pref_registry,
372     bool async) {
373   PrefServiceSyncableFactory factory;
374   PrepareFactory(
375       &factory,
376       policy_service,
377       NULL,  // managed_user_settings
378       new JsonPrefStore(
379           pref_filename, pref_io_task_runner, scoped_ptr<PrefFilter>()),
380       NULL,  // extension_prefs
381       async);
382   return factory.Create(pref_registry.get());
383 }
384
385 scoped_ptr<PrefServiceSyncable> CreateProfilePrefs(
386     const base::FilePath& profile_path,
387     base::SequencedTaskRunner* pref_io_task_runner,
388     policy::PolicyService* policy_service,
389     ManagedUserSettingsService* managed_user_settings,
390     const scoped_refptr<PrefStore>& extension_prefs,
391     const scoped_refptr<user_prefs::PrefRegistrySyncable>& pref_registry,
392     bool async) {
393   TRACE_EVENT0("browser", "chrome_prefs::CreateProfilePrefs");
394   PrefServiceSyncableFactory factory;
395   PrepareFactory(&factory,
396                  policy_service,
397                  managed_user_settings,
398                  scoped_refptr<PersistentPrefStore>(
399                      CreateProfilePrefStoreManager(profile_path)
400                          ->CreateProfilePrefStore(pref_io_task_runner)),
401                  extension_prefs,
402                  async);
403   return factory.CreateSyncable(pref_registry.get());
404 }
405
406 void SchedulePrefsFilePathVerification(const base::FilePath& profile_path) {
407 #if defined(OS_WIN)
408   // Only do prefs file verification on Windows.
409   const int kVerifyPrefsFileDelaySeconds = 60;
410   BrowserThread::GetBlockingPool()->PostDelayedTask(
411       FROM_HERE,
412       base::Bind(&VerifyPreferencesFile,
413                  ProfilePrefStoreManager::GetPrefFilePathFromProfilePath(
414                      profile_path)),
415       base::TimeDelta::FromSeconds(g_disable_delays_and_domain_check_for_testing
416                                        ? 0
417                                        : kVerifyPrefsFileDelaySeconds));
418 #endif
419 }
420
421 void DisableDelaysAndDomainCheckForTesting() {
422   g_disable_delays_and_domain_check_for_testing = true;
423 }
424
425 void SchedulePrefHashStoresUpdateCheck(
426     const base::FilePath& initial_profile_path) {
427   if (!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking) {
428     ProfilePrefStoreManager::ResetAllPrefHashStores(
429         g_browser_process->local_state());
430     return;
431   }
432
433   const int kDefaultPrefHashStoresUpdateCheckDelaySeconds = 55;
434   BrowserThread::PostDelayedTask(
435         BrowserThread::UI,
436         FROM_HERE,
437         base::Bind(&UpdateAllPrefHashStoresIfRequired,
438                    initial_profile_path),
439         base::TimeDelta::FromSeconds(
440             g_disable_delays_and_domain_check_for_testing ?
441                 0 : kDefaultPrefHashStoresUpdateCheckDelaySeconds));
442 }
443
444 void ResetPrefHashStore(const base::FilePath& profile_path) {
445   CreateProfilePrefStoreManager(profile_path)->ResetPrefHashStore();
446 }
447
448 bool InitializePrefsFromMasterPrefs(
449     const base::FilePath& profile_path,
450     const base::DictionaryValue& master_prefs) {
451   return CreateProfilePrefStoreManager(profile_path)
452       ->InitializePrefsFromMasterPrefs(master_prefs);
453 }
454
455 base::Time GetResetTime(Profile* profile) {
456   return ProfilePrefStoreManager::GetResetTime(profile->GetPrefs());
457 }
458
459 void ClearResetTime(Profile* profile) {
460   ProfilePrefStoreManager::ClearResetTime(profile->GetPrefs());
461 }
462
463 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
464   ProfilePrefStoreManager::RegisterProfilePrefs(registry);
465 }
466
467 void RegisterPrefs(PrefRegistrySimple* registry) {
468   ProfilePrefStoreManager::RegisterPrefs(registry);
469 }
470
471 }  // namespace chrome_prefs