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.h" 36 #include "chrome/browser/search_engines/default_search_manager.h" 37 #include "chrome/browser/search_engines/default_search_pref_migration.h" 38 #include "chrome/browser/sync/glue/sync_start_util.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 "components/sync_driver/pref_names.h" 44 #include "content/public/browser/browser_context.h" 45 #include "content/public/browser/browser_thread.h" 46 #include "extensions/browser/pref_names.h" 47 #include "grit/browser_resources.h" 48 #include "grit/chromium_strings.h" 49 #include "grit/generated_resources.h" 50 #include "sync/internal_api/public/base/model_type.h" 51 #include "ui/base/resource/resource_bundle.h" 52 53 #if defined(ENABLE_CONFIGURATION_POLICY) 54 #include "components/policy/core/browser/browser_policy_connector.h" 55 #include "components/policy/core/browser/configuration_policy_pref_store.h" 56 #include "components/policy/core/common/policy_types.h" 57 #endif 58 59 #if defined(ENABLE_MANAGED_USERS) 60 #include "chrome/browser/supervised_user/supervised_user_pref_store.h" 61 #endif 62 63 #if defined(OS_WIN) 64 #include "base/win/win_util.h" 65 #if defined(ENABLE_RLZ) 66 #include "rlz/lib/machine_id.h" 67 #endif // defined(ENABLE_RLZ) 68 #endif // defined(OS_WIN) 69 70 using content::BrowserContext; 71 using content::BrowserThread; 72 73 namespace { 74 75 // Whether we are in testing mode; can be enabled via 76 // DisableDelaysAndDomainCheckForTesting(). Forces startup checks to occur 77 // with no delay and ignores the presence of a domain when determining the 78 // active SettingsEnforcement group. 79 bool g_disable_delays_and_domain_check_for_testing = false; 80 81 // These preferences must be kept in sync with the TrackedPreference enum in 82 // tools/metrics/histograms/histograms.xml. To add a new preference, append it 83 // to the array and add a corresponding value to the histogram enum. Each 84 // tracked preference must be given a unique reporting ID. 85 const PrefHashFilter::TrackedPreferenceMetadata kTrackedPrefs[] = { 86 { 87 0, prefs::kShowHomeButton, 88 PrefHashFilter::ENFORCE_ON_LOAD, 89 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 90 }, 91 { 92 1, prefs::kHomePageIsNewTabPage, 93 PrefHashFilter::ENFORCE_ON_LOAD, 94 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 95 }, 96 { 97 2, prefs::kHomePage, 98 PrefHashFilter::ENFORCE_ON_LOAD, 99 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 100 }, 101 { 102 3, prefs::kRestoreOnStartup, 103 PrefHashFilter::ENFORCE_ON_LOAD, 104 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 105 }, 106 { 107 4, prefs::kURLsToRestoreOnStartup, 108 PrefHashFilter::ENFORCE_ON_LOAD, 109 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 110 }, 111 { 112 5, extensions::pref_names::kExtensions, 113 PrefHashFilter::NO_ENFORCEMENT, 114 PrefHashFilter::TRACKING_STRATEGY_SPLIT 115 }, 116 { 117 6, prefs::kGoogleServicesLastUsername, 118 PrefHashFilter::ENFORCE_ON_LOAD, 119 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 120 }, 121 { 122 7, prefs::kSearchProviderOverrides, 123 PrefHashFilter::ENFORCE_ON_LOAD, 124 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 125 }, 126 { 127 8, prefs::kDefaultSearchProviderSearchURL, 128 PrefHashFilter::ENFORCE_ON_LOAD, 129 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 130 }, 131 { 132 9, prefs::kDefaultSearchProviderKeyword, 133 PrefHashFilter::ENFORCE_ON_LOAD, 134 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 135 }, 136 { 137 10, prefs::kDefaultSearchProviderName, 138 PrefHashFilter::ENFORCE_ON_LOAD, 139 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 140 }, 141 #if !defined(OS_ANDROID) 142 { 143 11, prefs::kPinnedTabs, 144 PrefHashFilter::ENFORCE_ON_LOAD, 145 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 146 }, 147 #endif 148 { 149 12, extensions::pref_names::kKnownDisabled, 150 PrefHashFilter::NO_ENFORCEMENT, 151 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 152 }, 153 { 154 13, prefs::kProfileResetPromptMemento, 155 PrefHashFilter::ENFORCE_ON_LOAD, 156 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 157 }, 158 { 159 14, DefaultSearchManager::kDefaultSearchProviderDataPrefName, 160 PrefHashFilter::NO_ENFORCEMENT, 161 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 162 }, 163 { 164 // Protecting kPreferenceResetTime does two things: 165 // 1) It ensures this isn't accidently set by someone stomping the pref 166 // file. 167 // 2) More importantly, it declares kPreferenceResetTime as a protected 168 // pref which is required for it to be visible when queried via the 169 // SegregatedPrefStore. This is because it's written directly in the 170 // protected JsonPrefStore by that store's PrefHashFilter if there was 171 // a reset in FilterOnLoad and SegregatedPrefStore will not look for it 172 // in the protected JsonPrefStore unless it's declared as a protected 173 // preference here. 174 15, prefs::kPreferenceResetTime, 175 PrefHashFilter::ENFORCE_ON_LOAD, 176 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 177 }, 178 { 179 16, prefs::kSafeBrowsingIncidentReportSent, 180 PrefHashFilter::ENFORCE_ON_LOAD, 181 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 182 }, 183 { 184 17, sync_driver::prefs::kSyncRemainingRollbackTries, 185 PrefHashFilter::ENFORCE_ON_LOAD, 186 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 187 }, 188 }; 189 190 // The count of tracked preferences IDs across all platforms. 191 const size_t kTrackedPrefsReportingIDsCount = 18; 192 COMPILE_ASSERT(kTrackedPrefsReportingIDsCount >= arraysize(kTrackedPrefs), 193 need_to_increment_ids_count); 194 195 // Each group enforces a superset of the protection provided by the previous 196 // one. 197 enum SettingsEnforcementGroup { 198 GROUP_NO_ENFORCEMENT, 199 // Enforce protected settings on profile loads. 200 GROUP_ENFORCE_ALWAYS, 201 // Also enforce extension default search. 202 GROUP_ENFORCE_ALWAYS_WITH_DSE, 203 // Also enforce extension settings and default search. 204 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE, 205 // The default enforcement group contains all protection features. 206 GROUP_ENFORCE_DEFAULT 207 }; 208 209 SettingsEnforcementGroup GetSettingsEnforcementGroup() { 210 # if defined(OS_WIN) 211 if (!g_disable_delays_and_domain_check_for_testing) { 212 static bool first_call = true; 213 static const bool is_enrolled_to_domain = base::win::IsEnrolledToDomain(); 214 if (first_call) { 215 UMA_HISTOGRAM_BOOLEAN("Settings.TrackedPreferencesNoEnforcementOnDomain", 216 is_enrolled_to_domain); 217 first_call = false; 218 } 219 if (is_enrolled_to_domain) 220 return GROUP_NO_ENFORCEMENT; 221 } 222 #endif 223 224 struct { 225 const char* group_name; 226 SettingsEnforcementGroup group; 227 } static const kEnforcementLevelMap[] = { 228 { chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement, 229 GROUP_NO_ENFORCEMENT }, 230 { chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways, 231 GROUP_ENFORCE_ALWAYS }, 232 { chrome_prefs::internals:: 233 kSettingsEnforcementGroupEnforceAlwaysWithDSE, 234 GROUP_ENFORCE_ALWAYS_WITH_DSE }, 235 { chrome_prefs::internals:: 236 kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE, 237 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE }, 238 }; 239 240 // Use the strongest enforcement setting in the absence of a field trial 241 // config on Windows. Remember to update the OFFICIAL_BUILD section of 242 // extension_startup_browsertest.cc when updating the default value below. 243 // TODO(gab): Enforce this on all platforms. 244 SettingsEnforcementGroup enforcement_group = 245 #if defined(OS_WIN) 246 GROUP_ENFORCE_DEFAULT; 247 #else 248 GROUP_NO_ENFORCEMENT; 249 #endif 250 bool group_determined_from_trial = false; 251 base::FieldTrial* trial = 252 base::FieldTrialList::Find( 253 chrome_prefs::internals::kSettingsEnforcementTrialName); 254 if (trial) { 255 const std::string& group_name = trial->group_name(); 256 // ARRAYSIZE_UNSAFE must be used since the array is declared locally; it is 257 // only unsafe because it could not trigger a compile error on some 258 // non-array pointer types; this is fine since kEnforcementLevelMap is 259 // clearly an array. 260 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kEnforcementLevelMap); ++i) { 261 if (kEnforcementLevelMap[i].group_name == group_name) { 262 enforcement_group = kEnforcementLevelMap[i].group; 263 group_determined_from_trial = true; 264 break; 265 } 266 } 267 } 268 UMA_HISTOGRAM_BOOLEAN("Settings.EnforcementGroupDeterminedFromTrial", 269 group_determined_from_trial); 270 return enforcement_group; 271 } 272 273 // Returns the effective preference tracking configuration. 274 std::vector<PrefHashFilter::TrackedPreferenceMetadata> 275 GetTrackingConfiguration() { 276 const SettingsEnforcementGroup enforcement_group = 277 GetSettingsEnforcementGroup(); 278 279 std::vector<PrefHashFilter::TrackedPreferenceMetadata> result; 280 for (size_t i = 0; i < arraysize(kTrackedPrefs); ++i) { 281 PrefHashFilter::TrackedPreferenceMetadata data = kTrackedPrefs[i]; 282 283 if (GROUP_NO_ENFORCEMENT == enforcement_group) { 284 // Remove enforcement for all tracked preferences. 285 data.enforcement_level = PrefHashFilter::NO_ENFORCEMENT; 286 } 287 288 if (enforcement_group >= GROUP_ENFORCE_ALWAYS_WITH_DSE && 289 data.name == DefaultSearchManager::kDefaultSearchProviderDataPrefName) { 290 // Specifically enable default search settings enforcement. 291 data.enforcement_level = PrefHashFilter::ENFORCE_ON_LOAD; 292 } 293 294 if (enforcement_group >= GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE && 295 (data.name == extensions::pref_names::kExtensions || 296 data.name == extensions::pref_names::kKnownDisabled)) { 297 // Specifically enable extension settings enforcement and ensure 298 // kKnownDisabled follows it in the Protected Preferences. 299 // TODO(gab): Get rid of kKnownDisabled altogether. 300 data.enforcement_level = PrefHashFilter::ENFORCE_ON_LOAD; 301 } 302 303 result.push_back(data); 304 } 305 return result; 306 } 307 308 309 // Shows notifications which correspond to PersistentPrefStore's reading errors. 310 void HandleReadError(PersistentPrefStore::PrefReadError error) { 311 // Sample the histogram also for the successful case in order to get a 312 // baseline on the success rate in addition to the error distribution. 313 UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error, 314 PersistentPrefStore::PREF_READ_ERROR_MAX_ENUM); 315 316 if (error != PersistentPrefStore::PREF_READ_ERROR_NONE) { 317 #if !defined(OS_CHROMEOS) 318 // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for 319 // an example problem that this can cause. 320 // Do some diagnosis and try to avoid losing data. 321 int message_id = 0; 322 if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE || 323 error == PersistentPrefStore::PREF_READ_ERROR_LEVELDB_CORRUPTION) { 324 message_id = IDS_PREFERENCES_CORRUPT_ERROR; 325 } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) { 326 message_id = IDS_PREFERENCES_UNREADABLE_ERROR; 327 } 328 329 if (message_id) { 330 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 331 base::Bind(&ShowProfileErrorDialog, 332 PROFILE_ERROR_PREFERENCES, 333 message_id)); 334 } 335 #else 336 // On ChromeOS error screen with message about broken local state 337 // will be displayed. 338 #endif 339 } 340 } 341 342 scoped_ptr<ProfilePrefStoreManager> CreateProfilePrefStoreManager( 343 const base::FilePath& profile_path) { 344 std::string device_id; 345 #if defined(OS_WIN) && defined(ENABLE_RLZ) 346 // This is used by 347 // chrome/browser/extensions/api/music_manager_private/device_id_win.cc 348 // but that API is private (http://crbug.com/276485) and other platforms are 349 // not available synchronously. 350 // As part of improving pref metrics on other platforms we may want to find 351 // ways to defer preference loading until the device ID can be used. 352 rlz_lib::GetMachineId(&device_id); 353 #endif 354 return make_scoped_ptr(new ProfilePrefStoreManager( 355 profile_path, 356 GetTrackingConfiguration(), 357 kTrackedPrefsReportingIDsCount, 358 ResourceBundle::GetSharedInstance() 359 .GetRawDataResource(IDR_PREF_HASH_SEED_BIN) 360 .as_string(), 361 device_id, 362 g_browser_process->local_state())); 363 } 364 365 void PrepareFactory( 366 PrefServiceSyncableFactory* factory, 367 policy::PolicyService* policy_service, 368 SupervisedUserSettingsService* supervised_user_settings, 369 scoped_refptr<PersistentPrefStore> user_pref_store, 370 const scoped_refptr<PrefStore>& extension_prefs, 371 bool async) { 372 #if defined(ENABLE_CONFIGURATION_POLICY) 373 using policy::ConfigurationPolicyPrefStore; 374 factory->set_managed_prefs( 375 make_scoped_refptr(new ConfigurationPolicyPrefStore( 376 policy_service, 377 g_browser_process->browser_policy_connector()->GetHandlerList(), 378 policy::POLICY_LEVEL_MANDATORY))); 379 factory->set_recommended_prefs( 380 make_scoped_refptr(new ConfigurationPolicyPrefStore( 381 policy_service, 382 g_browser_process->browser_policy_connector()->GetHandlerList(), 383 policy::POLICY_LEVEL_RECOMMENDED))); 384 #endif // ENABLE_CONFIGURATION_POLICY 385 386 #if defined(ENABLE_MANAGED_USERS) 387 if (supervised_user_settings) { 388 factory->set_supervised_user_prefs( 389 make_scoped_refptr( 390 new SupervisedUserPrefStore(supervised_user_settings))); 391 } 392 #endif 393 394 factory->set_async(async); 395 factory->set_extension_prefs(extension_prefs); 396 factory->set_command_line_prefs( 397 make_scoped_refptr( 398 new CommandLinePrefStore(CommandLine::ForCurrentProcess()))); 399 factory->set_read_error_callback(base::Bind(&HandleReadError)); 400 factory->set_user_prefs(user_pref_store); 401 } 402 403 } // namespace 404 405 namespace chrome_prefs { 406 407 namespace internals { 408 409 const char kSettingsEnforcementTrialName[] = "SettingsEnforcement"; 410 const char kSettingsEnforcementGroupNoEnforcement[] = "no_enforcement"; 411 const char kSettingsEnforcementGroupEnforceAlways[] = "enforce_always"; 412 const char kSettingsEnforcementGroupEnforceAlwaysWithDSE[] = 413 "enforce_always_with_dse"; 414 const char kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE[] = 415 "enforce_always_with_extensions_and_dse"; 416 417 } // namespace internals 418 419 scoped_ptr<PrefService> CreateLocalState( 420 const base::FilePath& pref_filename, 421 base::SequencedTaskRunner* pref_io_task_runner, 422 policy::PolicyService* policy_service, 423 const scoped_refptr<PrefRegistry>& pref_registry, 424 bool async) { 425 PrefServiceSyncableFactory factory; 426 PrepareFactory( 427 &factory, 428 policy_service, 429 NULL, // supervised_user_settings 430 new JsonPrefStore( 431 pref_filename, pref_io_task_runner, scoped_ptr<PrefFilter>()), 432 NULL, // extension_prefs 433 async); 434 return factory.Create(pref_registry.get()); 435 } 436 437 scoped_ptr<PrefServiceSyncable> CreateProfilePrefs( 438 const base::FilePath& profile_path, 439 base::SequencedTaskRunner* pref_io_task_runner, 440 TrackedPreferenceValidationDelegate* validation_delegate, 441 policy::PolicyService* policy_service, 442 SupervisedUserSettingsService* supervised_user_settings, 443 const scoped_refptr<PrefStore>& extension_prefs, 444 const scoped_refptr<user_prefs::PrefRegistrySyncable>& pref_registry, 445 bool async) { 446 TRACE_EVENT0("browser", "chrome_prefs::CreateProfilePrefs"); 447 448 // A StartSyncFlare used to kick sync early in case of a reset event. This is 449 // done since sync may bring back the user's server value post-reset which 450 // could potentially cause a "settings flash" between the factory default and 451 // the re-instantiated server value. Starting sync ASAP minimizes the window 452 // before the server value is re-instantiated (this window can otherwise be 453 // as long as 10 seconds by default). 454 const base::Closure start_sync_flare_for_prefs = 455 base::Bind(sync_start_util::GetFlareForSyncableService(profile_path), 456 syncer::PREFERENCES); 457 458 PrefServiceSyncableFactory factory; 459 PrepareFactory(&factory, 460 policy_service, 461 supervised_user_settings, 462 scoped_refptr<PersistentPrefStore>( 463 CreateProfilePrefStoreManager(profile_path) 464 ->CreateProfilePrefStore(pref_io_task_runner, 465 start_sync_flare_for_prefs, 466 validation_delegate)), 467 extension_prefs, 468 async); 469 scoped_ptr<PrefServiceSyncable> pref_service = 470 factory.CreateSyncable(pref_registry.get()); 471 472 ConfigureDefaultSearchPrefMigrationToDictionaryValue(pref_service.get()); 473 474 return pref_service.Pass(); 475 } 476 477 void SchedulePrefsFilePathVerification(const base::FilePath& profile_path) { 478 #if defined(OS_WIN) 479 // Only do prefs file verification on Windows. 480 const int kVerifyPrefsFileDelaySeconds = 60; 481 BrowserThread::GetBlockingPool()->PostDelayedTask( 482 FROM_HERE, 483 base::Bind(&VerifyPreferencesFile, 484 ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( 485 profile_path)), 486 base::TimeDelta::FromSeconds(g_disable_delays_and_domain_check_for_testing 487 ? 0 488 : kVerifyPrefsFileDelaySeconds)); 489 #endif 490 } 491 492 void DisableDelaysAndDomainCheckForTesting() { 493 g_disable_delays_and_domain_check_for_testing = true; 494 } 495 496 bool InitializePrefsFromMasterPrefs( 497 const base::FilePath& profile_path, 498 const base::DictionaryValue& master_prefs) { 499 return CreateProfilePrefStoreManager(profile_path) 500 ->InitializePrefsFromMasterPrefs(master_prefs); 501 } 502 503 base::Time GetResetTime(Profile* profile) { 504 return ProfilePrefStoreManager::GetResetTime(profile->GetPrefs()); 505 } 506 507 void ClearResetTime(Profile* profile) { 508 ProfilePrefStoreManager::ClearResetTime(profile->GetPrefs()); 509 } 510 511 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { 512 ProfilePrefStoreManager::RegisterProfilePrefs(registry); 513 } 514 515 void RegisterPrefs(PrefRegistrySimple* registry) { 516 ProfilePrefStoreManager::RegisterPrefs(registry); 517 } 518 519 } // namespace chrome_prefs 520