1 // Copyright 2014 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/profile_pref_store_manager.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "base/file_util.h" 10 #include "base/json/json_file_value_serializer.h" 11 #include "base/logging.h" 12 #include "base/metrics/histogram.h" 13 #include "base/prefs/json_pref_store.h" 14 #include "base/prefs/persistent_pref_store.h" 15 #include "base/prefs/pref_registry_simple.h" 16 #include "chrome/browser/prefs/pref_hash_store_impl.h" 17 #include "chrome/browser/prefs/tracked/pref_service_hash_store_contents.h" 18 #include "chrome/browser/prefs/tracked/segregated_pref_store.h" 19 #include "chrome/browser/prefs/tracked/tracked_preferences_migration.h" 20 #include "chrome/common/chrome_constants.h" 21 #include "chrome/common/pref_names.h" 22 #include "components/pref_registry/pref_registry_syncable.h" 23 24 // TODO(erikwright): Enable this on Chrome OS and Android once MACs are moved 25 // out of Local State. This will resolve a race condition on Android and a 26 // privacy issue on ChromeOS. http://crbug.com/349158 27 const bool ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking = 28 #if defined(OS_ANDROID) || defined(OS_CHROMEOS) 29 false; 30 #else 31 true; 32 #endif 33 34 ProfilePrefStoreManager::ProfilePrefStoreManager( 35 const base::FilePath& profile_path, 36 const std::vector<PrefHashFilter::TrackedPreferenceMetadata>& 37 tracking_configuration, 38 size_t reporting_ids_count, 39 const std::string& seed, 40 const std::string& device_id, 41 PrefService* local_state) 42 : profile_path_(profile_path), 43 tracking_configuration_(tracking_configuration), 44 reporting_ids_count_(reporting_ids_count), 45 seed_(seed), 46 device_id_(device_id), 47 local_state_(local_state) {} 48 49 ProfilePrefStoreManager::~ProfilePrefStoreManager() {} 50 51 // static 52 void ProfilePrefStoreManager::RegisterPrefs(PrefRegistrySimple* registry) { 53 PrefServiceHashStoreContents::RegisterPrefs(registry); 54 } 55 56 // static 57 void ProfilePrefStoreManager::RegisterProfilePrefs( 58 user_prefs::PrefRegistrySyncable* registry) { 59 PrefHashFilter::RegisterProfilePrefs(registry); 60 } 61 62 // static 63 base::FilePath ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( 64 const base::FilePath& profile_path) { 65 return profile_path.Append(chrome::kPreferencesFilename); 66 } 67 68 // static 69 void ProfilePrefStoreManager::ResetAllPrefHashStores(PrefService* local_state) { 70 PrefServiceHashStoreContents::ResetAllPrefHashStores(local_state); 71 } 72 73 // static 74 base::Time ProfilePrefStoreManager::GetResetTime(PrefService* pref_service) { 75 return PrefHashFilter::GetResetTime(pref_service); 76 } 77 78 // static 79 void ProfilePrefStoreManager::ClearResetTime(PrefService* pref_service) { 80 PrefHashFilter::ClearResetTime(pref_service); 81 } 82 83 PersistentPrefStore* ProfilePrefStoreManager::CreateProfilePrefStore( 84 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner, 85 const base::Closure& on_reset_on_load, 86 TrackedPreferenceValidationDelegate* validation_delegate) { 87 scoped_ptr<PrefFilter> pref_filter; 88 if (!kPlatformSupportsPreferenceTracking) { 89 return new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_), 90 io_task_runner, 91 scoped_ptr<PrefFilter>()); 92 } 93 94 std::vector<PrefHashFilter::TrackedPreferenceMetadata> 95 unprotected_configuration; 96 std::vector<PrefHashFilter::TrackedPreferenceMetadata> 97 protected_configuration; 98 std::set<std::string> protected_pref_names; 99 std::set<std::string> unprotected_pref_names; 100 for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::const_iterator 101 it = tracking_configuration_.begin(); 102 it != tracking_configuration_.end(); 103 ++it) { 104 if (it->enforcement_level > PrefHashFilter::NO_ENFORCEMENT) { 105 protected_configuration.push_back(*it); 106 protected_pref_names.insert(it->name); 107 } else { 108 unprotected_configuration.push_back(*it); 109 unprotected_pref_names.insert(it->name); 110 } 111 } 112 113 scoped_ptr<PrefHashFilter> unprotected_pref_hash_filter( 114 new PrefHashFilter(GetPrefHashStore(false), 115 unprotected_configuration, 116 base::Closure(), 117 validation_delegate, 118 reporting_ids_count_, 119 false)); 120 scoped_ptr<PrefHashFilter> protected_pref_hash_filter( 121 new PrefHashFilter(GetPrefHashStore(true), 122 protected_configuration, 123 on_reset_on_load, 124 validation_delegate, 125 reporting_ids_count_, 126 true)); 127 128 PrefHashFilter* raw_unprotected_pref_hash_filter = 129 unprotected_pref_hash_filter.get(); 130 PrefHashFilter* raw_protected_pref_hash_filter = 131 protected_pref_hash_filter.get(); 132 133 scoped_refptr<JsonPrefStore> unprotected_pref_store( 134 new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_), 135 io_task_runner, 136 unprotected_pref_hash_filter.PassAs<PrefFilter>())); 137 // TODO(gab): Remove kDeprecatedProtectedPreferencesFilename as an alternate 138 // file in M40+. 139 scoped_refptr<JsonPrefStore> protected_pref_store(new JsonPrefStore( 140 profile_path_.Append(chrome::kSecurePreferencesFilename), 141 profile_path_.Append(chrome::kProtectedPreferencesFilenameDeprecated), 142 io_task_runner, 143 protected_pref_hash_filter.PassAs<PrefFilter>())); 144 145 SetupTrackedPreferencesMigration( 146 unprotected_pref_names, 147 protected_pref_names, 148 base::Bind(&JsonPrefStore::RemoveValueSilently, 149 unprotected_pref_store->AsWeakPtr()), 150 base::Bind(&JsonPrefStore::RemoveValueSilently, 151 protected_pref_store->AsWeakPtr()), 152 base::Bind(&JsonPrefStore::RegisterOnNextSuccessfulWriteCallback, 153 unprotected_pref_store->AsWeakPtr()), 154 base::Bind(&JsonPrefStore::RegisterOnNextSuccessfulWriteCallback, 155 protected_pref_store->AsWeakPtr()), 156 GetPrefHashStore(false), 157 GetPrefHashStore(true), 158 scoped_ptr<HashStoreContents>(new PrefServiceHashStoreContents( 159 profile_path_.AsUTF8Unsafe(), local_state_)), 160 raw_unprotected_pref_hash_filter, 161 raw_protected_pref_hash_filter); 162 163 return new SegregatedPrefStore(unprotected_pref_store, protected_pref_store, 164 protected_pref_names); 165 } 166 167 bool ProfilePrefStoreManager::InitializePrefsFromMasterPrefs( 168 const base::DictionaryValue& master_prefs) { 169 // Create the profile directory if it doesn't exist yet (very possible on 170 // first run). 171 if (!base::CreateDirectory(profile_path_)) 172 return false; 173 174 const base::DictionaryValue* to_serialize = &master_prefs; 175 scoped_ptr<base::DictionaryValue> copy; 176 177 if (kPlatformSupportsPreferenceTracking) { 178 copy.reset(master_prefs.DeepCopy()); 179 to_serialize = copy.get(); 180 PrefHashFilter(GetPrefHashStore(false), 181 tracking_configuration_, 182 base::Closure(), 183 NULL, 184 reporting_ids_count_, 185 false).Initialize(copy.get()); 186 } 187 188 // This will write out to a single combined file which will be immediately 189 // migrated to two files on load. 190 JSONFileValueSerializer serializer( 191 GetPrefFilePathFromProfilePath(profile_path_)); 192 193 // Call Serialize (which does IO) on the main thread, which would _normally_ 194 // be verboten. In this case however, we require this IO to synchronously 195 // complete before Chrome can start (as master preferences seed the Local 196 // State and Preferences files). This won't trip ThreadIORestrictions as they 197 // won't have kicked in yet on the main thread. 198 bool success = serializer.Serialize(*to_serialize); 199 200 UMA_HISTOGRAM_BOOLEAN("Settings.InitializedFromMasterPrefs", success); 201 return success; 202 } 203 204 PersistentPrefStore* 205 ProfilePrefStoreManager::CreateDeprecatedCombinedProfilePrefStore( 206 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) { 207 scoped_ptr<PrefFilter> pref_filter; 208 if (kPlatformSupportsPreferenceTracking) { 209 scoped_ptr<PrefHashStoreImpl> pref_hash_store_impl( 210 new PrefHashStoreImpl(seed_, device_id_, true)); 211 pref_hash_store_impl->set_legacy_hash_store_contents( 212 scoped_ptr<HashStoreContents>(new PrefServiceHashStoreContents( 213 profile_path_.AsUTF8Unsafe(), local_state_))); 214 pref_filter.reset( 215 new PrefHashFilter(pref_hash_store_impl.PassAs<PrefHashStore>(), 216 tracking_configuration_, 217 base::Closure(), 218 NULL, 219 reporting_ids_count_, 220 false)); 221 } 222 return new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_), 223 io_task_runner, 224 pref_filter.Pass()); 225 } 226 227 scoped_ptr<PrefHashStore> ProfilePrefStoreManager::GetPrefHashStore( 228 bool use_super_mac) { 229 DCHECK(kPlatformSupportsPreferenceTracking); 230 231 return scoped_ptr<PrefHashStore>(new PrefHashStoreImpl( 232 seed_, 233 device_id_, 234 use_super_mac)); 235 } 236