| Index: chrome/browser/sync/glue/password_model_associator.cc
|
| diff --git a/chrome/browser/sync/glue/password_model_associator.cc b/chrome/browser/sync/glue/password_model_associator.cc
|
| index 3551be56260c8d8478d40e242431c3e5757e9ab6..fd4daa1f2d63b8bb21a120424d279f2bcabe180f 100644
|
| --- a/chrome/browser/sync/glue/password_model_associator.cc
|
| +++ b/chrome/browser/sync/glue/password_model_associator.cc
|
| @@ -45,14 +45,9 @@ bool PasswordModelAssociator::AssociateModels() {
|
| abort_association_pending_ = false;
|
| }
|
|
|
| - sync_api::WriteTransaction trans(sync_service_->GetUserShare());
|
| - sync_api::ReadNode password_root(&trans);
|
| - if (!password_root.InitByTagLookup(kPasswordTag)) {
|
| - LOG(ERROR) << "Server did not create the top-level password node. We "
|
| - << "might be running against an out-of-date server.";
|
| - return false;
|
| - }
|
| -
|
| + // We must not be holding a transaction when we interact with the password
|
| + // store, as it can post tasks to the UI thread which can itself be blocked
|
| + // on our transaction, resulting in deadlock. (http://crbug.com/70658)
|
| std::vector<webkit_glue::PasswordForm*> passwords;
|
| if (!password_store_->FillAutofillableLogins(&passwords) ||
|
| !password_store_->FillBlacklistLogins(&passwords)) {
|
| @@ -64,76 +59,89 @@ bool PasswordModelAssociator::AssociateModels() {
|
| std::set<std::string> current_passwords;
|
| PasswordVector new_passwords;
|
| PasswordVector updated_passwords;
|
| -
|
| - for (std::vector<webkit_glue::PasswordForm*>::iterator ix = passwords.begin();
|
| - ix != passwords.end(); ++ix) {
|
| - if (IsAbortPending())
|
| + {
|
| + sync_api::WriteTransaction trans(sync_service_->GetUserShare());
|
| + sync_api::ReadNode password_root(&trans);
|
| + if (!password_root.InitByTagLookup(kPasswordTag)) {
|
| + LOG(ERROR) << "Server did not create the top-level password node. We "
|
| + << "might be running against an out-of-date server.";
|
| return false;
|
| - std::string tag = MakeTag(**ix);
|
| -
|
| - sync_api::ReadNode node(&trans);
|
| - if (node.InitByClientTagLookup(syncable::PASSWORDS, tag)) {
|
| - const sync_pb::PasswordSpecificsData& password =
|
| - node.GetPasswordSpecifics();
|
| - DCHECK_EQ(tag, MakeTag(password));
|
| + }
|
|
|
| - webkit_glue::PasswordForm new_password;
|
| + for (std::vector<webkit_glue::PasswordForm*>::iterator ix =
|
| + passwords.begin();
|
| + ix != passwords.end(); ++ix) {
|
| + if (IsAbortPending())
|
| + return false;
|
| + std::string tag = MakeTag(**ix);
|
| +
|
| + sync_api::ReadNode node(&trans);
|
| + if (node.InitByClientTagLookup(syncable::PASSWORDS, tag)) {
|
| + const sync_pb::PasswordSpecificsData& password =
|
| + node.GetPasswordSpecifics();
|
| + DCHECK_EQ(tag, MakeTag(password));
|
| +
|
| + webkit_glue::PasswordForm new_password;
|
| +
|
| + if (MergePasswords(password, **ix, &new_password)) {
|
| + sync_api::WriteNode write_node(&trans);
|
| + if (!write_node.InitByClientTagLookup(syncable::PASSWORDS, tag)) {
|
| + STLDeleteElements(&passwords);
|
| + LOG(ERROR) << "Failed to edit password sync node.";
|
| + return false;
|
| + }
|
| + WriteToSyncNode(new_password, &write_node);
|
| + updated_passwords.push_back(new_password);
|
| + }
|
|
|
| - if (MergePasswords(password, **ix, &new_password)) {
|
| - sync_api::WriteNode write_node(&trans);
|
| - if (!write_node.InitByClientTagLookup(syncable::PASSWORDS, tag)) {
|
| + Associate(&tag, node.GetId());
|
| + } else {
|
| + sync_api::WriteNode node(&trans);
|
| + if (!node.InitUniqueByCreation(syncable::PASSWORDS,
|
| + password_root, tag)) {
|
| STLDeleteElements(&passwords);
|
| - LOG(ERROR) << "Failed to edit password sync node.";
|
| + LOG(ERROR) << "Failed to create password sync node.";
|
| return false;
|
| }
|
| - WriteToSyncNode(new_password, &write_node);
|
| - updated_passwords.push_back(new_password);
|
| - }
|
|
|
| - Associate(&tag, node.GetId());
|
| - } else {
|
| - sync_api::WriteNode node(&trans);
|
| - if (!node.InitUniqueByCreation(syncable::PASSWORDS,
|
| - password_root, tag)) {
|
| - STLDeleteElements(&passwords);
|
| - LOG(ERROR) << "Failed to create password sync node.";
|
| - return false;
|
| - }
|
| + WriteToSyncNode(**ix, &node);
|
|
|
| - WriteToSyncNode(**ix, &node);
|
| + Associate(&tag, node.GetId());
|
| + }
|
|
|
| - Associate(&tag, node.GetId());
|
| + current_passwords.insert(tag);
|
| }
|
|
|
| - current_passwords.insert(tag);
|
| - }
|
| + STLDeleteElements(&passwords);
|
|
|
| - STLDeleteElements(&passwords);
|
| + int64 sync_child_id = password_root.GetFirstChildId();
|
| + while (sync_child_id != sync_api::kInvalidId) {
|
| + sync_api::ReadNode sync_child_node(&trans);
|
| + if (!sync_child_node.InitByIdLookup(sync_child_id)) {
|
| + LOG(ERROR) << "Failed to fetch child node.";
|
| + return false;
|
| + }
|
| + const sync_pb::PasswordSpecificsData& password =
|
| + sync_child_node.GetPasswordSpecifics();
|
| + std::string tag = MakeTag(password);
|
|
|
| - int64 sync_child_id = password_root.GetFirstChildId();
|
| - while (sync_child_id != sync_api::kInvalidId) {
|
| - sync_api::ReadNode sync_child_node(&trans);
|
| - if (!sync_child_node.InitByIdLookup(sync_child_id)) {
|
| - LOG(ERROR) << "Failed to fetch child node.";
|
| - return false;
|
| - }
|
| - const sync_pb::PasswordSpecificsData& password =
|
| - sync_child_node.GetPasswordSpecifics();
|
| - std::string tag = MakeTag(password);
|
| -
|
| - // The password only exists on the server. Add it to the local
|
| - // model.
|
| - if (current_passwords.find(tag) == current_passwords.end()) {
|
| - webkit_glue::PasswordForm new_password;
|
| -
|
| - CopyPassword(password, &new_password);
|
| - Associate(&tag, sync_child_node.GetId());
|
| - new_passwords.push_back(new_password);
|
| - }
|
| + // The password only exists on the server. Add it to the local
|
| + // model.
|
| + if (current_passwords.find(tag) == current_passwords.end()) {
|
| + webkit_glue::PasswordForm new_password;
|
|
|
| - sync_child_id = sync_child_node.GetSuccessorId();
|
| + CopyPassword(password, &new_password);
|
| + Associate(&tag, sync_child_node.GetId());
|
| + new_passwords.push_back(new_password);
|
| + }
|
| +
|
| + sync_child_id = sync_child_node.GetSuccessorId();
|
| + }
|
| }
|
|
|
| + // We must not be holding a transaction when we interact with the password
|
| + // store, as it can post tasks to the UI thread which can itself be blocked
|
| + // on our transaction, resulting in deadlock. (http://crbug.com/70658)
|
| if (!WriteToPasswordStore(&new_passwords, &updated_passwords, NULL)) {
|
| LOG(ERROR) << "Failed to write passwords.";
|
| return false;
|
|
|