chrome_pref_service_factory.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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 66using content::BrowserContext; 67using content::BrowserThread; 68 69namespace { 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. 75bool 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. 81const 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. 157const size_t kTrackedPrefsReportingIDsCount = 14; 158COMPILE_ASSERT(kTrackedPrefsReportingIDsCount >= arraysize(kTrackedPrefs), 159 need_to_increment_ids_count); 160 161enum 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 169SettingsEnforcementGroup 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 // TODO(gab): Switch the default to GROUP_ENFORCE_ALWAYS. 197 SettingsEnforcementGroup enforcement_group = GROUP_NO_ENFORCEMENT; 198 bool group_determined_from_trial = false; 199 base::FieldTrial* trial = 200 base::FieldTrialList::Find( 201 chrome_prefs::internals::kSettingsEnforcementTrialName); 202 if (trial) { 203 const std::string& group_name = trial->group_name(); 204 // ARRAYSIZE_UNSAFE must be used since the array is declared locally; it is 205 // only unsafe because it could not trigger a compile error on some 206 // non-array pointer types; this is fine since kEnforcementLevelMap is 207 // clearly an array. 208 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kEnforcementLevelMap); ++i) { 209 if (kEnforcementLevelMap[i].group_name == group_name) { 210 enforcement_group = kEnforcementLevelMap[i].group; 211 group_determined_from_trial = true; 212 break; 213 } 214 } 215 } 216 UMA_HISTOGRAM_BOOLEAN("Settings.EnforcementGroupDeterminedFromTrial", 217 group_determined_from_trial); 218 return enforcement_group; 219} 220 221// Returns the effective preference tracking configuration. 222std::vector<PrefHashFilter::TrackedPreferenceMetadata> 223GetTrackingConfiguration() { 224 const PrefHashFilter::EnforcementLevel maximum_level = 225 GetSettingsEnforcementGroup() == GROUP_NO_ENFORCEMENT 226 ? PrefHashFilter::NO_ENFORCEMENT 227 : PrefHashFilter::ENFORCE_ON_LOAD; 228 229 std::vector<PrefHashFilter::TrackedPreferenceMetadata> result; 230 for (size_t i = 0; i < arraysize(kTrackedPrefs); ++i) { 231 PrefHashFilter::TrackedPreferenceMetadata data = kTrackedPrefs[i]; 232 if (data.enforcement_level > maximum_level) 233 data.enforcement_level = maximum_level; 234 result.push_back(data); 235 } 236 return result; 237} 238 239 240// Shows notifications which correspond to PersistentPrefStore's reading errors. 241void HandleReadError(PersistentPrefStore::PrefReadError error) { 242 // Sample the histogram also for the successful case in order to get a 243 // baseline on the success rate in addition to the error distribution. 244 UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error, 245 PersistentPrefStore::PREF_READ_ERROR_MAX_ENUM); 246 247 if (error != PersistentPrefStore::PREF_READ_ERROR_NONE) { 248#if !defined(OS_CHROMEOS) 249 // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for 250 // an example problem that this can cause. 251 // Do some diagnosis and try to avoid losing data. 252 int message_id = 0; 253 if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE) { 254 message_id = IDS_PREFERENCES_CORRUPT_ERROR; 255 } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) { 256 message_id = IDS_PREFERENCES_UNREADABLE_ERROR; 257 } 258 259 if (message_id) { 260 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 261 base::Bind(&ShowProfileErrorDialog, 262 PROFILE_ERROR_PREFERENCES, 263 message_id)); 264 } 265#else 266 // On ChromeOS error screen with message about broken local state 267 // will be displayed. 268#endif 269 } 270} 271 272scoped_ptr<ProfilePrefStoreManager> CreateProfilePrefStoreManager( 273 const base::FilePath& profile_path) { 274 std::string device_id; 275#if defined(OS_WIN) && defined(ENABLE_RLZ) 276 // This is used by 277 // chrome/browser/extensions/api/music_manager_private/device_id_win.cc 278 // but that API is private (http://crbug.com/276485) and other platforms are 279 // not available synchronously. 280 // As part of improving pref metrics on other platforms we may want to find 281 // ways to defer preference loading until the device ID can be used. 282 rlz_lib::GetMachineId(&device_id); 283#endif 284 return make_scoped_ptr(new ProfilePrefStoreManager( 285 profile_path, 286 GetTrackingConfiguration(), 287 kTrackedPrefsReportingIDsCount, 288 ResourceBundle::GetSharedInstance() 289 .GetRawDataResource(IDR_PREF_HASH_SEED_BIN) 290 .as_string(), 291 device_id, 292 g_browser_process->local_state())); 293} 294 295void PrepareFactory( 296 PrefServiceSyncableFactory* factory, 297 policy::PolicyService* policy_service, 298 ManagedUserSettingsService* managed_user_settings, 299 scoped_refptr<PersistentPrefStore> user_pref_store, 300 const scoped_refptr<PrefStore>& extension_prefs, 301 bool async) { 302#if defined(ENABLE_CONFIGURATION_POLICY) 303 using policy::ConfigurationPolicyPrefStore; 304 factory->set_managed_prefs( 305 make_scoped_refptr(new ConfigurationPolicyPrefStore( 306 policy_service, 307 g_browser_process->browser_policy_connector()->GetHandlerList(), 308 policy::POLICY_LEVEL_MANDATORY))); 309 factory->set_recommended_prefs( 310 make_scoped_refptr(new ConfigurationPolicyPrefStore( 311 policy_service, 312 g_browser_process->browser_policy_connector()->GetHandlerList(), 313 policy::POLICY_LEVEL_RECOMMENDED))); 314#endif // ENABLE_CONFIGURATION_POLICY 315 316#if defined(ENABLE_MANAGED_USERS) 317 if (managed_user_settings) { 318 factory->set_supervised_user_prefs( 319 make_scoped_refptr(new SupervisedUserPrefStore(managed_user_settings))); 320 } 321#endif 322 323 factory->set_async(async); 324 factory->set_extension_prefs(extension_prefs); 325 factory->set_command_line_prefs( 326 make_scoped_refptr( 327 new CommandLinePrefStore(CommandLine::ForCurrentProcess()))); 328 factory->set_read_error_callback(base::Bind(&HandleReadError)); 329 factory->set_user_prefs(user_pref_store); 330} 331 332// Initialize/update preference hash stores for all profiles but the one whose 333// path matches |ignored_profile_path|. 334void UpdateAllPrefHashStoresIfRequired( 335 const base::FilePath& ignored_profile_path) { 336 if (GetSettingsEnforcementGroup() >= GROUP_ENFORCE_ALWAYS) 337 return; 338 const ProfileInfoCache& profile_info_cache = 339 g_browser_process->profile_manager()->GetProfileInfoCache(); 340 const size_t n_profiles = profile_info_cache.GetNumberOfProfiles(); 341 for (size_t i = 0; i < n_profiles; ++i) { 342 const base::FilePath profile_path = 343 profile_info_cache.GetPathOfProfileAtIndex(i); 344 if (profile_path != ignored_profile_path) { 345 CreateProfilePrefStoreManager(profile_path) 346 ->UpdateProfileHashStoreIfRequired( 347 JsonPrefStore::GetTaskRunnerForFile( 348 profile_path, BrowserThread::GetBlockingPool())); 349 } 350 } 351} 352 353} // namespace 354 355namespace chrome_prefs { 356 357namespace internals { 358 359const char kSettingsEnforcementTrialName[] = "SettingsEnforcement"; 360const char kSettingsEnforcementGroupNoEnforcement[] = "no_enforcement"; 361const char kSettingsEnforcementGroupEnforceOnload[] = "enforce_on_load"; 362const char kSettingsEnforcementGroupEnforceAlways[] = "enforce_always"; 363 364} // namespace internals 365 366scoped_ptr<PrefService> CreateLocalState( 367 const base::FilePath& pref_filename, 368 base::SequencedTaskRunner* pref_io_task_runner, 369 policy::PolicyService* policy_service, 370 const scoped_refptr<PrefRegistry>& pref_registry, 371 bool async) { 372 PrefServiceSyncableFactory factory; 373 PrepareFactory( 374 &factory, 375 policy_service, 376 NULL, // managed_user_settings 377 new JsonPrefStore( 378 pref_filename, pref_io_task_runner, scoped_ptr<PrefFilter>()), 379 NULL, // extension_prefs 380 async); 381 return factory.Create(pref_registry.get()); 382} 383 384scoped_ptr<PrefServiceSyncable> CreateProfilePrefs( 385 const base::FilePath& profile_path, 386 base::SequencedTaskRunner* pref_io_task_runner, 387 policy::PolicyService* policy_service, 388 ManagedUserSettingsService* managed_user_settings, 389 const scoped_refptr<PrefStore>& extension_prefs, 390 const scoped_refptr<user_prefs::PrefRegistrySyncable>& pref_registry, 391 bool async) { 392 TRACE_EVENT0("browser", "chrome_prefs::CreateProfilePrefs"); 393 PrefServiceSyncableFactory factory; 394 PrepareFactory(&factory, 395 policy_service, 396 managed_user_settings, 397 scoped_refptr<PersistentPrefStore>( 398 CreateProfilePrefStoreManager(profile_path) 399 ->CreateProfilePrefStore(pref_io_task_runner)), 400 extension_prefs, 401 async); 402 return factory.CreateSyncable(pref_registry.get()); 403} 404 405void SchedulePrefsFilePathVerification(const base::FilePath& profile_path) { 406#if defined(OS_WIN) 407 // Only do prefs file verification on Windows. 408 const int kVerifyPrefsFileDelaySeconds = 60; 409 BrowserThread::GetBlockingPool()->PostDelayedTask( 410 FROM_HERE, 411 base::Bind(&VerifyPreferencesFile, 412 ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( 413 profile_path)), 414 base::TimeDelta::FromSeconds(g_disable_delays_and_domain_check_for_testing 415 ? 0 416 : kVerifyPrefsFileDelaySeconds)); 417#endif 418} 419 420void DisableDelaysAndDomainCheckForTesting() { 421 g_disable_delays_and_domain_check_for_testing = true; 422} 423 424void SchedulePrefHashStoresUpdateCheck( 425 const base::FilePath& initial_profile_path) { 426 if (!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking) { 427 ProfilePrefStoreManager::ResetAllPrefHashStores( 428 g_browser_process->local_state()); 429 return; 430 } 431 432 const int kDefaultPrefHashStoresUpdateCheckDelaySeconds = 55; 433 BrowserThread::PostDelayedTask( 434 BrowserThread::UI, 435 FROM_HERE, 436 base::Bind(&UpdateAllPrefHashStoresIfRequired, 437 initial_profile_path), 438 base::TimeDelta::FromSeconds( 439 g_disable_delays_and_domain_check_for_testing ? 440 0 : kDefaultPrefHashStoresUpdateCheckDelaySeconds)); 441} 442 443void ResetPrefHashStore(const base::FilePath& profile_path) { 444 CreateProfilePrefStoreManager(profile_path)->ResetPrefHashStore(); 445} 446 447bool InitializePrefsFromMasterPrefs( 448 const base::FilePath& profile_path, 449 const base::DictionaryValue& master_prefs) { 450 return CreateProfilePrefStoreManager(profile_path) 451 ->InitializePrefsFromMasterPrefs(master_prefs); 452} 453 454base::Time GetResetTime(Profile* profile) { 455 return ProfilePrefStoreManager::GetResetTime(profile->GetPrefs()); 456} 457 458void ClearResetTime(Profile* profile) { 459 ProfilePrefStoreManager::ClearResetTime(profile->GetPrefs()); 460} 461 462void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { 463 ProfilePrefStoreManager::RegisterProfilePrefs(registry); 464} 465 466void RegisterPrefs(PrefRegistrySimple* registry) { 467 ProfilePrefStoreManager::RegisterPrefs(registry); 468} 469 470} // namespace chrome_prefs 471