Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Side by Side Diff: chrome/browser/prefs/pref_model_associator.cc

Issue 6995008: Implement new SyncAPI and convert Preferences to it. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Foward Declare++ Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/prefs/pref_model_associator.h" 5 #include "chrome/browser/prefs/pref_model_associator.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/utf_string_conversions.h" 10 #include "base/utf_string_conversions.h"
11 #include "base/values.h" 11 #include "base/values.h"
12 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/sync/api/sync_event.h"
13 #include "chrome/browser/sync/engine/syncapi.h"
14 #include "chrome/browser/sync/glue/generic_change_processor.h"
15 #include "chrome/browser/sync/profile_sync_service.h"
16 #include "chrome/browser/sync/protocol/preference_specifics.pb.h" 13 #include "chrome/browser/sync/protocol/preference_specifics.pb.h"
17 #include "chrome/common/pref_names.h" 14 #include "chrome/common/pref_names.h"
18 #include "content/browser/browser_thread.h"
19 #include "content/common/json_value_serializer.h" 15 #include "content/common/json_value_serializer.h"
20 #include "content/common/notification_service.h" 16 #include "content/common/notification_service.h"
21 17
22 using syncable::PREFERENCES; 18 using syncable::PREFERENCES;
23 19
24 PrefModelAssociator::PrefModelAssociator() 20 PrefModelAssociator::PrefModelAssociator()
25 : pref_service_(NULL), 21 : models_associated_(false),
26 sync_service_(NULL),
27 models_associated_(false),
28 processing_syncer_changes_(false), 22 processing_syncer_changes_(false),
29 change_processor_(NULL) { 23 pref_service_(NULL),
24 sync_processor_(NULL) {
30 } 25 }
31 26
32 PrefModelAssociator::PrefModelAssociator( 27 PrefModelAssociator::PrefModelAssociator(
33 PrefService* pref_service) 28 PrefService* pref_service)
34 : pref_service_(pref_service), 29 : models_associated_(false),
35 sync_service_(NULL),
36 models_associated_(false),
37 processing_syncer_changes_(false), 30 processing_syncer_changes_(false),
38 change_processor_(NULL) { 31 pref_service_(pref_service),
32 sync_processor_(NULL) {
39 DCHECK(CalledOnValidThread()); 33 DCHECK(CalledOnValidThread());
40 } 34 }
41 35
42 PrefModelAssociator::~PrefModelAssociator() { 36 PrefModelAssociator::~PrefModelAssociator() {
43 DCHECK(CalledOnValidThread()); 37 DCHECK(CalledOnValidThread());
44 change_processor_ = NULL; 38 sync_processor_ = NULL;
45 sync_service_ = NULL;
46 pref_service_ = NULL; 39 pref_service_ = NULL;
47 } 40 }
48 41
49 bool PrefModelAssociator::InitPrefNodeAndAssociate( 42 void PrefModelAssociator::InitPrefAndAssociate(
50 sync_api::WriteTransaction* trans, 43 const SyncData& sync_pref,
51 const sync_api::BaseNode& root, 44 const std::string& pref_name,
52 const PrefService::Preference* pref) { 45 SyncEventList* sync_changes) {
53 DCHECK(pref); 46 const PrefService::Preference* pref =
47 pref_service_->FindPreference(pref_name.c_str());
48 VLOG(1) << "Associating preference " << pref_name;
49 if (!pref->IsUserModifiable()) {
50 // This preference is controlled by policy. We don't need sync it, but if
51 // there is sync data we want to track it for possible future use.
52 if (sync_pref.IsValid())
53 untracked_pref_sync_data_[pref_name] = sync_pref;
54 return;
55 }
54 56
55 base::JSONReader reader; 57 base::JSONReader reader;
56 std::string tag = pref->name(); 58 if (sync_pref.IsValid()) {
57 sync_api::WriteNode node(trans); 59 // The server has a value for the preference, we have to reconcile it with
58 if (node.InitByClientTagLookup(PREFERENCES, tag)) { 60 // ours.
59 // The server has a value for the preference. 61 const sync_pb::PreferenceSpecifics& preference =
60 const sync_pb::PreferenceSpecifics& preference( 62 sync_pref.GetSpecifics().GetExtension(sync_pb::preference);
61 node.GetPreferenceSpecifics()); 63 DCHECK_EQ(pref->name(), preference.name());
62 DCHECK_EQ(tag, preference.name());
63
64 if (!pref->IsUserModifiable()) {
65 Associate(pref, node.GetId());
66 return true;
67 }
68 64
69 scoped_ptr<Value> value( 65 scoped_ptr<Value> value(
70 reader.JsonToValue(preference.value(), false, false)); 66 reader.JsonToValue(preference.value(), false, false));
71 std::string pref_name = preference.name();
72 if (!value.get()) { 67 if (!value.get()) {
73 LOG(ERROR) << "Failed to deserialize preference value: " 68 LOG(ERROR) << "Failed to deserialize preference value: "
74 << reader.GetErrorMessage(); 69 << reader.GetErrorMessage();
75 return false; 70 return;
76 } 71 }
77 72
78 // Merge the server value of this preference with the local value. 73 // Merge the server value of this preference with the local value.
79 scoped_ptr<Value> new_value(MergePreference(*pref, *value)); 74 scoped_ptr<Value> new_value(MergePreference(*pref, *value));
80 75
81 // Update the local preference based on what we got from the 76 // Update the local preference based on what we got from the
82 // sync server. 77 // sync server.
83 if (new_value->IsType(Value::TYPE_NULL)) { 78 if (new_value->IsType(Value::TYPE_NULL)) {
84 pref_service_->ClearPref(pref_name.c_str()); 79 pref_service_->ClearPref(pref_name.c_str());
85 } else if (!new_value->IsType(pref->GetType())) { 80 } else if (!new_value->IsType(pref->GetType())) {
86 LOG(WARNING) << "Synced value for " << preference.name() 81 LOG(WARNING) << "Synced value for " << preference.name()
87 << " is of type " << new_value->GetType() 82 << " is of type " << new_value->GetType()
88 << " which doesn't match pref type " << pref->GetType(); 83 << " which doesn't match pref type " << pref->GetType();
89 } else if (!pref->GetValue()->Equals(new_value.get())) { 84 } else if (!pref->GetValue()->Equals(new_value.get())) {
90 pref_service_->Set(pref_name.c_str(), *new_value); 85 pref_service_->Set(pref_name.c_str(), *new_value);
91 } 86 }
92 87
93 SendUpdateNotificationsIfNecessary(pref_name); 88 SendUpdateNotificationsIfNecessary(pref_name);
94 89
95 // If the merge resulted in an updated value, write it back to 90 // If the merge resulted in an updated value, inform the syncer.
96 // the sync node. 91 if (!value->Equals(new_value.get())) {
97 if (!value->Equals(new_value.get()) && 92 SyncData sync_data;
98 !WritePreferenceToNode(pref->name(), *new_value, &node)) { 93 if (!CreatePrefSyncData(pref->name(), *new_value, &sync_data)) {
99 return false; 94 LOG(ERROR) << "Failed to update preference.";
95 return;
96 }
97 sync_changes->push_back(SyncEvent(SyncEvent::ACTION_UPDATE, sync_data));
100 } 98 }
101 Associate(pref, node.GetId());
102 } else if (pref->IsUserControlled()) { 99 } else if (pref->IsUserControlled()) {
103 // The server doesn't have a value, but we have a user-controlled value, 100 // The server does not know about this preference and should be added
104 // so we push it to the server. 101 // to the syncer's database.
105 sync_api::WriteNode write_node(trans); 102 SyncData sync_data;
106 if (!write_node.InitUniqueByCreation(PREFERENCES, root, tag)) { 103 if (!CreatePrefSyncData(pref->name(), *pref->GetValue(), &sync_data)) {
107 LOG(ERROR) << "Failed to create preference sync node."; 104 LOG(ERROR) << "Failed to update preference.";
108 return false; 105 return;
106 }
107 sync_changes->push_back(SyncEvent(SyncEvent::ACTION_ADD, sync_data));
108 } else {
109 // This pref has a default value, we can ignore it. Once it gets changed,
110 // we'll send the new custom value to the syncer.
111 return;
112 }
113
114 // Make sure we add it to our list of synced preferences so we know what
115 // the server is aware of.
116 synced_preferences_.insert(pref_name);
117 return;
118 }
119
120 bool PrefModelAssociator::MergeDataAndStartSyncing(
121 syncable::ModelType type,
122 SyncEventProcessor* sync_processor,
123 const SyncDataList& initial_sync_data) {
124 DCHECK_EQ(type, PREFERENCES);
125 DCHECK(CalledOnValidThread());
126 DCHECK(!sync_processor_);
127 sync_processor_ = sync_processor;
128
129 SyncEventList new_events;
130 std::set<std::string> remaining_preferences = registered_preferences_;
131
132 // Go through and check for all preferences we care about that sync already
133 // knows about.
134 for (SyncDataList::const_iterator sync_iter = initial_sync_data.begin();
135 sync_iter != initial_sync_data.end();
136 ++sync_iter) {
137 DCHECK_EQ(PREFERENCES, sync_iter->GetDataType());
138 std::string sync_pref_name = sync_iter->GetSpecifics().
139 GetExtension(sync_pb::preference).name();
140 if (remaining_preferences.count(sync_pref_name) == 0) {
141 // We're not syncing this preference locally, ignore the sync data.
akalin 2011/05/19 00:58:45 Hmm. If we want to maintain the invariant that Ge
Nicolas Zea 2011/05/19 21:17:45 In the case of preferences, it also happens for pl
142 continue;
109 } 143 }
110 144
111 // Update the sync node with the local value for this preference. 145 remaining_preferences.erase(sync_pref_name);
112 if (!WritePreferenceToNode(pref->name(), *pref->GetValue(), &write_node)) 146 InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_events);
113 return false;
114
115 Associate(pref, write_node.GetId());
116 } else {
117 // This preference is handled by policy, not the user, and therefore
118 // we do not associate it.
119 } 147 }
120 148
121 return true; 149 // Go through and build sync data for any remaining preferences.
122 } 150 for (std::set<std::string>::iterator pref_name_iter =
123 151 remaining_preferences.begin();
124 bool PrefModelAssociator::AssociateModels() { 152 pref_name_iter != remaining_preferences.end();
125 DCHECK(CalledOnValidThread()); 153 ++pref_name_iter) {
126 154 InitPrefAndAssociate(SyncData(), *pref_name_iter, &new_events);
127 int64 root_id;
128 if (!GetSyncIdForTaggedNode(syncable::ModelTypeToRootTag(PREFERENCES),
129 &root_id)) {
130 LOG(ERROR) << "Server did not create the top-level preferences node. We "
131 << "might be running against an out-of-date server.";
132 return false;
133 } 155 }
134 156
135 sync_api::WriteTransaction trans(sync_service_->GetUserShare()); 157 // Push updates to sync.
136 sync_api::ReadNode root(&trans); 158 sync_processor_->ProcessSyncEvents(new_events);
137 if (!root.InitByIdLookup(root_id)) {
138 LOG(ERROR) << "Server did not create the top-level preferences node. We "
139 << "might be running against an out-of-date server.";
140 return false;
141 }
142
143 for (std::set<std::string>::iterator it = synced_preferences_.begin();
144 it != synced_preferences_.end(); ++it) {
145 std::string name = *it;
146 const PrefService::Preference* pref =
147 pref_service_->FindPreference(name.c_str());
148 VLOG(1) << "Associating preference " << name;
149 DCHECK(pref);
150 if (!pref->IsUserModifiable())
151 continue; // We don't sync preferences the user cannot change.
152 InitPrefNodeAndAssociate(&trans, root, pref);
153 }
154 models_associated_ = true; 159 models_associated_ = true;
155 return true; 160 return true;
156 } 161 }
157 162
158 bool PrefModelAssociator::DisassociateModels() { 163 void PrefModelAssociator::StopSyncing(syncable::ModelType type) {
159 id_map_.clear(); 164 DCHECK_EQ(type, PREFERENCES);
160 id_map_inverse_.clear();
161 models_associated_ = false; 165 models_associated_ = false;
162 return true; 166 sync_processor_ = NULL;
163 } 167 untracked_pref_sync_data_.clear();
164
165 bool PrefModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
166 DCHECK(has_nodes);
167 *has_nodes = false;
168 int64 preferences_sync_id;
169 if (!GetSyncIdForTaggedNode(syncable::ModelTypeToRootTag(PREFERENCES),
170 &preferences_sync_id)) {
171 LOG(ERROR) << "Server did not create the top-level preferences node. We "
172 << "might be running against an out-of-date server.";
173 return false;
174 }
175 sync_api::ReadTransaction trans(sync_service_->GetUserShare());
176
177 sync_api::ReadNode preferences_node(&trans);
178 if (!preferences_node.InitByIdLookup(preferences_sync_id)) {
179 LOG(ERROR) << "Server did not create the top-level preferences node. We "
180 << "might be running against an out-of-date server.";
181 return false;
182 }
183
184 // The sync model has user created nodes if the preferences folder has any
185 // children.
186 *has_nodes = sync_api::kInvalidId != preferences_node.GetFirstChildId();
187 return true;
188 }
189
190 int64 PrefModelAssociator::GetSyncIdFromChromeId(
191 const std::string& preference_name) {
192 PreferenceNameToSyncIdMap::const_iterator iter =
193 id_map_.find(preference_name);
194 return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
195 }
196
197 void PrefModelAssociator::Associate(
198 const PrefService::Preference* preference, int64 sync_id) {
199 DCHECK(CalledOnValidThread());
200
201 std::string name = preference->name();
202 DCHECK_NE(sync_api::kInvalidId, sync_id);
203 DCHECK_EQ(0U, id_map_.count(name));
204 DCHECK_EQ(0U, id_map_inverse_.count(sync_id));
205 id_map_[name] = sync_id;
206 id_map_inverse_[sync_id] = name;
207 }
208
209 void PrefModelAssociator::Disassociate(int64 sync_id) {
210 DCHECK(CalledOnValidThread());
211 SyncIdToPreferenceNameMap::iterator iter = id_map_inverse_.find(sync_id);
212 if (iter == id_map_inverse_.end())
213 return;
214 id_map_.erase(iter->second);
215 id_map_inverse_.erase(iter);
216 }
217
218 bool PrefModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
219 int64* sync_id) {
220 sync_api::ReadTransaction trans(sync_service_->GetUserShare());
221 sync_api::ReadNode sync_node(&trans);
222 if (!sync_node.InitByTagLookup(tag.c_str()))
223 return false;
224 *sync_id = sync_node.GetId();
225 return true;
226 } 168 }
227 169
228 Value* PrefModelAssociator::MergePreference( 170 Value* PrefModelAssociator::MergePreference(
229 const PrefService::Preference& local_pref, 171 const PrefService::Preference& local_pref,
230 const Value& server_value) { 172 const Value& server_value) {
231 const std::string& name(local_pref.name()); 173 const std::string& name(local_pref.name());
232 if (name == prefs::kURLsToRestoreOnStartup || 174 if (name == prefs::kURLsToRestoreOnStartup ||
233 name == prefs::kDesktopNotificationAllowedOrigins || 175 name == prefs::kDesktopNotificationAllowedOrigins ||
234 name == prefs::kDesktopNotificationDeniedOrigins) { 176 name == prefs::kDesktopNotificationDeniedOrigins) {
235 return MergeListValues(*local_pref.GetValue(), server_value); 177 return MergeListValues(*local_pref.GetValue(), server_value);
236 } 178 }
237 179
238 if (name == prefs::kContentSettingsPatterns || 180 if (name == prefs::kContentSettingsPatterns ||
239 name == prefs::kGeolocationContentSettings) { 181 name == prefs::kGeolocationContentSettings) {
240 return MergeDictionaryValues(*local_pref.GetValue(), server_value); 182 return MergeDictionaryValues(*local_pref.GetValue(), server_value);
241 } 183 }
242 184
243 // If this is not a specially handled preference, server wins. 185 // If this is not a specially handled preference, server wins.
244 return server_value.DeepCopy(); 186 return server_value.DeepCopy();
245 } 187 }
246 188
247 bool PrefModelAssociator::WritePreferenceToNode( 189 bool PrefModelAssociator::CreatePrefSyncData(
248 const std::string& name, 190 const std::string& name,
249 const Value& value, 191 const Value& value,
250 sync_api::WriteNode* node) { 192 SyncData* sync_data) {
251 std::string serialized; 193 std::string serialized;
252 JSONStringValueSerializer json(&serialized); 194 JSONStringValueSerializer json(&serialized);
akalin 2011/05/19 00:58:45 You can use JSONWriter::Write from base/json/json_
Nicolas Zea 2011/05/19 21:17:45 Added TODO for this, since it's kind of outside th
253 if (!json.Serialize(value)) { 195 if (!json.Serialize(value)) {
254 LOG(ERROR) << "Failed to serialize preference value."; 196 LOG(ERROR) << "Failed to serialize preference value.";
255 return false; 197 return false;
256 } 198 }
257 199
258 sync_pb::PreferenceSpecifics preference; 200 sync_pb::EntitySpecifics specifics;
259 preference.set_name(name); 201 sync_pb::PreferenceSpecifics* pref_specifics = specifics.MutableExtension(
260 preference.set_value(serialized); 202 sync_pb::preference);
261 node->SetPreferenceSpecifics(preference); 203 pref_specifics->set_name(name);
262 // TODO(viettrungluu): eliminate conversion (it's temporary) 204 pref_specifics->set_value(serialized);
263 node->SetTitle(UTF8ToWide(name)); 205 *sync_data = SyncData::CreateLocalData(name, specifics);
264 return true; 206 return true;
265 } 207 }
266 208
267 Value* PrefModelAssociator::MergeListValues(const Value& from_value, 209 Value* PrefModelAssociator::MergeListValues(const Value& from_value,
268 const Value& to_value) { 210 const Value& to_value) {
269 if (from_value.GetType() == Value::TYPE_NULL) 211 if (from_value.GetType() == Value::TYPE_NULL)
270 return to_value.DeepCopy(); 212 return to_value.DeepCopy();
271 if (to_value.GetType() == Value::TYPE_NULL) 213 if (to_value.GetType() == Value::TYPE_NULL)
272 return from_value.DeepCopy(); 214 return from_value.DeepCopy();
273 215
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 // The bookmark bar visibility preference requires a special 269 // The bookmark bar visibility preference requires a special
328 // notification to update the UI. 270 // notification to update the UI.
329 if (0 == pref_name.compare(prefs::kShowBookmarkBar)) { 271 if (0 == pref_name.compare(prefs::kShowBookmarkBar)) {
330 NotificationService::current()->Notify( 272 NotificationService::current()->Notify(
331 NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, 273 NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
332 Source<PrefModelAssociator>(this), 274 Source<PrefModelAssociator>(this),
333 NotificationService::NoDetails()); 275 NotificationService::NoDetails());
334 } 276 }
335 } 277 }
336 278
337 // Not implemented. 279 // Note: This will build a model of all preferences registered as syncable
338 void PrefModelAssociator::AbortAssociation() {} 280 // with user controlled data. We do not track any information for preferences
339 281 // not registered locally as syncable and do not inform the syncer of
340 bool PrefModelAssociator::CryptoReadyIfNecessary() { 282 // non-user controlled preferences.
341 // We only access the cryptographer while holding a transaction. 283 bool PrefModelAssociator::GetAllSyncData(syncable::ModelType type,
akalin 2011/05/19 00:58:45 You can make this function return SyncDataList dir
Nicolas Zea 2011/05/19 21:17:45 This would introduce a dependency on SyncData in t
akalin 2011/05/20 00:08:05 I think it's okay if there's a SyncData dependency
Nicolas Zea 2011/05/20 02:00:28 Done.
342 sync_api::ReadTransaction trans(sync_service_->GetUserShare()); 284 SyncDataList* current_data) {
343 syncable::ModelTypeSet encrypted_types; 285 DCHECK_EQ(PREFERENCES, type);
344 sync_service_->GetEncryptedDataTypes(&encrypted_types); 286 for (PreferenceSet::iterator iter = synced_preferences_.begin();
345 return encrypted_types.count(PREFERENCES) == 0 || 287 iter != synced_preferences_.end();
346 sync_service_->IsCryptographerReady(&trans); 288 ++iter) {
289 std::string name = *iter;
290 const PrefService::Preference* pref =
291 pref_service_->FindPreference(name.c_str());
292 SyncData sync_data;
293 if (!CreatePrefSyncData(name, *pref->GetValue(), &sync_data))
294 return false;
295 current_data->push_back(sync_data);
296 }
297 for (SyncDataMap::iterator iter = untracked_pref_sync_data_.begin();
298 iter != untracked_pref_sync_data_.end();
299 ++iter) {
300 current_data->push_back(iter->second);
301 }
302 return true;
347 } 303 }
348 304
349 void PrefModelAssociator::SetupSync( 305 void PrefModelAssociator::ProcessSyncEvents(const SyncEventList& event_list) {
350 ProfileSyncService* sync_service,
351 browser_sync::GenericChangeProcessor* change_processor) {
352 sync_service_ = sync_service;
353 change_processor_ = change_processor;
354 }
355
356 void PrefModelAssociator::ApplyChangesFromSync(
357 const sync_api::BaseTransaction* trans,
358 const sync_api::SyncManager::ChangeRecord* changes,
359 int change_count) {
360 if (!models_associated_) 306 if (!models_associated_)
361 return; 307 return;
362 AutoReset<bool> processing_changes(&processing_syncer_changes_, true); 308 AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
363 for (int i = 0; i < change_count; ++i) { 309 SyncEventList::const_iterator iter;
364 if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == 310 for (iter = event_list.begin(); iter != event_list.end(); ++iter) {
365 changes[i].action) { 311 DCHECK_EQ(PREFERENCES, iter->sync_data().GetDataType());
312
313 std::string name;
314 sync_pb::PreferenceSpecifics pref_specifics =
315 iter->sync_data().GetSpecifics().GetExtension(sync_pb::preference);
316 scoped_ptr<Value> value(ReadPreferenceSpecifics(pref_specifics,
317 &name));
318
319 if (iter->event_type() == SyncEvent::ACTION_DELETE) {
366 // We never delete preferences. 320 // We never delete preferences.
367 NOTREACHED(); 321 NOTREACHED();
akalin 2011/05/19 00:58:45 you can do: NOTREACHED() << "Attempted ..." sinc
Nicolas Zea 2011/05/19 21:17:45 Done.
322 LOG(ERROR) << "Attempted to process sync delete event for " << name
323 << ". Skipping.";
324 continue;
368 } 325 }
369 326
370 sync_api::ReadNode node(trans);
371 if (!node.InitByIdLookup(changes[i].id)) {
372 LOG(ERROR) << "Preference node lookup failed.";
373 return;
374 }
375 DCHECK(PREFERENCES == node.GetModelType());
376 std::string name;
377 sync_pb::PreferenceSpecifics pref_specifics =
378 node.GetPreferenceSpecifics();
379 scoped_ptr<Value> value(ReadPreferenceSpecifics(pref_specifics,
380 &name));
381 // Skip values we can't deserialize. 327 // Skip values we can't deserialize.
akalin 2011/05/19 00:58:45 I wonder if we should delete the sync data in this
Nicolas Zea 2011/05/19 21:17:45 Well, there's no real concept of deleting preferen
akalin 2011/05/20 00:08:05 I meant something like set the synced pref to a nu
Nicolas Zea 2011/05/20 02:00:28 Done.
382 if (!value.get()) 328 if (!value.get())
383 continue; 329 continue;
384 330
385 // It is possible that we may receive a change to a preference we do not 331 // It is possible that we may receive a change to a preference we do not
386 // want to sync. For example if the user is syncing a Mac client and a 332 // want to sync. For example if the user is syncing a Mac client and a
387 // Windows client, the Windows client does not support 333 // Windows client, the Windows client does not support
388 // kConfirmToQuitEnabled. Ignore updates from these preferences. 334 // kConfirmToQuitEnabled. Ignore updates from these preferences.
389 const char* pref_name = name.c_str(); 335 const char* pref_name = name.c_str();
akalin 2011/05/19 00:58:45 I guess this is another one of those corner cases.
Nicolas Zea 2011/05/19 21:17:45 Done.
390 if (!IsPrefRegistered(pref_name)) 336 if (!IsPrefRegistered(pref_name))
391 continue; 337 continue;
392 338
393 const PrefService::Preference* pref = 339 const PrefService::Preference* pref =
394 pref_service_->FindPreference(pref_name); 340 pref_service_->FindPreference(pref_name);
395 DCHECK(pref); 341 DCHECK(pref);
396 if (!pref->IsUserModifiable()) { 342 if (!pref->IsUserModifiable()) {
343 // This preference is controlled by policy, ignore for now, but keep
344 // the event around for possible later use.
345 untracked_pref_sync_data_[name] = iter->sync_data();
397 continue; 346 continue;
398 } 347 }
399 348
400 if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == 349 pref_service_->Set(pref_name, *value);
401 changes[i].action) {
402 pref_service_->ClearPref(pref_name);
403 } else {
404 pref_service_->Set(pref_name, *value);
405 350
406 // If this is a newly added node, associate. 351 // If this is a newly added node, associate.
407 if (sync_api::SyncManager::ChangeRecord::ACTION_ADD == 352 if (iter->event_type() == SyncEvent::ACTION_ADD) {
408 changes[i].action) { 353 synced_preferences_.insert(name);
409 Associate(pref, changes[i].id); 354 }
410 }
411 355
412 SendUpdateNotificationsIfNecessary(name); 356 SendUpdateNotificationsIfNecessary(name);
413 }
414 } 357 }
415 } 358 }
416 359
417 Value* PrefModelAssociator::ReadPreferenceSpecifics( 360 Value* PrefModelAssociator::ReadPreferenceSpecifics(
418 const sync_pb::PreferenceSpecifics& preference, 361 const sync_pb::PreferenceSpecifics& preference,
419 std::string* name) { 362 std::string* name) {
420 base::JSONReader reader; 363 base::JSONReader reader;
421 scoped_ptr<Value> value(reader.JsonToValue(preference.value(), false, false)); 364 scoped_ptr<Value> value(reader.JsonToValue(preference.value(), false, false));
422 if (!value.get()) { 365 if (!value.get()) {
423 std::string err = "Failed to deserialize preference value: " + 366 std::string err = "Failed to deserialize preference value: " +
424 reader.GetErrorMessage(); 367 reader.GetErrorMessage();
425 LOG(ERROR) << err; 368 LOG(ERROR) << err;
426 return NULL; 369 return NULL;
427 } 370 }
428 *name = preference.name(); 371 *name = preference.name();
429 return value.release(); 372 return value.release();
430 } 373 }
431 374
375 std::set<std::string> PrefModelAssociator::registered_preferences() const {
376 return registered_preferences_;
377 }
432 378
433 std::set<std::string> PrefModelAssociator::synced_preferences() const { 379 std::set<std::string> PrefModelAssociator::synced_preferences() const {
434 return synced_preferences_; 380 return synced_preferences_;
435 } 381 }
436 382
437 void PrefModelAssociator::RegisterPref(const char* name) { 383 void PrefModelAssociator::RegisterPref(const char* name) {
438 DCHECK(!models_associated_ && synced_preferences_.count(name) == 0); 384 DCHECK(!models_associated_ && registered_preferences_.count(name) == 0);
439 synced_preferences_.insert(name); 385 registered_preferences_.insert(name);
440 } 386 }
441 387
442 bool PrefModelAssociator::IsPrefRegistered(const char* name) { 388 bool PrefModelAssociator::IsPrefRegistered(const char* name) {
443 return synced_preferences_.count(name) > 0; 389 return registered_preferences_.count(name) > 0;
444 } 390 }
445 391
446 void PrefModelAssociator::ProcessPrefChange(const std::string& name) { 392 void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
447 if (processing_syncer_changes_) 393 if (processing_syncer_changes_)
448 return; // These are changes originating from us, ignore. 394 return; // These are changes originating from us, ignore.
449 395
450 // We only process changes if we've already associated models. 396 // We only process changes if we've already associated models.
451 if (!sync_service_ || !models_associated_) 397 if (!models_associated_)
452 return; 398 return;
453 399
454 const PrefService::Preference* preference = 400 const PrefService::Preference* preference =
455 pref_service_->FindPreference(name.c_str()); 401 pref_service_->FindPreference(name.c_str());
456 if (!IsPrefRegistered(name.c_str())) 402 if (!IsPrefRegistered(name.c_str()))
457 return; // We are not syncing this preference. 403 return; // We are not syncing this preference.
458 404
459 // The preference does not have a node. This can happen if the preference 405 SyncEventList events;
460 // held the default value at association time. Create one and associate.
461 int64 root_id;
462 if (!GetSyncIdForTaggedNode(syncable::ModelTypeToRootTag(PREFERENCES),
463 &root_id)) {
464 LOG(ERROR) << "Server did not create the top-level preferences node. We "
465 << "might be running against an out-of-date server.";
466 return;
467 }
468 406
469 int64 sync_id = GetSyncIdFromChromeId(name);
470 if (!preference->IsUserModifiable()) { 407 if (!preference->IsUserModifiable()) {
471 // If the preference is not currently user modifiable, disassociate, so that 408 // If the preference is not currently user modifiable, back up the
472 // if it becomes user modifiable me pick up the server value. 409 // previously synced value and remove it from our list of synced prefs.
473 Disassociate(sync_id); 410 if (synced_preferences_.count(name) > 0) {
411 synced_preferences_.erase(name);
412 SyncData sync_data;
413 if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) {
414 LOG(ERROR) << "Failed to update preference.";
415 return;
416 }
417 untracked_pref_sync_data_[name] = sync_data;
418 }
474 return; 419 return;
475 } 420 }
476 421
477 AutoReset<bool> processing_changes(&processing_syncer_changes_, true); 422 AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
478 sync_api::WriteTransaction trans(sync_service_->GetUserShare());
479 423
480 // Since we don't create sync nodes for preferences that are not under control 424 if (synced_preferences_.count(name) == 0) {
481 // of the user or still have their default value, this changed preference may 425 // This is a preference that changed locally but we were not syncing. This
482 // not have a sync node yet. If so, we create a node. Similarly, a preference 426 // happens when a preference was previously not user modifiable but now is,
483 // may become user-modifiable (e.g. due to laxer policy configuration), in 427 // or if it had a default value but the user set a custom one. We now care
484 // which case we also need to create a sync node and associate it. 428 // about the preference and must inform the syncer, as well as update our
485 if (sync_id == sync_api::kInvalidId) { 429 // own internal tracking.
486 sync_api::ReadNode root(&trans); 430 if (untracked_pref_sync_data_.count(name) > 0) {
487 if (!root.InitByIdLookup(root_id)) { 431 // We have sync data for this preference, merge it (this only happens
488 LOG(ERROR) << "Server did not create the top-level preferences node. We " 432 // when we went from policy-controlled to user controlled. Default values
489 << "might be running against an out-of-date server."; 433 // are always overwritten by syncer values).
434 InitPrefAndAssociate(untracked_pref_sync_data_[name], name, &events);
435 untracked_pref_sync_data_.erase(name);
436 } else {
437 InitPrefAndAssociate(SyncData(), name, &events);
438 }
439 } else {
440 // We're already syncing this preference, we just need to update the data.
441 SyncData sync_data;
442 if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) {
443 LOG(ERROR) << "Failed to update preference.";
490 return; 444 return;
491 } 445 }
492 InitPrefNodeAndAssociate(&trans, root, preference); 446 events.push_back(SyncEvent(SyncEvent::ACTION_UPDATE, sync_data));
493 } else {
494 sync_api::WriteNode node(&trans);
495 if (!node.InitByIdLookup(sync_id)) {
496 LOG(ERROR) << "Preference node lookup failed.";
497 return;
498 }
499
500 if (!WritePreferenceToNode(name, *preference->GetValue(), &node)) {
501 LOG(ERROR) << "Failed to update preference node.";
502 return;
503 }
504 } 447 }
448 sync_processor_->ProcessSyncEvents(events);
505 } 449 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698