Home | History | Annotate | Download | only in prefs
      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