Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sync/glue/autofill_model_associator.h"
      6 
      7 #include <functional>
      8 #include <vector>
      9 
     10 #include "base/string_number_conversions.h"
     11 #include "base/task.h"
     12 #include "base/time.h"
     13 #include "base/utf_string_conversions.h"
     14 #include "chrome/browser/autofill/autofill_profile.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/sync/engine/syncapi.h"
     17 #include "chrome/browser/sync/glue/autofill_change_processor.h"
     18 #include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
     19 #include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
     20 #include "chrome/browser/sync/profile_sync_service.h"
     21 #include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
     22 #include "chrome/browser/webdata/web_database.h"
     23 #include "chrome/common/guid.h"
     24 #include "content/browser/browser_thread.h"
     25 #include "net/base/escape.h"
     26 
     27 using base::TimeTicks;
     28 
     29 namespace browser_sync {
     30 
     31 const char kAutofillTag[] = "google_chrome_autofill";
     32 const char kAutofillEntryNamespaceTag[] = "autofill_entry|";
     33 
     34 struct AutofillModelAssociator::DataBundle {
     35   std::set<AutofillKey> current_entries;
     36   std::vector<AutofillEntry> new_entries;
     37   std::set<string16> current_profiles;
     38   std::vector<AutofillProfile*> updated_profiles;
     39   std::vector<AutofillProfile*> new_profiles;  // We own these pointers.
     40   ~DataBundle() { STLDeleteElements(&new_profiles); }
     41 };
     42 
     43 AutofillModelAssociator::AutofillModelAssociator(
     44     ProfileSyncService* sync_service,
     45     WebDatabase* web_database,
     46     PersonalDataManager* personal_data)
     47     : sync_service_(sync_service),
     48       web_database_(web_database),
     49       personal_data_(personal_data),
     50       autofill_node_id_(sync_api::kInvalidId),
     51       abort_association_pending_(false),
     52       number_of_entries_created_(0) {
     53   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     54   DCHECK(sync_service_);
     55   DCHECK(web_database_);
     56   DCHECK(personal_data_);
     57 }
     58 
     59 AutofillModelAssociator::~AutofillModelAssociator() {
     60   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     61 }
     62 
     63 bool AutofillModelAssociator::TraverseAndAssociateChromeAutofillEntries(
     64     sync_api::WriteTransaction* write_trans,
     65     const sync_api::ReadNode& autofill_root,
     66     const std::vector<AutofillEntry>& all_entries_from_db,
     67     std::set<AutofillKey>* current_entries,
     68     std::vector<AutofillEntry>* new_entries) {
     69 
     70   const std::vector<AutofillEntry>& entries = all_entries_from_db;
     71   for (std::vector<AutofillEntry>::const_iterator ix = entries.begin();
     72        ix != entries.end(); ++ix) {
     73     std::string tag = KeyToTag(ix->key().name(), ix->key().value());
     74     if (id_map_.find(tag) != id_map_.end()) {
     75       // It seems that name/value pairs are not unique in the web database.
     76       // As a result, we have to filter out duplicates here.  This is probably
     77       // a bug in the database.
     78       continue;
     79     }
     80 
     81     sync_api::ReadNode node(write_trans);
     82     if (node.InitByClientTagLookup(syncable::AUTOFILL, tag)) {
     83       const sync_pb::AutofillSpecifics& autofill(node.GetAutofillSpecifics());
     84       DCHECK_EQ(tag, KeyToTag(UTF8ToUTF16(autofill.name()),
     85                               UTF8ToUTF16(autofill.value())));
     86 
     87       std::vector<base::Time> timestamps;
     88       if (MergeTimestamps(autofill, ix->timestamps(), &timestamps)) {
     89         AutofillEntry new_entry(ix->key(), timestamps);
     90         new_entries->push_back(new_entry);
     91 
     92         sync_api::WriteNode write_node(write_trans);
     93         if (!write_node.InitByClientTagLookup(syncable::AUTOFILL, tag)) {
     94           LOG(ERROR) << "Failed to write autofill sync node.";
     95           return false;
     96         }
     97         AutofillChangeProcessor::WriteAutofillEntry(new_entry, &write_node);
     98       }
     99 
    100       Associate(&tag, node.GetId());
    101     } else {
    102       sync_api::WriteNode node(write_trans);
    103       if (!node.InitUniqueByCreation(syncable::AUTOFILL,
    104                                      autofill_root, tag)) {
    105         LOG(ERROR) << "Failed to create autofill sync node.";
    106         return false;
    107       }
    108       node.SetTitle(UTF8ToWide(tag));
    109       AutofillChangeProcessor::WriteAutofillEntry(*ix, &node);
    110       Associate(&tag, node.GetId());
    111       number_of_entries_created_++;
    112     }
    113 
    114     current_entries->insert(ix->key());
    115   }
    116   return true;
    117 }
    118 
    119 bool AutofillModelAssociator::LoadAutofillData(
    120     std::vector<AutofillEntry>* entries,
    121     std::vector<AutofillProfile*>* profiles) {
    122   if (IsAbortPending())
    123     return false;
    124   if (!web_database_->GetAutofillTable()->GetAllAutofillEntries(entries))
    125     return false;
    126 
    127   if (IsAbortPending())
    128     return false;
    129   if (!web_database_->GetAutofillTable()->GetAutofillProfiles(profiles))
    130     return false;
    131 
    132   return true;
    133 }
    134 
    135 bool AutofillModelAssociator::AssociateModels() {
    136   VLOG(1) << "Associating Autofill Models";
    137   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    138   {
    139     base::AutoLock lock(abort_association_pending_lock_);
    140     abort_association_pending_ = false;
    141   }
    142 
    143   // TODO(zork): Attempt to load the model association from storage.
    144   std::vector<AutofillEntry> entries;
    145   ScopedVector<AutofillProfile> profiles;
    146 
    147   if (!LoadAutofillData(&entries, &profiles.get())) {
    148     LOG(ERROR) << "Could not get the autofill data from WebDatabase.";
    149     return false;
    150   }
    151 
    152   DataBundle bundle;
    153   {
    154     sync_api::WriteTransaction trans(sync_service_->GetUserShare());
    155 
    156     sync_api::ReadNode autofill_root(&trans);
    157     if (!autofill_root.InitByTagLookup(kAutofillTag)) {
    158       LOG(ERROR) << "Server did not create the top-level autofill node. We "
    159                  << "might be running against an out-of-date server.";
    160       return false;
    161     }
    162 
    163     if (!TraverseAndAssociateChromeAutofillEntries(&trans, autofill_root,
    164         entries, &bundle.current_entries, &bundle.new_entries)) {
    165       return false;
    166     }
    167 
    168     if (!TraverseAndAssociateAllSyncNodes(
    169         &trans,
    170         autofill_root,
    171         &bundle,
    172         profiles.get())) {
    173       return false;
    174     }
    175   }
    176 
    177   // Since we're on the DB thread, we don't have to worry about updating
    178   // the autofill database after closing the write transaction, since
    179   // this is the only thread that writes to the database.  We also don't have
    180   // to worry about the sync model getting out of sync, because changes are
    181   // propagated to the ChangeProcessor on this thread.
    182   if (!SaveChangesToWebData(bundle)) {
    183     LOG(ERROR) << "Failed to update autofill entries.";
    184     return false;
    185   }
    186 
    187   if (sync_service_->GetAutofillMigrationState() !=
    188       syncable::MIGRATED) {
    189     syncable::AutofillMigrationDebugInfo debug_info;
    190     debug_info.autofill_entries_added_during_migration =
    191         number_of_entries_created_;
    192     sync_service_->SetAutofillMigrationDebugInfo(
    193         syncable::AutofillMigrationDebugInfo::ENTRIES_ADDED,
    194         debug_info);
    195   }
    196 
    197   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    198       new DoOptimisticRefreshForAutofill(personal_data_));
    199   return true;
    200 }
    201 
    202 bool AutofillModelAssociator::SaveChangesToWebData(const DataBundle& bundle) {
    203   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    204 
    205   if (IsAbortPending())
    206     return false;
    207 
    208   if (bundle.new_entries.size() &&
    209       !web_database_->GetAutofillTable()->UpdateAutofillEntries(
    210           bundle.new_entries)) {
    211     return false;
    212   }
    213 
    214   for (size_t i = 0; i < bundle.new_profiles.size(); i++) {
    215     if (IsAbortPending())
    216       return false;
    217     if (!web_database_->GetAutofillTable()->AddAutofillProfile(
    218         *bundle.new_profiles[i]))
    219       return false;
    220   }
    221 
    222   for (size_t i = 0; i < bundle.updated_profiles.size(); i++) {
    223     if (IsAbortPending())
    224       return false;
    225     if (!web_database_->GetAutofillTable()->UpdateAutofillProfile(
    226         *bundle.updated_profiles[i]))
    227       return false;
    228   }
    229   return true;
    230 }
    231 
    232 bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes(
    233     sync_api::WriteTransaction* write_trans,
    234     const sync_api::ReadNode& autofill_root,
    235     DataBundle* bundle,
    236     const std::vector<AutofillProfile*>& all_profiles_from_db) {
    237   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    238 
    239   bool autofill_profile_not_migrated = HasNotMigratedYet(write_trans);
    240 
    241   if (VLOG_IS_ON(2) && autofill_profile_not_migrated) {
    242     VLOG(2) << "[AUTOFILL MIGRATION]"
    243             << "Printing profiles from web db";
    244 
    245     for (std::vector<AutofillProfile*>::const_iterator ix =
    246         all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) {
    247       AutofillProfile* p = *ix;
    248       VLOG(2) << "[AUTOFILL MIGRATION]  "
    249               << p->GetInfo(NAME_FIRST)
    250               << p->GetInfo(NAME_LAST);
    251     }
    252   }
    253 
    254   if (autofill_profile_not_migrated) {
    255     VLOG(1) << "[AUTOFILL MIGRATION]"
    256             << "Iterating over sync db";
    257   }
    258 
    259   int64 sync_child_id = autofill_root.GetFirstChildId();
    260   while (sync_child_id != sync_api::kInvalidId) {
    261     sync_api::ReadNode sync_child(write_trans);
    262     if (!sync_child.InitByIdLookup(sync_child_id)) {
    263       LOG(ERROR) << "Failed to fetch child node.";
    264       return false;
    265     }
    266     const sync_pb::AutofillSpecifics& autofill(
    267         sync_child.GetAutofillSpecifics());
    268 
    269     if (autofill.has_value()) {
    270       AddNativeEntryIfNeeded(autofill, bundle, sync_child);
    271     } else if (autofill.has_profile()) {
    272       // Ignore autofill profiles if we are not upgrading.
    273       if (autofill_profile_not_migrated) {
    274         VLOG(2) << "[AUTOFILL MIGRATION] Looking for "
    275                 << autofill.profile().name_first()
    276                 << autofill.profile().name_last();
    277         AddNativeProfileIfNeeded(
    278             autofill.profile(),
    279             bundle,
    280             sync_child,
    281             all_profiles_from_db);
    282       }
    283     } else {
    284       NOTREACHED() << "AutofillSpecifics has no autofill data!";
    285     }
    286 
    287     sync_child_id = sync_child.GetSuccessorId();
    288   }
    289   return true;
    290 }
    291 
    292 // Define the functor to be used as the predicate in find_if call.
    293 struct CompareProfiles
    294   : public std::binary_function<AutofillProfile*, AutofillProfile*, bool> {
    295   bool operator() (AutofillProfile* p1, AutofillProfile* p2) const {
    296     if (p1->Compare(*p2) == 0)
    297       return true;
    298     else
    299       return false;
    300   }
    301 };
    302 
    303 AutofillProfile* AutofillModelAssociator::FindCorrespondingNodeFromWebDB(
    304     const sync_pb::AutofillProfileSpecifics& profile,
    305     const std::vector<AutofillProfile*>& all_profiles_from_db) {
    306   static std::string guid(guid::GenerateGUID());
    307   AutofillProfile p;
    308   p.set_guid(guid);
    309   if (!FillProfileWithServerData(&p, profile)) {
    310     // Not a big deal. We encountered an error. Just say this profile does not
    311     // exist.
    312     LOG(ERROR) << " Profile could not be associated";
    313     return NULL;
    314   }
    315 
    316   // Now instantiate the functor and call find_if.
    317   std::vector<AutofillProfile*>::const_iterator ix =
    318       std::find_if(all_profiles_from_db.begin(),
    319                    all_profiles_from_db.end(),
    320                    std::bind2nd(CompareProfiles(), &p));
    321 
    322   return (ix == all_profiles_from_db.end()) ? NULL : *ix;
    323 }
    324 
    325 void AutofillModelAssociator::AddNativeEntryIfNeeded(
    326     const sync_pb::AutofillSpecifics& autofill, DataBundle* bundle,
    327     const sync_api::ReadNode& node) {
    328   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    329   AutofillKey key(UTF8ToUTF16(autofill.name()), UTF8ToUTF16(autofill.value()));
    330 
    331   if (bundle->current_entries.find(key) == bundle->current_entries.end()) {
    332     std::vector<base::Time> timestamps;
    333     int timestamps_count = autofill.usage_timestamp_size();
    334     for (int c = 0; c < timestamps_count; ++c) {
    335       timestamps.push_back(base::Time::FromInternalValue(
    336           autofill.usage_timestamp(c)));
    337     }
    338     std::string tag(KeyToTag(key.name(), key.value()));
    339     Associate(&tag, node.GetId());
    340     bundle->new_entries.push_back(AutofillEntry(key, timestamps));
    341   }
    342 }
    343 
    344 void AutofillModelAssociator::AddNativeProfileIfNeeded(
    345     const sync_pb::AutofillProfileSpecifics& profile,
    346     DataBundle* bundle,
    347     const sync_api::ReadNode& node,
    348     const std::vector<AutofillProfile*>& all_profiles_from_db) {
    349 
    350   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    351 
    352   AutofillProfile* profile_in_web_db = FindCorrespondingNodeFromWebDB(
    353       profile, all_profiles_from_db);
    354 
    355   if (profile_in_web_db != NULL) {
    356     VLOG(1) << "[AUTOFILL MIGRATION]"
    357             << "Node found in web db. So associating";
    358     int64 sync_id = node.GetId();
    359     std::string guid = profile_in_web_db->guid();
    360     Associate(&guid, sync_id);
    361     return;
    362   } else {  // Create a new node.
    363     VLOG(1) << "[AUTOFILL MIGRATION]"
    364             << "Node not found in web db so creating and associating";
    365     std::string guid = guid::GenerateGUID();
    366     if (guid::IsValidGUID(guid) == false) {
    367       DCHECK(false) << "Guid generated is invalid " << guid;
    368       return;
    369     }
    370     Associate(&guid, node.GetId());
    371     AutofillProfile* p = new AutofillProfile(guid);
    372     FillProfileWithServerData(p, profile);
    373     bundle->new_profiles.push_back(p);
    374   }
    375 }
    376 
    377 bool AutofillModelAssociator::DisassociateModels() {
    378   id_map_.clear();
    379   id_map_inverse_.clear();
    380   return true;
    381 }
    382 
    383 bool AutofillModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
    384   DCHECK(has_nodes);
    385   *has_nodes = false;
    386   int64 autofill_sync_id;
    387   if (!GetSyncIdForTaggedNode(kAutofillTag, &autofill_sync_id)) {
    388     LOG(ERROR) << "Server did not create the top-level autofill node. We "
    389                << "might be running against an out-of-date server.";
    390     return false;
    391   }
    392   sync_api::ReadTransaction trans(sync_service_->GetUserShare());
    393 
    394   sync_api::ReadNode autofill_node(&trans);
    395   if (!autofill_node.InitByIdLookup(autofill_sync_id)) {
    396     LOG(ERROR) << "Server did not create the top-level autofill node. We "
    397                << "might be running against an out-of-date server.";
    398     return false;
    399   }
    400 
    401   // The sync model has user created nodes if the autofill folder has any
    402   // children.
    403   *has_nodes = sync_api::kInvalidId != autofill_node.GetFirstChildId();
    404   return true;
    405 }
    406 
    407 void AutofillModelAssociator::AbortAssociation() {
    408   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    409   base::AutoLock lock(abort_association_pending_lock_);
    410   abort_association_pending_ = true;
    411 }
    412 
    413 const std::string*
    414 AutofillModelAssociator::GetChromeNodeFromSyncId(int64 sync_id) {
    415   SyncIdToAutofillMap::const_iterator iter = id_map_inverse_.find(sync_id);
    416   return iter == id_map_inverse_.end() ? NULL : &(iter->second);
    417 }
    418 
    419 bool AutofillModelAssociator::InitSyncNodeFromChromeId(
    420     const std::string& node_id,
    421     sync_api::BaseNode* sync_node) {
    422   return false;
    423 }
    424 
    425 int64 AutofillModelAssociator::GetSyncIdFromChromeId(
    426     const std::string& autofill) {
    427   AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill);
    428   return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
    429 }
    430 
    431 void AutofillModelAssociator::Associate(
    432     const std::string* autofill, int64 sync_id) {
    433   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    434   DCHECK_NE(sync_api::kInvalidId, sync_id);
    435   DCHECK(id_map_.find(*autofill) == id_map_.end());
    436   DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
    437   id_map_[*autofill] = sync_id;
    438   id_map_inverse_[sync_id] = *autofill;
    439 }
    440 
    441 void AutofillModelAssociator::Disassociate(int64 sync_id) {
    442   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    443   SyncIdToAutofillMap::iterator iter = id_map_inverse_.find(sync_id);
    444   if (iter == id_map_inverse_.end())
    445     return;
    446   CHECK(id_map_.erase(iter->second));
    447   id_map_inverse_.erase(iter);
    448 }
    449 
    450 bool AutofillModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
    451                                                      int64* sync_id) {
    452   sync_api::ReadTransaction trans(sync_service_->GetUserShare());
    453   sync_api::ReadNode sync_node(&trans);
    454   if (!sync_node.InitByTagLookup(tag.c_str()))
    455     return false;
    456   *sync_id = sync_node.GetId();
    457   return true;
    458 }
    459 
    460 bool AutofillModelAssociator::IsAbortPending() {
    461   base::AutoLock lock(abort_association_pending_lock_);
    462   return abort_association_pending_;
    463 }
    464 
    465 // static
    466 std::string AutofillModelAssociator::KeyToTag(const string16& name,
    467                                               const string16& value) {
    468   std::string ns(kAutofillEntryNamespaceTag);
    469   return ns + EscapePath(UTF16ToUTF8(name)) + "|" +
    470          EscapePath(UTF16ToUTF8(value));
    471 }
    472 
    473 // static
    474 bool AutofillModelAssociator::MergeTimestamps(
    475     const sync_pb::AutofillSpecifics& autofill,
    476     const std::vector<base::Time>& timestamps,
    477     std::vector<base::Time>* new_timestamps) {
    478   DCHECK(new_timestamps);
    479   std::set<base::Time> timestamp_union(timestamps.begin(),
    480                                        timestamps.end());
    481 
    482   size_t timestamps_count = autofill.usage_timestamp_size();
    483 
    484   bool different = timestamps.size() != timestamps_count;
    485   for (size_t c = 0; c < timestamps_count; ++c) {
    486     if (timestamp_union.insert(base::Time::FromInternalValue(
    487             autofill.usage_timestamp(c))).second) {
    488       different = true;
    489     }
    490   }
    491 
    492   if (different) {
    493     new_timestamps->insert(new_timestamps->begin(),
    494                            timestamp_union.begin(),
    495                            timestamp_union.end());
    496   }
    497   return different;
    498 }
    499 
    500 // Helper to compare the local value and cloud value of a field, merge into
    501 // the local value if they differ, and return whether the merge happened.
    502 bool MergeField(FormGroup* f, AutofillFieldType t,
    503                 const std::string& specifics_field) {
    504   if (UTF16ToUTF8(f->GetInfo(t)) == specifics_field)
    505     return false;
    506   f->SetInfo(t, UTF8ToUTF16(specifics_field));
    507   return true;
    508 }
    509 
    510 // static
    511 bool AutofillModelAssociator::FillProfileWithServerData(
    512     AutofillProfile* merge_into,
    513     const sync_pb::AutofillProfileSpecifics& specifics) {
    514   bool diff = false;
    515   AutofillProfile* p = merge_into;
    516   const sync_pb::AutofillProfileSpecifics& s(specifics);
    517   diff = MergeField(p, NAME_FIRST, s.name_first()) || diff;
    518   diff = MergeField(p, NAME_LAST, s.name_last()) || diff;
    519   diff = MergeField(p, NAME_MIDDLE, s.name_middle()) || diff;
    520   diff = MergeField(p, ADDRESS_HOME_LINE1, s.address_home_line1()) || diff;
    521   diff = MergeField(p, ADDRESS_HOME_LINE2, s.address_home_line2()) || diff;
    522   diff = MergeField(p, ADDRESS_HOME_CITY, s.address_home_city()) || diff;
    523   diff = MergeField(p, ADDRESS_HOME_STATE, s.address_home_state()) || diff;
    524   diff = MergeField(p, ADDRESS_HOME_COUNTRY, s.address_home_country()) || diff;
    525   diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff;
    526   diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff;
    527   diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff;
    528   diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number())
    529       || diff;
    530   diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number())
    531       || diff;
    532   return diff;
    533 }
    534 
    535 bool AutofillModelAssociator::HasNotMigratedYet(
    536     const sync_api::BaseTransaction* trans) {
    537 
    538   // Now read the current value from the directory.
    539   syncable::AutofillMigrationState autofill_migration_state =
    540       sync_service_->GetAutofillMigrationState();
    541 
    542   DCHECK_NE(autofill_migration_state, syncable::NOT_DETERMINED);
    543 
    544   if (autofill_migration_state== syncable::NOT_DETERMINED) {
    545     VLOG(1) << "Autofill migration state is not determined inside "
    546             << " model associator";
    547   }
    548 
    549   if (autofill_migration_state == syncable::NOT_MIGRATED) {
    550     return true;
    551   }
    552 
    553   if (autofill_migration_state == syncable::INSUFFICIENT_INFO_TO_DETERMINE) {
    554       VLOG(1) << "[AUTOFILL MIGRATION]"
    555               << "current autofill migration state is insufficient info to"
    556               << "determine.";
    557       sync_api::ReadNode autofill_profile_root_node(trans);
    558       if (!autofill_profile_root_node.InitByTagLookup(
    559           browser_sync::kAutofillProfileTag) ||
    560           autofill_profile_root_node.GetFirstChildId()==
    561             static_cast<int64>(0)) {
    562         sync_service_->SetAutofillMigrationState(
    563             syncable::NOT_MIGRATED);
    564 
    565         VLOG(1) << "[AUTOFILL MIGRATION]"
    566                 << "Current autofill migration state is NOT Migrated because"
    567                 << "legacy autofill root node is present whereas new "
    568                 << "Autofill profile root node is absent.";
    569         return true;
    570       }
    571 
    572       sync_service_->SetAutofillMigrationState(syncable::MIGRATED);
    573 
    574       VLOG(1) << "[AUTOFILL MIGRATION]"
    575               << "Current autofill migration state is migrated.";
    576   }
    577 
    578   return false;
    579 }
    580 
    581 bool AutofillModelAssociator::CryptoReadyIfNecessary() {
    582   // We only access the cryptographer while holding a transaction.
    583   sync_api::ReadTransaction trans(sync_service_->GetUserShare());
    584   syncable::ModelTypeSet encrypted_types;
    585   sync_service_->GetEncryptedDataTypes(&encrypted_types);
    586   return encrypted_types.count(syncable::AUTOFILL) == 0 ||
    587          sync_service_->IsCryptographerReady(&trans);
    588 }
    589 
    590 }  // namespace browser_sync
    591