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(¤t_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