supervised_user_settings_service.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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/supervised_user/supervised_user_settings_service.h" 6 7#include "base/callback.h" 8#include "base/json/json_reader.h" 9#include "base/json/json_writer.h" 10#include "base/prefs/json_pref_store.h" 11#include "base/prefs/pref_filter.h" 12#include "base/strings/string_util.h" 13#include "base/threading/sequenced_worker_pool.h" 14#include "chrome/browser/supervised_user/supervised_user_url_filter.h" 15#include "chrome/common/chrome_constants.h" 16#include "content/public/browser/browser_thread.h" 17#include "content/public/browser/user_metrics.h" 18#include "sync/api/sync_change.h" 19#include "sync/api/sync_error_factory.h" 20#include "sync/protocol/sync.pb.h" 21 22using base::DictionaryValue; 23using base::JSONReader; 24using base::UserMetricsAction; 25using base::Value; 26using content::BrowserThread; 27using syncer::SUPERVISED_USER_SETTINGS; 28using syncer::ModelType; 29using syncer::SyncChange; 30using syncer::SyncChangeList; 31using syncer::SyncChangeProcessor; 32using syncer::SyncData; 33using syncer::SyncDataList; 34using syncer::SyncError; 35using syncer::SyncErrorFactory; 36using syncer::SyncMergeResult; 37 38const char kAtomicSettings[] = "atomic_settings"; 39const char kSupervisedUserInternalItemPrefix[] = "X-"; 40const char kQueuedItems[] = "queued_items"; 41const char kSplitSettingKeySeparator = ':'; 42const char kSplitSettings[] = "split_settings"; 43 44namespace { 45 46bool SettingShouldApplyToPrefs(const std::string& name) { 47 return !StartsWithASCII(name, kSupervisedUserInternalItemPrefix, false); 48} 49 50} // namespace 51 52SupervisedUserSettingsService::SupervisedUserSettingsService() 53 : active_(false), local_settings_(new base::DictionaryValue) {} 54 55SupervisedUserSettingsService::~SupervisedUserSettingsService() {} 56 57void SupervisedUserSettingsService::Init( 58 base::FilePath profile_path, 59 base::SequencedTaskRunner* sequenced_task_runner, 60 bool load_synchronously) { 61 base::FilePath path = 62 profile_path.Append(chrome::kSupervisedUserSettingsFilename); 63 PersistentPrefStore* store = new JsonPrefStore( 64 path, sequenced_task_runner, scoped_ptr<PrefFilter>()); 65 Init(store); 66 if (load_synchronously) 67 store_->ReadPrefs(); 68 else 69 store_->ReadPrefsAsync(NULL); 70} 71 72void SupervisedUserSettingsService::Init( 73 scoped_refptr<PersistentPrefStore> store) { 74 DCHECK(!store_.get()); 75 store_ = store; 76 store_->AddObserver(this); 77} 78 79void SupervisedUserSettingsService::Subscribe( 80 const SettingsCallback& callback) { 81 if (IsReady()) { 82 scoped_ptr<base::DictionaryValue> settings = GetSettings(); 83 callback.Run(settings.get()); 84 } 85 86 subscribers_.push_back(callback); 87} 88 89void SupervisedUserSettingsService::SetActive(bool active) { 90 active_ = active; 91 InformSubscribers(); 92} 93 94bool SupervisedUserSettingsService::IsReady() { 95 return store_->IsInitializationComplete(); 96} 97 98void SupervisedUserSettingsService::Clear() { 99 store_->RemoveValue(kAtomicSettings); 100 store_->RemoveValue(kSplitSettings); 101} 102 103// static 104std::string SupervisedUserSettingsService::MakeSplitSettingKey( 105 const std::string& prefix, 106 const std::string& key) { 107 return prefix + kSplitSettingKeySeparator + key; 108} 109 110void SupervisedUserSettingsService::UploadItem(const std::string& key, 111 scoped_ptr<base::Value> value) { 112 DCHECK(!SettingShouldApplyToPrefs(key)); 113 114 std::string key_suffix = key; 115 base::DictionaryValue* dict = NULL; 116 if (sync_processor_) { 117 content::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Syncing")); 118 dict = GetDictionaryAndSplitKey(&key_suffix); 119 DCHECK(GetQueuedItems()->empty()); 120 SyncChangeList change_list; 121 SyncData data = CreateSyncDataForSetting(key, *value); 122 SyncChange::SyncChangeType change_type = 123 dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE 124 : SyncChange::ACTION_ADD; 125 change_list.push_back(SyncChange(FROM_HERE, change_type, data)); 126 SyncError error = 127 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); 128 DCHECK(!error.IsSet()) << error.ToString(); 129 } else { 130 // Queue the item up to be uploaded when we start syncing 131 // (in MergeDataAndStartSyncing()). 132 content::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Queued")); 133 dict = GetQueuedItems(); 134 } 135 dict->SetWithoutPathExpansion(key_suffix, value.release()); 136} 137 138void SupervisedUserSettingsService::SetLocalSettingForTesting( 139 const std::string& key, 140 scoped_ptr<base::Value> value) { 141 if (value) 142 local_settings_->SetWithoutPathExpansion(key, value.release()); 143 else 144 local_settings_->RemoveWithoutPathExpansion(key, NULL); 145 146 InformSubscribers(); 147} 148 149// static 150SyncData SupervisedUserSettingsService::CreateSyncDataForSetting( 151 const std::string& name, 152 const base::Value& value) { 153 std::string json_value; 154 base::JSONWriter::Write(&value, &json_value); 155 ::sync_pb::EntitySpecifics specifics; 156 specifics.mutable_managed_user_setting()->set_name(name); 157 specifics.mutable_managed_user_setting()->set_value(json_value); 158 return SyncData::CreateLocalData(name, name, specifics); 159} 160 161void SupervisedUserSettingsService::Shutdown() { 162 store_->RemoveObserver(this); 163} 164 165SyncMergeResult SupervisedUserSettingsService::MergeDataAndStartSyncing( 166 ModelType type, 167 const SyncDataList& initial_sync_data, 168 scoped_ptr<SyncChangeProcessor> sync_processor, 169 scoped_ptr<SyncErrorFactory> error_handler) { 170 DCHECK_EQ(SUPERVISED_USER_SETTINGS, type); 171 sync_processor_ = sync_processor.Pass(); 172 error_handler_ = error_handler.Pass(); 173 174 // Clear all atomic and split settings, then recreate them from Sync data. 175 Clear(); 176 for (SyncDataList::const_iterator it = initial_sync_data.begin(); 177 it != initial_sync_data.end(); ++it) { 178 DCHECK_EQ(SUPERVISED_USER_SETTINGS, it->GetDataType()); 179 const ::sync_pb::ManagedUserSettingSpecifics& supervised_user_setting = 180 it->GetSpecifics().managed_user_setting(); 181 scoped_ptr<base::Value> value( 182 JSONReader::Read(supervised_user_setting.value())); 183 std::string name_suffix = supervised_user_setting.name(); 184 base::DictionaryValue* dict = GetDictionaryAndSplitKey(&name_suffix); 185 dict->SetWithoutPathExpansion(name_suffix, value.release()); 186 } 187 store_->ReportValueChanged(kAtomicSettings); 188 store_->ReportValueChanged(kSplitSettings); 189 InformSubscribers(); 190 191 // Upload all the queued up items (either with an ADD or an UPDATE action, 192 // depending on whether they already exist) and move them to split settings. 193 SyncChangeList change_list; 194 base::DictionaryValue* queued_items = GetQueuedItems(); 195 for (base::DictionaryValue::Iterator it(*queued_items); !it.IsAtEnd(); 196 it.Advance()) { 197 std::string key_suffix = it.key(); 198 base::DictionaryValue* dict = GetDictionaryAndSplitKey(&key_suffix); 199 SyncData data = CreateSyncDataForSetting(it.key(), it.value()); 200 SyncChange::SyncChangeType change_type = 201 dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE 202 : SyncChange::ACTION_ADD; 203 change_list.push_back(SyncChange(FROM_HERE, change_type, data)); 204 dict->SetWithoutPathExpansion(key_suffix, it.value().DeepCopy()); 205 } 206 queued_items->Clear(); 207 208 SyncMergeResult result(SUPERVISED_USER_SETTINGS); 209 // Process all the accumulated changes from the queued items. 210 if (change_list.size() > 0) { 211 store_->ReportValueChanged(kQueuedItems); 212 result.set_error( 213 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); 214 } 215 216 // TODO(bauerb): Statistics? 217 return result; 218} 219 220void SupervisedUserSettingsService::StopSyncing(ModelType type) { 221 DCHECK_EQ(syncer::SUPERVISED_USER_SETTINGS, type); 222 sync_processor_.reset(); 223 error_handler_.reset(); 224} 225 226SyncDataList SupervisedUserSettingsService::GetAllSyncData( 227 ModelType type) const { 228 DCHECK_EQ(syncer::SUPERVISED_USER_SETTINGS, type); 229 SyncDataList data; 230 for (base::DictionaryValue::Iterator it(*GetAtomicSettings()); !it.IsAtEnd(); 231 it.Advance()) { 232 data.push_back(CreateSyncDataForSetting(it.key(), it.value())); 233 } 234 for (base::DictionaryValue::Iterator it(*GetSplitSettings()); !it.IsAtEnd(); 235 it.Advance()) { 236 const base::DictionaryValue* dict = NULL; 237 it.value().GetAsDictionary(&dict); 238 for (base::DictionaryValue::Iterator jt(*dict); 239 !jt.IsAtEnd(); jt.Advance()) { 240 data.push_back(CreateSyncDataForSetting( 241 MakeSplitSettingKey(it.key(), jt.key()), jt.value())); 242 } 243 } 244 DCHECK_EQ(0u, GetQueuedItems()->size()); 245 return data; 246} 247 248SyncError SupervisedUserSettingsService::ProcessSyncChanges( 249 const tracked_objects::Location& from_here, 250 const SyncChangeList& change_list) { 251 for (SyncChangeList::const_iterator it = change_list.begin(); 252 it != change_list.end(); ++it) { 253 SyncData data = it->sync_data(); 254 DCHECK_EQ(SUPERVISED_USER_SETTINGS, data.GetDataType()); 255 const ::sync_pb::ManagedUserSettingSpecifics& supervised_user_setting = 256 data.GetSpecifics().managed_user_setting(); 257 std::string key = supervised_user_setting.name(); 258 base::DictionaryValue* dict = GetDictionaryAndSplitKey(&key); 259 switch (it->change_type()) { 260 case SyncChange::ACTION_ADD: 261 case SyncChange::ACTION_UPDATE: { 262 scoped_ptr<base::Value> value( 263 JSONReader::Read(supervised_user_setting.value())); 264 if (dict->HasKey(key)) { 265 DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_ADD) 266 << "Value for key " << key << " already exists"; 267 } else { 268 DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_UPDATE) 269 << "Value for key " << key << " doesn't exist yet"; 270 } 271 dict->SetWithoutPathExpansion(key, value.release()); 272 break; 273 } 274 case SyncChange::ACTION_DELETE: { 275 DLOG_IF(WARNING, !dict->HasKey(key)) << "Trying to delete nonexistent " 276 << "key " << key; 277 dict->RemoveWithoutPathExpansion(key, NULL); 278 break; 279 } 280 case SyncChange::ACTION_INVALID: { 281 NOTREACHED(); 282 break; 283 } 284 } 285 } 286 store_->ReportValueChanged(kAtomicSettings); 287 store_->ReportValueChanged(kSplitSettings); 288 InformSubscribers(); 289 290 SyncError error; 291 return error; 292} 293 294void SupervisedUserSettingsService::OnPrefValueChanged(const std::string& key) { 295} 296 297void SupervisedUserSettingsService::OnInitializationCompleted(bool success) { 298 DCHECK(success); 299 DCHECK(IsReady()); 300 InformSubscribers(); 301} 302 303base::DictionaryValue* SupervisedUserSettingsService::GetOrCreateDictionary( 304 const std::string& key) const { 305 base::Value* value = NULL; 306 base::DictionaryValue* dict = NULL; 307 if (store_->GetMutableValue(key, &value)) { 308 bool success = value->GetAsDictionary(&dict); 309 DCHECK(success); 310 } else { 311 dict = new base::DictionaryValue; 312 store_->SetValue(key, dict); 313 } 314 315 return dict; 316} 317 318base::DictionaryValue* 319SupervisedUserSettingsService::GetAtomicSettings() const { 320 return GetOrCreateDictionary(kAtomicSettings); 321} 322 323base::DictionaryValue* SupervisedUserSettingsService::GetSplitSettings() const { 324 return GetOrCreateDictionary(kSplitSettings); 325} 326 327base::DictionaryValue* SupervisedUserSettingsService::GetQueuedItems() const { 328 return GetOrCreateDictionary(kQueuedItems); 329} 330 331base::DictionaryValue* SupervisedUserSettingsService::GetDictionaryAndSplitKey( 332 std::string* key) const { 333 size_t pos = key->find_first_of(kSplitSettingKeySeparator); 334 if (pos == std::string::npos) 335 return GetAtomicSettings(); 336 337 base::DictionaryValue* split_settings = GetSplitSettings(); 338 std::string prefix = key->substr(0, pos); 339 base::DictionaryValue* dict = NULL; 340 if (!split_settings->GetDictionary(prefix, &dict)) { 341 dict = new base::DictionaryValue; 342 DCHECK(!split_settings->HasKey(prefix)); 343 split_settings->Set(prefix, dict); 344 } 345 key->erase(0, pos + 1); 346 return dict; 347} 348 349scoped_ptr<base::DictionaryValue> SupervisedUserSettingsService::GetSettings() { 350 DCHECK(IsReady()); 351 if (!active_) 352 return scoped_ptr<base::DictionaryValue>(); 353 354 scoped_ptr<base::DictionaryValue> settings(local_settings_->DeepCopy()); 355 356 base::DictionaryValue* atomic_settings = GetAtomicSettings(); 357 for (base::DictionaryValue::Iterator it(*atomic_settings); !it.IsAtEnd(); 358 it.Advance()) { 359 if (!SettingShouldApplyToPrefs(it.key())) 360 continue; 361 362 settings->Set(it.key(), it.value().DeepCopy()); 363 } 364 365 base::DictionaryValue* split_settings = GetSplitSettings(); 366 for (base::DictionaryValue::Iterator it(*split_settings); !it.IsAtEnd(); 367 it.Advance()) { 368 if (!SettingShouldApplyToPrefs(it.key())) 369 continue; 370 371 settings->Set(it.key(), it.value().DeepCopy()); 372 } 373 374 return settings.Pass(); 375} 376 377void SupervisedUserSettingsService::InformSubscribers() { 378 if (!IsReady()) 379 return; 380 381 scoped_ptr<base::DictionaryValue> settings = GetSettings(); 382 for (std::vector<SettingsCallback>::iterator it = subscribers_.begin(); 383 it != subscribers_.end(); ++it) { 384 it->Run(settings.get()); 385 } 386} 387