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