// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/prefs/profile_pref_store_manager.h" #include "base/bind.h" #include "base/callback.h" #include "base/files/file_util.h" #include "base/json/json_file_value_serializer.h" #include "base/logging.h" #include "base/metrics/histogram.h" #include "base/prefs/json_pref_store.h" #include "base/prefs/persistent_pref_store.h" #include "base/prefs/pref_registry_simple.h" #include "base/sequenced_task_runner.h" #include "chrome/browser/prefs/tracked/pref_hash_store_impl.h" #include "chrome/browser/prefs/tracked/pref_service_hash_store_contents.h" #include "chrome/browser/prefs/tracked/segregated_pref_store.h" #include "chrome/browser/prefs/tracked/tracked_preferences_migration.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" namespace { void RemoveValueSilently(const base::WeakPtr pref_store, const std::string& key) { if (pref_store) { pref_store->RemoveValueSilently( key, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); } } } // namespace // Preference tracking and protection is not required on platforms where other // apps do not have access to chrome's persistent storage. const bool ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking = #if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_IOS) false; #else true; #endif ProfilePrefStoreManager::ProfilePrefStoreManager( const base::FilePath& profile_path, const std::vector& tracking_configuration, size_t reporting_ids_count, const std::string& seed, const std::string& device_id, PrefService* local_state) : profile_path_(profile_path), tracking_configuration_(tracking_configuration), reporting_ids_count_(reporting_ids_count), seed_(seed), device_id_(device_id), local_state_(local_state) {} ProfilePrefStoreManager::~ProfilePrefStoreManager() {} // static void ProfilePrefStoreManager::RegisterPrefs(PrefRegistrySimple* registry) { PrefServiceHashStoreContents::RegisterPrefs(registry); } // static void ProfilePrefStoreManager::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { PrefHashFilter::RegisterProfilePrefs(registry); } // static base::FilePath ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( const base::FilePath& profile_path) { return profile_path.Append(chrome::kPreferencesFilename); } // static void ProfilePrefStoreManager::ResetAllPrefHashStores(PrefService* local_state) { PrefServiceHashStoreContents::ResetAllPrefHashStores(local_state); } // static base::Time ProfilePrefStoreManager::GetResetTime(PrefService* pref_service) { return PrefHashFilter::GetResetTime(pref_service); } // static void ProfilePrefStoreManager::ClearResetTime(PrefService* pref_service) { PrefHashFilter::ClearResetTime(pref_service); } PersistentPrefStore* ProfilePrefStoreManager::CreateProfilePrefStore( const scoped_refptr& io_task_runner, const base::Closure& on_reset_on_load, TrackedPreferenceValidationDelegate* validation_delegate) { scoped_ptr pref_filter; if (!kPlatformSupportsPreferenceTracking) { return new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_), io_task_runner.get(), scoped_ptr()); } std::vector unprotected_configuration; std::vector protected_configuration; std::set protected_pref_names; std::set unprotected_pref_names; for (std::vector::const_iterator it = tracking_configuration_.begin(); it != tracking_configuration_.end(); ++it) { if (it->enforcement_level > PrefHashFilter::NO_ENFORCEMENT) { protected_configuration.push_back(*it); protected_pref_names.insert(it->name); } else { unprotected_configuration.push_back(*it); unprotected_pref_names.insert(it->name); } } scoped_ptr unprotected_pref_hash_filter( new PrefHashFilter(GetPrefHashStore(false), unprotected_configuration, base::Closure(), validation_delegate, reporting_ids_count_, false)); scoped_ptr protected_pref_hash_filter( new PrefHashFilter(GetPrefHashStore(true), protected_configuration, on_reset_on_load, validation_delegate, reporting_ids_count_, true)); PrefHashFilter* raw_unprotected_pref_hash_filter = unprotected_pref_hash_filter.get(); PrefHashFilter* raw_protected_pref_hash_filter = protected_pref_hash_filter.get(); scoped_refptr unprotected_pref_store( new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_), io_task_runner.get(), unprotected_pref_hash_filter.Pass())); // TODO(gab): Remove kDeprecatedProtectedPreferencesFilename as an alternate // file in M40+. scoped_refptr protected_pref_store(new JsonPrefStore( profile_path_.Append(chrome::kSecurePreferencesFilename), profile_path_.Append(chrome::kProtectedPreferencesFilenameDeprecated), io_task_runner.get(), protected_pref_hash_filter.Pass())); SetupTrackedPreferencesMigration( unprotected_pref_names, protected_pref_names, base::Bind(&RemoveValueSilently, unprotected_pref_store->AsWeakPtr()), base::Bind(&RemoveValueSilently, protected_pref_store->AsWeakPtr()), base::Bind(&JsonPrefStore::RegisterOnNextSuccessfulWriteCallback, unprotected_pref_store->AsWeakPtr()), base::Bind(&JsonPrefStore::RegisterOnNextSuccessfulWriteCallback, protected_pref_store->AsWeakPtr()), GetPrefHashStore(false), GetPrefHashStore(true), scoped_ptr(new PrefServiceHashStoreContents( profile_path_.AsUTF8Unsafe(), local_state_)), raw_unprotected_pref_hash_filter, raw_protected_pref_hash_filter); return new SegregatedPrefStore(unprotected_pref_store, protected_pref_store, protected_pref_names); } bool ProfilePrefStoreManager::InitializePrefsFromMasterPrefs( const base::DictionaryValue& master_prefs) { // Create the profile directory if it doesn't exist yet (very possible on // first run). if (!base::CreateDirectory(profile_path_)) return false; const base::DictionaryValue* to_serialize = &master_prefs; scoped_ptr copy; if (kPlatformSupportsPreferenceTracking) { copy.reset(master_prefs.DeepCopy()); to_serialize = copy.get(); PrefHashFilter(GetPrefHashStore(false), tracking_configuration_, base::Closure(), NULL, reporting_ids_count_, false).Initialize(copy.get()); } // This will write out to a single combined file which will be immediately // migrated to two files on load. JSONFileValueSerializer serializer( GetPrefFilePathFromProfilePath(profile_path_)); // Call Serialize (which does IO) on the main thread, which would _normally_ // be verboten. In this case however, we require this IO to synchronously // complete before Chrome can start (as master preferences seed the Local // State and Preferences files). This won't trip ThreadIORestrictions as they // won't have kicked in yet on the main thread. bool success = serializer.Serialize(*to_serialize); UMA_HISTOGRAM_BOOLEAN("Settings.InitializedFromMasterPrefs", success); return success; } PersistentPrefStore* ProfilePrefStoreManager::CreateDeprecatedCombinedProfilePrefStore( const scoped_refptr& io_task_runner) { scoped_ptr pref_filter; if (kPlatformSupportsPreferenceTracking) { scoped_ptr pref_hash_store_impl( new PrefHashStoreImpl(seed_, device_id_, true)); pref_hash_store_impl->set_legacy_hash_store_contents( scoped_ptr(new PrefServiceHashStoreContents( profile_path_.AsUTF8Unsafe(), local_state_))); pref_filter.reset(new PrefHashFilter(pref_hash_store_impl.Pass(), tracking_configuration_, base::Closure(), NULL, reporting_ids_count_, false)); } return new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_), io_task_runner.get(), pref_filter.Pass()); } scoped_ptr ProfilePrefStoreManager::GetPrefHashStore( bool use_super_mac) { DCHECK(kPlatformSupportsPreferenceTracking); return scoped_ptr(new PrefHashStoreImpl( seed_, device_id_, use_super_mac)); }