OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/glue/autofill_model_associator.h" | 5 #include "chrome/browser/sync/glue/autofill_model_associator.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/task.h" | 9 #include "base/task.h" |
10 #include "base/time.h" | 10 #include "base/time.h" |
11 #include "base/string_number_conversions.h" | 11 #include "base/string_number_conversions.h" |
12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
13 #include "chrome/browser/autofill/autofill_profile.h" | 13 #include "chrome/browser/autofill/autofill_profile.h" |
14 #include "chrome/browser/browser_thread.h" | 14 #include "chrome/browser/browser_thread.h" |
15 #include "chrome/browser/guid.h" | 15 #include "chrome/browser/guid.h" |
| 16 #include "chrome/browser/prefs/pref_service.h" |
16 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/browser/sync/engine/syncapi.h" | 18 #include "chrome/browser/sync/engine/syncapi.h" |
18 #include "chrome/browser/sync/glue/autofill_change_processor.h" | 19 #include "chrome/browser/sync/glue/autofill_change_processor.h" |
| 20 #include "chrome/browser/sync/glue/autofill_profile_model_associator.h" |
| 21 #include "chrome/browser/sync/glue/do_optimistic_refresh_task.h" |
19 #include "chrome/browser/sync/profile_sync_service.h" | 22 #include "chrome/browser/sync/profile_sync_service.h" |
20 #include "chrome/browser/sync/protocol/autofill_specifics.pb.h" | 23 #include "chrome/browser/sync/protocol/autofill_specifics.pb.h" |
21 #include "chrome/browser/webdata/web_database.h" | 24 #include "chrome/browser/webdata/web_database.h" |
| 25 #include "chrome/common/pref_names.h" |
22 #include "net/base/escape.h" | 26 #include "net/base/escape.h" |
23 | 27 |
24 using base::TimeTicks; | 28 using base::TimeTicks; |
25 | 29 |
26 namespace browser_sync { | 30 namespace browser_sync { |
27 | 31 |
28 const char kAutofillTag[] = "google_chrome_autofill"; | 32 const char kAutofillTag[] = "google_chrome_autofill"; |
29 const char kAutofillEntryNamespaceTag[] = "autofill_entry|"; | 33 const char kAutofillEntryNamespaceTag[] = "autofill_entry|"; |
30 | 34 |
31 struct AutofillModelAssociator::DataBundle { | 35 struct AutofillModelAssociator::DataBundle { |
32 std::set<AutofillKey> current_entries; | 36 std::set<AutofillKey> current_entries; |
33 std::vector<AutofillEntry> new_entries; | 37 std::vector<AutofillEntry> new_entries; |
34 std::set<string16> current_profiles; | 38 std::set<string16> current_profiles; |
35 std::vector<AutoFillProfile*> updated_profiles; | 39 std::vector<AutoFillProfile*> updated_profiles; |
36 std::vector<AutoFillProfile*> new_profiles; // We own these pointers. | 40 std::vector<AutoFillProfile*> new_profiles; // We own these pointers. |
37 ~DataBundle() { STLDeleteElements(&new_profiles); } | 41 ~DataBundle() { STLDeleteElements(&new_profiles); } |
38 }; | 42 }; |
39 | 43 |
40 AutofillModelAssociator::DoOptimisticRefreshTask::DoOptimisticRefreshTask( | |
41 PersonalDataManager* pdm) : pdm_(pdm) {} | |
42 | |
43 AutofillModelAssociator::DoOptimisticRefreshTask::~DoOptimisticRefreshTask() {} | |
44 | |
45 void AutofillModelAssociator::DoOptimisticRefreshTask::Run() { | |
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
47 pdm_->Refresh(); | |
48 } | |
49 | |
50 AutofillModelAssociator::AutofillModelAssociator( | 44 AutofillModelAssociator::AutofillModelAssociator( |
51 ProfileSyncService* sync_service, | 45 ProfileSyncService* sync_service, |
52 WebDatabase* web_database, | 46 WebDatabase* web_database, |
53 PersonalDataManager* personal_data) | 47 PersonalDataManager* personal_data) |
54 : sync_service_(sync_service), | 48 : sync_service_(sync_service), |
55 web_database_(web_database), | 49 web_database_(web_database), |
56 personal_data_(personal_data), | 50 personal_data_(personal_data), |
57 autofill_node_id_(sync_api::kInvalidId), | 51 autofill_node_id_(sync_api::kInvalidId), |
58 abort_association_pending_(false) { | 52 abort_association_pending_(false), |
| 53 number_of_entries_created_(0) { |
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
60 DCHECK(sync_service_); | 55 DCHECK(sync_service_); |
61 DCHECK(web_database_); | 56 DCHECK(web_database_); |
62 DCHECK(personal_data_); | 57 DCHECK(personal_data_); |
63 } | 58 } |
64 | 59 |
65 AutofillModelAssociator::~AutofillModelAssociator() { | 60 AutofillModelAssociator::~AutofillModelAssociator() { |
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
67 } | 62 } |
68 | 63 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 } else { | 102 } else { |
108 sync_api::WriteNode node(write_trans); | 103 sync_api::WriteNode node(write_trans); |
109 if (!node.InitUniqueByCreation(syncable::AUTOFILL, | 104 if (!node.InitUniqueByCreation(syncable::AUTOFILL, |
110 autofill_root, tag)) { | 105 autofill_root, tag)) { |
111 LOG(ERROR) << "Failed to create autofill sync node."; | 106 LOG(ERROR) << "Failed to create autofill sync node."; |
112 return false; | 107 return false; |
113 } | 108 } |
114 node.SetTitle(UTF8ToWide(tag)); | 109 node.SetTitle(UTF8ToWide(tag)); |
115 AutofillChangeProcessor::WriteAutofillEntry(*ix, &node); | 110 AutofillChangeProcessor::WriteAutofillEntry(*ix, &node); |
116 Associate(&tag, node.GetId()); | 111 Associate(&tag, node.GetId()); |
| 112 number_of_entries_created_++; |
117 } | 113 } |
118 | 114 |
119 current_entries->insert(ix->key()); | 115 current_entries->insert(ix->key()); |
120 } | 116 } |
121 return true; | 117 return true; |
122 } | 118 } |
123 | 119 |
124 bool AutofillModelAssociator::MakeNewAutofillProfileSyncNode( | |
125 sync_api::WriteTransaction* trans, const sync_api::BaseNode& autofill_root, | |
126 const std::string& tag, const AutoFillProfile& profile, int64* sync_id) { | |
127 sync_api::WriteNode node(trans); | |
128 if (!node.InitUniqueByCreation(syncable::AUTOFILL, autofill_root, tag)) { | |
129 LOG(ERROR) << "Failed to create autofill sync node."; | |
130 return false; | |
131 } | |
132 node.SetTitle(UTF8ToWide(tag)); | |
133 AutofillChangeProcessor::WriteAutofillProfile(profile, &node); | |
134 *sync_id = node.GetId(); | |
135 return true; | |
136 } | |
137 | |
138 | |
139 bool AutofillModelAssociator::LoadAutofillData( | 120 bool AutofillModelAssociator::LoadAutofillData( |
140 std::vector<AutofillEntry>* entries, | 121 std::vector<AutofillEntry>* entries, |
141 std::vector<AutoFillProfile*>* profiles) { | 122 std::vector<AutoFillProfile*>* profiles) { |
142 if (IsAbortPending()) | 123 if (IsAbortPending()) |
143 return false; | 124 return false; |
144 if (!web_database_->GetAllAutofillEntries(entries)) | 125 if (!web_database_->GetAllAutofillEntries(entries)) |
145 return false; | 126 return false; |
146 | 127 |
147 if (IsAbortPending()) | 128 if (IsAbortPending()) |
148 return false; | 129 return false; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 // Since we're on the DB thread, we don't have to worry about updating | 179 // Since we're on the DB thread, we don't have to worry about updating |
199 // the autofill database after closing the write transaction, since | 180 // the autofill database after closing the write transaction, since |
200 // this is the only thread that writes to the database. We also don't have | 181 // this is the only thread that writes to the database. We also don't have |
201 // to worry about the sync model getting out of sync, because changes are | 182 // to worry about the sync model getting out of sync, because changes are |
202 // propogated to the ChangeProcessor on this thread. | 183 // propogated to the ChangeProcessor on this thread. |
203 if (!SaveChangesToWebData(bundle)) { | 184 if (!SaveChangesToWebData(bundle)) { |
204 LOG(ERROR) << "Failed to update autofill entries."; | 185 LOG(ERROR) << "Failed to update autofill entries."; |
205 return false; | 186 return false; |
206 } | 187 } |
207 | 188 |
| 189 if (sync_service_->backend()->GetAutofillMigrationState() != |
| 190 syncable::MIGRATED) { |
| 191 syncable::AutofillMigrationDebugInfo debug_info; |
| 192 debug_info.autofill_entries_added_during_migration = |
| 193 number_of_entries_created_; |
| 194 sync_service_->backend()->SetAutofillMigrationDebugInfo( |
| 195 syncable::AutofillMigrationDebugInfo::ENTRIES_ADDED, |
| 196 debug_info); |
| 197 } |
| 198 |
208 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 199 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
209 new DoOptimisticRefreshTask(personal_data_)); | 200 new DoOptimisticRefreshForAutofill(personal_data_)); |
210 return true; | 201 return true; |
211 } | 202 } |
212 | 203 |
213 bool AutofillModelAssociator::SaveChangesToWebData(const DataBundle& bundle) { | 204 bool AutofillModelAssociator::SaveChangesToWebData(const DataBundle& bundle) { |
214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
215 | 206 |
216 if (IsAbortPending()) | 207 if (IsAbortPending()) |
217 return false; | 208 return false; |
218 | 209 |
219 if (bundle.new_entries.size() && | 210 if (bundle.new_entries.size() && |
(...skipping 17 matching lines...) Expand all Loading... |
237 return true; | 228 return true; |
238 } | 229 } |
239 | 230 |
240 bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes( | 231 bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes( |
241 sync_api::WriteTransaction* write_trans, | 232 sync_api::WriteTransaction* write_trans, |
242 const sync_api::ReadNode& autofill_root, | 233 const sync_api::ReadNode& autofill_root, |
243 DataBundle* bundle, | 234 DataBundle* bundle, |
244 const std::vector<AutoFillProfile*>& all_profiles_from_db) { | 235 const std::vector<AutoFillProfile*>& all_profiles_from_db) { |
245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
246 | 237 |
| 238 bool autofill_profile_not_migrated = HasNotMigratedYet(write_trans); |
| 239 |
| 240 if (MigrationLoggingEnabled() && |
| 241 autofill_profile_not_migrated) { |
| 242 VLOG(1) << "[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(1) << "[AUTOFILL MIGRATION] " |
| 249 << p->GetFieldText(AutoFillType(NAME_FIRST)) |
| 250 << p->GetFieldText(AutoFillType(NAME_LAST)); |
| 251 } |
| 252 } |
| 253 |
| 254 if (MigrationLoggingEnabled() && autofill_profile_not_migrated) { |
| 255 VLOG(1) << "[AUTOFILL MIGRATION]" |
| 256 << "Iterating over sync db"; |
| 257 } |
| 258 |
247 int64 sync_child_id = autofill_root.GetFirstChildId(); | 259 int64 sync_child_id = autofill_root.GetFirstChildId(); |
248 while (sync_child_id != sync_api::kInvalidId) { | 260 while (sync_child_id != sync_api::kInvalidId) { |
249 sync_api::ReadNode sync_child(write_trans); | 261 sync_api::ReadNode sync_child(write_trans); |
250 if (!sync_child.InitByIdLookup(sync_child_id)) { | 262 if (!sync_child.InitByIdLookup(sync_child_id)) { |
251 LOG(ERROR) << "Failed to fetch child node."; | 263 LOG(ERROR) << "Failed to fetch child node."; |
252 return false; | 264 return false; |
253 } | 265 } |
254 const sync_pb::AutofillSpecifics& autofill( | 266 const sync_pb::AutofillSpecifics& autofill( |
255 sync_child.GetAutofillSpecifics()); | 267 sync_child.GetAutofillSpecifics()); |
256 | 268 |
257 if (autofill.has_value()) { | 269 if (autofill.has_value()) { |
258 AddNativeEntryIfNeeded(autofill, bundle, sync_child); | 270 AddNativeEntryIfNeeded(autofill, bundle, sync_child); |
259 } else if (autofill.has_profile() && HasNotMigratedYet()) { | 271 } else if (autofill.has_profile()) { |
260 // Ignore autofill profiles if we are not upgrading. | 272 // Ignore autofill profiles if we are not upgrading. |
261 AddNativeProfileIfNeeded( | 273 if (autofill_profile_not_migrated) { |
262 autofill.profile(), | 274 if (MigrationLoggingEnabled()) { |
263 bundle, | 275 VLOG(1) << "[AUTOFILL MIGRATION] Looking for " |
264 sync_child, | 276 << autofill.profile().name_first() |
265 all_profiles_from_db); | 277 << autofill.profile().name_last(); |
| 278 } |
| 279 AddNativeProfileIfNeeded( |
| 280 autofill.profile(), |
| 281 bundle, |
| 282 sync_child, |
| 283 all_profiles_from_db); |
| 284 } |
266 } else { | 285 } else { |
267 NOTREACHED() << "AutofillSpecifics has no autofill data!"; | 286 NOTREACHED() << "AutofillSpecifics has no autofill data!"; |
268 } | 287 } |
269 | 288 |
270 sync_child_id = sync_child.GetSuccessorId(); | 289 sync_child_id = sync_child.GetSuccessorId(); |
271 } | 290 } |
272 return true; | 291 return true; |
273 } | 292 } |
274 | 293 |
275 // Define the functor to be used as the predicate in find_if call. | 294 // Define the functor to be used as the predicate in find_if call. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 } | 344 } |
326 | 345 |
327 void AutofillModelAssociator::AddNativeProfileIfNeeded( | 346 void AutofillModelAssociator::AddNativeProfileIfNeeded( |
328 const sync_pb::AutofillProfileSpecifics& profile, | 347 const sync_pb::AutofillProfileSpecifics& profile, |
329 DataBundle* bundle, | 348 DataBundle* bundle, |
330 const sync_api::ReadNode& node, | 349 const sync_api::ReadNode& node, |
331 const std::vector<AutoFillProfile*>& all_profiles_from_db) { | 350 const std::vector<AutoFillProfile*>& all_profiles_from_db) { |
332 | 351 |
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
334 | 353 |
335 scoped_ptr<AutoFillProfile> profile_in_web_db(FindCorrespondingNodeFromWebDB( | 354 AutoFillProfile* profile_in_web_db = FindCorrespondingNodeFromWebDB( |
336 profile, all_profiles_from_db)); | 355 profile, all_profiles_from_db); |
337 | 356 |
338 if (profile_in_web_db.get() != NULL) { | 357 if (profile_in_web_db != NULL) { |
| 358 if (MigrationLoggingEnabled()) { |
| 359 VLOG(1) << "[AUTOFILL MIGRATION]" |
| 360 << "Node found in web db. So associating"; |
| 361 } |
339 int64 sync_id = node.GetId(); | 362 int64 sync_id = node.GetId(); |
340 std::string guid = profile_in_web_db->guid(); | 363 std::string guid = profile_in_web_db->guid(); |
341 Associate(&guid, sync_id); | 364 Associate(&guid, sync_id); |
342 return; | 365 return; |
343 } else { // Create a new node. | 366 } else { // Create a new node. |
| 367 if (MigrationLoggingEnabled()) { |
| 368 VLOG(1) << "[AUTOFILL MIGRATION]" |
| 369 << "Node not found in web db so creating and associating"; |
| 370 } |
344 std::string guid = guid::GenerateGUID(); | 371 std::string guid = guid::GenerateGUID(); |
345 Associate(&guid, node.GetId()); | 372 Associate(&guid, node.GetId()); |
346 AutoFillProfile* p = new AutoFillProfile(guid); | 373 AutoFillProfile* p = new AutoFillProfile(guid); |
347 FillProfileWithServerData(p, profile); | 374 FillProfileWithServerData(p, profile); |
348 bundle->new_profiles.push_back(p); | 375 bundle->new_profiles.push_back(p); |
349 } | 376 } |
350 } | 377 } |
351 | 378 |
352 bool AutofillModelAssociator::DisassociateModels() { | 379 bool AutofillModelAssociator::DisassociateModels() { |
353 id_map_.clear(); | 380 id_map_.clear(); |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff; | 529 diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff; |
503 diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff; | 530 diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff; |
504 diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff; | 531 diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff; |
505 diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number()) | 532 diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number()) |
506 || diff; | 533 || diff; |
507 diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number()) | 534 diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number()) |
508 || diff; | 535 || diff; |
509 return diff; | 536 return diff; |
510 } | 537 } |
511 | 538 |
512 bool AutofillModelAssociator::HasNotMigratedYet() { | 539 bool AutofillModelAssociator::HasNotMigratedYet( |
513 return true; | 540 const sync_api::BaseTransaction* trans) { |
| 541 |
| 542 // Now read the current value from the directory. |
| 543 syncable::AutofillMigrationState autofill_migration_state = |
| 544 sync_service()->backend()->GetAutofillMigrationState(); |
| 545 |
| 546 DCHECK_NE(autofill_migration_state, syncable::NOT_DETERMINED); |
| 547 |
| 548 if (autofill_migration_state== syncable::NOT_DETERMINED) { |
| 549 VLOG(1) << "Autofill migration state is not determined inside " |
| 550 << " model associator"; |
| 551 } |
| 552 |
| 553 if (autofill_migration_state == syncable::NOT_MIGRATED) { |
| 554 return true; |
| 555 } |
| 556 |
| 557 if (autofill_migration_state == syncable::INSUFFICIENT_INFO_TO_DETERMINE) { |
| 558 if (MigrationLoggingEnabled()) { |
| 559 VLOG(1) << "[AUTOFILL MIGRATION]" |
| 560 << "current autofill migration state is insufficient info to" |
| 561 << "determine."; |
| 562 } |
| 563 sync_api::ReadNode autofill_profile_root_node(trans); |
| 564 if (!autofill_profile_root_node.InitByTagLookup( |
| 565 browser_sync::kAutofillProfileTag) || |
| 566 autofill_profile_root_node.GetFirstChildId()== |
| 567 static_cast<int64>(0)) { |
| 568 sync_service()->backend()->SetAutofillMigrationState( |
| 569 syncable::NOT_MIGRATED); |
| 570 |
| 571 if (MigrationLoggingEnabled()) { |
| 572 VLOG(1) << "[AUTOFILL MIGRATION]" |
| 573 << "Current autofill migration state is NOT Migrated because" |
| 574 << "legacy autofill root node is present whereas new " |
| 575 << "Autofill profile root node is absent."; |
| 576 } |
| 577 return true; |
| 578 } |
| 579 |
| 580 sync_service()->backend()->SetAutofillMigrationState(syncable::MIGRATED); |
| 581 |
| 582 if (MigrationLoggingEnabled()) { |
| 583 VLOG(1) << "[AUTOFILL MIGRATION]" |
| 584 << "Current autofill migration state is migrated."; |
| 585 } |
| 586 } |
| 587 |
| 588 return false; |
514 } | 589 } |
515 | 590 |
| 591 bool AutofillModelAssociator::MigrationLoggingEnabled() { |
| 592 // [TODO] enable logging via a command line flag. |
| 593 return false; |
| 594 } |
516 } // namespace browser_sync | 595 } // namespace browser_sync |
| 596 |
OLD | NEW |