| Index: chrome/browser/sync/glue/autofill_profile_model_associator.cc
|
| ===================================================================
|
| --- chrome/browser/sync/glue/autofill_profile_model_associator.cc (revision 99989)
|
| +++ chrome/browser/sync/glue/autofill_profile_model_associator.cc (working copy)
|
| @@ -1,518 +0,0 @@
|
| -// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
|
| -
|
| -#include "base/tracked.h"
|
| -#include "base/utf_string_conversions.h"
|
| -#include "chrome/browser/sync/api/sync_error.h"
|
| -#include "chrome/browser/sync/glue/autofill_profile_change_processor.h"
|
| -#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
|
| -#include "chrome/browser/sync/internal_api/read_node.h"
|
| -#include "chrome/browser/sync/internal_api/read_transaction.h"
|
| -#include "chrome/browser/sync/internal_api/write_node.h"
|
| -#include "chrome/browser/sync/internal_api/write_transaction.h"
|
| -#include "chrome/browser/sync/profile_sync_service.h"
|
| -#include "chrome/browser/webdata/autofill_table.h"
|
| -#include "chrome/browser/webdata/web_database.h"
|
| -#include "chrome/common/guid.h"
|
| -
|
| -using sync_api::ReadNode;
|
| -namespace browser_sync {
|
| -
|
| -const char kAutofillProfileTag[] = "google_chrome_autofill_profiles";
|
| -
|
| -AutofillProfileModelAssociator::AutofillProfileModelAssociator(
|
| - ProfileSyncService* sync_service,
|
| - WebDatabase* web_database,
|
| - PersonalDataManager* personal_data)
|
| - : sync_service_(sync_service),
|
| - web_database_(web_database),
|
| - personal_data_(personal_data),
|
| - autofill_node_id_(sync_api::kInvalidId),
|
| - abort_association_pending_(false),
|
| - number_of_profiles_created_(0) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| - DCHECK(sync_service_);
|
| - DCHECK(web_database_);
|
| - DCHECK(personal_data_);
|
| -}
|
| -
|
| -AutofillProfileModelAssociator::~AutofillProfileModelAssociator() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| -}
|
| -
|
| -AutofillProfileModelAssociator::AutofillProfileModelAssociator()
|
| - : sync_service_(NULL),
|
| - web_database_(NULL),
|
| - personal_data_(NULL),
|
| - autofill_node_id_(0),
|
| - abort_association_pending_(false),
|
| - number_of_profiles_created_(0) {
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutofillProfiles(
|
| - sync_api::WriteTransaction* write_trans,
|
| - const sync_api::ReadNode& autofill_root,
|
| - const std::vector<AutofillProfile*>& all_profiles_from_db,
|
| - std::set<std::string>* current_profiles,
|
| - std::vector<AutofillProfile*>* updated_profiles,
|
| - std::vector<AutofillProfile*>* new_profiles,
|
| - std::vector<std::string>* profiles_to_delete) {
|
| -
|
| - if (VLOG_IS_ON(2)) {
|
| - VLOG(2) << "[AUTOFILL MIGRATION]"
|
| - << "Printing profiles from web db";
|
| -
|
| - for (std::vector<AutofillProfile*>::const_iterator ix =
|
| - all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) {
|
| - AutofillProfile* p = *ix;
|
| - VLOG(2) << "[AUTOFILL MIGRATION] "
|
| - << p->GetInfo(NAME_FIRST)
|
| - << p->GetInfo(NAME_LAST)
|
| - << p->guid();
|
| - }
|
| - }
|
| -
|
| - VLOG(1) << "[AUTOFILL MIGRATION]"
|
| - << "Looking for the above data in sync db..";
|
| -
|
| - // Alias the all_profiles_from_db so we fit in 80 characters
|
| - const std::vector<AutofillProfile*>& profiles(all_profiles_from_db);
|
| - for (std::vector<AutofillProfile*>::const_iterator ix = profiles.begin();
|
| - ix != profiles.end();
|
| - ++ix) {
|
| - std::string guid((*ix)->guid());
|
| - if (guid::IsValidGUID(guid) == false) {
|
| - DCHECK(false) << "Guid in the web db is invalid " << guid;
|
| - continue;
|
| - }
|
| -
|
| - ReadNode node(write_trans);
|
| - if (node.InitByClientTagLookup(syncable::AUTOFILL_PROFILE, guid) &&
|
| - // The following check is to ensure the given sync node is not already
|
| - // associated with another profile. That could happen if the user has
|
| - // the same profile duplicated.
|
| - current_profiles->find(guid) == current_profiles->end()) {
|
| - VLOG(2) << "[AUTOFILL MIGRATION]"
|
| - << " Found in sync db: "
|
| - << (*ix)->GetInfo(NAME_FIRST)
|
| - << (*ix)->GetInfo(NAME_LAST)
|
| - << (*ix)->guid()
|
| - << " so associating with node id " << node.GetId();
|
| - const sync_pb::AutofillProfileSpecifics& autofill(
|
| - node.GetAutofillProfileSpecifics());
|
| - if (OverwriteProfileWithServerData(*ix, autofill)) {
|
| - updated_profiles->push_back(*ix);
|
| - }
|
| - Associate(&guid, node.GetId());
|
| - current_profiles->insert(guid);
|
| - } else {
|
| - MakeNewAutofillProfileSyncNodeIfNeeded(write_trans,
|
| - autofill_root,
|
| - (**ix),
|
| - new_profiles,
|
| - current_profiles,
|
| - profiles_to_delete);
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::GetSyncIdForTaggedNode(
|
| - const std::string& tag,
|
| - int64* sync_id) {
|
| - sync_api::ReadTransaction trans(FROM_HERE, 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;
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::LoadAutofillData(
|
| - std::vector<AutofillProfile*>* profiles) {
|
| - if (IsAbortPending())
|
| - return false;
|
| -
|
| - if (!web_database_->GetAutofillTable()->GetAutofillProfiles(profiles))
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::AssociateModels(SyncError* error) {
|
| - VLOG(1) << "Associating Autofill Models";
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| - {
|
| - base::AutoLock lock(abort_association_pending_lock_);
|
| - abort_association_pending_ = false;
|
| - }
|
| -
|
| - ScopedVector<AutofillProfile> profiles;
|
| -
|
| - if (!LoadAutofillData(&profiles.get())) {
|
| - error->Reset(FROM_HERE,
|
| - "Could not get the autofill data from WebDatabase.",
|
| - model_type());
|
| - return false;
|
| - }
|
| -
|
| - VLOG(1) << "[AUTOFILL MIGRATION]"
|
| - << " Now associating to the new autofill profile model associator"
|
| - << " root node";
|
| - DataBundle bundle;
|
| - {
|
| - // The write transaction lock is held inside this block.
|
| - // We do all the web db operations outside this block.
|
| - sync_api::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
|
| -
|
| - sync_api::ReadNode autofill_root(&trans);
|
| - if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) {
|
| - error->Reset(FROM_HERE,
|
| - "Server did not create the top-level autofill node. We "
|
| - "might be running against an out-of-date server.",
|
| - model_type());
|
| - return false;
|
| - }
|
| -
|
| - if (!TraverseAndAssociateChromeAutofillProfiles(&trans, autofill_root,
|
| - profiles.get(), &bundle.current_profiles,
|
| - &bundle.updated_profiles,
|
| - &bundle.new_profiles,
|
| - &bundle.profiles_to_delete) ||
|
| - !TraverseAndAssociateAllSyncNodes(&trans, autofill_root, &bundle)) {
|
| - error->Reset(FROM_HERE,
|
| - "Failed to associate all sync nodes.",
|
| - model_type());
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - if (!SaveChangesToWebData(bundle)) {
|
| - error->Reset(FROM_HERE, "Failed to update webdata.", model_type());
|
| - return false;
|
| - }
|
| -
|
| - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
| - new DoOptimisticRefreshForAutofill(personal_data_));
|
| - return true;
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::DisassociateModels(SyncError* error) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| - id_map_.clear();
|
| - id_map_inverse_.clear();
|
| - return true;
|
| -}
|
| -
|
| -// Helper to compare the local value and cloud value of a field, merge into
|
| -// the local value if they differ, and return whether the merge happened.
|
| -bool AutofillProfileModelAssociator::MergeField(FormGroup* f,
|
| - AutofillFieldType t,
|
| - const std::string& specifics_field) {
|
| - if (UTF16ToUTF8(f->GetInfo(t)) == specifics_field)
|
| - return false;
|
| - f->SetInfo(t, UTF8ToUTF16(specifics_field));
|
| - return true;
|
| -}
|
| -bool AutofillProfileModelAssociator::SyncModelHasUserCreatedNodes(
|
| - bool *has_nodes) {
|
| - CHECK_NE(has_nodes, reinterpret_cast<bool*>(NULL));
|
| - sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
|
| -
|
| - sync_api::ReadNode node(&trans);
|
| -
|
| - if (!node.InitByTagLookup(kAutofillProfileTag)) {
|
| - LOG(ERROR) << "Sever did not create a top level node"
|
| - << "Out of data server or autofill type not enabled";
|
| - return false;
|
| - }
|
| -
|
| - *has_nodes = sync_api::kInvalidId != node.GetFirstChildId();
|
| - return true;
|
| -}
|
| -// static
|
| -bool AutofillProfileModelAssociator::OverwriteProfileWithServerData(
|
| - AutofillProfile* merge_into,
|
| - const sync_pb::AutofillProfileSpecifics& specifics) {
|
| - bool diff = false;
|
| - AutofillProfile* p = merge_into;
|
| - const sync_pb::AutofillProfileSpecifics& s(specifics);
|
| - diff = MergeField(p, NAME_FIRST, s.name_first()) || diff;
|
| - diff = MergeField(p, NAME_LAST, s.name_last()) || diff;
|
| - diff = MergeField(p, NAME_MIDDLE, s.name_middle()) || diff;
|
| - diff = MergeField(p, ADDRESS_HOME_LINE1, s.address_home_line1()) || diff;
|
| - diff = MergeField(p, ADDRESS_HOME_LINE2, s.address_home_line2()) || diff;
|
| - diff = MergeField(p, ADDRESS_HOME_CITY, s.address_home_city()) || diff;
|
| - diff = MergeField(p, ADDRESS_HOME_STATE, s.address_home_state()) || diff;
|
| - diff = MergeField(p, ADDRESS_HOME_COUNTRY, s.address_home_country()) || diff;
|
| - diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff;
|
| - diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff;
|
| - diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff;
|
| - diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number())
|
| - || diff;
|
| - diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number())
|
| - || diff;
|
| - return diff;
|
| -}
|
| -
|
| -
|
| -int64 AutofillProfileModelAssociator::FindSyncNodeWithProfile(
|
| - sync_api::WriteTransaction* trans,
|
| - const sync_api::BaseNode& autofill_root,
|
| - const AutofillProfile& profile_from_db,
|
| - std::set<std::string>* current_profiles) {
|
| - int64 sync_child_id = autofill_root.GetFirstChildId();
|
| - while (sync_child_id != sync_api::kInvalidId) {
|
| - ReadNode read_node(trans);
|
| - AutofillProfile p;
|
| - if (!read_node.InitByIdLookup(sync_child_id)) {
|
| - LOG(ERROR) << "unable to find the id given by getfirst child " <<
|
| - sync_child_id;
|
| - return sync_api::kInvalidId;
|
| - }
|
| - const sync_pb::AutofillProfileSpecifics& autofill_specifics(
|
| - read_node.GetAutofillProfileSpecifics());
|
| -
|
| - // This find should be fast as the set uses tree.
|
| - if (current_profiles->find(autofill_specifics.guid())
|
| - == current_profiles->end()) {
|
| - OverwriteProfileWithServerData(&p, autofill_specifics);
|
| - if (p.Compare(profile_from_db) == 0) {
|
| - return sync_child_id;
|
| - }
|
| - }
|
| - sync_child_id = read_node.GetSuccessorId();
|
| - }
|
| -
|
| - return sync_api::kInvalidId;
|
| -}
|
| -bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNodeIfNeeded(
|
| - sync_api::WriteTransaction* trans,
|
| - const sync_api::BaseNode& autofill_root,
|
| - const AutofillProfile& profile,
|
| - std::vector<AutofillProfile*>* new_profiles,
|
| - std::set<std::string>* current_profiles,
|
| - std::vector<std::string>* profiles_to_delete) {
|
| -
|
| - int64 sync_node_id = FindSyncNodeWithProfile(trans,
|
| - autofill_root,
|
| - profile,
|
| - current_profiles);
|
| - if (sync_node_id != sync_api::kInvalidId) {
|
| - // In case of duplicates throw away the local profile and apply the
|
| - // server profile.(The only difference between the 2 profiles are the guids)
|
| - profiles_to_delete->push_back(profile.guid());
|
| - sync_api::ReadNode read_node(trans);
|
| - if (!read_node.InitByIdLookup(sync_node_id)) {
|
| - LOG(ERROR);
|
| - return false;
|
| - }
|
| - const sync_pb::AutofillProfileSpecifics& autofill_specifics(
|
| - read_node.GetAutofillProfileSpecifics());
|
| - if (guid::IsValidGUID(autofill_specifics.guid()) == false) {
|
| - NOTREACHED() << "Guid in the web db is invalid " <<
|
| - autofill_specifics.guid();
|
| - return false;
|
| - }
|
| - AutofillProfile* p = new AutofillProfile(autofill_specifics.guid());
|
| - OverwriteProfileWithServerData(p, autofill_specifics);
|
| - new_profiles->push_back(p);
|
| - std::string guid = autofill_specifics.guid();
|
| - Associate(&guid, sync_node_id);
|
| - current_profiles->insert(autofill_specifics.guid());
|
| - VLOG(2) << "[AUTOFILL MIGRATION]"
|
| - << "Found in sync db but with a different guid: "
|
| - << UTF16ToUTF8(profile.GetInfo(NAME_FIRST))
|
| - << UTF16ToUTF8(profile.GetInfo(NAME_LAST))
|
| - << "New guid " << autofill_specifics.guid() << " sync node id "
|
| - << sync_node_id << " so associating. Profile to be deleted "
|
| - << profile.guid();
|
| - } else {
|
| - sync_api::WriteNode node(trans);
|
| -
|
| - // The profile.guid() is expected to be a valid guid. The caller is expected
|
| - // to pass in a valid profile object with a valid guid. Having to check in
|
| - // 2 places(the caller and here) is not optimal.
|
| - if (!node.InitUniqueByCreation(
|
| - syncable::AUTOFILL_PROFILE, autofill_root, profile.guid())) {
|
| - LOG(ERROR) << "Failed to create autofill sync node.";
|
| - return false;
|
| - }
|
| - node.SetTitle(UTF8ToWide(profile.guid()));
|
| - VLOG(2) << "[AUTOFILL MIGRATION]"
|
| - << "NOT Found in sync db "
|
| - << UTF16ToUTF8(profile.GetInfo(NAME_FIRST))
|
| - << UTF16ToUTF8(profile.GetInfo(NAME_LAST))
|
| - << profile.guid()
|
| - << " so creating a new sync node. Sync node id "
|
| - << node.GetId();
|
| - AutofillProfileChangeProcessor::WriteAutofillProfile(profile, &node);
|
| - current_profiles->insert(profile.guid());
|
| - std::string guid = profile.guid();
|
| - Associate(&guid, node.GetId());
|
| - number_of_profiles_created_++;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::TraverseAndAssociateAllSyncNodes(
|
| - sync_api::WriteTransaction* write_trans,
|
| - const sync_api::ReadNode& autofill_root,
|
| - DataBundle* bundle) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| - VLOG(1) << "[AUTOFILL MIGRATION] "
|
| - << " Iterating over sync nodes of autofill profile root node";
|
| -
|
| - int64 sync_child_id = autofill_root.GetFirstChildId();
|
| - while (sync_child_id != sync_api::kInvalidId) {
|
| - ReadNode sync_child(write_trans);
|
| - if (!sync_child.InitByIdLookup(sync_child_id)) {
|
| - LOG(ERROR) << "Failed to fetch child node.";
|
| - return false;
|
| - }
|
| - const sync_pb::AutofillProfileSpecifics& autofill(
|
| - sync_child.GetAutofillProfileSpecifics());
|
| -
|
| - AddNativeProfileIfNeeded(autofill, bundle, sync_child);
|
| -
|
| - sync_child_id = sync_child.GetSuccessorId();
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void AutofillProfileModelAssociator::AddNativeProfileIfNeeded(
|
| - const sync_pb::AutofillProfileSpecifics& profile,
|
| - DataBundle* bundle,
|
| - const sync_api::ReadNode& node) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| -
|
| - VLOG(2) << "[AUTOFILL MIGRATION] "
|
| - << "Trying to lookup "
|
| - << profile.name_first()
|
| - << " "
|
| - << profile.name_last()
|
| - << "sync node id " << node.GetId()
|
| - << " Guid " << profile.guid()
|
| - << " in the web db";
|
| -
|
| - if (guid::IsValidGUID(profile.guid()) == false) {
|
| - DCHECK(false) << "Guid in the sync db is invalid " << profile.guid();
|
| - return;
|
| - }
|
| -
|
| - if (bundle->current_profiles.find(profile.guid()) ==
|
| - bundle->current_profiles.end()) {
|
| - std::string guid(profile.guid());
|
| - Associate(&guid, node.GetId());
|
| - AutofillProfile* p = new AutofillProfile(profile.guid());
|
| - OverwriteProfileWithServerData(p, profile);
|
| - bundle->new_profiles.push_back(p);
|
| - VLOG(2) << "[AUTOFILL MIGRATION] "
|
| - << " Did not find one so creating it on web db";
|
| - } else {
|
| - VLOG(2) << "[AUTOFILL MIGRATION] "
|
| - << " Found it on web db. Moving on ";
|
| - }
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::SaveChangesToWebData(
|
| - const DataBundle& bundle) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| -
|
| - if (IsAbortPending())
|
| - return false;
|
| -
|
| - for (size_t i = 0; i < bundle.new_profiles.size(); i++) {
|
| - if (IsAbortPending())
|
| - return false;
|
| - if (!web_database_->GetAutofillTable()->AddAutofillProfile(
|
| - *bundle.new_profiles[i]))
|
| - return false;
|
| - }
|
| -
|
| - for (size_t i = 0; i < bundle.updated_profiles.size(); i++) {
|
| - if (IsAbortPending())
|
| - return false;
|
| - if (!web_database_->GetAutofillTable()->UpdateAutofillProfile(
|
| - *bundle.updated_profiles[i]))
|
| - return false;
|
| - }
|
| -
|
| - for (size_t i = 0; i< bundle.profiles_to_delete.size(); ++i) {
|
| - if (IsAbortPending())
|
| - return false;
|
| - if (!web_database_->GetAutofillTable()->RemoveAutofillProfile(
|
| - bundle.profiles_to_delete[i]))
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::InitSyncNodeFromChromeId(
|
| - const std::string& node_id,
|
| - sync_api::BaseNode* sync_node) {
|
| - return false;
|
| -}
|
| -
|
| -void AutofillProfileModelAssociator::Associate(
|
| - const std::string* autofill,
|
| - int64 sync_id) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| - DCHECK_NE(sync_api::kInvalidId, sync_id);
|
| - DCHECK(id_map_.find(*autofill) == id_map_.end());
|
| - DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
|
| - id_map_[*autofill] = sync_id;
|
| - id_map_inverse_[sync_id] = *autofill;
|
| -}
|
| -
|
| -void AutofillProfileModelAssociator::Disassociate(int64 sync_id) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
|
| - SyncIdToAutofillMap::iterator iter = id_map_inverse_.find(sync_id);
|
| - if (iter == id_map_inverse_.end())
|
| - return;
|
| - CHECK(id_map_.erase(iter->second));
|
| - id_map_inverse_.erase(iter);
|
| -}
|
| -
|
| -int64 AutofillProfileModelAssociator::GetSyncIdFromChromeId(
|
| - const std::string& autofill) {
|
| - AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill);
|
| - return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
|
| -}
|
| -
|
| -void AutofillProfileModelAssociator::AbortAssociation() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - base::AutoLock lock(abort_association_pending_lock_);
|
| - abort_association_pending_ = true;
|
| -}
|
| -
|
| -const std::string* AutofillProfileModelAssociator::GetChromeNodeFromSyncId(
|
| - int64 sync_id) {
|
| - SyncIdToAutofillMap::const_iterator iter = id_map_inverse_.find(sync_id);
|
| - return iter == id_map_inverse_.end() ? NULL : &(iter->second);
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::IsAbortPending() {
|
| - base::AutoLock lock(abort_association_pending_lock_);
|
| - return abort_association_pending_;
|
| -}
|
| -
|
| -AutofillProfileModelAssociator::DataBundle::DataBundle() {}
|
| -
|
| -AutofillProfileModelAssociator::DataBundle::~DataBundle() {
|
| - STLDeleteElements(&new_profiles);
|
| -}
|
| -
|
| -bool AutofillProfileModelAssociator::CryptoReadyIfNecessary() {
|
| - // We only access the cryptographer while holding a transaction.
|
| - sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
|
| - syncable::ModelTypeSet encrypted_types;
|
| - encrypted_types = sync_api::GetEncryptedTypes(&trans);
|
| - return encrypted_types.count(syncable::AUTOFILL_PROFILE) == 0 ||
|
| - sync_service_->IsCryptographerReady(&trans);
|
| -}
|
| -
|
| -} // namespace browser_sync
|
|
|