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.
5 #include "chrome/browser/prefs/profile_pref_store_manager.h"
7 #include "base/file_util.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/json_pref_store.h"
12 #include "base/prefs/persistent_pref_store.h"
13 #include "base/prefs/pref_registry_simple.h"
14 #include "chrome/browser/prefs/pref_hash_store_impl.h"
15 #include "chrome/browser/prefs/tracked/pref_service_hash_store_contents.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/user_prefs/pref_registry_syncable.h"
22 // An in-memory PrefStore backed by an immutable DictionaryValue.
23 class DictionaryPrefStore : public PrefStore {
25 explicit DictionaryPrefStore(const base::DictionaryValue* dictionary)
26 : dictionary_(dictionary) {}
28 virtual bool GetValue(const std::string& key,
29 const base::Value** result) const OVERRIDE {
30 const base::Value* tmp = NULL;
31 if (!dictionary_->Get(key, &tmp))
40 virtual ~DictionaryPrefStore() {}
42 const base::DictionaryValue* dictionary_;
44 DISALLOW_COPY_AND_ASSIGN(DictionaryPrefStore);
49 // TODO(erikwright): Enable this on Chrome OS and Android once MACs are moved
50 // out of Local State. This will resolve a race condition on Android and a
51 // privacy issue on ChromeOS. http://crbug.com/349158
52 const bool ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking =
53 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
59 // Waits for a PrefStore to be initialized and then initializes the
60 // corresponding PrefHashStore.
61 // The observer deletes itself when its work is completed.
62 class ProfilePrefStoreManager::InitializeHashStoreObserver
63 : public PrefStore::Observer {
65 // Creates an observer that will initialize |pref_hash_store| with the
66 // contents of |pref_store| when the latter is fully loaded.
67 InitializeHashStoreObserver(
68 const std::vector<PrefHashFilter::TrackedPreferenceMetadata>&
69 tracking_configuration,
70 size_t reporting_ids_count,
71 const scoped_refptr<PrefStore>& pref_store,
72 scoped_ptr<PrefHashStoreImpl> pref_hash_store_impl)
73 : tracking_configuration_(tracking_configuration),
74 reporting_ids_count_(reporting_ids_count),
75 pref_store_(pref_store),
76 pref_hash_store_impl_(pref_hash_store_impl.Pass()) {}
78 virtual ~InitializeHashStoreObserver();
80 // PrefStore::Observer implementation.
81 virtual void OnPrefValueChanged(const std::string& key) OVERRIDE;
82 virtual void OnInitializationCompleted(bool succeeded) OVERRIDE;
85 const std::vector<PrefHashFilter::TrackedPreferenceMetadata>
86 tracking_configuration_;
87 const size_t reporting_ids_count_;
88 scoped_refptr<PrefStore> pref_store_;
89 scoped_ptr<PrefHashStoreImpl> pref_hash_store_impl_;
91 DISALLOW_COPY_AND_ASSIGN(InitializeHashStoreObserver);
94 ProfilePrefStoreManager::InitializeHashStoreObserver::
95 ~InitializeHashStoreObserver() {}
97 void ProfilePrefStoreManager::InitializeHashStoreObserver::OnPrefValueChanged(
98 const std::string& key) {}
101 ProfilePrefStoreManager::InitializeHashStoreObserver::OnInitializationCompleted(
103 // If we successfully loaded the preferences _and_ the PrefHashStoreImpl
104 // hasn't been initialized by someone else in the meantime, initialize it now.
105 const PrefHashStoreImpl::StoreVersion pre_update_version =
106 pref_hash_store_impl_->GetCurrentVersion();
107 if (succeeded && pre_update_version < PrefHashStoreImpl::VERSION_LATEST) {
108 PrefHashFilter(pref_hash_store_impl_.PassAs<PrefHashStore>(),
109 tracking_configuration_,
110 reporting_ids_count_).Initialize(*pref_store_);
111 UMA_HISTOGRAM_ENUMERATION(
112 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
114 PrefHashStoreImpl::VERSION_LATEST + 1);
116 pref_store_->RemoveObserver(this);
120 ProfilePrefStoreManager::ProfilePrefStoreManager(
121 const base::FilePath& profile_path,
122 const std::vector<PrefHashFilter::TrackedPreferenceMetadata>&
123 tracking_configuration,
124 size_t reporting_ids_count,
125 const std::string& seed,
126 const std::string& device_id,
127 PrefService* local_state)
128 : profile_path_(profile_path),
129 tracking_configuration_(tracking_configuration),
130 reporting_ids_count_(reporting_ids_count),
132 device_id_(device_id),
133 local_state_(local_state) {}
135 ProfilePrefStoreManager::~ProfilePrefStoreManager() {}
138 void ProfilePrefStoreManager::RegisterPrefs(PrefRegistrySimple* registry) {
139 PrefServiceHashStoreContents::RegisterPrefs(registry);
143 void ProfilePrefStoreManager::RegisterProfilePrefs(
144 user_prefs::PrefRegistrySyncable* registry) {
145 PrefHashFilter::RegisterProfilePrefs(registry);
149 base::FilePath ProfilePrefStoreManager::GetPrefFilePathFromProfilePath(
150 const base::FilePath& profile_path) {
151 return profile_path.Append(chrome::kPreferencesFilename);
155 void ProfilePrefStoreManager::ResetAllPrefHashStores(PrefService* local_state) {
156 PrefServiceHashStoreContents::ResetAllPrefHashStores(local_state);
160 base::Time ProfilePrefStoreManager::GetResetTime(PrefService* pref_service) {
161 return PrefHashFilter::GetResetTime(pref_service);
165 void ProfilePrefStoreManager::ClearResetTime(PrefService* pref_service) {
166 PrefHashFilter::ClearResetTime(pref_service);
169 void ProfilePrefStoreManager::ResetPrefHashStore() {
170 if (kPlatformSupportsPreferenceTracking)
171 GetPrefHashStoreImpl()->Reset();
174 PersistentPrefStore* ProfilePrefStoreManager::CreateProfilePrefStore(
175 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) {
176 scoped_ptr<PrefFilter> pref_filter;
177 if (kPlatformSupportsPreferenceTracking) {
179 new PrefHashFilter(GetPrefHashStoreImpl().PassAs<PrefHashStore>(),
180 tracking_configuration_,
181 reporting_ids_count_));
183 return new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_),
188 void ProfilePrefStoreManager::UpdateProfileHashStoreIfRequired(
189 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) {
190 if (!kPlatformSupportsPreferenceTracking)
192 scoped_ptr<PrefHashStoreImpl> pref_hash_store_impl(GetPrefHashStoreImpl());
193 const PrefHashStoreImpl::StoreVersion current_version =
194 pref_hash_store_impl->GetCurrentVersion();
195 UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferencesAlternateStoreVersion",
197 PrefHashStoreImpl::VERSION_LATEST + 1);
199 // Update the pref hash store if it's not at the latest version.
200 if (current_version != PrefHashStoreImpl::VERSION_LATEST) {
201 scoped_refptr<JsonPrefStore> pref_store =
202 new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_),
204 scoped_ptr<PrefFilter>());
205 pref_store->AddObserver(
206 new InitializeHashStoreObserver(tracking_configuration_,
207 reporting_ids_count_,
209 pref_hash_store_impl.Pass()));
210 pref_store->ReadPrefsAsync(NULL);
214 bool ProfilePrefStoreManager::InitializePrefsFromMasterPrefs(
215 const base::DictionaryValue& master_prefs) {
216 // Create the profile directory if it doesn't exist yet (very possible on
218 if (!base::CreateDirectory(profile_path_))
221 JSONFileValueSerializer serializer(
222 GetPrefFilePathFromProfilePath(profile_path_));
224 // Call Serialize (which does IO) on the main thread, which would _normally_
225 // be verboten. In this case however, we require this IO to synchronously
226 // complete before Chrome can start (as master preferences seed the Local
227 // State and Preferences files). This won't trip ThreadIORestrictions as they
228 // won't have kicked in yet on the main thread.
229 bool success = serializer.Serialize(master_prefs);
231 if (success && kPlatformSupportsPreferenceTracking) {
232 scoped_refptr<const PrefStore> pref_store(
233 new DictionaryPrefStore(&master_prefs));
234 PrefHashFilter(GetPrefHashStoreImpl().PassAs<PrefHashStore>(),
235 tracking_configuration_,
236 reporting_ids_count_).Initialize(*pref_store);
239 UMA_HISTOGRAM_BOOLEAN("Settings.InitializedFromMasterPrefs", success);
243 scoped_ptr<PrefHashStoreImpl> ProfilePrefStoreManager::GetPrefHashStoreImpl() {
244 DCHECK(kPlatformSupportsPreferenceTracking);
246 return make_scoped_ptr(new PrefHashStoreImpl(
249 scoped_ptr<HashStoreContents>(new PrefServiceHashStoreContents(
250 profile_path_.AsUTF8Unsafe(), local_state_))));