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

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 rogerm'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 has already been run on this major version.
1586 if (pref_service_->GetInteger(prefs::kAutofillLastVersionDeduped) >=
1587 current_major_version)
1588 return false;
1589
1590 std::vector<AutofillProfile*> existing_profiles = web_profiles_.get();
1591 std::unordered_set<AutofillProfile*> profiles_to_delete;
1592 profiles_to_delete.reserve(existing_profiles.size());
1593
1594 DedupeProfiles(&existing_profiles, &profiles_to_delete);
1595
1596 // Apply the changes to the database.
1597 for (AutofillProfile* profile : existing_profiles) {
1598 // If the profile was set to be deleted, remove it from the database.
1599 if (profiles_to_delete.count(profile)) {
1600 database_->RemoveAutofillProfile(profile->guid());
1601 } else {
1602 // Otherwise, update the profile in the database.
1603 database_->UpdateAutofillProfile(*profile);
1604 }
1605 }
1606
1607 // Set the pref to the current major version.
1608 pref_service_->SetInteger(prefs::kAutofillLastVersionDeduped,
1609 current_major_version);
1610
1611 // Refresh the local cache and send notifications to observers.
1612 Refresh();
1613
1614 return true;
1615 }
1616
1617 void PersonalDataManager::DedupeProfiles(
1618 std::vector<AutofillProfile*>* existing_profiles,
1619 std::unordered_set<AutofillProfile*>* profiles_to_delete) {
1620 AutofillMetrics::LogNumberOfProfilesConsideredForDedupe(
1621 existing_profiles->size());
1622
1623 // Sort the profiles by frecency with all the verified profiles at the end.
1624 // That way the most relevant profiles will get merged into the less relevant
1625 // profiles, which keeps the syntax of the most relevant profiles data.
1626 // Verified profiles are put at the end because they do not merge into other
1627 // profiles, so the loop can be stopped when we reach those. However they need
1628 // to be in the vector because an unverified profile trying to merge into a
1629 // similar verified profile will be discarded.
1630 base::Time comparison_time = base::Time::Now();
1631 std::sort(existing_profiles->begin(), existing_profiles->end(),
1632 [comparison_time](const AutofillDataModel* a,
1633 const AutofillDataModel* b) {
1634 if (a->IsVerified() != b->IsVerified())
1635 return !a->IsVerified();
1636 return a->CompareFrecency(b, comparison_time);
1637 });
1638
1639 for (size_t i = 0; i < existing_profiles->size(); ++i) {
1640 AutofillProfile* profile_to_merge = (*existing_profiles)[i];
1641
1642 // If the profile was set to be deleted, skip it. It has already been
1643 // merged into another profile.
1644 if (profiles_to_delete->count(profile_to_merge))
1645 continue;
1646
1647 // If we have reached the verified profiles, stop trying to merge. Verified
1648 // profiles do not get merged.
1649 if (profile_to_merge->IsVerified())
1650 break;
1651
1652 // If we have not reached the last profile, try to merge |profile_to_merge|
1653 // with all the less relevant |existing_profiles|.
1654 for (size_t j = i + 1; j < existing_profiles->size(); ++j) {
1655 // Don't try to merge a profile that was already set for deletion. Also
1656 // don't try to merge with profiles with a different PrimaryValue
1657 // because they are not similar.
1658 AutofillProfile* existing_profile = (*existing_profiles)[j];
1659 if (!profiles_to_delete->count(existing_profile) &&
1660 existing_profile->PrimaryValue(app_locale_) ==
1661 profile_to_merge->PrimaryValue(app_locale_)) {
1662 // If the profiles are found to be similar, |profile_to_merge|'s non
1663 // empty data will overwrite the |existing_profile|'s data.
1664 // |existing_profile| will have added the complementary data from
1665 // |profile_to_merge| and will keep the most relevant syntax for data
1666 // present in both profiles.
1667 if (existing_profile->SaveAdditionalInfo(*profile_to_merge,
1668 app_locale_)) {
1669 // Since |profile_to_merge| was a duplicate of |existing_profile|
1670 // and was merged sucessfully, it can now be deleted.
1671 profiles_to_delete->insert(profile_to_merge);
1672
1673 // Now try to merge the new resulting profile with the rest of the
1674 // existing profiles.
1675 profile_to_merge = existing_profile;
1676
1677 // Verified profiles do not get merged. Save some time by not
1678 // trying.
1679 if (profile_to_merge->IsVerified())
1680 break;
1681 }
1682 }
1683 }
1684 }
1685 AutofillMetrics::LogNumberOfProfilesRemovedDuringDedupe(
1686 profiles_to_delete->size());
1687 }
1688
1629 } // namespace autofill 1689 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698