1 // Copyright 2015 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 "components/browsing_data/core/counters/autofill_counter.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <utility>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "components/autofill/core/browser/data_model/autofill_profile.h"
14 #include "components/autofill/core/browser/data_model/credit_card.h"
15 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
16 #include "components/browsing_data/core/pref_names.h"
17 #include "components/sync/driver/sync_service.h"
18 #include "components/sync/driver/sync_user_settings.h"
19
20 namespace {
21
IsAutofillSyncEnabled(const syncer::SyncService * sync_service)22 bool IsAutofillSyncEnabled(const syncer::SyncService* sync_service) {
23 return sync_service &&
24 sync_service->GetUserSettings()->IsFirstSetupComplete() &&
25 sync_service->IsSyncFeatureActive() &&
26 sync_service->GetActiveDataTypes().Has(syncer::AUTOFILL);
27 }
28
29 } // namespace
30
31 namespace browsing_data {
32
AutofillCounter(scoped_refptr<autofill::AutofillWebDataService> web_data_service,syncer::SyncService * sync_service)33 AutofillCounter::AutofillCounter(
34 scoped_refptr<autofill::AutofillWebDataService> web_data_service,
35 syncer::SyncService* sync_service)
36 : web_data_service_(web_data_service),
37 sync_tracker_(this, sync_service),
38 suggestions_query_(0),
39 credit_cards_query_(0),
40 addresses_query_(0),
41 num_suggestions_(0),
42 num_credit_cards_(0),
43 num_addresses_(0) {}
44
~AutofillCounter()45 AutofillCounter::~AutofillCounter() {
46 CancelAllRequests();
47 }
48
OnInitialized()49 void AutofillCounter::OnInitialized() {
50 DCHECK(web_data_service_);
51 sync_tracker_.OnInitialized(base::BindRepeating(&IsAutofillSyncEnabled));
52 }
53
GetPrefName() const54 const char* AutofillCounter::GetPrefName() const {
55 return browsing_data::prefs::kDeleteFormData;
56 }
57
SetPeriodStartForTesting(const base::Time & period_start_for_testing)58 void AutofillCounter::SetPeriodStartForTesting(
59 const base::Time& period_start_for_testing) {
60 period_start_for_testing_ = period_start_for_testing;
61 }
62
SetPeriodEndForTesting(const base::Time & period_end_for_testing)63 void AutofillCounter::SetPeriodEndForTesting(
64 const base::Time& period_end_for_testing) {
65 period_end_for_testing_ = period_end_for_testing;
66 }
67
Count()68 void AutofillCounter::Count() {
69 const base::Time start = period_start_for_testing_.is_null()
70 ? GetPeriodStart()
71 : period_start_for_testing_;
72 const base::Time end = period_end_for_testing_.is_null()
73 ? GetPeriodEnd()
74 : period_end_for_testing_;
75
76 CancelAllRequests();
77
78 // Count the autocomplete suggestions (also called form elements in Autofill).
79 // Note that |AutofillTable::RemoveFormElementsAddedBetween| only deletes
80 // those whose entire existence (i.e. the interval between creation time
81 // and last modified time) lies within the deletion time range. Otherwise,
82 // it only decreases the count property, but always to a nonzero value,
83 // and the suggestion is retained. Therefore here as well, we must only count
84 // the entries that are entirely contained in [start, end).
85 // Further, many of these entries may contain the same values, as they are
86 // simply the same data point entered on different forms. For example,
87 // [name, value] pairs such as:
88 // ["mail", "example@example.com"]
89 // ["email", "example@example.com"]
90 // ["e-mail", "example@example.com"]
91 // are stored as three separate entries, but from the user's perspective,
92 // they constitute the same suggestion - "my email". Therefore, for the final
93 // output, we will consider all entries with the same value as one suggestion,
94 // and increment the counter only if all entries with the given value are
95 // contained in the interval [start, end).
96 suggestions_query_ =
97 web_data_service_->GetCountOfValuesContainedBetween(start, end, this);
98
99 // Count the credit cards.
100 credit_cards_query_ = web_data_service_->GetCreditCards(this);
101
102 // Count the addresses.
103 addresses_query_ = web_data_service_->GetAutofillProfiles(this);
104 }
105
OnWebDataServiceRequestDone(WebDataServiceBase::Handle handle,std::unique_ptr<WDTypedResult> result)106 void AutofillCounter::OnWebDataServiceRequestDone(
107 WebDataServiceBase::Handle handle,
108 std::unique_ptr<WDTypedResult> result) {
109 DCHECK(thread_checker_.CalledOnValidThread());
110
111 if (!result) {
112 // CancelAllRequests will cancel all queries that are active; the query that
113 // just failed is complete and cannot be canceled so zero it out.
114 if (handle == suggestions_query_) {
115 suggestions_query_ = 0;
116 } else if (handle == credit_cards_query_) {
117 credit_cards_query_ = 0;
118 } else if (handle == addresses_query_) {
119 addresses_query_ = 0;
120 } else {
121 NOTREACHED();
122 }
123
124 CancelAllRequests();
125 return;
126 }
127
128 const base::Time start = period_start_for_testing_.is_null()
129 ? GetPeriodStart()
130 : period_start_for_testing_;
131 const base::Time end = period_end_for_testing_.is_null()
132 ? GetPeriodEnd()
133 : period_end_for_testing_;
134
135 if (handle == suggestions_query_) {
136 // Autocomplete suggestions.
137 DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType());
138 num_suggestions_ =
139 static_cast<const WDResult<int>*>(result.get())->GetValue();
140 suggestions_query_ = 0;
141
142 } else if (handle == credit_cards_query_) {
143 // Credit cards.
144 DCHECK_EQ(AUTOFILL_CREDITCARDS_RESULT, result->GetType());
145 auto credit_cards =
146 static_cast<
147 WDResult<std::vector<std::unique_ptr<autofill::CreditCard>>>*>(
148 result.get())
149 ->GetValue();
150
151 num_credit_cards_ = std::count_if(
152 credit_cards.begin(), credit_cards.end(),
153 [start, end](const std::unique_ptr<autofill::CreditCard>& card) {
154 return (card->modification_date() >= start &&
155 card->modification_date() < end);
156 });
157 credit_cards_query_ = 0;
158
159 } else if (handle == addresses_query_) {
160 // Addresses.
161 DCHECK_EQ(AUTOFILL_PROFILES_RESULT, result->GetType());
162 auto addresses =
163 static_cast<
164 WDResult<std::vector<std::unique_ptr<autofill::AutofillProfile>>>*>(
165 result.get())
166 ->GetValue();
167
168 num_addresses_ = std::count_if(
169 addresses.begin(), addresses.end(),
170 [start,
171 end](const std::unique_ptr<autofill::AutofillProfile>& address) {
172 return (address->modification_date() >= start &&
173 address->modification_date() < end);
174 });
175 addresses_query_ = 0;
176
177 } else {
178 NOTREACHED() << "No such query: " << handle;
179 }
180
181 // If we still have pending queries, do not report data yet.
182 if (suggestions_query_ || credit_cards_query_ || addresses_query_)
183 return;
184
185 auto reported_result = std::make_unique<AutofillResult>(
186 this, num_suggestions_, num_credit_cards_, num_addresses_,
187 sync_tracker_.IsSyncActive());
188 ReportResult(std::move(reported_result));
189 }
190
CancelAllRequests()191 void AutofillCounter::CancelAllRequests() {
192 if (suggestions_query_)
193 web_data_service_->CancelRequest(suggestions_query_);
194 if (credit_cards_query_)
195 web_data_service_->CancelRequest(credit_cards_query_);
196 if (addresses_query_)
197 web_data_service_->CancelRequest(addresses_query_);
198 }
199
200 // AutofillCounter::AutofillResult ---------------------------------------------
201
AutofillResult(const AutofillCounter * source,ResultInt num_suggestions,ResultInt num_credit_cards,ResultInt num_addresses,bool autofill_sync_enabled_)202 AutofillCounter::AutofillResult::AutofillResult(const AutofillCounter* source,
203 ResultInt num_suggestions,
204 ResultInt num_credit_cards,
205 ResultInt num_addresses,
206 bool autofill_sync_enabled_)
207 : SyncResult(source, num_suggestions, autofill_sync_enabled_),
208 num_credit_cards_(num_credit_cards),
209 num_addresses_(num_addresses) {}
210
~AutofillResult()211 AutofillCounter::AutofillResult::~AutofillResult() {}
212
213 } // namespace browsing_data
214