1 // Copyright (c) 2012 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 "base/prefs/pref_value_store.h" 6 7 #include "base/logging.h" 8 #include "base/prefs/pref_notifier.h" 9 #include "base/prefs/pref_observer.h" 10 11 PrefValueStore::PrefStoreKeeper::PrefStoreKeeper() 12 : pref_value_store_(NULL), 13 type_(PrefValueStore::INVALID_STORE) { 14 } 15 16 PrefValueStore::PrefStoreKeeper::~PrefStoreKeeper() { 17 if (pref_store_.get()) { 18 pref_store_->RemoveObserver(this); 19 pref_store_ = NULL; 20 } 21 pref_value_store_ = NULL; 22 } 23 24 void PrefValueStore::PrefStoreKeeper::Initialize( 25 PrefValueStore* store, 26 PrefStore* pref_store, 27 PrefValueStore::PrefStoreType type) { 28 if (pref_store_.get()) { 29 pref_store_->RemoveObserver(this); 30 DCHECK_EQ(0U, pref_store_->NumberOfObservers()); 31 } 32 type_ = type; 33 pref_value_store_ = store; 34 pref_store_ = pref_store; 35 if (pref_store_.get()) 36 pref_store_->AddObserver(this); 37 } 38 39 void PrefValueStore::PrefStoreKeeper::OnPrefValueChanged( 40 const std::string& key) { 41 pref_value_store_->OnPrefValueChanged(type_, key); 42 } 43 44 void PrefValueStore::PrefStoreKeeper::OnInitializationCompleted( 45 bool succeeded) { 46 pref_value_store_->OnInitializationCompleted(type_, succeeded); 47 } 48 49 PrefValueStore::PrefValueStore(PrefStore* managed_prefs, 50 PrefStore* extension_prefs, 51 PrefStore* command_line_prefs, 52 PrefStore* user_prefs, 53 PrefStore* recommended_prefs, 54 PrefStore* default_prefs, 55 PrefNotifier* pref_notifier) 56 : pref_notifier_(pref_notifier), 57 initialization_failed_(false) { 58 InitPrefStore(MANAGED_STORE, managed_prefs); 59 InitPrefStore(EXTENSION_STORE, extension_prefs); 60 InitPrefStore(COMMAND_LINE_STORE, command_line_prefs); 61 InitPrefStore(USER_STORE, user_prefs); 62 InitPrefStore(RECOMMENDED_STORE, recommended_prefs); 63 InitPrefStore(DEFAULT_STORE, default_prefs); 64 65 CheckInitializationCompleted(); 66 } 67 68 PrefValueStore::~PrefValueStore() {} 69 70 PrefValueStore* PrefValueStore::CloneAndSpecialize( 71 PrefStore* managed_prefs, 72 PrefStore* extension_prefs, 73 PrefStore* command_line_prefs, 74 PrefStore* user_prefs, 75 PrefStore* recommended_prefs, 76 PrefStore* default_prefs, 77 PrefNotifier* pref_notifier) { 78 DCHECK(pref_notifier); 79 if (!managed_prefs) 80 managed_prefs = GetPrefStore(MANAGED_STORE); 81 if (!extension_prefs) 82 extension_prefs = GetPrefStore(EXTENSION_STORE); 83 if (!command_line_prefs) 84 command_line_prefs = GetPrefStore(COMMAND_LINE_STORE); 85 if (!user_prefs) 86 user_prefs = GetPrefStore(USER_STORE); 87 if (!recommended_prefs) 88 recommended_prefs = GetPrefStore(RECOMMENDED_STORE); 89 if (!default_prefs) 90 default_prefs = GetPrefStore(DEFAULT_STORE); 91 92 return new PrefValueStore( 93 managed_prefs, extension_prefs, command_line_prefs, user_prefs, 94 recommended_prefs, default_prefs, pref_notifier); 95 } 96 97 void PrefValueStore::set_callback(const PrefChangedCallback& callback) { 98 pref_changed_callback_ = callback; 99 } 100 101 bool PrefValueStore::GetValue(const std::string& name, 102 base::Value::Type type, 103 const base::Value** out_value) const { 104 // Check the |PrefStore|s in order of their priority from highest to lowest, 105 // looking for the first preference value with the given |name| and |type|. 106 for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { 107 if (GetValueFromStoreWithType(name.c_str(), type, 108 static_cast<PrefStoreType>(i), out_value)) 109 return true; 110 } 111 return false; 112 } 113 114 bool PrefValueStore::GetRecommendedValue(const std::string& name, 115 base::Value::Type type, 116 const base::Value** out_value) const { 117 return GetValueFromStoreWithType(name.c_str(), type, RECOMMENDED_STORE, 118 out_value); 119 } 120 121 void PrefValueStore::NotifyPrefChanged( 122 const char* path, 123 PrefValueStore::PrefStoreType new_store) { 124 DCHECK(new_store != INVALID_STORE); 125 // A notification is sent when the pref value in any store changes. If this 126 // store is currently being overridden by a higher-priority store, the 127 // effective value of the pref will not have changed. 128 pref_notifier_->OnPreferenceChanged(path); 129 if (!pref_changed_callback_.is_null()) 130 pref_changed_callback_.Run(path); 131 } 132 133 bool PrefValueStore::PrefValueInManagedStore(const char* name) const { 134 return PrefValueInStore(name, MANAGED_STORE); 135 } 136 137 bool PrefValueStore::PrefValueInExtensionStore(const char* name) const { 138 return PrefValueInStore(name, EXTENSION_STORE); 139 } 140 141 bool PrefValueStore::PrefValueInUserStore(const char* name) const { 142 return PrefValueInStore(name, USER_STORE); 143 } 144 145 bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const { 146 return ControllingPrefStoreForPref(name) == EXTENSION_STORE; 147 } 148 149 bool PrefValueStore::PrefValueFromUserStore(const char* name) const { 150 return ControllingPrefStoreForPref(name) == USER_STORE; 151 } 152 153 bool PrefValueStore::PrefValueFromRecommendedStore(const char* name) const { 154 return ControllingPrefStoreForPref(name) == RECOMMENDED_STORE; 155 } 156 157 bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const { 158 return ControllingPrefStoreForPref(name) == DEFAULT_STORE; 159 } 160 161 bool PrefValueStore::PrefValueUserModifiable(const char* name) const { 162 PrefStoreType effective_store = ControllingPrefStoreForPref(name); 163 return effective_store >= USER_STORE || 164 effective_store == INVALID_STORE; 165 } 166 167 bool PrefValueStore::PrefValueExtensionModifiable(const char* name) const { 168 PrefStoreType effective_store = ControllingPrefStoreForPref(name); 169 return effective_store >= EXTENSION_STORE || 170 effective_store == INVALID_STORE; 171 } 172 173 void PrefValueStore::UpdateCommandLinePrefStore(PrefStore* command_line_prefs) { 174 InitPrefStore(COMMAND_LINE_STORE, command_line_prefs); 175 } 176 177 bool PrefValueStore::PrefValueInStore( 178 const char* name, 179 PrefValueStore::PrefStoreType store) const { 180 // Declare a temp Value* and call GetValueFromStore, 181 // ignoring the output value. 182 const base::Value* tmp_value = NULL; 183 return GetValueFromStore(name, store, &tmp_value); 184 } 185 186 bool PrefValueStore::PrefValueInStoreRange( 187 const char* name, 188 PrefValueStore::PrefStoreType first_checked_store, 189 PrefValueStore::PrefStoreType last_checked_store) const { 190 if (first_checked_store > last_checked_store) { 191 NOTREACHED(); 192 return false; 193 } 194 195 for (size_t i = first_checked_store; 196 i <= static_cast<size_t>(last_checked_store); ++i) { 197 if (PrefValueInStore(name, static_cast<PrefStoreType>(i))) 198 return true; 199 } 200 return false; 201 } 202 203 PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref( 204 const char* name) const { 205 for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { 206 if (PrefValueInStore(name, static_cast<PrefStoreType>(i))) 207 return static_cast<PrefStoreType>(i); 208 } 209 return INVALID_STORE; 210 } 211 212 bool PrefValueStore::GetValueFromStore(const char* name, 213 PrefValueStore::PrefStoreType store_type, 214 const base::Value** out_value) const { 215 // Only return true if we find a value and it is the correct type, so stale 216 // values with the incorrect type will be ignored. 217 const PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(store_type)); 218 if (store && store->GetValue(name, out_value)) 219 return true; 220 221 // No valid value found for the given preference name: set the return value 222 // to false. 223 *out_value = NULL; 224 return false; 225 } 226 227 bool PrefValueStore::GetValueFromStoreWithType( 228 const char* name, 229 base::Value::Type type, 230 PrefStoreType store, 231 const base::Value** out_value) const { 232 if (GetValueFromStore(name, store, out_value)) { 233 if ((*out_value)->IsType(type)) 234 return true; 235 236 LOG(WARNING) << "Expected type for " << name << " is " << type 237 << " but got " << (*out_value)->GetType() 238 << " in store " << store; 239 } 240 241 *out_value = NULL; 242 return false; 243 } 244 245 void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type, 246 const std::string& key) { 247 NotifyPrefChanged(key.c_str(), type); 248 } 249 250 void PrefValueStore::OnInitializationCompleted( 251 PrefValueStore::PrefStoreType type, bool succeeded) { 252 if (initialization_failed_) 253 return; 254 if (!succeeded) { 255 initialization_failed_ = true; 256 pref_notifier_->OnInitializationCompleted(false); 257 return; 258 } 259 CheckInitializationCompleted(); 260 } 261 262 void PrefValueStore::InitPrefStore(PrefValueStore::PrefStoreType type, 263 PrefStore* pref_store) { 264 pref_stores_[type].Initialize(this, pref_store, type); 265 } 266 267 void PrefValueStore::CheckInitializationCompleted() { 268 if (initialization_failed_) 269 return; 270 for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { 271 scoped_refptr<PrefStore> store = 272 GetPrefStore(static_cast<PrefStoreType>(i)); 273 if (store.get() && !store->IsInitializationComplete()) 274 return; 275 } 276 pref_notifier_->OnInitializationCompleted(true); 277 } 278