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