Revert 271602 "Implementation of leveldb-backed PrefStore."
[chromium-blink-merge.git] / chrome / browser / prefs / chrome_pref_service_factory.cc
blob390bfc7f67defb3fac489b7ccb6ecedc8b360138
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.
5 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
7 #include <string>
8 #include <vector>
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/search_engines/default_search_manager.h"
38 #include "chrome/browser/search_engines/default_search_pref_migration.h"
39 #include "chrome/browser/ui/profile_error_dialog.h"
40 #include "chrome/common/chrome_constants.h"
41 #include "chrome/common/pref_names.h"
42 #include "components/pref_registry/pref_registry_syncable.h"
43 #include "content/public/browser/browser_context.h"
44 #include "content/public/browser/browser_thread.h"
45 #include "extensions/browser/pref_names.h"
46 #include "grit/browser_resources.h"
47 #include "grit/chromium_strings.h"
48 #include "grit/generated_resources.h"
49 #include "ui/base/resource/resource_bundle.h"
51 #if defined(ENABLE_CONFIGURATION_POLICY)
52 #include "components/policy/core/browser/browser_policy_connector.h"
53 #include "components/policy/core/browser/configuration_policy_pref_store.h"
54 #include "components/policy/core/common/policy_types.h"
55 #endif
57 #if defined(ENABLE_MANAGED_USERS)
58 #include "chrome/browser/managed_mode/supervised_user_pref_store.h"
59 #endif
61 #if defined(OS_WIN)
62 #include "base/win/win_util.h"
63 #if defined(ENABLE_RLZ)
64 #include "rlz/lib/machine_id.h"
65 #endif // defined(ENABLE_RLZ)
66 #endif // defined(OS_WIN)
68 using content::BrowserContext;
69 using content::BrowserThread;
71 namespace {
73 // Whether we are in testing mode; can be enabled via
74 // DisableDelaysAndDomainCheckForTesting(). Forces startup checks to occur
75 // with no delay and ignores the presence of a domain when determining the
76 // active SettingsEnforcement group.
77 bool g_disable_delays_and_domain_check_for_testing = false;
79 // These preferences must be kept in sync with the TrackedPreference enum in
80 // tools/metrics/histograms/histograms.xml. To add a new preference, append it
81 // to the array and add a corresponding value to the histogram enum. Each
82 // tracked preference must be given a unique reporting ID.
83 const PrefHashFilter::TrackedPreferenceMetadata kTrackedPrefs[] = {
85 0, prefs::kShowHomeButton,
86 PrefHashFilter::ENFORCE_ON_LOAD,
87 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
90 1, prefs::kHomePageIsNewTabPage,
91 PrefHashFilter::ENFORCE_ON_LOAD,
92 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
95 2, prefs::kHomePage,
96 PrefHashFilter::ENFORCE_ON_LOAD,
97 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
100 3, prefs::kRestoreOnStartup,
101 PrefHashFilter::ENFORCE_ON_LOAD,
102 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
105 4, prefs::kURLsToRestoreOnStartup,
106 PrefHashFilter::ENFORCE_ON_LOAD,
107 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
110 5, extensions::pref_names::kExtensions,
111 PrefHashFilter::NO_ENFORCEMENT,
112 PrefHashFilter::TRACKING_STRATEGY_SPLIT
115 6, prefs::kGoogleServicesLastUsername,
116 PrefHashFilter::ENFORCE_ON_LOAD,
117 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
120 7, prefs::kSearchProviderOverrides,
121 PrefHashFilter::ENFORCE_ON_LOAD,
122 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
125 8, prefs::kDefaultSearchProviderSearchURL,
126 PrefHashFilter::ENFORCE_ON_LOAD,
127 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
130 9, prefs::kDefaultSearchProviderKeyword,
131 PrefHashFilter::ENFORCE_ON_LOAD,
132 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
135 10, prefs::kDefaultSearchProviderName,
136 PrefHashFilter::ENFORCE_ON_LOAD,
137 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
139 #if !defined(OS_ANDROID)
141 11, prefs::kPinnedTabs,
142 PrefHashFilter::ENFORCE_ON_LOAD,
143 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
145 #endif
147 12, extensions::pref_names::kKnownDisabled,
148 PrefHashFilter::NO_ENFORCEMENT,
149 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
152 13, prefs::kProfileResetPromptMemento,
153 PrefHashFilter::ENFORCE_ON_LOAD,
154 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
157 14, DefaultSearchManager::kDefaultSearchProviderDataPrefName,
158 PrefHashFilter::NO_ENFORCEMENT,
159 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
162 // Protecting kPreferenceResetTime does two things:
163 // 1) It ensures this isn't accidently set by someone stomping the pref
164 // file.
165 // 2) More importantly, it declares kPreferenceResetTime as a protected
166 // pref which is required for it to be visible when queried via the
167 // SegregatedPrefStore. This is because it's written directly in the
168 // protected JsonPrefStore by that store's PrefHashFilter if there was
169 // a reset in FilterOnLoad and SegregatedPrefStore will not look for it
170 // in the protected JsonPrefStore unless it's declared as a protected
171 // preference here.
172 15, prefs::kPreferenceResetTime,
173 PrefHashFilter::ENFORCE_ON_LOAD,
174 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
178 // The count of tracked preferences IDs across all platforms.
179 const size_t kTrackedPrefsReportingIDsCount = 16;
180 COMPILE_ASSERT(kTrackedPrefsReportingIDsCount >= arraysize(kTrackedPrefs),
181 need_to_increment_ids_count);
183 // Each group enforces a superset of the protection provided by the previous
184 // one.
185 enum SettingsEnforcementGroup {
186 GROUP_NO_ENFORCEMENT,
187 // Only enforce settings on profile loads; still allow seeding of unloaded
188 // profiles.
189 GROUP_ENFORCE_ON_LOAD,
190 // Also disallow seeding of unloaded profiles.
191 GROUP_ENFORCE_ALWAYS,
192 // Also enforce extension settings.
193 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS,
194 // Also enforce extension settings and default search.
195 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE,
196 // The default enforcement group contains all protection features.
197 GROUP_ENFORCE_DEFAULT
200 SettingsEnforcementGroup GetSettingsEnforcementGroup() {
201 # if defined(OS_WIN)
202 if (!g_disable_delays_and_domain_check_for_testing) {
203 static bool first_call = true;
204 static const bool is_enrolled_to_domain = base::win::IsEnrolledToDomain();
205 if (first_call) {
206 UMA_HISTOGRAM_BOOLEAN("Settings.TrackedPreferencesNoEnforcementOnDomain",
207 is_enrolled_to_domain);
208 first_call = false;
210 if (is_enrolled_to_domain)
211 return GROUP_NO_ENFORCEMENT;
213 #endif
215 struct {
216 const char* group_name;
217 SettingsEnforcementGroup group;
218 } static const kEnforcementLevelMap[] = {
219 { chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement,
220 GROUP_NO_ENFORCEMENT },
221 { chrome_prefs::internals::kSettingsEnforcementGroupEnforceOnload,
222 GROUP_ENFORCE_ON_LOAD },
223 { chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways,
224 GROUP_ENFORCE_ALWAYS },
225 { chrome_prefs::internals::
226 kSettingsEnforcementGroupEnforceAlwaysWithExtensions,
227 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS },
228 { chrome_prefs::internals::
229 kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE,
230 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE },
233 // Use the strongest enforcement setting in the absence of a field trial
234 // config on Windows. Remember to update the OFFICIAL_BUILD sections of
235 // pref_hash_browsertest.cc and extension_startup_browsertest.cc when updating
236 // the default value below.
237 // TODO(gab): Enforce this on all platforms.
238 SettingsEnforcementGroup enforcement_group =
239 #if defined(OS_WIN)
240 GROUP_ENFORCE_DEFAULT;
241 #else
242 GROUP_NO_ENFORCEMENT;
243 #endif
244 bool group_determined_from_trial = false;
245 base::FieldTrial* trial =
246 base::FieldTrialList::Find(
247 chrome_prefs::internals::kSettingsEnforcementTrialName);
248 if (trial) {
249 const std::string& group_name = trial->group_name();
250 // ARRAYSIZE_UNSAFE must be used since the array is declared locally; it is
251 // only unsafe because it could not trigger a compile error on some
252 // non-array pointer types; this is fine since kEnforcementLevelMap is
253 // clearly an array.
254 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kEnforcementLevelMap); ++i) {
255 if (kEnforcementLevelMap[i].group_name == group_name) {
256 enforcement_group = kEnforcementLevelMap[i].group;
257 group_determined_from_trial = true;
258 break;
262 UMA_HISTOGRAM_BOOLEAN("Settings.EnforcementGroupDeterminedFromTrial",
263 group_determined_from_trial);
264 return enforcement_group;
267 // Returns the effective preference tracking configuration.
268 std::vector<PrefHashFilter::TrackedPreferenceMetadata>
269 GetTrackingConfiguration() {
270 const SettingsEnforcementGroup enforcement_group =
271 GetSettingsEnforcementGroup();
273 std::vector<PrefHashFilter::TrackedPreferenceMetadata> result;
274 for (size_t i = 0; i < arraysize(kTrackedPrefs); ++i) {
275 PrefHashFilter::TrackedPreferenceMetadata data = kTrackedPrefs[i];
277 if (GROUP_NO_ENFORCEMENT == enforcement_group) {
278 // Remove enforcement for all tracked preferences.
279 data.enforcement_level = PrefHashFilter::NO_ENFORCEMENT;
282 if (enforcement_group >= GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS &&
283 (data.name == extensions::pref_names::kExtensions ||
284 data.name == extensions::pref_names::kKnownDisabled)) {
285 // Specifically enable extension settings enforcement and ensure
286 // kKnownDisabled follows it in the Protected Preferences.
287 // TODO(gab): Get rid of kKnownDisabled altogether.
288 data.enforcement_level = PrefHashFilter::ENFORCE_ON_LOAD;
291 if (enforcement_group >= GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE &&
292 data.name == DefaultSearchManager::kDefaultSearchProviderDataPrefName) {
293 // Specifically enable default search settings enforcement.
294 data.enforcement_level = PrefHashFilter::ENFORCE_ON_LOAD;
297 result.push_back(data);
299 return result;
303 // Shows notifications which correspond to PersistentPrefStore's reading errors.
304 void HandleReadError(PersistentPrefStore::PrefReadError error) {
305 // Sample the histogram also for the successful case in order to get a
306 // baseline on the success rate in addition to the error distribution.
307 UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error,
308 PersistentPrefStore::PREF_READ_ERROR_MAX_ENUM);
310 if (error != PersistentPrefStore::PREF_READ_ERROR_NONE) {
311 #if !defined(OS_CHROMEOS)
312 // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
313 // an example problem that this can cause.
314 // Do some diagnosis and try to avoid losing data.
315 int message_id = 0;
316 if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE) {
317 message_id = IDS_PREFERENCES_CORRUPT_ERROR;
318 } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) {
319 message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
322 if (message_id) {
323 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
324 base::Bind(&ShowProfileErrorDialog,
325 PROFILE_ERROR_PREFERENCES,
326 message_id));
328 #else
329 // On ChromeOS error screen with message about broken local state
330 // will be displayed.
331 #endif
335 scoped_ptr<ProfilePrefStoreManager> CreateProfilePrefStoreManager(
336 const base::FilePath& profile_path) {
337 std::string device_id;
338 #if defined(OS_WIN) && defined(ENABLE_RLZ)
339 // This is used by
340 // chrome/browser/extensions/api/music_manager_private/device_id_win.cc
341 // but that API is private (http://crbug.com/276485) and other platforms are
342 // not available synchronously.
343 // As part of improving pref metrics on other platforms we may want to find
344 // ways to defer preference loading until the device ID can be used.
345 rlz_lib::GetMachineId(&device_id);
346 #endif
347 return make_scoped_ptr(new ProfilePrefStoreManager(
348 profile_path,
349 GetTrackingConfiguration(),
350 kTrackedPrefsReportingIDsCount,
351 ResourceBundle::GetSharedInstance()
352 .GetRawDataResource(IDR_PREF_HASH_SEED_BIN)
353 .as_string(),
354 device_id,
355 g_browser_process->local_state()));
358 void PrepareFactory(
359 PrefServiceSyncableFactory* factory,
360 policy::PolicyService* policy_service,
361 ManagedUserSettingsService* managed_user_settings,
362 scoped_refptr<PersistentPrefStore> user_pref_store,
363 const scoped_refptr<PrefStore>& extension_prefs,
364 bool async) {
365 #if defined(ENABLE_CONFIGURATION_POLICY)
366 using policy::ConfigurationPolicyPrefStore;
367 factory->set_managed_prefs(
368 make_scoped_refptr(new ConfigurationPolicyPrefStore(
369 policy_service,
370 g_browser_process->browser_policy_connector()->GetHandlerList(),
371 policy::POLICY_LEVEL_MANDATORY)));
372 factory->set_recommended_prefs(
373 make_scoped_refptr(new ConfigurationPolicyPrefStore(
374 policy_service,
375 g_browser_process->browser_policy_connector()->GetHandlerList(),
376 policy::POLICY_LEVEL_RECOMMENDED)));
377 #endif // ENABLE_CONFIGURATION_POLICY
379 #if defined(ENABLE_MANAGED_USERS)
380 if (managed_user_settings) {
381 factory->set_supervised_user_prefs(
382 make_scoped_refptr(new SupervisedUserPrefStore(managed_user_settings)));
384 #endif
386 factory->set_async(async);
387 factory->set_extension_prefs(extension_prefs);
388 factory->set_command_line_prefs(
389 make_scoped_refptr(
390 new CommandLinePrefStore(CommandLine::ForCurrentProcess())));
391 factory->set_read_error_callback(base::Bind(&HandleReadError));
392 factory->set_user_prefs(user_pref_store);
395 // Initialize/update preference hash stores for all profiles but the one whose
396 // path matches |ignored_profile_path|.
397 void UpdateAllPrefHashStoresIfRequired(
398 const base::FilePath& ignored_profile_path) {
399 const ProfileInfoCache& profile_info_cache =
400 g_browser_process->profile_manager()->GetProfileInfoCache();
401 const size_t n_profiles = profile_info_cache.GetNumberOfProfiles();
402 for (size_t i = 0; i < n_profiles; ++i) {
403 const base::FilePath profile_path =
404 profile_info_cache.GetPathOfProfileAtIndex(i);
405 if (profile_path != ignored_profile_path) {
406 CreateProfilePrefStoreManager(profile_path)
407 ->UpdateProfileHashStoreIfRequired(
408 JsonPrefStore::GetTaskRunnerForFile(
409 profile_path, BrowserThread::GetBlockingPool()));
414 } // namespace
416 namespace chrome_prefs {
418 namespace internals {
420 const char kSettingsEnforcementTrialName[] = "SettingsEnforcement";
421 const char kSettingsEnforcementGroupNoEnforcement[] = "no_enforcement";
422 const char kSettingsEnforcementGroupEnforceOnload[] = "enforce_on_load";
423 const char kSettingsEnforcementGroupEnforceAlways[] = "enforce_always";
424 const char kSettingsEnforcementGroupEnforceAlwaysWithExtensions[] =
425 "enforce_always_with_extensions";
426 const char kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE[] =
427 "enforce_always_with_extensions_and_dse";
429 } // namespace internals
431 scoped_ptr<PrefService> CreateLocalState(
432 const base::FilePath& pref_filename,
433 base::SequencedTaskRunner* pref_io_task_runner,
434 policy::PolicyService* policy_service,
435 const scoped_refptr<PrefRegistry>& pref_registry,
436 bool async) {
437 PrefServiceSyncableFactory factory;
438 PrepareFactory(
439 &factory,
440 policy_service,
441 NULL, // managed_user_settings
442 new JsonPrefStore(
443 pref_filename, pref_io_task_runner, scoped_ptr<PrefFilter>()),
444 NULL, // extension_prefs
445 async);
446 return factory.Create(pref_registry.get());
449 scoped_ptr<PrefServiceSyncable> CreateProfilePrefs(
450 const base::FilePath& profile_path,
451 base::SequencedTaskRunner* pref_io_task_runner,
452 policy::PolicyService* policy_service,
453 ManagedUserSettingsService* managed_user_settings,
454 const scoped_refptr<PrefStore>& extension_prefs,
455 const scoped_refptr<user_prefs::PrefRegistrySyncable>& pref_registry,
456 bool async) {
457 TRACE_EVENT0("browser", "chrome_prefs::CreateProfilePrefs");
458 PrefServiceSyncableFactory factory;
459 PrepareFactory(&factory,
460 policy_service,
461 managed_user_settings,
462 scoped_refptr<PersistentPrefStore>(
463 CreateProfilePrefStoreManager(profile_path)
464 ->CreateProfilePrefStore(pref_io_task_runner)),
465 extension_prefs,
466 async);
467 scoped_ptr<PrefServiceSyncable> pref_service =
468 factory.CreateSyncable(pref_registry.get());
470 ConfigureDefaultSearchPrefMigrationToDictionaryValue(pref_service.get());
472 return pref_service.Pass();
475 void SchedulePrefsFilePathVerification(const base::FilePath& profile_path) {
476 #if defined(OS_WIN)
477 // Only do prefs file verification on Windows.
478 const int kVerifyPrefsFileDelaySeconds = 60;
479 BrowserThread::GetBlockingPool()->PostDelayedTask(
480 FROM_HERE,
481 base::Bind(&VerifyPreferencesFile,
482 ProfilePrefStoreManager::GetPrefFilePathFromProfilePath(
483 profile_path)),
484 base::TimeDelta::FromSeconds(g_disable_delays_and_domain_check_for_testing
486 : kVerifyPrefsFileDelaySeconds));
487 #endif
490 void DisableDelaysAndDomainCheckForTesting() {
491 g_disable_delays_and_domain_check_for_testing = true;
494 void SchedulePrefHashStoresUpdateCheck(
495 const base::FilePath& initial_profile_path) {
496 if (!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking) {
497 ProfilePrefStoreManager::ResetAllPrefHashStores(
498 g_browser_process->local_state());
499 return;
502 if (GetSettingsEnforcementGroup() >= GROUP_ENFORCE_ALWAYS)
503 return;
505 const int kDefaultPrefHashStoresUpdateCheckDelaySeconds = 55;
506 BrowserThread::PostDelayedTask(
507 BrowserThread::UI,
508 FROM_HERE,
509 base::Bind(&UpdateAllPrefHashStoresIfRequired,
510 initial_profile_path),
511 base::TimeDelta::FromSeconds(
512 g_disable_delays_and_domain_check_for_testing ?
513 0 : kDefaultPrefHashStoresUpdateCheckDelaySeconds));
516 void ResetPrefHashStore(const base::FilePath& profile_path) {
517 CreateProfilePrefStoreManager(profile_path)->ResetPrefHashStore();
520 bool InitializePrefsFromMasterPrefs(
521 const base::FilePath& profile_path,
522 const base::DictionaryValue& master_prefs) {
523 return CreateProfilePrefStoreManager(profile_path)
524 ->InitializePrefsFromMasterPrefs(master_prefs);
527 base::Time GetResetTime(Profile* profile) {
528 return ProfilePrefStoreManager::GetResetTime(profile->GetPrefs());
531 void ClearResetTime(Profile* profile) {
532 ProfilePrefStoreManager::ClearResetTime(profile->GetPrefs());
535 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
536 ProfilePrefStoreManager::RegisterProfilePrefs(registry);
539 void RegisterPrefs(PrefRegistrySimple* registry) {
540 ProfilePrefStoreManager::RegisterPrefs(registry);
543 } // namespace chrome_prefs