• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
~DataBundlebrowser_sync::AutofillModelAssociator::DataBundle40   ~DataBundle() { STLDeleteElements(&new_profiles); }
41 };
42 
AutofillModelAssociator(ProfileSyncService * sync_service,WebDatabase * web_database,PersonalDataManager * personal_data)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 
~AutofillModelAssociator()59 AutofillModelAssociator::~AutofillModelAssociator() {
60   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
61 }
62 
TraverseAndAssociateChromeAutofillEntries(sync_api::WriteTransaction * write_trans,const sync_api::ReadNode & autofill_root,const std::vector<AutofillEntry> & all_entries_from_db,std::set<AutofillKey> * current_entries,std::vector<AutofillEntry> * new_entries)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 
LoadAutofillData(std::vector<AutofillEntry> * entries,std::vector<AutofillProfile * > * profiles)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 
AssociateModels()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 
SaveChangesToWebData(const DataBundle & bundle)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 
TraverseAndAssociateAllSyncNodes(sync_api::WriteTransaction * write_trans,const sync_api::ReadNode & autofill_root,DataBundle * bundle,const std::vector<AutofillProfile * > & all_profiles_from_db)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> {
operator ()browser_sync::CompareProfiles295   bool operator() (AutofillProfile* p1, AutofillProfile* p2) const {
296     if (p1->Compare(*p2) == 0)
297       return true;
298     else
299       return false;
300   }
301 };
302 
FindCorrespondingNodeFromWebDB(const sync_pb::AutofillProfileSpecifics & profile,const std::vector<AutofillProfile * > & all_profiles_from_db)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 
AddNativeEntryIfNeeded(const sync_pb::AutofillSpecifics & autofill,DataBundle * bundle,const sync_api::ReadNode & node)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 
AddNativeProfileIfNeeded(const sync_pb::AutofillProfileSpecifics & profile,DataBundle * bundle,const sync_api::ReadNode & node,const std::vector<AutofillProfile * > & all_profiles_from_db)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 
DisassociateModels()377 bool AutofillModelAssociator::DisassociateModels() {
378   id_map_.clear();
379   id_map_inverse_.clear();
380   return true;
381 }
382 
SyncModelHasUserCreatedNodes(bool * has_nodes)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 
AbortAssociation()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*
GetChromeNodeFromSyncId(int64 sync_id)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 
InitSyncNodeFromChromeId(const std::string & node_id,sync_api::BaseNode * sync_node)419 bool AutofillModelAssociator::InitSyncNodeFromChromeId(
420     const std::string& node_id,
421     sync_api::BaseNode* sync_node) {
422   return false;
423 }
424 
GetSyncIdFromChromeId(const std::string & autofill)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 
Associate(const std::string * autofill,int64 sync_id)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 
Disassociate(int64 sync_id)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 
GetSyncIdForTaggedNode(const std::string & tag,int64 * sync_id)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 
IsAbortPending()460 bool AutofillModelAssociator::IsAbortPending() {
461   base::AutoLock lock(abort_association_pending_lock_);
462   return abort_association_pending_;
463 }
464 
465 // static
KeyToTag(const string16 & name,const string16 & value)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
MergeTimestamps(const sync_pb::AutofillSpecifics & autofill,const std::vector<base::Time> & timestamps,std::vector<base::Time> * new_timestamps)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.
MergeField(FormGroup * f,AutofillFieldType t,const std::string & specifics_field)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
FillProfileWithServerData(AutofillProfile * merge_into,const sync_pb::AutofillProfileSpecifics & specifics)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 
HasNotMigratedYet(const sync_api::BaseTransaction * trans)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 
CryptoReadyIfNecessary()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