pref_value_store.cc revision 62178e3990b32e9c89bb7d6f06605044b31adba2
1// Copyright (c) 2010 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/pref_value_store.h"
6
7#ifndef ANDROID
8#include "chrome/browser/browser_thread.h"
9#include "chrome/browser/extensions/extension_pref_store.h"
10#include "chrome/browser/policy/configuration_policy_pref_store.h"
11#include "chrome/browser/prefs/command_line_pref_store.h"
12#endif
13#include "chrome/browser/prefs/default_pref_store.h"
14#ifndef ANDROID
15#include "chrome/common/json_pref_store.h"
16#include "chrome/common/notification_service.h"
17#endif
18
19namespace {
20
21// Returns true if the actual value is a valid type for the expected type when
22// found in the given store.
23bool IsValidType(Value::ValueType expected, Value::ValueType actual,
24                 PrefNotifier::PrefStoreType store) {
25  if (expected == actual)
26    return true;
27
28  // Dictionaries and lists are allowed to hold TYPE_NULL values too, but only
29  // in the default pref store.
30  if (store == PrefNotifier::DEFAULT_STORE &&
31      actual == Value::TYPE_NULL &&
32      (expected == Value::TYPE_DICTIONARY || expected == Value::TYPE_LIST)) {
33    return true;
34  }
35  return false;
36}
37
38}  // namespace
39
40// static
41PrefValueStore* PrefValueStore::CreatePrefValueStore(
42    const FilePath& pref_filename,
43    Profile* profile,
44    bool user_only) {
45#ifdef ANDROID
46  return new PrefValueStore(NULL, NULL, NULL, NULL, NULL, NULL, new DefaultPrefStore());
47#else
48  using policy::ConfigurationPolicyPrefStore;
49  ConfigurationPolicyPrefStore* managed = NULL;
50  ConfigurationPolicyPrefStore* device_management = NULL;
51  ExtensionPrefStore* extension = NULL;
52  CommandLinePrefStore* command_line = NULL;
53  ConfigurationPolicyPrefStore* recommended = NULL;
54
55  JsonPrefStore* user = new JsonPrefStore(
56      pref_filename,
57      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
58  DefaultPrefStore* default_store = new DefaultPrefStore();
59
60  if (!user_only) {
61    managed =
62        ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore();
63    device_management =
64        ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore();
65    extension = new ExtensionPrefStore(profile, PrefNotifier::EXTENSION_STORE);
66    command_line = new CommandLinePrefStore(CommandLine::ForCurrentProcess());
67    recommended =
68        ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore();
69  }
70
71  return new PrefValueStore(managed, device_management, extension,
72                            command_line, user, recommended, default_store);
73#endif
74}
75
76PrefValueStore::~PrefValueStore() {}
77
78bool PrefValueStore::GetValue(const std::string& name,
79                              Value** out_value) const {
80  // Check the |PrefStore|s in order of their priority from highest to lowest
81  // to find the value of the preference described by the given preference name.
82  for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
83    if (GetValueFromStore(name.c_str(),
84                          static_cast<PrefNotifier::PrefStoreType>(i),
85                          out_value))
86      return true;
87  }
88  return false;
89}
90
91bool PrefValueStore::GetUserValue(const std::string& name,
92                                  Value** out_value) const {
93  return GetValueFromStore(name.c_str(), PrefNotifier::USER_STORE, out_value);
94}
95
96void PrefValueStore::RegisterPreferenceType(const std::string& name,
97                                            Value::ValueType type) {
98  pref_types_[name] = type;
99}
100
101Value::ValueType PrefValueStore::GetRegisteredType(
102    const std::string& name) const {
103  PrefTypeMap::const_iterator found = pref_types_.find(name);
104  if (found == pref_types_.end())
105    return Value::TYPE_NULL;
106  return found->second;
107}
108
109bool PrefValueStore::WritePrefs() {
110  bool success = true;
111  for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
112    if (pref_stores_[i].get())
113      success = pref_stores_[i]->WritePrefs() && success;
114  }
115  return success;
116}
117
118void PrefValueStore::ScheduleWritePrefs() {
119  for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
120    if (pref_stores_[i].get())
121      pref_stores_[i]->ScheduleWritePrefs();
122  }
123}
124
125PrefStore::PrefReadError PrefValueStore::ReadPrefs() {
126  PrefStore::PrefReadError result = PrefStore::PREF_READ_ERROR_NONE;
127  for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
128    if (pref_stores_[i].get()) {
129      PrefStore::PrefReadError this_error = pref_stores_[i]->ReadPrefs();
130      if (result == PrefStore::PREF_READ_ERROR_NONE)
131        result = this_error;
132    }
133  }
134
135  if (HasPolicyConflictingUserProxySettings()) {
136    LOG(WARNING) << "user-requested proxy options have been overridden"
137                 << " by a proxy configuration specified in a centrally"
138                 << " administered policy.";
139  }
140
141  // TODO(markusheintz): Return a better error status: maybe a struct with
142  // the error status of all PrefStores.
143  return result;
144}
145
146bool PrefValueStore::HasPrefPath(const char* path) const {
147  Value* tmp_value = NULL;
148  const std::string name(path);
149  bool rv = GetValue(name, &tmp_value);
150  // Merely registering a pref doesn't count as "having" it: we require a
151  // non-default value set.
152  return rv && !PrefValueFromDefaultStore(path);
153}
154
155bool PrefValueStore::PrefHasChanged(const char* path,
156                                    PrefNotifier::PrefStoreType new_store) {
157  DCHECK(new_store != PrefNotifier::INVALID_STORE);
158  // Replying that the pref has changed may cause problems, but it's the safer
159  // choice.
160  if (new_store == PrefNotifier::INVALID_STORE)
161    return true;
162
163  PrefNotifier::PrefStoreType controller = ControllingPrefStoreForPref(path);
164  DCHECK(controller != PrefNotifier::INVALID_STORE);
165  if (controller == PrefNotifier::INVALID_STORE)
166    return true;
167
168  // If the pref is controlled by a higher-priority store, its effective value
169  // cannot have changed.
170  if (controller < new_store)
171    return false;
172
173  // Otherwise, we take the pref store's word that something changed.
174  return true;
175}
176
177// Note the |DictionaryValue| referenced by the |PrefStore| USER_STORE
178// (returned by the method prefs()) takes the ownership of the Value referenced
179// by in_value.
180bool PrefValueStore::SetUserPrefValue(const char* name, Value* in_value) {
181  Value* old_value = NULL;
182  pref_stores_[PrefNotifier::USER_STORE]->prefs()->Get(name, &old_value);
183  bool value_changed = !(old_value && old_value->Equals(in_value));
184
185  pref_stores_[PrefNotifier::USER_STORE]->prefs()->Set(name, in_value);
186  return value_changed;
187}
188
189// Note the |DictionaryValue| referenced by the |PrefStore| DEFAULT_STORE
190// (returned by the method prefs()) takes the ownership of the Value referenced
191// by in_value.
192void PrefValueStore::SetDefaultPrefValue(const char* name, Value* in_value) {
193  pref_stores_[PrefNotifier::DEFAULT_STORE]->prefs()->Set(name, in_value);
194}
195
196bool PrefValueStore::ReadOnly() {
197  return pref_stores_[PrefNotifier::USER_STORE]->ReadOnly();
198}
199
200bool PrefValueStore::RemoveUserPrefValue(const char* name) {
201  if (pref_stores_[PrefNotifier::USER_STORE].get()) {
202    return pref_stores_[PrefNotifier::USER_STORE]->prefs()->Remove(name, NULL);
203  }
204  return false;
205}
206
207bool PrefValueStore::PrefValueInManagedPlatformStore(const char* name) const {
208  return PrefValueInStore(name, PrefNotifier::MANAGED_PLATFORM_STORE);
209}
210
211bool PrefValueStore::PrefValueInDeviceManagementStore(const char* name) const {
212  return PrefValueInStore(name, PrefNotifier::DEVICE_MANAGEMENT_STORE);
213}
214
215bool PrefValueStore::PrefValueInExtensionStore(const char* name) const {
216  return PrefValueInStore(name, PrefNotifier::EXTENSION_STORE);
217}
218
219bool PrefValueStore::PrefValueInUserStore(const char* name) const {
220  return PrefValueInStore(name, PrefNotifier::USER_STORE);
221}
222
223bool PrefValueStore::PrefValueInStoreRange(
224    const char* name,
225    PrefNotifier::PrefStoreType first_checked_store,
226    PrefNotifier::PrefStoreType last_checked_store) {
227  if (first_checked_store > last_checked_store) {
228    NOTREACHED();
229    return false;
230  }
231
232  for (size_t i = first_checked_store;
233       i <= static_cast<size_t>(last_checked_store); ++i) {
234    if (PrefValueInStore(name, static_cast<PrefNotifier::PrefStoreType>(i)))
235      return true;
236  }
237  return false;
238}
239
240bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const {
241  return ControllingPrefStoreForPref(name) == PrefNotifier::EXTENSION_STORE;
242}
243
244bool PrefValueStore::PrefValueFromUserStore(const char* name) const {
245  return ControllingPrefStoreForPref(name) == PrefNotifier::USER_STORE;
246}
247
248bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const {
249  return ControllingPrefStoreForPref(name) == PrefNotifier::DEFAULT_STORE;
250}
251
252bool PrefValueStore::PrefValueUserModifiable(const char* name) const {
253  PrefNotifier::PrefStoreType effective_store =
254      ControllingPrefStoreForPref(name);
255  return effective_store >= PrefNotifier::USER_STORE ||
256         effective_store == PrefNotifier::INVALID_STORE;
257}
258
259PrefNotifier::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
260    const char* name) const {
261  for (int i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
262    if (PrefValueInStore(name, static_cast<PrefNotifier::PrefStoreType>(i)))
263      return static_cast<PrefNotifier::PrefStoreType>(i);
264  }
265  return PrefNotifier::INVALID_STORE;
266}
267
268bool PrefValueStore::PrefValueInStore(
269    const char* name,
270    PrefNotifier::PrefStoreType store) const {
271  // Declare a temp Value* and call GetValueFromStore,
272  // ignoring the output value.
273  Value* tmp_value = NULL;
274  return GetValueFromStore(name, store, &tmp_value);
275}
276
277bool PrefValueStore::GetValueFromStore(
278    const char* name,
279    PrefNotifier::PrefStoreType store,
280    Value** out_value) const {
281  // Only return true if we find a value and it is the correct type, so stale
282  // values with the incorrect type will be ignored.
283  if (pref_stores_[store].get() &&
284      pref_stores_[store]->prefs()->Get(name, out_value)) {
285    // If the value is the sentinel that redirects to the default
286    // store, re-fetch the value from the default store explicitly.
287    // Because the default values are not available when creating
288    // stores, the default value must be fetched dynamically for every
289    // redirect.
290    if (PrefStore::IsUseDefaultSentinelValue(*out_value)) {
291      DCHECK(pref_stores_[PrefNotifier::DEFAULT_STORE].get());
292      if (!pref_stores_[PrefNotifier::DEFAULT_STORE]->prefs()->Get(name,
293                                                                   out_value)) {
294        *out_value = NULL;
295        return false;
296      }
297      store = PrefNotifier::DEFAULT_STORE;
298    }
299    if (IsValidType(GetRegisteredType(name), (*out_value)->GetType(), store))
300      return true;
301  }
302  // No valid value found for the given preference name: set the return false.
303  *out_value = NULL;
304  return false;
305}
306
307#ifndef ANDROID
308void PrefValueStore::RefreshPolicyPrefsOnFileThread(
309    BrowserThread::ID calling_thread_id,
310    PrefStore* new_managed_platform_pref_store,
311    PrefStore* new_device_management_pref_store,
312    PrefStore* new_recommended_pref_store,
313    AfterRefreshCallback* callback_pointer) {
314  scoped_ptr<AfterRefreshCallback> callback(callback_pointer);
315  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
316  scoped_ptr<PrefStore> managed_platform_pref_store(
317      new_managed_platform_pref_store);
318  scoped_ptr<PrefStore> device_management_pref_store(
319      new_device_management_pref_store);
320  scoped_ptr<PrefStore> recommended_pref_store(new_recommended_pref_store);
321
322  PrefStore::PrefReadError read_error =
323      new_managed_platform_pref_store->ReadPrefs();
324  if (read_error != PrefStore::PREF_READ_ERROR_NONE) {
325    LOG(ERROR) << "refresh of managed policy failed: PrefReadError = "
326               << read_error;
327    return;
328  }
329
330  read_error = new_device_management_pref_store->ReadPrefs();
331  if (read_error != PrefStore::PREF_READ_ERROR_NONE) {
332    LOG(ERROR) << "refresh of device management policy failed: "
333               << "PrefReadError = " << read_error;
334    return;
335  }
336
337  read_error = new_recommended_pref_store->ReadPrefs();
338  if (read_error != PrefStore::PREF_READ_ERROR_NONE) {
339    LOG(ERROR) << "refresh of recommended policy failed: PrefReadError = "
340               << read_error;
341    return;
342  }
343
344  BrowserThread::PostTask(
345      calling_thread_id, FROM_HERE,
346      NewRunnableMethod(this,
347                        &PrefValueStore::RefreshPolicyPrefsCompletion,
348                        managed_platform_pref_store.release(),
349                        device_management_pref_store.release(),
350                        recommended_pref_store.release(),
351                        callback.release()));
352}
353
354void PrefValueStore::RefreshPolicyPrefsCompletion(
355    PrefStore* new_managed_platform_pref_store,
356    PrefStore* new_device_management_pref_store,
357    PrefStore* new_recommended_pref_store,
358    AfterRefreshCallback* callback_pointer) {
359  scoped_ptr<AfterRefreshCallback> callback(callback_pointer);
360
361  // Determine the paths of all the changed preferences values in the three
362  // policy-related stores (managed platform, device management and
363  // recommended).
364  DictionaryValue* managed_platform_prefs_before(
365      pref_stores_[PrefNotifier::MANAGED_PLATFORM_STORE]->prefs());
366  DictionaryValue* managed_platform_prefs_after(
367      new_managed_platform_pref_store->prefs());
368  DictionaryValue* device_management_prefs_before(
369      pref_stores_[PrefNotifier::DEVICE_MANAGEMENT_STORE]->prefs());
370  DictionaryValue* device_management_prefs_after(
371      new_device_management_pref_store->prefs());
372  DictionaryValue* recommended_prefs_before(
373      pref_stores_[PrefNotifier::RECOMMENDED_STORE]->prefs());
374  DictionaryValue* recommended_prefs_after(new_recommended_pref_store->prefs());
375
376  std::vector<std::string> changed_managed_platform_paths;
377  managed_platform_prefs_before->GetDifferingPaths(managed_platform_prefs_after,
378                                          &changed_managed_platform_paths);
379
380  std::vector<std::string> changed_device_management_paths;
381  device_management_prefs_before->GetDifferingPaths(
382      device_management_prefs_after,
383      &changed_device_management_paths);
384
385  std::vector<std::string> changed_recommended_paths;
386  recommended_prefs_before->GetDifferingPaths(recommended_prefs_after,
387                                              &changed_recommended_paths);
388
389  // Merge all three vectors of changed value paths together, filtering
390  // duplicates in a post-processing step.
391  std::vector<std::string> all_changed_managed_platform_paths(
392      changed_managed_platform_paths.size() +
393      changed_device_management_paths.size());
394
395  std::vector<std::string>::iterator last_insert =
396      std::merge(changed_managed_platform_paths.begin(),
397                 changed_managed_platform_paths.end(),
398                 changed_device_management_paths.begin(),
399                 changed_device_management_paths.end(),
400                 all_changed_managed_platform_paths.begin());
401  all_changed_managed_platform_paths.resize(
402      last_insert - all_changed_managed_platform_paths.begin());
403
404  std::vector<std::string> changed_paths(
405      all_changed_managed_platform_paths.size() +
406      changed_recommended_paths.size());
407  last_insert = std::merge(all_changed_managed_platform_paths.begin(),
408                           all_changed_managed_platform_paths.end(),
409                           changed_recommended_paths.begin(),
410                           changed_recommended_paths.end(),
411                           changed_paths.begin());
412  changed_paths.resize(last_insert - changed_paths.begin());
413
414  last_insert = unique(changed_paths.begin(), changed_paths.end());
415  changed_paths.resize(last_insert - changed_paths.begin());
416
417  // Replace the old stores with the new and send notification of the changed
418  // preferences.
419  pref_stores_[PrefNotifier::MANAGED_PLATFORM_STORE].reset(
420      new_managed_platform_pref_store);
421  pref_stores_[PrefNotifier::DEVICE_MANAGEMENT_STORE].reset(
422      new_device_management_pref_store);
423  pref_stores_[PrefNotifier::RECOMMENDED_STORE].reset(
424      new_recommended_pref_store);
425  callback->Run(changed_paths);
426}
427
428void PrefValueStore::RefreshPolicyPrefs(
429    AfterRefreshCallback* callback) {
430  using policy::ConfigurationPolicyPrefStore;
431  // Because loading of policy information must happen on the FILE
432  // thread, it's not possible to just replace the contents of the
433  // managed and recommended stores in place due to possible
434  // concurrent access from the UI thread. Instead, new stores are
435  // created and the refreshed policy read into them. The new stores
436  // are swapped with the old from a Task on the UI thread after the
437  // load is complete.
438  PrefStore* new_managed_platform_pref_store(
439      ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore());
440  PrefStore* new_device_management_pref_store(
441      ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore());
442  PrefStore* new_recommended_pref_store(
443      ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore());
444  BrowserThread::ID current_thread_id;
445  CHECK(BrowserThread::GetCurrentThreadIdentifier(&current_thread_id));
446  BrowserThread::PostTask(
447      BrowserThread::FILE, FROM_HERE,
448      NewRunnableMethod(this,
449                        &PrefValueStore::RefreshPolicyPrefsOnFileThread,
450                        current_thread_id,
451                        new_managed_platform_pref_store,
452                        new_device_management_pref_store,
453                        new_recommended_pref_store,
454                        callback));
455}
456#endif // ANDROID
457
458bool PrefValueStore::HasPolicyConflictingUserProxySettings() {
459#if !defined(ANDROID)
460  using policy::ConfigurationPolicyPrefStore;
461  ConfigurationPolicyPrefStore::ProxyPreferenceSet proxy_prefs;
462  ConfigurationPolicyPrefStore::GetProxyPreferenceSet(&proxy_prefs);
463  ConfigurationPolicyPrefStore::ProxyPreferenceSet::const_iterator i;
464  for (i = proxy_prefs.begin(); i != proxy_prefs.end(); ++i) {
465    if ((PrefValueInManagedPlatformStore(*i) ||
466         PrefValueInDeviceManagementStore(*i)) &&
467        PrefValueInStoreRange(*i,
468                              PrefNotifier::COMMAND_LINE_STORE,
469                              PrefNotifier::USER_STORE))
470      return true;
471  }
472#endif
473  return false;
474}
475
476PrefValueStore::PrefValueStore(PrefStore* managed_platform_prefs,
477                               PrefStore* device_management_prefs,
478                               PrefStore* extension_prefs,
479                               PrefStore* command_line_prefs,
480                               PrefStore* user_prefs,
481                               PrefStore* recommended_prefs,
482                               PrefStore* default_prefs) {
483  // NULL default pref store is usually bad, but may be OK for some unit tests.
484  if (!default_prefs)
485    LOG(WARNING) << "default pref store is null";
486  pref_stores_[PrefNotifier::MANAGED_PLATFORM_STORE].reset(
487      managed_platform_prefs);
488  pref_stores_[PrefNotifier::DEVICE_MANAGEMENT_STORE].reset(
489      device_management_prefs);
490  pref_stores_[PrefNotifier::EXTENSION_STORE].reset(extension_prefs);
491  pref_stores_[PrefNotifier::COMMAND_LINE_STORE].reset(command_line_prefs);
492  pref_stores_[PrefNotifier::USER_STORE].reset(user_prefs);
493  pref_stores_[PrefNotifier::RECOMMENDED_STORE].reset(recommended_prefs);
494  pref_stores_[PrefNotifier::DEFAULT_STORE].reset(default_prefs);
495}
496