pref_value_store.cc revision 82855d1006d8ec9d2190b6ca599820b0ab39e4fc
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, new DefaultPrefStore());
47#else
48  using policy::ConfigurationPolicyPrefStore;
49  ConfigurationPolicyPrefStore* managed = NULL;
50  ExtensionPrefStore* extension = NULL;
51  CommandLinePrefStore* command_line = NULL;
52  ConfigurationPolicyPrefStore* recommended = NULL;
53
54  JsonPrefStore* user = new JsonPrefStore(
55      pref_filename,
56      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
57  DefaultPrefStore* default_store = new DefaultPrefStore();
58
59  if (!user_only) {
60    managed = ConfigurationPolicyPrefStore::CreateManagedPolicyPrefStore();
61    extension = new ExtensionPrefStore(profile, PrefNotifier::EXTENSION_STORE);
62    command_line = new CommandLinePrefStore(CommandLine::ForCurrentProcess());
63    recommended =
64        ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore();
65  }
66  return new PrefValueStore(managed, extension, command_line, user,
67                            recommended, default_store);
68#endif
69}
70
71PrefValueStore::~PrefValueStore() {}
72
73bool PrefValueStore::GetValue(const std::string& name,
74                              Value** out_value) const {
75  // Check the |PrefStore|s in order of their priority from highest to lowest
76  // to find the value of the preference described by the given preference name.
77  for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
78    if (GetValueFromStore(name.c_str(),
79                          static_cast<PrefNotifier::PrefStoreType>(i),
80                          out_value))
81      return true;
82  }
83  return false;
84}
85
86bool PrefValueStore::GetUserValue(const std::string& name,
87                                  Value** out_value) const {
88  return GetValueFromStore(name.c_str(), PrefNotifier::USER_STORE, out_value);
89}
90
91void PrefValueStore::RegisterPreferenceType(const std::string& name,
92                                            Value::ValueType type) {
93  pref_types_[name] = type;
94}
95
96Value::ValueType PrefValueStore::GetRegisteredType(
97    const std::string& name) const {
98  PrefTypeMap::const_iterator found = pref_types_.find(name);
99  if (found == pref_types_.end())
100    return Value::TYPE_NULL;
101  return found->second;
102}
103
104bool PrefValueStore::WritePrefs() {
105  bool success = true;
106  for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
107    if (pref_stores_[i].get())
108      success = pref_stores_[i]->WritePrefs() && success;
109  }
110  return success;
111}
112
113void PrefValueStore::ScheduleWritePrefs() {
114  for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
115    if (pref_stores_[i].get())
116      pref_stores_[i]->ScheduleWritePrefs();
117  }
118}
119
120PrefStore::PrefReadError PrefValueStore::ReadPrefs() {
121  PrefStore::PrefReadError result = PrefStore::PREF_READ_ERROR_NONE;
122  for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
123    if (pref_stores_[i].get()) {
124      PrefStore::PrefReadError this_error = pref_stores_[i]->ReadPrefs();
125      if (result == PrefStore::PREF_READ_ERROR_NONE)
126        result = this_error;
127    }
128  }
129
130  if (HasPolicyConflictingUserProxySettings()) {
131    LOG(WARNING) << "user-requested proxy options have been overridden"
132                 << " by a proxy configuration specified in a centrally"
133                 << " administered policy.";
134  }
135
136  // TODO(markusheintz): Return a better error status: maybe a struct with
137  // the error status of all PrefStores.
138  return result;
139}
140
141bool PrefValueStore::HasPrefPath(const char* path) const {
142  Value* tmp_value = NULL;
143  const std::string name(path);
144  bool rv = GetValue(name, &tmp_value);
145  // Merely registering a pref doesn't count as "having" it: we require a
146  // non-default value set.
147  return rv && !PrefValueFromDefaultStore(path);
148}
149
150bool PrefValueStore::PrefHasChanged(const char* path,
151                                    PrefNotifier::PrefStoreType new_store) {
152  DCHECK(new_store != PrefNotifier::INVALID_STORE);
153  // Replying that the pref has changed may cause problems, but it's the safer
154  // choice.
155  if (new_store == PrefNotifier::INVALID_STORE)
156    return true;
157
158  PrefNotifier::PrefStoreType controller = ControllingPrefStoreForPref(path);
159  DCHECK(controller != PrefNotifier::INVALID_STORE);
160  if (controller == PrefNotifier::INVALID_STORE)
161    return true;
162
163  // If the pref is controlled by a higher-priority store, its effective value
164  // cannot have changed.
165  if (controller < new_store)
166    return false;
167
168  // Otherwise, we take the pref store's word that something changed.
169  return true;
170}
171
172// Note the |DictionaryValue| referenced by the |PrefStore| USER_STORE
173// (returned by the method prefs()) takes the ownership of the Value referenced
174// by in_value.
175bool PrefValueStore::SetUserPrefValue(const char* name, Value* in_value) {
176  Value* old_value = NULL;
177  pref_stores_[PrefNotifier::USER_STORE]->prefs()->Get(name, &old_value);
178  bool value_changed = !(old_value && old_value->Equals(in_value));
179
180  pref_stores_[PrefNotifier::USER_STORE]->prefs()->Set(name, in_value);
181  return value_changed;
182}
183
184// Note the |DictionaryValue| referenced by the |PrefStore| DEFAULT_STORE
185// (returned by the method prefs()) takes the ownership of the Value referenced
186// by in_value.
187void PrefValueStore::SetDefaultPrefValue(const char* name, Value* in_value) {
188  pref_stores_[PrefNotifier::DEFAULT_STORE]->prefs()->Set(name, in_value);
189}
190
191bool PrefValueStore::ReadOnly() {
192  return pref_stores_[PrefNotifier::USER_STORE]->ReadOnly();
193}
194
195bool PrefValueStore::RemoveUserPrefValue(const char* name) {
196  if (pref_stores_[PrefNotifier::USER_STORE].get()) {
197    return pref_stores_[PrefNotifier::USER_STORE]->prefs()->Remove(name, NULL);
198  }
199  return false;
200}
201
202bool PrefValueStore::PrefValueInManagedStore(const char* name) const {
203  return PrefValueInStore(name, PrefNotifier::MANAGED_STORE);
204}
205
206bool PrefValueStore::PrefValueInExtensionStore(const char* name) const {
207  return PrefValueInStore(name, PrefNotifier::EXTENSION_STORE);
208}
209
210bool PrefValueStore::PrefValueInUserStore(const char* name) const {
211  return PrefValueInStore(name, PrefNotifier::USER_STORE);
212}
213
214bool PrefValueStore::PrefValueInStoreRange(
215    const char* name,
216    PrefNotifier::PrefStoreType first_checked_store,
217    PrefNotifier::PrefStoreType last_checked_store) {
218  if (first_checked_store > last_checked_store) {
219    NOTREACHED();
220    return false;
221  }
222
223  for (size_t i = first_checked_store;
224       i <= static_cast<size_t>(last_checked_store); ++i) {
225    if (PrefValueInStore(name, static_cast<PrefNotifier::PrefStoreType>(i)))
226      return true;
227  }
228  return false;
229}
230
231bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const {
232  return ControllingPrefStoreForPref(name) == PrefNotifier::EXTENSION_STORE;
233}
234
235bool PrefValueStore::PrefValueFromUserStore(const char* name) const {
236  return ControllingPrefStoreForPref(name) == PrefNotifier::USER_STORE;
237}
238
239bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const {
240  return ControllingPrefStoreForPref(name) == PrefNotifier::DEFAULT_STORE;
241}
242
243bool PrefValueStore::PrefValueUserModifiable(const char* name) const {
244  PrefNotifier::PrefStoreType effective_store =
245      ControllingPrefStoreForPref(name);
246  return effective_store >= PrefNotifier::USER_STORE ||
247         effective_store == PrefNotifier::INVALID_STORE;
248}
249
250PrefNotifier::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
251    const char* name) const {
252  for (int i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
253    if (PrefValueInStore(name, static_cast<PrefNotifier::PrefStoreType>(i)))
254      return static_cast<PrefNotifier::PrefStoreType>(i);
255  }
256  return PrefNotifier::INVALID_STORE;
257}
258
259bool PrefValueStore::PrefValueInStore(
260    const char* name,
261    PrefNotifier::PrefStoreType store) const {
262  // Declare a temp Value* and call GetValueFromStore,
263  // ignoring the output value.
264  Value* tmp_value = NULL;
265  return GetValueFromStore(name, store, &tmp_value);
266}
267
268bool PrefValueStore::GetValueFromStore(
269    const char* name,
270    PrefNotifier::PrefStoreType store,
271    Value** out_value) const {
272  // Only return true if we find a value and it is the correct type, so stale
273  // values with the incorrect type will be ignored.
274  if (pref_stores_[store].get() &&
275      pref_stores_[store]->prefs()->Get(name, out_value)) {
276    // If the value is the sentinel that redirects to the default
277    // store, re-fetch the value from the default store explicitly.
278    // Because the default values are not available when creating
279    // stores, the default value must be fetched dynamically for every
280    // redirect.
281    if (PrefStore::IsUseDefaultSentinelValue(*out_value)) {
282      DCHECK(pref_stores_[PrefNotifier::DEFAULT_STORE].get());
283      if (!pref_stores_[PrefNotifier::DEFAULT_STORE]->prefs()->Get(name,
284                                                                   out_value)) {
285        *out_value = NULL;
286        return false;
287      }
288      store = PrefNotifier::DEFAULT_STORE;
289    }
290    if (IsValidType(GetRegisteredType(name), (*out_value)->GetType(), store))
291      return true;
292  }
293  // No valid value found for the given preference name: set the return false.
294  *out_value = NULL;
295  return false;
296}
297
298#ifndef ANDROID
299void PrefValueStore::RefreshPolicyPrefsCompletion(
300    PrefStore* new_managed_pref_store,
301    PrefStore* new_recommended_pref_store,
302    AfterRefreshCallback* callback_pointer) {
303  scoped_ptr<AfterRefreshCallback> callback(callback_pointer);
304  DictionaryValue* managed_prefs_before(
305      pref_stores_[PrefNotifier::MANAGED_STORE]->prefs());
306  DictionaryValue* managed_prefs_after(new_managed_pref_store->prefs());
307  DictionaryValue* recommended_prefs_before(
308      pref_stores_[PrefNotifier::RECOMMENDED_STORE]->prefs());
309  DictionaryValue* recommended_prefs_after(new_recommended_pref_store->prefs());
310
311  std::vector<std::string> changed_managed_paths;
312  managed_prefs_before->GetDifferingPaths(managed_prefs_after,
313                                          &changed_managed_paths);
314
315  std::vector<std::string> changed_recommended_paths;
316  recommended_prefs_before->GetDifferingPaths(recommended_prefs_after,
317                                              &changed_recommended_paths);
318
319  std::vector<std::string> changed_paths(changed_managed_paths.size() +
320                                         changed_recommended_paths.size());
321  std::vector<std::string>::iterator last_insert =
322      std::merge(changed_managed_paths.begin(),
323                 changed_managed_paths.end(),
324                 changed_recommended_paths.begin(),
325                 changed_recommended_paths.end(),
326                 changed_paths.begin());
327  changed_paths.resize(last_insert - changed_paths.begin());
328
329  pref_stores_[PrefNotifier::MANAGED_STORE].reset(new_managed_pref_store);
330  pref_stores_[PrefNotifier::RECOMMENDED_STORE].reset(
331      new_recommended_pref_store);
332  callback->Run(changed_paths);
333}
334
335void PrefValueStore::RefreshPolicyPrefsOnFileThread(
336    BrowserThread::ID calling_thread_id,
337    PrefStore* new_managed_pref_store,
338    PrefStore* new_recommended_pref_store,
339    AfterRefreshCallback* callback_pointer) {
340  scoped_ptr<AfterRefreshCallback> callback(callback_pointer);
341  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
342  scoped_ptr<PrefStore> managed_pref_store(new_managed_pref_store);
343  scoped_ptr<PrefStore> recommended_pref_store(new_recommended_pref_store);
344
345  PrefStore::PrefReadError read_error = new_managed_pref_store->ReadPrefs();
346  if (read_error != PrefStore::PREF_READ_ERROR_NONE) {
347    LOG(ERROR) << "refresh of managed policy failed: PrefReadError = "
348               << read_error;
349    return;
350  }
351
352  read_error = new_recommended_pref_store->ReadPrefs();
353  if (read_error != PrefStore::PREF_READ_ERROR_NONE) {
354    LOG(ERROR) << "refresh of recommended policy failed: PrefReadError = "
355               << read_error;
356    return;
357  }
358
359  BrowserThread::PostTask(
360      calling_thread_id, FROM_HERE,
361      NewRunnableMethod(this,
362                        &PrefValueStore::RefreshPolicyPrefsCompletion,
363                        managed_pref_store.release(),
364                        recommended_pref_store.release(),
365                        callback.release()));
366}
367
368void PrefValueStore::RefreshPolicyPrefs(
369    AfterRefreshCallback* callback) {
370  using policy::ConfigurationPolicyPrefStore;
371  // Because loading of policy information must happen on the FILE
372  // thread, it's not possible to just replace the contents of the
373  // managed and recommended stores in place due to possible
374  // concurrent access from the UI thread. Instead, new stores are
375  // created and the refreshed policy read into them. The new stores
376  // are swapped with the old from a Task on the UI thread after the
377  // load is complete.
378  PrefStore* new_managed_pref_store(
379      ConfigurationPolicyPrefStore::CreateManagedPolicyPrefStore());
380  PrefStore* new_recommended_pref_store(
381      ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore());
382  BrowserThread::ID current_thread_id;
383  CHECK(BrowserThread::GetCurrentThreadIdentifier(&current_thread_id));
384  BrowserThread::PostTask(
385      BrowserThread::FILE, FROM_HERE,
386      NewRunnableMethod(this,
387                        &PrefValueStore::RefreshPolicyPrefsOnFileThread,
388                        current_thread_id,
389                        new_managed_pref_store,
390                        new_recommended_pref_store,
391                        callback));
392}
393#endif // ANDROID
394
395bool PrefValueStore::HasPolicyConflictingUserProxySettings() {
396#if !defined(ANDROID)
397  using policy::ConfigurationPolicyPrefStore;
398  ConfigurationPolicyPrefStore::ProxyPreferenceSet proxy_prefs;
399  ConfigurationPolicyPrefStore::GetProxyPreferenceSet(&proxy_prefs);
400  ConfigurationPolicyPrefStore::ProxyPreferenceSet::const_iterator i;
401  for (i = proxy_prefs.begin(); i != proxy_prefs.end(); ++i) {
402    if (PrefValueInManagedStore(*i) &&
403        PrefValueInStoreRange(*i,
404                              PrefNotifier::COMMAND_LINE_STORE,
405                              PrefNotifier::USER_STORE))
406      return true;
407  }
408#endif
409  return false;
410}
411
412PrefValueStore::PrefValueStore(PrefStore* managed_prefs,
413                               PrefStore* extension_prefs,
414                               PrefStore* command_line_prefs,
415                               PrefStore* user_prefs,
416                               PrefStore* recommended_prefs,
417                               PrefStore* default_prefs) {
418  // NULL default pref store is usually bad, but may be OK for some unit tests.
419  if (!default_prefs)
420    LOG(WARNING) << "default pref store is null";
421  pref_stores_[PrefNotifier::MANAGED_STORE].reset(managed_prefs);
422  pref_stores_[PrefNotifier::EXTENSION_STORE].reset(extension_prefs);
423  pref_stores_[PrefNotifier::COMMAND_LINE_STORE].reset(command_line_prefs);
424  pref_stores_[PrefNotifier::USER_STORE].reset(user_prefs);
425  pref_stores_[PrefNotifier::RECOMMENDED_STORE].reset(recommended_prefs);
426  pref_stores_[PrefNotifier::DEFAULT_STORE].reset(default_prefs);
427}
428