Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / prefs / profile_pref_store_manager.cc
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/file_util.h"
9 #include "base/json/json_file_value_serializer.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/json_pref_store.h"
13 #include "base/prefs/persistent_pref_store.h"
14 #include "base/prefs/pref_registry_simple.h"
15 #include "chrome/browser/prefs/pref_hash_store_impl.h"
16 #include "chrome/browser/prefs/tracked/pref_service_hash_store_contents.h"
17 #include "chrome/browser/prefs/tracked/segregated_pref_store.h"
18 #include "chrome/browser/prefs/tracked/tracked_preferences_migration.h"
19 #include "chrome/common/chrome_constants.h"
20 #include "chrome/common/pref_names.h"
21 #include "components/user_prefs/pref_registry_syncable.h"
22
23 namespace {
24
25 // An adaptor that allows a PrefHashStoreImpl to access a preference store
26 // directly as a dictionary. Uses an equivalent layout to
27 // PrefStoreHashStoreContents.
28 class DictionaryHashStoreContents : public HashStoreContents {
29  public:
30   // Instantiates a HashStoreContents that is a copy of |to_copy|. The copy is
31   // mutable but does not affect the original, nor is it persisted to disk in
32   // any other way.
33   explicit DictionaryHashStoreContents(const HashStoreContents& to_copy)
34       : hash_store_id_(to_copy.hash_store_id()),
35         super_mac_(to_copy.GetSuperMac()) {
36     if (to_copy.IsInitialized())
37       dictionary_.reset(to_copy.GetContents()->DeepCopy());
38     int version = 0;
39     if (to_copy.GetVersion(&version))
40       version_.reset(new int(version));
41   }
42
43   // HashStoreContents implementation
44   virtual std::string hash_store_id() const OVERRIDE { return hash_store_id_; }
45
46   virtual void Reset() OVERRIDE {
47     dictionary_.reset();
48     super_mac_.clear();
49     version_.reset();
50   }
51
52   virtual bool IsInitialized() const OVERRIDE {
53     return dictionary_;
54   }
55
56   virtual const base::DictionaryValue* GetContents() const OVERRIDE{
57     return dictionary_.get();
58   }
59
60   virtual scoped_ptr<MutableDictionary> GetMutableContents() OVERRIDE {
61     return scoped_ptr<MutableDictionary>(
62         new SimpleMutableDictionary(this));
63   }
64
65   virtual std::string GetSuperMac() const OVERRIDE { return super_mac_; }
66
67   virtual void SetSuperMac(const std::string& super_mac) OVERRIDE {
68     super_mac_ = super_mac;
69   }
70
71   virtual bool GetVersion(int* version) const OVERRIDE {
72     if (!version_)
73       return false;
74     *version = *version_;
75     return true;
76   }
77
78   virtual void SetVersion(int version) OVERRIDE {
79     version_.reset(new int(version));
80   }
81
82   virtual void CommitPendingWrite() OVERRIDE {}
83
84  private:
85   class SimpleMutableDictionary
86       : public HashStoreContents::MutableDictionary {
87    public:
88     explicit SimpleMutableDictionary(DictionaryHashStoreContents* outer)
89         : outer_(outer) {}
90
91     virtual ~SimpleMutableDictionary() {}
92
93     // MutableDictionary implementation
94     virtual base::DictionaryValue* operator->() OVERRIDE {
95       if (!outer_->dictionary_)
96         outer_->dictionary_.reset(new base::DictionaryValue);
97       return outer_->dictionary_.get();
98     }
99
100    private:
101     DictionaryHashStoreContents* outer_;
102
103     DISALLOW_COPY_AND_ASSIGN(SimpleMutableDictionary);
104   };
105
106   const std::string hash_store_id_;
107   std::string super_mac_;
108   scoped_ptr<int> version_;
109   scoped_ptr<base::DictionaryValue> dictionary_;
110
111   DISALLOW_COPY_AND_ASSIGN(DictionaryHashStoreContents);
112 };
113
114 // An in-memory PrefStore backed by an immutable DictionaryValue.
115 class DictionaryPrefStore : public PrefStore {
116  public:
117   explicit DictionaryPrefStore(const base::DictionaryValue* dictionary)
118       : dictionary_(dictionary) {}
119
120   virtual bool GetValue(const std::string& key,
121                         const base::Value** result) const OVERRIDE {
122     const base::Value* tmp = NULL;
123     if (!dictionary_->Get(key, &tmp))
124       return false;
125
126     if (result)
127       *result = tmp;
128     return true;
129   }
130
131  private:
132   virtual ~DictionaryPrefStore() {}
133
134   const base::DictionaryValue* dictionary_;
135
136   DISALLOW_COPY_AND_ASSIGN(DictionaryPrefStore);
137 };
138
139 // Waits for a PrefStore to be initialized and then initializes the
140 // corresponding PrefHashStore.
141 // The observer deletes itself when its work is completed.
142 class InitializeHashStoreObserver : public PrefStore::Observer {
143  public:
144   // Creates an observer that will initialize |pref_hash_store| with the
145   // contents of |pref_store| when the latter is fully loaded.
146   InitializeHashStoreObserver(
147       const std::vector<PrefHashFilter::TrackedPreferenceMetadata>&
148           tracking_configuration,
149       size_t reporting_ids_count,
150       const scoped_refptr<PrefStore>& pref_store,
151       scoped_ptr<PrefHashStoreImpl> pref_hash_store_impl)
152       : tracking_configuration_(tracking_configuration),
153         reporting_ids_count_(reporting_ids_count),
154         pref_store_(pref_store),
155         pref_hash_store_impl_(pref_hash_store_impl.Pass()) {}
156
157   virtual ~InitializeHashStoreObserver();
158
159   // PrefStore::Observer implementation.
160   virtual void OnPrefValueChanged(const std::string& key) OVERRIDE;
161   virtual void OnInitializationCompleted(bool succeeded) OVERRIDE;
162
163  private:
164   const std::vector<PrefHashFilter::TrackedPreferenceMetadata>
165       tracking_configuration_;
166   const size_t reporting_ids_count_;
167   scoped_refptr<PrefStore> pref_store_;
168   scoped_ptr<PrefHashStoreImpl> pref_hash_store_impl_;
169
170   DISALLOW_COPY_AND_ASSIGN(InitializeHashStoreObserver);
171 };
172
173 InitializeHashStoreObserver::~InitializeHashStoreObserver() {}
174
175 void InitializeHashStoreObserver::OnPrefValueChanged(const std::string& key) {}
176
177 void InitializeHashStoreObserver::OnInitializationCompleted(bool succeeded) {
178   // If we successfully loaded the preferences _and_ the PrefHashStoreImpl
179   // hasn't been initialized by someone else in the meantime, initialize it now.
180   const PrefHashStoreImpl::StoreVersion pre_update_version =
181       pref_hash_store_impl_->GetCurrentVersion();
182   if (succeeded && pre_update_version < PrefHashStoreImpl::VERSION_LATEST) {
183     PrefHashFilter(pref_hash_store_impl_.PassAs<PrefHashStore>(),
184                    tracking_configuration_,
185                    reporting_ids_count_).Initialize(*pref_store_);
186     UMA_HISTOGRAM_ENUMERATION(
187         "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
188         pre_update_version,
189         PrefHashStoreImpl::VERSION_LATEST + 1);
190   }
191   pref_store_->RemoveObserver(this);
192   delete this;
193 }
194
195 }  // namespace
196
197 // TODO(erikwright): Enable this on Chrome OS and Android once MACs are moved
198 // out of Local State. This will resolve a race condition on Android and a
199 // privacy issue on ChromeOS. http://crbug.com/349158
200 const bool ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking =
201 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
202     false;
203 #else
204     true;
205 #endif
206
207 ProfilePrefStoreManager::ProfilePrefStoreManager(
208     const base::FilePath& profile_path,
209     const std::vector<PrefHashFilter::TrackedPreferenceMetadata>&
210         tracking_configuration,
211     size_t reporting_ids_count,
212     const std::string& seed,
213     const std::string& device_id,
214     PrefService* local_state)
215     : profile_path_(profile_path),
216       tracking_configuration_(tracking_configuration),
217       reporting_ids_count_(reporting_ids_count),
218       seed_(seed),
219       device_id_(device_id),
220       local_state_(local_state) {}
221
222 ProfilePrefStoreManager::~ProfilePrefStoreManager() {}
223
224 // static
225 void ProfilePrefStoreManager::RegisterPrefs(PrefRegistrySimple* registry) {
226   PrefServiceHashStoreContents::RegisterPrefs(registry);
227 }
228
229 // static
230 void ProfilePrefStoreManager::RegisterProfilePrefs(
231     user_prefs::PrefRegistrySyncable* registry) {
232   PrefHashFilter::RegisterProfilePrefs(registry);
233 }
234
235 // static
236 base::FilePath ProfilePrefStoreManager::GetPrefFilePathFromProfilePath(
237     const base::FilePath& profile_path) {
238   return profile_path.Append(chrome::kPreferencesFilename);
239 }
240
241 // static
242 void ProfilePrefStoreManager::ResetAllPrefHashStores(PrefService* local_state) {
243   PrefServiceHashStoreContents::ResetAllPrefHashStores(local_state);
244 }
245
246 //  static
247 base::Time ProfilePrefStoreManager::GetResetTime(PrefService* pref_service) {
248   return PrefHashFilter::GetResetTime(pref_service);
249 }
250
251 // static
252 void ProfilePrefStoreManager::ClearResetTime(PrefService* pref_service) {
253   PrefHashFilter::ClearResetTime(pref_service);
254 }
255
256 void ProfilePrefStoreManager::ResetPrefHashStore() {
257   if (kPlatformSupportsPreferenceTracking)
258     GetPrefHashStoreImpl()->Reset();
259 }
260
261 PersistentPrefStore* ProfilePrefStoreManager::CreateProfilePrefStore(
262     const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) {
263   scoped_ptr<PrefFilter> pref_filter;
264   if (!kPlatformSupportsPreferenceTracking) {
265     return new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_),
266                              io_task_runner,
267                              scoped_ptr<PrefFilter>());
268   }
269
270   std::vector<PrefHashFilter::TrackedPreferenceMetadata>
271       unprotected_configuration;
272   std::vector<PrefHashFilter::TrackedPreferenceMetadata>
273       protected_configuration;
274   std::set<std::string> protected_pref_names;
275   std::set<std::string> unprotected_pref_names;
276   for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::const_iterator
277            it = tracking_configuration_.begin();
278        it != tracking_configuration_.end();
279        ++it) {
280     if (it->enforcement_level > PrefHashFilter::NO_ENFORCEMENT) {
281       protected_configuration.push_back(*it);
282       protected_pref_names.insert(it->name);
283     } else {
284       unprotected_configuration.push_back(*it);
285       unprotected_pref_names.insert(it->name);
286     }
287   }
288
289   scoped_ptr<PrefHashFilter> unprotected_pref_hash_filter(
290       new PrefHashFilter(GetPrefHashStoreImpl().PassAs<PrefHashStore>(),
291                          unprotected_configuration,
292                          reporting_ids_count_));
293   scoped_ptr<PrefHashFilter> protected_pref_hash_filter(
294       new PrefHashFilter(GetPrefHashStoreImpl().PassAs<PrefHashStore>(),
295                          protected_configuration,
296                          reporting_ids_count_));
297
298   PrefHashFilter* raw_unprotected_pref_hash_filter =
299       unprotected_pref_hash_filter.get();
300   PrefHashFilter* raw_protected_pref_hash_filter =
301       protected_pref_hash_filter.get();
302
303   scoped_refptr<JsonPrefStore> unprotected_pref_store(
304       new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_),
305                         io_task_runner,
306                         unprotected_pref_hash_filter.PassAs<PrefFilter>()));
307   scoped_refptr<JsonPrefStore> protected_pref_store(new JsonPrefStore(
308       profile_path_.Append(chrome::kProtectedPreferencesFilename),
309       io_task_runner,
310       protected_pref_hash_filter.PassAs<PrefFilter>()));
311
312   SetupTrackedPreferencesMigration(
313       unprotected_pref_names,
314       protected_pref_names,
315       base::Bind(&JsonPrefStore::RemoveValueSilently,
316                  unprotected_pref_store->AsWeakPtr()),
317       base::Bind(&JsonPrefStore::RemoveValueSilently,
318                  protected_pref_store->AsWeakPtr()),
319       base::Bind(&JsonPrefStore::RegisterOnNextSuccessfulWriteCallback,
320                  unprotected_pref_store->AsWeakPtr()),
321       base::Bind(&JsonPrefStore::RegisterOnNextSuccessfulWriteCallback,
322                  protected_pref_store->AsWeakPtr()),
323       raw_unprotected_pref_hash_filter,
324       raw_protected_pref_hash_filter);
325
326   return new SegregatedPrefStore(unprotected_pref_store, protected_pref_store,
327                                  protected_pref_names);
328 }
329
330 void ProfilePrefStoreManager::UpdateProfileHashStoreIfRequired(
331     const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) {
332   if (!kPlatformSupportsPreferenceTracking)
333     return;
334   scoped_ptr<PrefHashStoreImpl> pref_hash_store_impl(GetPrefHashStoreImpl());
335   const PrefHashStoreImpl::StoreVersion current_version =
336       pref_hash_store_impl->GetCurrentVersion();
337   UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferencesAlternateStoreVersion",
338                             current_version,
339                             PrefHashStoreImpl::VERSION_LATEST + 1);
340
341   // Update the pref hash store if it's not at the latest version.
342   if (current_version != PrefHashStoreImpl::VERSION_LATEST) {
343     scoped_refptr<JsonPrefStore> pref_store =
344         new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_),
345                           io_task_runner,
346                           scoped_ptr<PrefFilter>());
347     pref_store->AddObserver(
348         new InitializeHashStoreObserver(tracking_configuration_,
349                                         reporting_ids_count_,
350                                         pref_store,
351                                         pref_hash_store_impl.Pass()));
352     pref_store->ReadPrefsAsync(NULL);
353   }
354 }
355
356 bool ProfilePrefStoreManager::InitializePrefsFromMasterPrefs(
357     const base::DictionaryValue& master_prefs) {
358   // Create the profile directory if it doesn't exist yet (very possible on
359   // first run).
360   if (!base::CreateDirectory(profile_path_))
361     return false;
362
363   // This will write out to a single combined file which will be immediately
364   // migrated to two files on load.
365   JSONFileValueSerializer serializer(
366       GetPrefFilePathFromProfilePath(profile_path_));
367
368   // Call Serialize (which does IO) on the main thread, which would _normally_
369   // be verboten. In this case however, we require this IO to synchronously
370   // complete before Chrome can start (as master preferences seed the Local
371   // State and Preferences files). This won't trip ThreadIORestrictions as they
372   // won't have kicked in yet on the main thread.
373   bool success = serializer.Serialize(master_prefs);
374
375   if (success && kPlatformSupportsPreferenceTracking) {
376     scoped_refptr<const PrefStore> pref_store(
377         new DictionaryPrefStore(&master_prefs));
378     PrefHashFilter(GetPrefHashStoreImpl().PassAs<PrefHashStore>(),
379                    tracking_configuration_,
380                    reporting_ids_count_).Initialize(*pref_store);
381   }
382
383   UMA_HISTOGRAM_BOOLEAN("Settings.InitializedFromMasterPrefs", success);
384   return success;
385 }
386
387 PersistentPrefStore*
388 ProfilePrefStoreManager::CreateDeprecatedCombinedProfilePrefStore(
389     const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) {
390   scoped_ptr<PrefFilter> pref_filter;
391   if (kPlatformSupportsPreferenceTracking) {
392     pref_filter.reset(
393         new PrefHashFilter(GetPrefHashStoreImpl().PassAs<PrefHashStore>(),
394                            tracking_configuration_,
395                            reporting_ids_count_));
396   }
397   return new JsonPrefStore(GetPrefFilePathFromProfilePath(profile_path_),
398                            io_task_runner,
399                            pref_filter.Pass());
400 }
401
402 scoped_ptr<PrefHashStoreImpl> ProfilePrefStoreManager::GetPrefHashStoreImpl() {
403   DCHECK(kPlatformSupportsPreferenceTracking);
404
405   return make_scoped_ptr(new PrefHashStoreImpl(
406       seed_,
407       device_id_,
408       scoped_ptr<HashStoreContents>(new PrefServiceHashStoreContents(
409           profile_path_.AsUTF8Unsafe(), local_state_))));
410 }