supervised_user_settings_service.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_settings_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/callback.h"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/json/json_reader.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/json/json_writer.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/prefs/json_pref_store.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_filter.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/string_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_url_filter.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "sync/api/sync_change.h"
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "sync/api/sync_error_factory.h"
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "sync/protocol/sync.pb.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using base::DictionaryValue;
237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)using base::JSONReader;
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::UserMetricsAction;
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using base::Value;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using syncer::SUPERVISED_USER_SETTINGS;
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using syncer::ModelType;
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using syncer::SyncChange;
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using syncer::SyncChangeList;
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using syncer::SyncChangeProcessor;
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using syncer::SyncData;
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using syncer::SyncDataList;
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using syncer::SyncError;
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using syncer::SyncErrorFactory;
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using syncer::SyncMergeResult;
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const char kAtomicSettings[] = "atomic_settings";
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char kSupervisedUserInternalItemPrefix[] = "X-";
407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const char kQueuedItems[] = "queued_items";
417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const char kSplitSettingKeySeparator = ':';
427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const char kSplitSettings[] = "split_settings";
437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace {
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool SettingShouldApplyToPrefs(const std::string& name) {
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return !StartsWithASCII(name, kSupervisedUserInternalItemPrefix, false);
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserSettingsService::SupervisedUserSettingsService()
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : active_(false), local_settings_(new base::DictionaryValue) {}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserSettingsService::~SupervisedUserSettingsService() {}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::Init(
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    base::FilePath profile_path,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::SequencedTaskRunner* sequenced_task_runner,
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    bool load_synchronously) {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path =
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      profile_path.Append(chrome::kSupervisedUserSettingsFilename);
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PersistentPrefStore* store = new JsonPrefStore(
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      path, sequenced_task_runner, scoped_ptr<PrefFilter>());
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  Init(store);
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (load_synchronously)
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    store_->ReadPrefs();
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    store_->ReadPrefsAsync(NULL);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::Init(
7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_refptr<PersistentPrefStore> store) {
7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!store_);
7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  store_ = store;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  store_->AddObserver(this);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::Subscribe(
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const SettingsCallback& callback) {
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (IsReady()) {
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_ptr<base::DictionaryValue> settings = GetSettings();
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    callback.Run(settings.get());
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  subscribers_.push_back(callback);
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::SetActive(bool active) {
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  active_ = active;
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  InformSubscribers();
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SupervisedUserSettingsService::IsReady() {
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return store_->IsInitializationComplete();
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::Clear() {
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  store_->RemoveValue(kAtomicSettings);
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  store_->RemoveValue(kSplitSettings);
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// static
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)std::string SupervisedUserSettingsService::MakeSplitSettingKey(
1057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& prefix,
1067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& key) {
1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return prefix + kSplitSettingKeySeparator + key;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::UploadItem(const std::string& key,
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                               scoped_ptr<base::Value> value) {
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!SettingShouldApplyToPrefs(key));
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::string key_suffix = key;
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = NULL;
1167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (sync_processor_) {
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    content::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Syncing"));
1187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    dict = GetDictionaryAndSplitKey(&key_suffix);
1197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(GetQueuedItems()->empty());
1207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    SyncChangeList change_list;
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    SyncData data = CreateSyncDataForSetting(key, *value);
1227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    SyncChange::SyncChangeType change_type =
1237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE
1247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                 : SyncChange::ACTION_ADD;
1257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    change_list.push_back(SyncChange(FROM_HERE, change_type, data));
1267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    SyncError error =
1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(!error.IsSet()) << error.ToString();
1297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  } else {
13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Queue the item up to be uploaded when we start syncing
13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // (in MergeDataAndStartSyncing()).
13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    content::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Queued"));
1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    dict = GetQueuedItems();
1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  dict->SetWithoutPathExpansion(key_suffix, value.release());
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::SetLocalSettingForTesting(
1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& key,
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::Value> value) {
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (value)
14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    local_settings_->SetWithoutPathExpansion(key, value.release());
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    local_settings_->RemoveWithoutPathExpansion(key, NULL);
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  InformSubscribers();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// static
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SyncData SupervisedUserSettingsService::CreateSyncDataForSetting(
1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& name,
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Value& value) {
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::string json_value;
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::JSONWriter::Write(&value, &json_value);
1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ::sync_pb::EntitySpecifics specifics;
1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  specifics.mutable_managed_user_setting()->set_name(name);
1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  specifics.mutable_managed_user_setting()->set_value(json_value);
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return SyncData::CreateLocalData(name, name, specifics);
1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::Shutdown() {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  store_->RemoveObserver(this);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SyncMergeResult SupervisedUserSettingsService::MergeDataAndStartSyncing(
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ModelType type,
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const SyncDataList& initial_sync_data,
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_ptr<SyncChangeProcessor> sync_processor,
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_ptr<SyncErrorFactory> error_handler) {
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_EQ(SUPERVISED_USER_SETTINGS, type);
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  sync_processor_ = sync_processor.Pass();
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  error_handler_ = error_handler.Pass();
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Clear all atomic and split settings, then recreate them from Sync data.
1757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Clear();
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (SyncDataList::const_iterator it = initial_sync_data.begin();
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       it != initial_sync_data.end(); ++it) {
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK_EQ(SUPERVISED_USER_SETTINGS, it->GetDataType());
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ::sync_pb::ManagedUserSettingSpecifics& supervised_user_setting =
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        it->GetSpecifics().managed_user_setting();
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::Value> value(
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        JSONReader::Read(supervised_user_setting.value()));
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::string name_suffix = supervised_user_setting.name();
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* dict = GetDictionaryAndSplitKey(&name_suffix);
1857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    dict->SetWithoutPathExpansion(name_suffix, value.release());
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
1877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  store_->ReportValueChanged(kAtomicSettings);
1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  store_->ReportValueChanged(kSplitSettings);
18958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  InformSubscribers();
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Upload all the queued up items (either with an ADD or an UPDATE action,
1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // depending on whether they already exist) and move them to split settings.
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SyncChangeList change_list;
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* queued_items = GetQueuedItems();
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (base::DictionaryValue::Iterator it(*queued_items); !it.IsAtEnd();
1967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)       it.Advance()) {
1977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    std::string key_suffix = it.key();
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* dict = GetDictionaryAndSplitKey(&key_suffix);
19958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    SyncData data = CreateSyncDataForSetting(it.key(), it.value());
2007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    SyncChange::SyncChangeType change_type =
2017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE
2027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                 : SyncChange::ACTION_ADD;
2037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    change_list.push_back(SyncChange(FROM_HERE, change_type, data));
2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    dict->SetWithoutPathExpansion(key_suffix, it.value().DeepCopy());
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
2067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  queued_items->Clear();
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SyncMergeResult result(SUPERVISED_USER_SETTINGS);
2097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Process all the accumulated changes from the queued items.
2107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (change_list.size() > 0) {
2117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    store_->ReportValueChanged(kQueuedItems);
2127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    result.set_error(
2137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
2147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
2157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // TODO(bauerb): Statistics?
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return result;
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::StopSyncing(ModelType type) {
221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_EQ(syncer::SUPERVISED_USER_SETTINGS, type);
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  sync_processor_.reset();
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  error_handler_.reset();
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SyncDataList SupervisedUserSettingsService::GetAllSyncData(
22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ModelType type) const {
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_EQ(syncer::SUPERVISED_USER_SETTINGS, type);
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SyncDataList data;
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (base::DictionaryValue::Iterator it(*GetAtomicSettings()); !it.IsAtEnd();
2317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)       it.Advance()) {
23258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    data.push_back(CreateSyncDataForSetting(it.key(), it.value()));
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (base::DictionaryValue::Iterator it(*GetSplitSettings()); !it.IsAtEnd();
2357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)       it.Advance()) {
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::DictionaryValue* dict = NULL;
2377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    it.value().GetAsDictionary(&dict);
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (base::DictionaryValue::Iterator jt(*dict);
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         !jt.IsAtEnd(); jt.Advance()) {
24058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      data.push_back(CreateSyncDataForSetting(
24158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          MakeSplitSettingKey(it.key(), jt.key()), jt.value()));
2427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
2437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
2447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK_EQ(0u, GetQueuedItems()->size());
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return data;
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SyncError SupervisedUserSettingsService::ProcessSyncChanges(
24990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const tracked_objects::Location& from_here,
25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const SyncChangeList& change_list) {
25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (SyncChangeList::const_iterator it = change_list.begin();
25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       it != change_list.end(); ++it) {
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SyncData data = it->sync_data();
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK_EQ(SUPERVISED_USER_SETTINGS, data.GetDataType());
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ::sync_pb::ManagedUserSettingSpecifics& supervised_user_setting =
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        data.GetSpecifics().managed_user_setting();
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::string key = supervised_user_setting.name();
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* dict = GetDictionaryAndSplitKey(&key);
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    switch (it->change_type()) {
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SyncChange::ACTION_ADD:
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SyncChange::ACTION_UPDATE: {
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        scoped_ptr<base::Value> value(
263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            JSONReader::Read(supervised_user_setting.value()));
2647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        if (dict->HasKey(key)) {
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_ADD)
2667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)              << "Value for key " << key << " already exists";
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        } else {
26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_UPDATE)
2697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)              << "Value for key " << key << " doesn't exist yet";
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
2717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        dict->SetWithoutPathExpansion(key, value.release());
27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SyncChange::ACTION_DELETE: {
2757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        DLOG_IF(WARNING, !dict->HasKey(key)) << "Trying to delete nonexistent "
2767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                             << "key " << key;
2777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        dict->RemoveWithoutPathExpansion(key, NULL);
27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
27990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SyncChange::ACTION_INVALID: {
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        NOTREACHED();
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
2867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  store_->ReportValueChanged(kAtomicSettings);
2877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  store_->ReportValueChanged(kSplitSettings);
28858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  InformSubscribers();
2897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  SyncError error;
29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return error;
29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::OnPrefValueChanged(const std::string& key) {
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
29658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::OnInitializationCompleted(bool success) {
29858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(success);
29958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(IsReady());
30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  InformSubscribers();
3017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)base::DictionaryValue* SupervisedUserSettingsService::GetOrCreateDictionary(
3047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& key) const {
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Value* value = NULL;
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = NULL;
3077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (store_->GetMutableValue(key, &value)) {
3087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    bool success = value->GetAsDictionary(&dict);
3097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(success);
3107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  } else {
3117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    dict = new base::DictionaryValue;
3127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    store_->SetValue(key, dict);
3137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return dict;
3167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)base::DictionaryValue*
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserSettingsService::GetAtomicSettings() const {
3207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return GetOrCreateDictionary(kAtomicSettings);
3217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)base::DictionaryValue* SupervisedUserSettingsService::GetSplitSettings() const {
3247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return GetOrCreateDictionary(kSplitSettings);
3257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)base::DictionaryValue* SupervisedUserSettingsService::GetQueuedItems() const {
3287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return GetOrCreateDictionary(kQueuedItems);
3297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)base::DictionaryValue* SupervisedUserSettingsService::GetDictionaryAndSplitKey(
3327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    std::string* key) const {
3337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  size_t pos = key->find_first_of(kSplitSettingKeySeparator);
3347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (pos == std::string::npos)
3357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return GetAtomicSettings();
3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* split_settings = GetSplitSettings();
3387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::string prefix = key->substr(0, pos);
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = NULL;
3407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!split_settings->GetDictionary(prefix, &dict)) {
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dict = new base::DictionaryValue;
3427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(!split_settings->HasKey(prefix));
3437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    split_settings->Set(prefix, dict);
3447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  key->erase(0, pos + 1);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<base::DictionaryValue> SupervisedUserSettingsService::GetSettings() {
35058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(IsReady());
35158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!active_)
35258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
35358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> settings(local_settings_->DeepCopy());
3557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* atomic_settings = GetAtomicSettings();
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (base::DictionaryValue::Iterator it(*atomic_settings); !it.IsAtEnd();
3587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)       it.Advance()) {
35958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!SettingShouldApplyToPrefs(it.key()))
3607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      continue;
3617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
36258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    settings->Set(it.key(), it.value().DeepCopy());
3637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* split_settings = GetSplitSettings();
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (base::DictionaryValue::Iterator it(*split_settings); !it.IsAtEnd();
3677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)       it.Advance()) {
36858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!SettingShouldApplyToPrefs(it.key()))
3697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      continue;
3707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
37158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    settings->Set(it.key(), it.value().DeepCopy());
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return settings.Pass();
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSettingsService::InformSubscribers() {
37858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!IsReady())
37958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
38058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
38158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> settings = GetSettings();
38258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (std::vector<SettingsCallback>::iterator it = subscribers_.begin();
38358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       it != subscribers_.end(); ++it) {
38458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    it->Run(settings.get());
38558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
38658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
387