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

Unified 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: Rebase and fix compile 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/prefs/pref_model_associator.h ('k') | chrome/browser/prefs/pref_service.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
}
« no previous file with comments | « chrome/browser/prefs/pref_model_associator.h ('k') | chrome/browser/prefs/pref_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698