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

Unified Diff: chrome/browser/password_manager/password_syncable_service.cc

Issue 139443004: Password sync refactoring: implemented ProcessSyncChanges() and GetAllSyncData() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added DCHECK() into ProcessSyncChanges() Created 6 years, 10 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
Index: chrome/browser/password_manager/password_syncable_service.cc
diff --git a/chrome/browser/password_manager/password_syncable_service.cc b/chrome/browser/password_manager/password_syncable_service.cc
index ef127e6325be2d5e0367867dcfe24e8de1154714..4bee8dcfb921b752c302c982e6799be3a864e1ca 100644
--- a/chrome/browser/password_manager/password_syncable_service.cc
+++ b/chrome/browser/password_manager/password_syncable_service.cc
@@ -15,10 +15,17 @@
namespace {
+// Describes the result of merging sync and local passwords.
+enum MergeResult {
+ IDENTICAL,
+ SYNC,
+ LOCAL,
+};
+
// Merges the local and sync passwords and outputs the entry into
-// |new_password_form|. Returns true if the local and the sync passwords differ.
-// Returns false if they are identical.
-bool MergeLocalAndSyncPasswords(
+// |new_password_form|. Returns MergeResult value describing the content of
+// |new_password_form|.
+MergeResult MergeLocalAndSyncPasswords(
const sync_pb::PasswordSpecificsData& password_specifics,
const autofill::PasswordForm& password_form,
autofill::PasswordForm* new_password_form) {
@@ -40,18 +47,18 @@ bool MergeLocalAndSyncPasswords(
password_form.date_created.ToInternalValue() ==
password_specifics.date_created() &&
password_form.blacklisted_by_user == password_specifics.blacklisted()) {
- return false;
+ return IDENTICAL;
}
// If the passwords differ, take the one that was created more recently.
if (base::Time::FromInternalValue(password_specifics.date_created()) <=
password_form.date_created) {
*new_password_form = password_form;
- } else {
- PasswordFromSpecifics(password_specifics, new_password_form);
+ return LOCAL;
}
- return true;
+ PasswordFromSpecifics(password_specifics, new_password_form);
+ return SYNC;
}
std::string MakePasswordSyncTag(const std::string& origin_url,
@@ -114,30 +121,19 @@ syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing(
sync_error_factory_ = sync_error_factory.Pass();
sync_processor_ = sync_processor.Pass();
+ // We add all the db entries as |new_local_entries| initially. During model
+ // association entries that match a sync entry will be removed and this list
+ // will only contain entries that are not in sync.
ScopedVector<autofill::PasswordForm> password_entries;
- if (!password_store_->FillAutofillableLogins(&password_entries.get())) {
- // Password store often fails to load passwords. Track failures with UMA.
- // (http://crbug.com/249000)
- UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad",
- syncer::PASSWORDS,
- syncer::MODEL_TYPE_COUNT);
+ PasswordEntryMap new_local_entries;
+ if (!ReadFromPasswordStore(&password_entries, &new_local_entries)) {
+ DCHECK(sync_error_factory_);
merge_result.set_error(sync_error_factory_->CreateAndUploadError(
FROM_HERE,
"Failed to get passwords from store."));
return merge_result;
}
- PasswordEntryMap new_local_entries;
- for (PasswordForms::iterator it = password_entries.begin();
- it != password_entries.end(); ++it) {
- autofill::PasswordForm* password_form = *it;
- // We add all the db entries as |new_local_entries| initially. During
- // model association entries that match a sync entry will be
- // removed and this list will only contain entries that are not in sync.
- new_local_entries.insert(
- std::make_pair(MakePasswordSyncTag(*password_form), password_form));
- }
-
merge_result.set_num_items_before_association(new_local_entries.size());
// List that contains the entries that are known only to sync.
@@ -160,7 +156,8 @@ syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing(
}
WriteToPasswordStore(new_sync_entries.get(),
- updated_sync_entries.get());
+ updated_sync_entries.get(),
+ PasswordForms());
merge_result.set_num_items_after_association(
merge_result.num_items_before_association() + new_sync_entries.size());
@@ -190,18 +187,83 @@ void PasswordSyncableService::StopSyncing(syncer::ModelType type) {
syncer::SyncDataList PasswordSyncableService::GetAllSyncData(
syncer::ModelType type) const {
+ DCHECK_EQ(syncer::PASSWORDS, type);
+ ScopedVector<autofill::PasswordForm> password_entries;
+ ReadFromPasswordStore(&password_entries, NULL);
+
syncer::SyncDataList sync_data;
+ for (PasswordForms::iterator it = password_entries.begin();
+ it != password_entries.end(); ++it) {
+ sync_data.push_back(SyncDataFromPassword(**it));
+ }
return sync_data;
}
syncer::SyncError PasswordSyncableService::ProcessSyncChanges(
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) {
- syncer::SyncError error(FROM_HERE,
- syncer::SyncError::UNRECOVERABLE_ERROR,
- "Password Syncable Service Not Implemented.",
- syncer::PASSWORDS);
- return error;
+ // The |db_entries_map| and associated vectors are filled only in case of
+ // update change.
+ PasswordEntryMap db_entries_map;
+ ScopedVector<autofill::PasswordForm> password_db_entries;
+ ScopedVector<autofill::PasswordForm> new_sync_entries;
+ ScopedVector<autofill::PasswordForm> updated_sync_entries;
+ ScopedVector<autofill::PasswordForm> deleted_entries;
+ bool has_read_passwords = false;
+
+ for (syncer::SyncChangeList::const_iterator it = change_list.begin();
+ it != change_list.end();
+ ++it) {
+ switch (it->change_type()) {
+ case syncer::SyncChange::ACTION_ADD: {
+ const sync_pb::EntitySpecifics& specifics =
+ it->sync_data().GetSpecifics();
+ new_sync_entries.push_back(new autofill::PasswordForm);
+ PasswordFromSpecifics(specifics.password().client_only_encrypted_data(),
+ new_sync_entries.back());
+ break;
+ }
+ case syncer::SyncChange::ACTION_UPDATE: {
+ if (!has_read_passwords) {
+ if (ReadFromPasswordStore(&password_db_entries,
+ &db_entries_map)) {
+ has_read_passwords = true;
+ } else {
+ return sync_error_factory_->CreateAndUploadError(
+ FROM_HERE,
+ "Failed to get passwords from store.");
+ }
+ }
+ syncer::SyncChangeList sync_changes;
+
+ CreateOrUpdateEntry(it->sync_data(),
+ &db_entries_map,
+ &new_sync_entries,
+ &updated_sync_entries,
+ &sync_changes);
+ DCHECK(sync_changes.empty());
+ break;
+ }
+
+ case syncer::SyncChange::ACTION_DELETE: {
+ const sync_pb::EntitySpecifics& specifics =
+ it->sync_data().GetSpecifics();
+ const sync_pb::PasswordSpecificsData& password_specifics(
+ specifics.password().client_only_encrypted_data());
+ deleted_entries.push_back(new autofill::PasswordForm);
+ PasswordFromSpecifics(password_specifics, deleted_entries.back());
+ break;
+ }
+ case syncer::SyncChange::ACTION_INVALID:
+ return sync_error_factory_->CreateAndUploadError(
+ FROM_HERE,
+ "Failed to process sync changes for passwords datatype.");
+ }
+ }
+ WriteToPasswordStore(new_sync_entries.get(),
+ updated_sync_entries.get(),
+ deleted_entries.get());
+ return syncer::SyncError();
}
void PasswordSyncableService::ActOnPasswordStoreChanges(
@@ -220,9 +282,37 @@ void PasswordSyncableService::ActOnPasswordStoreChanges(
sync_processor_->ProcessSyncChanges(FROM_HERE, sync_changes);
}
+bool PasswordSyncableService::ReadFromPasswordStore(
+ ScopedVector<autofill::PasswordForm>* password_entries,
+ PasswordEntryMap* passwords_entry_map) const {
+ DCHECK(password_entries);
+ if (!password_store_->FillAutofillableLogins(&password_entries->get()) ||
+ !password_store_->FillBlacklistLogins(&password_entries->get())) {
+ // Password store often fails to load passwords. Track failures with UMA.
+ // (http://crbug.com/249000)
+ UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad",
+ ModelTypeToHistogramInt(syncer::PASSWORDS),
+ syncer::MODEL_TYPE_COUNT);
+ return false;
+ }
+
+ if (!passwords_entry_map)
+ return true;
+
+ for (PasswordForms::iterator it = password_entries->begin();
+ it != password_entries->end(); ++it) {
+ autofill::PasswordForm* password_form = *it;
+ passwords_entry_map->insert(
+ std::make_pair(MakePasswordSyncTag(*password_form), password_form));
+ }
+
+ return true;
+}
+
void PasswordSyncableService::WriteToPasswordStore(
const PasswordForms& new_entries,
- const PasswordForms& updated_entries) {
+ const PasswordForms& updated_entries,
+ const PasswordForms& deleted_entries) {
PasswordStoreChangeList changes;
for (std::vector<autofill::PasswordForm*>::const_iterator it =
new_entries.begin();
@@ -238,6 +328,13 @@ void PasswordSyncableService::WriteToPasswordStore(
AppendChanges(password_store_->UpdateLoginImpl(**it), &changes);
}
+ for (std::vector<autofill::PasswordForm*>::const_iterator it =
+ deleted_entries.begin();
+ it != deleted_entries.end();
+ ++it) {
+ AppendChanges(password_store_->RemoveLoginImpl(**it), &changes);
+ }
+
// We have to notify password store observers of the change by hand since
// we use internal password store interfaces to make changes synchronously.
NotifyPasswordStoreOfLoginChanges(changes);
@@ -272,18 +369,20 @@ void PasswordSyncableService::CreateOrUpdateEntry(
// The entry is in password store. If the entries are not identical, then
// the entries need to be merged.
scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm);
- if (MergeLocalAndSyncPasswords(password_specifics,
- *existing_local_entry_iter->second,
- new_password.get())) {
- // Rather than checking which database -- sync or local -- needs updating,
- // simply push an update to both. This will end up being a noop for the
- // database that didn't need an update.
- updated_db_entries->push_back(
- syncer::SyncChange(FROM_HERE,
- syncer::SyncChange::ACTION_UPDATE,
- SyncDataFromPassword(*new_password)));
-
- updated_sync_entries->push_back(new_password.release());
+ switch (MergeLocalAndSyncPasswords(password_specifics,
+ *existing_local_entry_iter->second,
+ new_password.get())) {
+ case IDENTICAL:
+ break;
+ case SYNC:
+ updated_sync_entries->push_back(new_password.release());
+ break;
+ case LOCAL:
+ updated_db_entries->push_back(
+ syncer::SyncChange(FROM_HERE,
+ syncer::SyncChange::ACTION_UPDATE,
+ SyncDataFromPassword(*new_password)));
+ break;
}
// Remove the entry from the entry map to indicate a match has been found.
// Entries that remain in the map at the end of associating all sync entries

Powered by Google App Engine
This is Rietveld 408576698