Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(992)

Side by Side Diff: components/autofill/core/browser/personal_data_manager.cc

Issue 2074253002: [Autofill] Dedupe profiles on each major version. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed mathp's comments Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "components/autofill/core/browser/personal_data_manager.h" 5 #include "components/autofill/core/browser/personal_data_manager.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <algorithm> 8 #include <algorithm>
9 #include <list> 9 #include <list>
10 #include <map> 10 #include <map>
(...skipping 21 matching lines...) Expand all
32 #include "components/autofill/core/browser/phone_number_i18n.h" 32 #include "components/autofill/core/browser/phone_number_i18n.h"
33 #include "components/autofill/core/browser/validation.h" 33 #include "components/autofill/core/browser/validation.h"
34 #include "components/autofill/core/common/autofill_pref_names.h" 34 #include "components/autofill/core/common/autofill_pref_names.h"
35 #include "components/autofill/core/common/autofill_switches.h" 35 #include "components/autofill/core/common/autofill_switches.h"
36 #include "components/autofill/core/common/autofill_util.h" 36 #include "components/autofill/core/common/autofill_util.h"
37 #include "components/prefs/pref_service.h" 37 #include "components/prefs/pref_service.h"
38 #include "components/signin/core/browser/account_tracker_service.h" 38 #include "components/signin/core/browser/account_tracker_service.h"
39 #include "components/signin/core/browser/signin_manager.h" 39 #include "components/signin/core/browser/signin_manager.h"
40 #include "components/signin/core/common/signin_pref_names.h" 40 #include "components/signin/core/common/signin_pref_names.h"
41 #include "components/variations/variations_associated_data.h" 41 #include "components/variations/variations_associated_data.h"
42 #include "components/version_info/version_info.h"
42 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_da ta.h" 43 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_da ta.h"
43 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_fo rmatter.h" 44 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_fo rmatter.h"
44 45
45 namespace autofill { 46 namespace autofill {
46 namespace { 47 namespace {
47 48
48 using ::i18n::addressinput::AddressField; 49 using ::i18n::addressinput::AddressField;
49 using ::i18n::addressinput::GetStreetAddressLinesAsSingleLine; 50 using ::i18n::addressinput::GetStreetAddressLinesAsSingleLine;
50 using ::i18n::addressinput::STREET_ADDRESS; 51 using ::i18n::addressinput::STREET_ADDRESS;
51 52
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 pending_profiles_query_ = 0; 318 pending_profiles_query_ = 0;
318 return; 319 return;
319 } 320 }
320 321
321 switch (result->GetType()) { 322 switch (result->GetType()) {
322 case AUTOFILL_PROFILES_RESULT: 323 case AUTOFILL_PROFILES_RESULT:
323 if (h == pending_profiles_query_) { 324 if (h == pending_profiles_query_) {
324 ReceiveLoadedDbValues(h, result, &pending_profiles_query_, 325 ReceiveLoadedDbValues(h, result, &pending_profiles_query_,
325 &web_profiles_); 326 &web_profiles_);
326 LogProfileCount(); // This only logs local profiles. 327 LogProfileCount(); // This only logs local profiles.
327 ApplyProfileUseDatesFix(); 328 // Since these two routines both re-launch the database queries, don't
329 // run them on the same query response.
330 if (!ApplyDedupingRoutine())
331 ApplyProfileUseDatesFix();
328 } else { 332 } else {
329 ReceiveLoadedDbValues(h, result, &pending_server_profiles_query_, 333 ReceiveLoadedDbValues(h, result, &pending_server_profiles_query_,
330 &server_profiles_); 334 &server_profiles_);
331 335
332 if (!server_profiles_.empty()) { 336 if (!server_profiles_.empty()) {
333 std::string account_id = signin_manager_->GetAuthenticatedAccountId(); 337 std::string account_id = signin_manager_->GetAuthenticatedAccountId();
334 base::string16 email = 338 base::string16 email =
335 base::UTF8ToUTF16( 339 base::UTF8ToUTF16(
336 account_tracker_->GetAccountInfo(account_id).email); 340 account_tracker_->GetAccountInfo(account_id).email);
337 341
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after
928 if (!matching_profile_found && 932 if (!matching_profile_found &&
929 !new_profile.PrimaryValue(app_locale_).empty() && 933 !new_profile.PrimaryValue(app_locale_).empty() &&
930 existing_profile->SaveAdditionalInfo(new_profile, app_locale)) { 934 existing_profile->SaveAdditionalInfo(new_profile, app_locale)) {
931 // Unverified profiles should always be updated with the newer data, 935 // Unverified profiles should always be updated with the newer data,
932 // whereas verified profiles should only ever be overwritten by verified 936 // whereas verified profiles should only ever be overwritten by verified
933 // data. If an automatically aggregated profile would overwrite a 937 // data. If an automatically aggregated profile would overwrite a
934 // verified profile, just drop it. 938 // verified profile, just drop it.
935 matching_profile_found = true; 939 matching_profile_found = true;
936 guid = existing_profile->guid(); 940 guid = existing_profile->guid();
937 941
938 if (IsAutofillProfileCleanupEnabled()) {
939 // Look for duplicates of |existing_profile| to merge into.
940 FindMergeAndDeleteDuplicateProfiles(existing_profiles,
941 existing_profile);
942 }
943
944 // We set the modification date so that immediate requests for profiles 942 // We set the modification date so that immediate requests for profiles
945 // will properly reflect the fact that this profile has been modified 943 // will properly reflect the fact that this profile has been modified
946 // recently. After writing to the database and refreshing the local copies 944 // recently. After writing to the database and refreshing the local copies
947 // the profile will have a very slightly newer time reflecting what's 945 // the profile will have a very slightly newer time reflecting what's
948 // actually stored in the database. 946 // actually stored in the database.
949 existing_profile->set_modification_date(base::Time::Now()); 947 existing_profile->set_modification_date(base::Time::Now());
950 } 948 }
951 merged_profiles->push_back(*existing_profile); 949 merged_profiles->push_back(*existing_profile);
952 } 950 }
953 951
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after
1549 if (IsFeatureSubstringMatchEnabled()) { 1547 if (IsFeatureSubstringMatchEnabled()) {
1550 std::stable_sort(suggestions.begin(), suggestions.end(), 1548 std::stable_sort(suggestions.begin(), suggestions.end(),
1551 [](const Suggestion& a, const Suggestion& b) { 1549 [](const Suggestion& a, const Suggestion& b) {
1552 return a.match < b.match; 1550 return a.match < b.match;
1553 }); 1551 });
1554 } 1552 }
1555 1553
1556 return suggestions; 1554 return suggestions;
1557 } 1555 }
1558 1556
1559 void PersonalDataManager::FindMergeAndDeleteDuplicateProfiles(
1560 const std::vector<AutofillProfile*>& existing_profiles,
1561 AutofillProfile* profile_to_merge) {
1562 std::vector<std::string> profile_guids_to_delete;
1563
1564 FindAndMergeDuplicateProfiles(existing_profiles, profile_to_merge,
1565 &profile_guids_to_delete);
1566
1567 // Delete the duplicate profiles.
1568 for (const std::string& profile_guid_to_delete : profile_guids_to_delete) {
1569 RemoveByGUID(profile_guid_to_delete);
1570 }
1571 }
1572
1573 void PersonalDataManager::FindAndMergeDuplicateProfiles(
1574 const std::vector<AutofillProfile*>& existing_profiles,
1575 AutofillProfile* profile_to_merge,
1576 std::vector<std::string>* profile_guids_to_delete) {
1577 AutofillMetrics::LogNumberOfProfilesConsideredForDedupe(
1578 existing_profiles.size());
1579 for (AutofillProfile* existing_profile : existing_profiles) {
1580 // Don't try to merge a profile with itself or with any profile with a
1581 // different PrimaryValue.
1582 if (existing_profile->guid() != profile_to_merge->guid() &&
1583 AutofillProfile::CanonicalizeProfileString(
1584 existing_profile->PrimaryValue(app_locale_)) ==
1585 AutofillProfile::CanonicalizeProfileString(
1586 profile_to_merge->PrimaryValue(app_locale_))) {
1587 if (existing_profile->SaveAdditionalInfo(*profile_to_merge,
1588 app_locale_)) {
1589 // Since |profile_to_merge| was a duplicate of |existing_profile| and
1590 // was merged sucessfully, it can now be deleted. The only exception is
1591 // if |profile_to_merge| is verified and |existing_profile| is not.
1592 // Verified profiles only merge with other verified profiles.
1593 if (!profile_to_merge->IsVerified() || existing_profile->IsVerified())
1594 profile_guids_to_delete->push_back(profile_to_merge->guid());
1595
1596 // Now try to merge the new resulting profile with the rest of the
1597 // existing profiles.
1598 profile_to_merge = existing_profile;
1599 }
1600 }
1601 }
1602
1603 AutofillMetrics::LogNumberOfProfilesRemovedDuringDedupe(
1604 profile_guids_to_delete->size());
1605 }
1606
1607 void PersonalDataManager::ApplyProfileUseDatesFix() { 1557 void PersonalDataManager::ApplyProfileUseDatesFix() {
1608 // Don't run if the fix has already been applied. 1558 // Don't run if the fix has already been applied.
1609 if (pref_service_->GetBoolean(prefs::kAutofillProfileUseDatesFixed)) 1559 if (pref_service_->GetBoolean(prefs::kAutofillProfileUseDatesFixed))
1610 return; 1560 return;
1611 1561
1612 std::vector<AutofillProfile> profiles; 1562 std::vector<AutofillProfile> profiles;
1613 bool has_changed_data = false; 1563 bool has_changed_data = false;
1614 for (AutofillProfile* profile : web_profiles()) { 1564 for (AutofillProfile* profile : web_profiles()) {
1615 if (profile->use_date() == base::Time()) { 1565 if (profile->use_date() == base::Time()) {
1616 profile->set_use_date(base::Time::Now() - base::TimeDelta::FromDays(14)); 1566 profile->set_use_date(base::Time::Now() - base::TimeDelta::FromDays(14));
1617 has_changed_data = true; 1567 has_changed_data = true;
1618 } 1568 }
1619 profiles.push_back(*profile); 1569 profiles.push_back(*profile);
1620 } 1570 }
1621 1571
1622 // Set the pref so that this fix is never run again. 1572 // Set the pref so that this fix is never run again.
1623 pref_service_->SetBoolean(prefs::kAutofillProfileUseDatesFixed, true); 1573 pref_service_->SetBoolean(prefs::kAutofillProfileUseDatesFixed, true);
1624 1574
1625 if (has_changed_data) 1575 if (has_changed_data)
1626 SetProfiles(&profiles); 1576 SetProfiles(&profiles);
1627 } 1577 }
1628 1578
1579 bool PersonalDataManager::ApplyDedupingRoutine() {
1580 if (!IsAutofillProfileCleanupEnabled())
1581 return false;
1582
1583 int current_major_version = atoi(version_info::GetVersionNumber().c_str());
1584
1585 // Check if the deduping routine was run on this major version.
Roger McFarlane (Chromium) 2016/06/20 18:40:04 nit: ...was already run... or, better yet, ...h
sebsg 2016/06/20 19:12:19 Done.
1586 if (!(pref_service_->GetInteger(prefs::kAutofillLastVersionDeduped) <
Mathieu 2016/06/20 15:48:54 I think I would prefer >=, it's cleaner.
sebsg 2016/06/20 19:12:19 Done.
1587 current_major_version))
1588 return false;
1589
1590 std::vector<AutofillProfile*> existing_profiles = web_profiles_.get();
1591 std::set<std::string> profile_guids_to_delete;
Roger McFarlane (Chromium) 2016/06/20 18:40:04 micro-optimizations: * Why reference the profiles
sebsg 2016/06/20 19:12:19 Done.
1592
1593 DedupeProfiles(&existing_profiles, &profile_guids_to_delete);
1594
1595 // Set the pref to the current major version.
1596 pref_service_->SetInteger(prefs::kAutofillLastVersionDeduped,
Roger McFarlane (Chromium) 2016/06/20 18:40:04 unless there is no possibility of failure beyond t
sebsg 2016/06/20 19:12:19 Done.
1597 current_major_version);
1598
1599 // Apply the changes to the database.
1600 for (AutofillProfile* profile : existing_profiles) {
1601 // If the profile was set to be deleted, remove it from the database.
1602 if (profile_guids_to_delete.count(profile->guid())) {
1603 database_->RemoveAutofillProfile(profile->guid());
1604 } else {
1605 // Otherwise, update the profile in the database.
1606 database_->UpdateAutofillProfile(*profile);
1607 }
1608 }
1609
1610 // Refresh the local cache and send notifications to observers.
1611 Refresh();
1612
1613 return true;
1614 }
1615
1616 void PersonalDataManager::DedupeProfiles(
1617 std::vector<AutofillProfile*>* existing_profiles,
1618 std::set<std::string>* profile_guids_to_delete) {
Roger McFarlane (Chromium) 2016/06/20 18:40:04 unordered_set, reserved existing_profiles.size()
sebsg 2016/06/20 19:12:19 Done.
1619 // Sort the profiles by frecency with all the verified profiles at the end.
1620 // That way the most relevant profiles will get merged into the less relevant
1621 // profiles, which keeps the syntax of the most relevant profiles data.
1622 // Verified profiles are put at the end because they do not merge into other
1623 // profiles, so the loop can be stopped when we reach those. However they need
1624 // to be in the vector because an unverified profile trying to merge into a
1625 // similar verified profile will be discarded.
1626 base::Time comparison_time = base::Time::Now();
1627 std::sort(existing_profiles->begin(), existing_profiles->end(),
1628 [comparison_time](const AutofillDataModel* a,
1629 const AutofillDataModel* b) {
1630 if (a->IsVerified() != b->IsVerified())
1631 return !a->IsVerified();
1632 return a->CompareFrecency(b, comparison_time);
1633 });
1634
1635 AutofillMetrics::LogNumberOfProfilesConsideredForDedupe(
Roger McFarlane (Chromium) 2016/06/20 18:40:04 move the log to the beginning... since it's not a
sebsg 2016/06/20 19:12:19 Done.
1636 existing_profiles->size());
1637
1638 for (size_t i = 0; i < existing_profiles->size(); ++i) {
1639 AutofillProfile* profile_to_merge = (*existing_profiles)[i];
1640
1641 // If the profile was set to be deleted, skip it. It has already been
1642 // merged into another profile.
1643 if (profile_guids_to_delete->count(profile_to_merge->guid()))
1644 continue;
1645
1646 // If we have reached the verified profiles, stop trying to merge. Verified
1647 // profiles do not get merged.
1648 if (profile_to_merge->IsVerified())
1649 break;
1650
1651 // If we have not reached the last profile.
1652 if (i + 1 < existing_profiles->size()) {
Roger McFarlane (Chromium) 2016/06/20 18:40:04 this is redundant with the bounds in the enclosed
sebsg 2016/06/20 19:12:19 Done.
1653 // Try to merge |profile_to_merge| with all the less relevant
1654 // |existing_profiles|.
1655 for (size_t j = i + 1; j < existing_profiles->size(); ++j) {
1656 // Don't try to merge a profile that was already set for deletion. Also
1657 // don't try to merge with profiles with a different PrimaryValue
1658 // because they are not similar.
1659 AutofillProfile* existing_profile = (*existing_profiles)[j];
1660 if (!profile_guids_to_delete->count(existing_profile->guid()) &&
1661 existing_profile->PrimaryValue(app_locale_) ==
1662 profile_to_merge->PrimaryValue(app_locale_)) {
1663 // If the profiles are found to be similar, |profile_to_merge|'s non
1664 // empty data will overwrite the |existing_profile|'s data.
1665 // |existing_profile| will have added the complementary data from
1666 // |profile_to_merge| and will keep the most relevant syntax for data
1667 // present in both profiles.
1668 if (existing_profile->SaveAdditionalInfo(*profile_to_merge,
1669 app_locale_)) {
1670 // Since |profile_to_merge| was a duplicate of |existing_profile|
1671 // and was merged sucessfully, it can now be deleted.
1672 profile_guids_to_delete->insert(profile_to_merge->guid());
1673
1674 // Now try to merge the new resulting profile with the rest of the
1675 // existing profiles.
1676 profile_to_merge = existing_profile;
1677
1678 // Verified profiles do not get merged. Save some time by not
1679 // trying.
1680 if (profile_to_merge->IsVerified())
Roger McFarlane (Chromium) 2016/06/20 18:40:04 this check seems too late. I think you need to ch
sebsg 2016/06/20 19:12:19 The |existing_profile| can (and should sometimes)
Roger McFarlane (Chromium) 2016/06/20 19:18:36 Acknowledged.
1681 break;
1682 }
1683 }
1684 }
1685 }
1686 }
1687 AutofillMetrics::LogNumberOfProfilesRemovedDuringDedupe(
1688 profile_guids_to_delete->size());
1689 }
1690
1629 } // namespace autofill 1691 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698