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