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"
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"
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"
55 #if defined(ENABLE_MANAGED_USERS)
56 #include "chrome/browser/managed_mode/supervised_user_pref_store.h"
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)
66 using content::BrowserContext;
67 using content::BrowserThread;
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;
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[] = {
83 0, prefs::kShowHomeButton,
84 PrefHashFilter::ENFORCE_ON_LOAD,
85 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
88 1, prefs::kHomePageIsNewTabPage,
89 PrefHashFilter::ENFORCE_ON_LOAD,
90 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
94 PrefHashFilter::ENFORCE_ON_LOAD,
95 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
98 3, prefs::kRestoreOnStartup,
99 PrefHashFilter::ENFORCE_ON_LOAD,
100 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
103 4, prefs::kURLsToRestoreOnStartup,
104 PrefHashFilter::ENFORCE_ON_LOAD,
105 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
108 5, extensions::pref_names::kExtensions,
109 PrefHashFilter::NO_ENFORCEMENT,
110 PrefHashFilter::TRACKING_STRATEGY_SPLIT
113 6, prefs::kGoogleServicesLastUsername,
114 PrefHashFilter::ENFORCE_ON_LOAD,
115 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
118 7, prefs::kSearchProviderOverrides,
119 PrefHashFilter::ENFORCE_ON_LOAD,
120 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
123 8, prefs::kDefaultSearchProviderSearchURL,
124 PrefHashFilter::ENFORCE_ON_LOAD,
125 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
128 9, prefs::kDefaultSearchProviderKeyword,
129 PrefHashFilter::ENFORCE_ON_LOAD,
130 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
133 10, prefs::kDefaultSearchProviderName,
134 PrefHashFilter::ENFORCE_ON_LOAD,
135 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
137 #if !defined(OS_ANDROID)
139 11, prefs::kPinnedTabs,
140 PrefHashFilter::ENFORCE_ON_LOAD,
141 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
145 12, extensions::pref_names::kKnownDisabled,
146 PrefHashFilter::NO_ENFORCEMENT,
147 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
150 13, prefs::kProfileResetPromptMemento,
151 PrefHashFilter::ENFORCE_ON_LOAD,
152 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
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);
161 // Each group enforces a superset of the protection provided by the previous
163 enum SettingsEnforcementGroup {
164 GROUP_NO_ENFORCEMENT,
165 // Only enforce settings on profile loads; still allow seeding of unloaded
167 GROUP_ENFORCE_ON_LOAD,
168 // Also disallow seeding of unloaded profiles.
169 GROUP_ENFORCE_ALWAYS,
170 // Also enforce extension settings.
171 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS,
172 // The default enforcement group contains all protection features.
173 GROUP_ENFORCE_DEFAULT
176 SettingsEnforcementGroup GetSettingsEnforcementGroup() {
178 if (!g_disable_delays_and_domain_check_for_testing) {
179 static bool first_call = true;
180 static const bool is_enrolled_to_domain = base::win::IsEnrolledToDomain();
182 UMA_HISTOGRAM_BOOLEAN("Settings.TrackedPreferencesNoEnforcementOnDomain",
183 is_enrolled_to_domain);
186 if (is_enrolled_to_domain)
187 return GROUP_NO_ENFORCEMENT;
192 const char* group_name;
193 SettingsEnforcementGroup group;
194 } static const kEnforcementLevelMap[] = {
195 { chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement,
196 GROUP_NO_ENFORCEMENT },
197 { chrome_prefs::internals::kSettingsEnforcementGroupEnforceOnload,
198 GROUP_ENFORCE_ON_LOAD },
199 { chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways,
200 GROUP_ENFORCE_ALWAYS },
201 { chrome_prefs::internals::
202 kSettingsEnforcementGroupEnforceAlwaysWithExtensions,
203 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS },
206 // Use the strongest enforcement setting in the absence of a field trial
207 // config on Windows. Remember to update the OFFICIAL_BUILD sections of
208 // pref_hash_browsertest.cc and extension_startup_browsertest.cc when updating
209 // the default value below.
210 // TODO(gab): Enforce this on all platforms.
211 SettingsEnforcementGroup enforcement_group =
213 GROUP_ENFORCE_DEFAULT;
215 GROUP_NO_ENFORCEMENT;
217 bool group_determined_from_trial = false;
218 base::FieldTrial* trial =
219 base::FieldTrialList::Find(
220 chrome_prefs::internals::kSettingsEnforcementTrialName);
222 const std::string& group_name = trial->group_name();
223 // ARRAYSIZE_UNSAFE must be used since the array is declared locally; it is
224 // only unsafe because it could not trigger a compile error on some
225 // non-array pointer types; this is fine since kEnforcementLevelMap is
227 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kEnforcementLevelMap); ++i) {
228 if (kEnforcementLevelMap[i].group_name == group_name) {
229 enforcement_group = kEnforcementLevelMap[i].group;
230 group_determined_from_trial = true;
235 UMA_HISTOGRAM_BOOLEAN("Settings.EnforcementGroupDeterminedFromTrial",
236 group_determined_from_trial);
237 return enforcement_group;
240 // Returns the effective preference tracking configuration.
241 std::vector<PrefHashFilter::TrackedPreferenceMetadata>
242 GetTrackingConfiguration() {
243 const SettingsEnforcementGroup enforcement_group =
244 GetSettingsEnforcementGroup();
246 std::vector<PrefHashFilter::TrackedPreferenceMetadata> result;
247 for (size_t i = 0; i < arraysize(kTrackedPrefs); ++i) {
248 PrefHashFilter::TrackedPreferenceMetadata data = kTrackedPrefs[i];
250 switch (enforcement_group) {
251 case GROUP_NO_ENFORCEMENT:
252 // Remove enforcement for all tracked preferences.
253 data.enforcement_level = PrefHashFilter::NO_ENFORCEMENT;
255 case GROUP_ENFORCE_ON_LOAD: // Falls through.
256 case GROUP_ENFORCE_ALWAYS:
257 // Keep the default enforcement level for this tracked preference.
259 case GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS: // Falls through.
260 case GROUP_ENFORCE_DEFAULT:
261 // Specifically enable extension settings enforcement.
262 if (data.name == extensions::pref_names::kExtensions)
263 data.enforcement_level = PrefHashFilter::ENFORCE_ON_LOAD;
266 result.push_back(data);
272 // Shows notifications which correspond to PersistentPrefStore's reading errors.
273 void HandleReadError(PersistentPrefStore::PrefReadError error) {
274 // Sample the histogram also for the successful case in order to get a
275 // baseline on the success rate in addition to the error distribution.
276 UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error,
277 PersistentPrefStore::PREF_READ_ERROR_MAX_ENUM);
279 if (error != PersistentPrefStore::PREF_READ_ERROR_NONE) {
280 #if !defined(OS_CHROMEOS)
281 // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
282 // an example problem that this can cause.
283 // Do some diagnosis and try to avoid losing data.
285 if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE) {
286 message_id = IDS_PREFERENCES_CORRUPT_ERROR;
287 } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) {
288 message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
292 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
293 base::Bind(&ShowProfileErrorDialog,
294 PROFILE_ERROR_PREFERENCES,
298 // On ChromeOS error screen with message about broken local state
299 // will be displayed.
304 scoped_ptr<ProfilePrefStoreManager> CreateProfilePrefStoreManager(
305 const base::FilePath& profile_path) {
306 std::string device_id;
307 #if defined(OS_WIN) && defined(ENABLE_RLZ)
309 // chrome/browser/extensions/api/music_manager_private/device_id_win.cc
310 // but that API is private (http://crbug.com/276485) and other platforms are
311 // not available synchronously.
312 // As part of improving pref metrics on other platforms we may want to find
313 // ways to defer preference loading until the device ID can be used.
314 rlz_lib::GetMachineId(&device_id);
316 return make_scoped_ptr(new ProfilePrefStoreManager(
318 GetTrackingConfiguration(),
319 kTrackedPrefsReportingIDsCount,
320 ResourceBundle::GetSharedInstance()
321 .GetRawDataResource(IDR_PREF_HASH_SEED_BIN)
324 g_browser_process->local_state()));
328 PrefServiceSyncableFactory* factory,
329 policy::PolicyService* policy_service,
330 ManagedUserSettingsService* managed_user_settings,
331 scoped_refptr<PersistentPrefStore> user_pref_store,
332 const scoped_refptr<PrefStore>& extension_prefs,
334 #if defined(ENABLE_CONFIGURATION_POLICY)
335 using policy::ConfigurationPolicyPrefStore;
336 factory->set_managed_prefs(
337 make_scoped_refptr(new ConfigurationPolicyPrefStore(
339 g_browser_process->browser_policy_connector()->GetHandlerList(),
340 policy::POLICY_LEVEL_MANDATORY)));
341 factory->set_recommended_prefs(
342 make_scoped_refptr(new ConfigurationPolicyPrefStore(
344 g_browser_process->browser_policy_connector()->GetHandlerList(),
345 policy::POLICY_LEVEL_RECOMMENDED)));
346 #endif // ENABLE_CONFIGURATION_POLICY
348 #if defined(ENABLE_MANAGED_USERS)
349 if (managed_user_settings) {
350 factory->set_supervised_user_prefs(
351 make_scoped_refptr(new SupervisedUserPrefStore(managed_user_settings)));
355 factory->set_async(async);
356 factory->set_extension_prefs(extension_prefs);
357 factory->set_command_line_prefs(
359 new CommandLinePrefStore(CommandLine::ForCurrentProcess())));
360 factory->set_read_error_callback(base::Bind(&HandleReadError));
361 factory->set_user_prefs(user_pref_store);
364 // Initialize/update preference hash stores for all profiles but the one whose
365 // path matches |ignored_profile_path|.
366 void UpdateAllPrefHashStoresIfRequired(
367 const base::FilePath& ignored_profile_path) {
368 if (GetSettingsEnforcementGroup() >= GROUP_ENFORCE_ALWAYS)
370 const ProfileInfoCache& profile_info_cache =
371 g_browser_process->profile_manager()->GetProfileInfoCache();
372 const size_t n_profiles = profile_info_cache.GetNumberOfProfiles();
373 for (size_t i = 0; i < n_profiles; ++i) {
374 const base::FilePath profile_path =
375 profile_info_cache.GetPathOfProfileAtIndex(i);
376 if (profile_path != ignored_profile_path) {
377 CreateProfilePrefStoreManager(profile_path)
378 ->UpdateProfileHashStoreIfRequired(
379 JsonPrefStore::GetTaskRunnerForFile(
380 profile_path, BrowserThread::GetBlockingPool()));
387 namespace chrome_prefs {
389 namespace internals {
391 const char kSettingsEnforcementTrialName[] = "SettingsEnforcement";
392 const char kSettingsEnforcementGroupNoEnforcement[] = "no_enforcement";
393 const char kSettingsEnforcementGroupEnforceOnload[] = "enforce_on_load";
394 const char kSettingsEnforcementGroupEnforceAlways[] = "enforce_always";
395 const char kSettingsEnforcementGroupEnforceAlwaysWithExtensions[] =
396 "enforce_always_with_extensions";
398 } // namespace internals
400 scoped_ptr<PrefService> CreateLocalState(
401 const base::FilePath& pref_filename,
402 base::SequencedTaskRunner* pref_io_task_runner,
403 policy::PolicyService* policy_service,
404 const scoped_refptr<PrefRegistry>& pref_registry,
406 PrefServiceSyncableFactory factory;
410 NULL, // managed_user_settings
412 pref_filename, pref_io_task_runner, scoped_ptr<PrefFilter>()),
413 NULL, // extension_prefs
415 return factory.Create(pref_registry.get());
418 scoped_ptr<PrefServiceSyncable> CreateProfilePrefs(
419 const base::FilePath& profile_path,
420 base::SequencedTaskRunner* pref_io_task_runner,
421 policy::PolicyService* policy_service,
422 ManagedUserSettingsService* managed_user_settings,
423 const scoped_refptr<PrefStore>& extension_prefs,
424 const scoped_refptr<user_prefs::PrefRegistrySyncable>& pref_registry,
426 TRACE_EVENT0("browser", "chrome_prefs::CreateProfilePrefs");
427 PrefServiceSyncableFactory factory;
428 PrepareFactory(&factory,
430 managed_user_settings,
431 scoped_refptr<PersistentPrefStore>(
432 CreateProfilePrefStoreManager(profile_path)
433 ->CreateProfilePrefStore(pref_io_task_runner)),
436 return factory.CreateSyncable(pref_registry.get());
439 void SchedulePrefsFilePathVerification(const base::FilePath& profile_path) {
441 // Only do prefs file verification on Windows.
442 const int kVerifyPrefsFileDelaySeconds = 60;
443 BrowserThread::GetBlockingPool()->PostDelayedTask(
445 base::Bind(&VerifyPreferencesFile,
446 ProfilePrefStoreManager::GetPrefFilePathFromProfilePath(
448 base::TimeDelta::FromSeconds(g_disable_delays_and_domain_check_for_testing
450 : kVerifyPrefsFileDelaySeconds));
454 void DisableDelaysAndDomainCheckForTesting() {
455 g_disable_delays_and_domain_check_for_testing = true;
458 void SchedulePrefHashStoresUpdateCheck(
459 const base::FilePath& initial_profile_path) {
460 if (!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking) {
461 ProfilePrefStoreManager::ResetAllPrefHashStores(
462 g_browser_process->local_state());
466 const int kDefaultPrefHashStoresUpdateCheckDelaySeconds = 55;
467 BrowserThread::PostDelayedTask(
470 base::Bind(&UpdateAllPrefHashStoresIfRequired,
471 initial_profile_path),
472 base::TimeDelta::FromSeconds(
473 g_disable_delays_and_domain_check_for_testing ?
474 0 : kDefaultPrefHashStoresUpdateCheckDelaySeconds));
477 void ResetPrefHashStore(const base::FilePath& profile_path) {
478 CreateProfilePrefStoreManager(profile_path)->ResetPrefHashStore();
481 bool InitializePrefsFromMasterPrefs(
482 const base::FilePath& profile_path,
483 const base::DictionaryValue& master_prefs) {
484 return CreateProfilePrefStoreManager(profile_path)
485 ->InitializePrefsFromMasterPrefs(master_prefs);
488 base::Time GetResetTime(Profile* profile) {
489 return ProfilePrefStoreManager::GetResetTime(profile->GetPrefs());
492 void ClearResetTime(Profile* profile) {
493 ProfilePrefStoreManager::ClearResetTime(profile->GetPrefs());
496 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
497 ProfilePrefStoreManager::RegisterProfilePrefs(registry);
500 void RegisterPrefs(PrefRegistrySimple* registry) {
501 ProfilePrefStoreManager::RegisterPrefs(registry);
504 } // namespace chrome_prefs