| Index: chrome/browser/prefs/pref_model_associator.cc
|
| diff --git a/chrome/browser/prefs/pref_model_associator.cc b/chrome/browser/prefs/pref_model_associator.cc
|
| index 9875d77a8692875ce9f55928f961e0901d2f3ad9..5708a1c8338bfaf98f539e169d593fdfec41163c 100644
|
| --- a/chrome/browser/prefs/pref_model_associator.cc
|
| +++ b/chrome/browser/prefs/pref_model_associator.cc
|
| @@ -9,70 +9,65 @@
|
| #include "base/logging.h"
|
| #include "base/utf_string_conversions.h"
|
| #include "base/values.h"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "chrome/browser/sync/engine/syncapi.h"
|
| -#include "chrome/browser/sync/glue/generic_change_processor.h"
|
| -#include "chrome/browser/sync/profile_sync_service.h"
|
| +#include "chrome/browser/sync/api/sync_change.h"
|
| #include "chrome/browser/sync/protocol/preference_specifics.pb.h"
|
| #include "chrome/common/pref_names.h"
|
| -#include "content/browser/browser_thread.h"
|
| #include "content/common/json_value_serializer.h"
|
| #include "content/common/notification_service.h"
|
|
|
| using syncable::PREFERENCES;
|
|
|
| PrefModelAssociator::PrefModelAssociator()
|
| - : pref_service_(NULL),
|
| - sync_service_(NULL),
|
| - models_associated_(false),
|
| + : models_associated_(false),
|
| processing_syncer_changes_(false),
|
| - change_processor_(NULL) {
|
| + pref_service_(NULL),
|
| + sync_processor_(NULL) {
|
| }
|
|
|
| PrefModelAssociator::PrefModelAssociator(
|
| PrefService* pref_service)
|
| - : pref_service_(pref_service),
|
| - sync_service_(NULL),
|
| - models_associated_(false),
|
| + : models_associated_(false),
|
| processing_syncer_changes_(false),
|
| - change_processor_(NULL) {
|
| + pref_service_(pref_service),
|
| + sync_processor_(NULL) {
|
| DCHECK(CalledOnValidThread());
|
| }
|
|
|
| PrefModelAssociator::~PrefModelAssociator() {
|
| DCHECK(CalledOnValidThread());
|
| - change_processor_ = NULL;
|
| - sync_service_ = NULL;
|
| + sync_processor_ = NULL;
|
| pref_service_ = NULL;
|
| }
|
|
|
| -bool PrefModelAssociator::InitPrefNodeAndAssociate(
|
| - sync_api::WriteTransaction* trans,
|
| - const sync_api::BaseNode& root,
|
| - const PrefService::Preference* pref) {
|
| - DCHECK(pref);
|
| +void PrefModelAssociator::InitPrefAndAssociate(
|
| + const SyncData& sync_pref,
|
| + const std::string& pref_name,
|
| + SyncChangeList* sync_changes) {
|
| + const PrefService::Preference* pref =
|
| + pref_service_->FindPreference(pref_name.c_str());
|
| + VLOG(1) << "Associating preference " << pref_name;
|
| + if (!pref->IsUserModifiable()) {
|
| + // This preference is controlled by policy. We don't need sync it, but if
|
| + // there is sync data we want to track it for possible future use.
|
| + if (sync_pref.IsValid())
|
| + untracked_pref_sync_data_[pref_name] = sync_pref;
|
| + return;
|
| + }
|
|
|
| base::JSONReader reader;
|
| - std::string tag = pref->name();
|
| - sync_api::WriteNode node(trans);
|
| - if (node.InitByClientTagLookup(PREFERENCES, tag)) {
|
| - // The server has a value for the preference.
|
| - const sync_pb::PreferenceSpecifics& preference(
|
| - node.GetPreferenceSpecifics());
|
| - DCHECK_EQ(tag, preference.name());
|
| -
|
| - if (!pref->IsUserModifiable()) {
|
| - Associate(pref, node.GetId());
|
| - return true;
|
| - }
|
| + if (sync_pref.IsValid()) {
|
| + // The server has a value for the preference, we have to reconcile it with
|
| + // ours.
|
| + const sync_pb::PreferenceSpecifics& preference =
|
| + sync_pref.GetSpecifics().GetExtension(sync_pb::preference);
|
| + DCHECK_EQ(pref->name(), preference.name());
|
|
|
| scoped_ptr<Value> value(
|
| reader.JsonToValue(preference.value(), false, false));
|
| - std::string pref_name = preference.name();
|
| if (!value.get()) {
|
| LOG(ERROR) << "Failed to deserialize preference value: "
|
| << reader.GetErrorMessage();
|
| - return false;
|
| + return;
|
| }
|
|
|
| // Merge the server value of this preference with the local value.
|
| @@ -92,137 +87,88 @@ bool PrefModelAssociator::InitPrefNodeAndAssociate(
|
|
|
| SendUpdateNotificationsIfNecessary(pref_name);
|
|
|
| - // If the merge resulted in an updated value, write it back to
|
| - // the sync node.
|
| - if (!value->Equals(new_value.get()) &&
|
| - !WritePreferenceToNode(pref->name(), *new_value, &node)) {
|
| - return false;
|
| + // If the merge resulted in an updated value, inform the syncer.
|
| + if (!value->Equals(new_value.get())) {
|
| + SyncData sync_data;
|
| + if (!CreatePrefSyncData(pref->name(), *new_value, &sync_data)) {
|
| + LOG(ERROR) << "Failed to update preference.";
|
| + return;
|
| + }
|
| + sync_changes->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
|
| }
|
| - Associate(pref, node.GetId());
|
| } else if (pref->IsUserControlled()) {
|
| - // The server doesn't have a value, but we have a user-controlled value,
|
| - // so we push it to the server.
|
| - sync_api::WriteNode write_node(trans);
|
| - if (!write_node.InitUniqueByCreation(PREFERENCES, root, tag)) {
|
| - LOG(ERROR) << "Failed to create preference sync node.";
|
| - return false;
|
| + // The server does not know about this preference and should be added
|
| + // to the syncer's database.
|
| + SyncData sync_data;
|
| + if (!CreatePrefSyncData(pref->name(), *pref->GetValue(), &sync_data)) {
|
| + LOG(ERROR) << "Failed to update preference.";
|
| + return;
|
| }
|
| -
|
| - // Update the sync node with the local value for this preference.
|
| - if (!WritePreferenceToNode(pref->name(), *pref->GetValue(), &write_node))
|
| - return false;
|
| -
|
| - Associate(pref, write_node.GetId());
|
| + sync_changes->push_back(SyncChange(SyncChange::ACTION_ADD, sync_data));
|
| } else {
|
| - // This preference is handled by policy, not the user, and therefore
|
| - // we do not associate it.
|
| + // This pref has a default value, we can ignore it. Once it gets changed,
|
| + // we'll send the new custom value to the syncer.
|
| + return;
|
| }
|
|
|
| - return true;
|
| + // Make sure we add it to our list of synced preferences so we know what
|
| + // the server is aware of.
|
| + synced_preferences_.insert(pref_name);
|
| + return;
|
| }
|
|
|
| -bool PrefModelAssociator::AssociateModels() {
|
| +bool PrefModelAssociator::MergeDataAndStartSyncing(
|
| + syncable::ModelType type,
|
| + const SyncDataList& initial_sync_data,
|
| + SyncChangeProcessor* sync_processor) {
|
| + DCHECK_EQ(type, PREFERENCES);
|
| DCHECK(CalledOnValidThread());
|
| + DCHECK(!sync_processor_);
|
| + sync_processor_ = sync_processor;
|
| +
|
| + SyncChangeList new_changes;
|
| + std::set<std::string> remaining_preferences = registered_preferences_;
|
| +
|
| + // Go through and check for all preferences we care about that sync already
|
| + // knows about.
|
| + for (SyncDataList::const_iterator sync_iter = initial_sync_data.begin();
|
| + sync_iter != initial_sync_data.end();
|
| + ++sync_iter) {
|
| + DCHECK_EQ(PREFERENCES, sync_iter->GetDataType());
|
| + std::string sync_pref_name = sync_iter->GetSpecifics().
|
| + GetExtension(sync_pb::preference).name();
|
| + if (remaining_preferences.count(sync_pref_name) == 0) {
|
| + // We're not syncing this preference locally, ignore the sync data.
|
| + // TODO(zea): Eventually we want to be able to have the syncable service
|
| + // reconstruct all sync data for it's datatype (therefore having
|
| + // GetAllSyncData be a complete representation). We should store this data
|
| + // somewhere, even if we don't use it.
|
| + continue;
|
| + }
|
|
|
| - int64 root_id;
|
| - if (!GetSyncIdForTaggedNode(syncable::ModelTypeToRootTag(PREFERENCES),
|
| - &root_id)) {
|
| - LOG(ERROR) << "Server did not create the top-level preferences node. We "
|
| - << "might be running against an out-of-date server.";
|
| - return false;
|
| + remaining_preferences.erase(sync_pref_name);
|
| + InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes);
|
| }
|
|
|
| - sync_api::WriteTransaction trans(sync_service_->GetUserShare());
|
| - sync_api::ReadNode root(&trans);
|
| - if (!root.InitByIdLookup(root_id)) {
|
| - LOG(ERROR) << "Server did not create the top-level preferences node. We "
|
| - << "might be running against an out-of-date server.";
|
| - return false;
|
| + // Go through and build sync data for any remaining preferences.
|
| + for (std::set<std::string>::iterator pref_name_iter =
|
| + remaining_preferences.begin();
|
| + pref_name_iter != remaining_preferences.end();
|
| + ++pref_name_iter) {
|
| + InitPrefAndAssociate(SyncData(), *pref_name_iter, &new_changes);
|
| }
|
|
|
| - for (std::set<std::string>::iterator it = synced_preferences_.begin();
|
| - it != synced_preferences_.end(); ++it) {
|
| - std::string name = *it;
|
| - const PrefService::Preference* pref =
|
| - pref_service_->FindPreference(name.c_str());
|
| - VLOG(1) << "Associating preference " << name;
|
| - DCHECK(pref);
|
| - if (!pref->IsUserModifiable())
|
| - continue; // We don't sync preferences the user cannot change.
|
| - InitPrefNodeAndAssociate(&trans, root, pref);
|
| - }
|
| + // Push updates to sync.
|
| + sync_processor_->ProcessSyncChanges(new_changes);
|
| models_associated_ = true;
|
| return true;
|
| }
|
|
|
| -bool PrefModelAssociator::DisassociateModels() {
|
| - id_map_.clear();
|
| - id_map_inverse_.clear();
|
| +void PrefModelAssociator::StopSyncing(syncable::ModelType type) {
|
| + DCHECK_EQ(type, PREFERENCES);
|
| models_associated_ = false;
|
| - return true;
|
| -}
|
| -
|
| -bool PrefModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
|
| - DCHECK(has_nodes);
|
| - *has_nodes = false;
|
| - int64 preferences_sync_id;
|
| - if (!GetSyncIdForTaggedNode(syncable::ModelTypeToRootTag(PREFERENCES),
|
| - &preferences_sync_id)) {
|
| - LOG(ERROR) << "Server did not create the top-level preferences node. We "
|
| - << "might be running against an out-of-date server.";
|
| - return false;
|
| - }
|
| - sync_api::ReadTransaction trans(sync_service_->GetUserShare());
|
| -
|
| - sync_api::ReadNode preferences_node(&trans);
|
| - if (!preferences_node.InitByIdLookup(preferences_sync_id)) {
|
| - LOG(ERROR) << "Server did not create the top-level preferences node. We "
|
| - << "might be running against an out-of-date server.";
|
| - return false;
|
| - }
|
| -
|
| - // The sync model has user created nodes if the preferences folder has any
|
| - // children.
|
| - *has_nodes = sync_api::kInvalidId != preferences_node.GetFirstChildId();
|
| - return true;
|
| -}
|
| -
|
| -int64 PrefModelAssociator::GetSyncIdFromChromeId(
|
| - const std::string& preference_name) {
|
| - PreferenceNameToSyncIdMap::const_iterator iter =
|
| - id_map_.find(preference_name);
|
| - return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
|
| -}
|
| -
|
| -void PrefModelAssociator::Associate(
|
| - const PrefService::Preference* preference, int64 sync_id) {
|
| - DCHECK(CalledOnValidThread());
|
| -
|
| - std::string name = preference->name();
|
| - DCHECK_NE(sync_api::kInvalidId, sync_id);
|
| - DCHECK_EQ(0U, id_map_.count(name));
|
| - DCHECK_EQ(0U, id_map_inverse_.count(sync_id));
|
| - id_map_[name] = sync_id;
|
| - id_map_inverse_[sync_id] = name;
|
| -}
|
| -
|
| -void PrefModelAssociator::Disassociate(int64 sync_id) {
|
| - DCHECK(CalledOnValidThread());
|
| - SyncIdToPreferenceNameMap::iterator iter = id_map_inverse_.find(sync_id);
|
| - if (iter == id_map_inverse_.end())
|
| - return;
|
| - id_map_.erase(iter->second);
|
| - id_map_inverse_.erase(iter);
|
| -}
|
| -
|
| -bool PrefModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
|
| - int64* sync_id) {
|
| - sync_api::ReadTransaction trans(sync_service_->GetUserShare());
|
| - sync_api::ReadNode sync_node(&trans);
|
| - if (!sync_node.InitByTagLookup(tag.c_str()))
|
| - return false;
|
| - *sync_id = sync_node.GetId();
|
| - return true;
|
| + sync_processor_ = NULL;
|
| + untracked_pref_sync_data_.clear();
|
| }
|
|
|
| Value* PrefModelAssociator::MergePreference(
|
| @@ -244,23 +190,25 @@ Value* PrefModelAssociator::MergePreference(
|
| return server_value.DeepCopy();
|
| }
|
|
|
| -bool PrefModelAssociator::WritePreferenceToNode(
|
| +bool PrefModelAssociator::CreatePrefSyncData(
|
| const std::string& name,
|
| const Value& value,
|
| - sync_api::WriteNode* node) {
|
| + SyncData* sync_data) {
|
| std::string serialized;
|
| + // TODO(zea): consider JSONWriter::Write since you don't have to check
|
| + // failures to deserialize.
|
| JSONStringValueSerializer json(&serialized);
|
| if (!json.Serialize(value)) {
|
| LOG(ERROR) << "Failed to serialize preference value.";
|
| return false;
|
| }
|
|
|
| - sync_pb::PreferenceSpecifics preference;
|
| - preference.set_name(name);
|
| - preference.set_value(serialized);
|
| - node->SetPreferenceSpecifics(preference);
|
| - // TODO(viettrungluu): eliminate conversion (it's temporary)
|
| - node->SetTitle(UTF8ToWide(name));
|
| + sync_pb::EntitySpecifics specifics;
|
| + sync_pb::PreferenceSpecifics* pref_specifics = specifics.MutableExtension(
|
| + sync_pb::preference);
|
| + pref_specifics->set_name(name);
|
| + pref_specifics->set_value(serialized);
|
| + *sync_data = SyncData::CreateLocalData(name, specifics);
|
| return true;
|
| }
|
|
|
| @@ -334,51 +282,58 @@ void PrefModelAssociator::SendUpdateNotificationsIfNecessary(
|
| }
|
| }
|
|
|
| -// Not implemented.
|
| -void PrefModelAssociator::AbortAssociation() {}
|
| -
|
| -bool PrefModelAssociator::CryptoReadyIfNecessary() {
|
| - // We only access the cryptographer while holding a transaction.
|
| - sync_api::ReadTransaction trans(sync_service_->GetUserShare());
|
| - syncable::ModelTypeSet encrypted_types;
|
| - sync_service_->GetEncryptedDataTypes(&encrypted_types);
|
| - return encrypted_types.count(PREFERENCES) == 0 ||
|
| - sync_service_->IsCryptographerReady(&trans);
|
| -}
|
| -
|
| -void PrefModelAssociator::SetupSync(
|
| - ProfileSyncService* sync_service,
|
| - browser_sync::GenericChangeProcessor* change_processor) {
|
| - sync_service_ = sync_service;
|
| - change_processor_ = change_processor;
|
| +// Note: This will build a model of all preferences registered as syncable
|
| +// with user controlled data. We do not track any information for preferences
|
| +// not registered locally as syncable and do not inform the syncer of
|
| +// non-user controlled preferences.
|
| +SyncDataList PrefModelAssociator::GetAllSyncData(syncable::ModelType type)
|
| + const {
|
| + DCHECK_EQ(PREFERENCES, type);
|
| + SyncDataList current_data;
|
| + for (PreferenceSet::const_iterator iter = synced_preferences_.begin();
|
| + iter != synced_preferences_.end();
|
| + ++iter) {
|
| + std::string name = *iter;
|
| + const PrefService::Preference* pref =
|
| + pref_service_->FindPreference(name.c_str());
|
| + SyncData sync_data;
|
| + if (!CreatePrefSyncData(name, *pref->GetValue(), &sync_data))
|
| + continue;
|
| + current_data.push_back(sync_data);
|
| + }
|
| + for (SyncDataMap::const_iterator iter = untracked_pref_sync_data_.begin();
|
| + iter != untracked_pref_sync_data_.end();
|
| + ++iter) {
|
| + current_data.push_back(iter->second);
|
| + }
|
| + return current_data;
|
| }
|
|
|
| -void PrefModelAssociator::ApplyChangesFromSync(
|
| - const sync_api::BaseTransaction* trans,
|
| - const sync_api::SyncManager::ChangeRecord* changes,
|
| - int change_count) {
|
| +void PrefModelAssociator::ProcessSyncChanges(
|
| + const SyncChangeList& change_list) {
|
| if (!models_associated_)
|
| return;
|
| AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
|
| - for (int i = 0; i < change_count; ++i) {
|
| - if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
|
| - changes[i].action) {
|
| - // We never delete preferences.
|
| - NOTREACHED();
|
| - }
|
| + SyncChangeList::const_iterator iter;
|
| + for (iter = change_list.begin(); iter != change_list.end(); ++iter) {
|
| + DCHECK_EQ(PREFERENCES, iter->sync_data().GetDataType());
|
|
|
| - sync_api::ReadNode node(trans);
|
| - if (!node.InitByIdLookup(changes[i].id)) {
|
| - LOG(ERROR) << "Preference node lookup failed.";
|
| - return;
|
| - }
|
| - DCHECK(PREFERENCES == node.GetModelType());
|
| std::string name;
|
| sync_pb::PreferenceSpecifics pref_specifics =
|
| - node.GetPreferenceSpecifics();
|
| + iter->sync_data().GetSpecifics().GetExtension(sync_pb::preference);
|
| scoped_ptr<Value> value(ReadPreferenceSpecifics(pref_specifics,
|
| &name));
|
| +
|
| + if (iter->change_type() == SyncChange::ACTION_DELETE) {
|
| + // We never delete preferences.
|
| + NOTREACHED() << "Attempted to process sync delete change for " << name
|
| + << ". Skipping.";
|
| + continue;
|
| + }
|
| +
|
| // Skip values we can't deserialize.
|
| + // TODO(zea): consider taking some further action such as erasing the bad
|
| + // data.
|
| if (!value.get())
|
| continue;
|
|
|
| @@ -394,23 +349,20 @@ void PrefModelAssociator::ApplyChangesFromSync(
|
| pref_service_->FindPreference(pref_name);
|
| DCHECK(pref);
|
| if (!pref->IsUserModifiable()) {
|
| + // This preference is controlled by policy, ignore for now, but keep
|
| + // the data around for possible later use.
|
| + untracked_pref_sync_data_[name] = iter->sync_data();
|
| continue;
|
| }
|
|
|
| - if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
|
| - changes[i].action) {
|
| - pref_service_->ClearPref(pref_name);
|
| - } else {
|
| - pref_service_->Set(pref_name, *value);
|
| -
|
| - // If this is a newly added node, associate.
|
| - if (sync_api::SyncManager::ChangeRecord::ACTION_ADD ==
|
| - changes[i].action) {
|
| - Associate(pref, changes[i].id);
|
| - }
|
| + pref_service_->Set(pref_name, *value);
|
|
|
| - SendUpdateNotificationsIfNecessary(name);
|
| + // If this is a newly added node, associate.
|
| + if (iter->change_type() == SyncChange::ACTION_ADD) {
|
| + synced_preferences_.insert(name);
|
| }
|
| +
|
| + SendUpdateNotificationsIfNecessary(name);
|
| }
|
| }
|
|
|
| @@ -429,18 +381,21 @@ Value* PrefModelAssociator::ReadPreferenceSpecifics(
|
| return value.release();
|
| }
|
|
|
| +std::set<std::string> PrefModelAssociator::registered_preferences() const {
|
| + return registered_preferences_;
|
| +}
|
|
|
| std::set<std::string> PrefModelAssociator::synced_preferences() const {
|
| return synced_preferences_;
|
| }
|
|
|
| void PrefModelAssociator::RegisterPref(const char* name) {
|
| - DCHECK(!models_associated_ && synced_preferences_.count(name) == 0);
|
| - synced_preferences_.insert(name);
|
| + DCHECK(!models_associated_ && registered_preferences_.count(name) == 0);
|
| + registered_preferences_.insert(name);
|
| }
|
|
|
| bool PrefModelAssociator::IsPrefRegistered(const char* name) {
|
| - return synced_preferences_.count(name) > 0;
|
| + return registered_preferences_.count(name) > 0;
|
| }
|
|
|
| void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
|
| @@ -448,7 +403,7 @@ void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
|
| return; // These are changes originating from us, ignore.
|
|
|
| // We only process changes if we've already associated models.
|
| - if (!sync_service_ || !models_associated_)
|
| + if (!models_associated_)
|
| return;
|
|
|
| const PrefService::Preference* preference =
|
| @@ -456,50 +411,48 @@ void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
|
| if (!IsPrefRegistered(name.c_str()))
|
| return; // We are not syncing this preference.
|
|
|
| - // The preference does not have a node. This can happen if the preference
|
| - // held the default value at association time. Create one and associate.
|
| - int64 root_id;
|
| - if (!GetSyncIdForTaggedNode(syncable::ModelTypeToRootTag(PREFERENCES),
|
| - &root_id)) {
|
| - LOG(ERROR) << "Server did not create the top-level preferences node. We "
|
| - << "might be running against an out-of-date server.";
|
| - return;
|
| - }
|
| + SyncChangeList changes;
|
|
|
| - int64 sync_id = GetSyncIdFromChromeId(name);
|
| if (!preference->IsUserModifiable()) {
|
| - // If the preference is not currently user modifiable, disassociate, so that
|
| - // if it becomes user modifiable me pick up the server value.
|
| - Disassociate(sync_id);
|
| + // If the preference is not currently user modifiable, back up the
|
| + // previously synced value and remove it from our list of synced prefs.
|
| + if (synced_preferences_.count(name) > 0) {
|
| + synced_preferences_.erase(name);
|
| + SyncData sync_data;
|
| + if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) {
|
| + LOG(ERROR) << "Failed to update preference.";
|
| + return;
|
| + }
|
| + untracked_pref_sync_data_[name] = sync_data;
|
| + }
|
| return;
|
| }
|
|
|
| AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
|
| - sync_api::WriteTransaction trans(sync_service_->GetUserShare());
|
| -
|
| - // Since we don't create sync nodes for preferences that are not under control
|
| - // of the user or still have their default value, this changed preference may
|
| - // not have a sync node yet. If so, we create a node. Similarly, a preference
|
| - // may become user-modifiable (e.g. due to laxer policy configuration), in
|
| - // which case we also need to create a sync node and associate it.
|
| - if (sync_id == sync_api::kInvalidId) {
|
| - sync_api::ReadNode root(&trans);
|
| - if (!root.InitByIdLookup(root_id)) {
|
| - LOG(ERROR) << "Server did not create the top-level preferences node. We "
|
| - << "might be running against an out-of-date server.";
|
| - return;
|
| +
|
| + if (synced_preferences_.count(name) == 0) {
|
| + // This is a preference that changed locally but we were not syncing. This
|
| + // happens when a preference was previously not user modifiable but now is,
|
| + // or if it had a default value but the user set a custom one. We now care
|
| + // about the preference and must inform the syncer, as well as update our
|
| + // own internal tracking.
|
| + if (untracked_pref_sync_data_.count(name) > 0) {
|
| + // We have sync data for this preference, merge it (this only happens
|
| + // when we went from policy-controlled to user controlled. Default values
|
| + // are always overwritten by syncer values).
|
| + InitPrefAndAssociate(untracked_pref_sync_data_[name], name, &changes);
|
| + untracked_pref_sync_data_.erase(name);
|
| + } else {
|
| + InitPrefAndAssociate(SyncData(), name, &changes);
|
| }
|
| - InitPrefNodeAndAssociate(&trans, root, preference);
|
| } else {
|
| - sync_api::WriteNode node(&trans);
|
| - if (!node.InitByIdLookup(sync_id)) {
|
| - LOG(ERROR) << "Preference node lookup failed.";
|
| - return;
|
| - }
|
| -
|
| - if (!WritePreferenceToNode(name, *preference->GetValue(), &node)) {
|
| - LOG(ERROR) << "Failed to update preference node.";
|
| + // We're already syncing this preference, we just need to update the data.
|
| + SyncData sync_data;
|
| + if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) {
|
| + LOG(ERROR) << "Failed to update preference.";
|
| return;
|
| }
|
| + changes.push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
|
| }
|
| + sync_processor_->ProcessSyncChanges(changes);
|
| }
|
|
|