1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/preference_change_processor.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/auto_reset.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/json/json_reader.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/preference_model_associator.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/profile_sync_service.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/json_value_serializer.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPreferenceChangeProcessor::PreferenceChangeProcessor(
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PreferenceModelAssociator* model_associator,
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UnrecoverableErrorHandler* error_handler)
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : ChangeProcessor(error_handler),
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      pref_service_(NULL),
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      model_associator_(model_associator),
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      processing_pref_change_(false) {
32731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(model_associator);
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(error_handler);
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPreferenceChangeProcessor::~PreferenceChangeProcessor() {
38731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PreferenceChangeProcessor::Observe(NotificationType type,
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationSource& source,
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationDetails& details) {
44731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(running());
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(NotificationType::PREF_CHANGED == type);
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(pref_service_, Source<PrefService>(source).ptr());
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Avoid recursion.
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (processing_pref_change_)
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  AutoReset<bool> guard(&processing_pref_change_, true);
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string* name = Details<std::string>(details).ptr();
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const PrefService::Preference* preference =
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      pref_service_->FindPreference((*name).c_str());
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(preference);
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int64 sync_id = model_associator_->GetSyncIdFromChromeId(*name);
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool user_modifiable = preference->IsUserModifiable();
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!user_modifiable) {
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // We do not track preferences the user cannot change.
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    model_associator_->Disassociate(sync_id);
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::WriteTransaction trans(share_handle());
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::WriteNode node(&trans);
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Since we don't create sync nodes for preferences that are not under control
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // of the user or still have their default value, this changed preference may
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // not have a sync node yet. If so, we create a node. Similarly, a preference
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // may become user-modifiable (e.g. due to laxer policy configuration), in
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // which case we also need to create a sync node and associate it.
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (sync_api::kInvalidId == sync_id) {
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::ReadNode root(&trans);
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!root.InitByTagLookup(browser_sync::kPreferencesTag)) {
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_handler()->OnUnrecoverableError(FROM_HERE, "Can't find root.");
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // InitPrefNodeAndAssociate takes care of writing the value to the sync
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // node if appropriate.
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!model_associator_->InitPrefNodeAndAssociate(&trans,
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                                     root,
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                                     preference)) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_handler()->OnUnrecoverableError(FROM_HERE,
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                            "Can't create sync node.");
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!node.InitByIdLookup(sync_id)) {
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    error_handler()->OnUnrecoverableError(FROM_HERE,
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          "Preference node lookup failed.");
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!PreferenceModelAssociator::WritePreferenceToNode(
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          preference->name(),
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          *preference->GetValue(),
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &node)) {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_handler()->OnUnrecoverableError(FROM_HERE,
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          "Failed to update preference node.");
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PreferenceChangeProcessor::ApplyChangesFromSyncModel(
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_api::BaseTransaction* trans,
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_api::SyncManager::ChangeRecord* changes,
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int change_count) {
112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!running())
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StopObserving();
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < change_count; ++i) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::ReadNode node(trans);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(ncarter): Can't look up the name for deletions: lookup of
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // deleted items fails at the syncapi layer.  However, the node should
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // generally still exist in the syncable database; we just need to
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // plumb the syncapi so that it succeeds.
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        changes[i].action) {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Until the above is fixed, we have no choice but to ignore deletions.
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "No way to handle pref deletion";
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!node.InitByIdLookup(changes[i].id)) {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_handler()->OnUnrecoverableError(FROM_HERE,
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            "Preference node lookup failed.");
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(syncable::PREFERENCES == node.GetModelType());
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string name;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<Value> value(ReadPreference(&node, &name));
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Skip values we can't deserialize.
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!value.get())
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // It is possible that we may receive a change to a preference we
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // do not want to sync.  For example if the user is syncing a Mac
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // client and a Windows client, the Windows client does not
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // support kConfirmToQuitEnabled.  Ignore updates from these
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // preferences.
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const char* pref_name = name.c_str();
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (model_associator_->synced_preferences().count(pref_name) == 0)
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't try to overwrite preferences not controllable by the user.
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const PrefService::Preference* pref =
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        pref_service_->FindPreference(pref_name);
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(pref);
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!pref->IsUserModifiable())
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        changes[i].action) {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      pref_service_->ClearPref(pref_name);
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      pref_service_->Set(pref_name, *value);
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If this is a newly added node, associate.
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (sync_api::SyncManager::ChangeRecord::ACTION_ADD ==
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          changes[i].action) {
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const PrefService::Preference* preference =
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            pref_service_->FindPreference(name.c_str());
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        model_associator_->Associate(preference, changes[i].id);
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model_associator_->AfterUpdateOperations(name);
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartObserving();
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochValue* PreferenceChangeProcessor::ReadPreference(
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::ReadNode* node,
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string* name) {
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const sync_pb::PreferenceSpecifics& preference(
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      node->GetPreferenceSpecifics());
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::JSONReader reader;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<Value> value(reader.JsonToValue(preference.value(), false, false));
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!value.get()) {
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string err = "Failed to deserialize preference value: " +
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        reader.GetErrorMessage();
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_handler()->OnUnrecoverableError(FROM_HERE, err);
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  *name = preference.name();
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return value.release();
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PreferenceChangeProcessor::StartImpl(Profile* profile) {
197731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pref_service_ = profile->GetPrefs();
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Init(pref_service_);
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartObserving();
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PreferenceChangeProcessor::StopImpl() {
204731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StopObserving();
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pref_service_ = NULL;
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PreferenceChangeProcessor::StartObserving() {
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(pref_service_);
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (std::set<std::string>::const_iterator it =
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model_associator_->synced_preferences().begin();
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      it != model_associator_->synced_preferences().end(); ++it) {
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    registrar_.Add((*it).c_str(), this);
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PreferenceChangeProcessor::StopObserving() {
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(pref_service_);
2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (std::set<std::string>::const_iterator it =
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model_associator_->synced_preferences().begin();
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      it != model_associator_->synced_preferences().end(); ++it) {
2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    registrar_.Remove((*it).c_str(), this);
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
229