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

Side by Side Diff: components/password_manager/core/browser/affiliation_backend.cc

Issue 2953443002: Revert of Reland: Move the files related to Android <-> Web credentials to a separate folder. (Closed)
Patch Set: Created 3 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
(Empty)
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/password_manager/core/browser/affiliation_backend.h"
6
7 #include <stdint.h>
8 #include <algorithm>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/location.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/threading/thread_checker.h"
17 #include "base/time/clock.h"
18 #include "base/time/tick_clock.h"
19 #include "base/time/time.h"
20 #include "components/password_manager/core/browser/affiliation_database.h"
21 #include "components/password_manager/core/browser/affiliation_fetch_throttler.h "
22 #include "components/password_manager/core/browser/affiliation_fetcher.h"
23 #include "components/password_manager/core/browser/facet_manager.h"
24 #include "net/url_request/url_request_context_getter.h"
25
26 namespace password_manager {
27
28 AffiliationBackend::AffiliationBackend(
29 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
30 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
31 std::unique_ptr<base::Clock> time_source,
32 std::unique_ptr<base::TickClock> time_tick_source)
33 : request_context_getter_(request_context_getter),
34 task_runner_(task_runner),
35 clock_(std::move(time_source)),
36 tick_clock_(std::move(time_tick_source)),
37 construction_time_(clock_->Now()),
38 weak_ptr_factory_(this) {
39 DCHECK_LT(base::Time(), clock_->Now());
40 }
41
42 AffiliationBackend::~AffiliationBackend() {
43 }
44
45 void AffiliationBackend::Initialize(const base::FilePath& db_path) {
46 thread_checker_.reset(new base::ThreadChecker);
47
48 DCHECK(!throttler_);
49 throttler_.reset(
50 new AffiliationFetchThrottler(this, task_runner_, tick_clock_.get()));
51
52 // TODO(engedy): Currently, when Init() returns false, it always poisons the
53 // DB, so subsequent operations will silently fail. Consider either fully
54 // committing to this approach and making Init() a void, or handling the
55 // return value here. See: https://crbug.com/478831.
56 cache_.reset(new AffiliationDatabase());
57 cache_->Init(db_path);
58 }
59
60 void AffiliationBackend::GetAffiliations(
61 const FacetURI& facet_uri,
62 StrategyOnCacheMiss cache_miss_strategy,
63 const AffiliationService::ResultCallback& callback,
64 const scoped_refptr<base::TaskRunner>& callback_task_runner) {
65 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
66
67 FacetManager* facet_manager = GetOrCreateFacetManager(facet_uri);
68 DCHECK(facet_manager);
69 facet_manager->GetAffiliations(cache_miss_strategy, callback,
70 callback_task_runner);
71
72 if (facet_manager->CanBeDiscarded())
73 facet_managers_.erase(facet_uri);
74 }
75
76 void AffiliationBackend::Prefetch(const FacetURI& facet_uri,
77 const base::Time& keep_fresh_until) {
78 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
79
80 FacetManager* facet_manager = GetOrCreateFacetManager(facet_uri);
81 DCHECK(facet_manager);
82 facet_manager->Prefetch(keep_fresh_until);
83
84 if (facet_manager->CanBeDiscarded())
85 facet_managers_.erase(facet_uri);
86 }
87
88 void AffiliationBackend::CancelPrefetch(const FacetURI& facet_uri,
89 const base::Time& keep_fresh_until) {
90 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
91
92 auto facet_manager_it = facet_managers_.find(facet_uri);
93 if (facet_manager_it == facet_managers_.end())
94 return;
95 facet_manager_it->second->CancelPrefetch(keep_fresh_until);
96
97 if (facet_manager_it->second->CanBeDiscarded())
98 facet_managers_.erase(facet_uri);
99 }
100
101 void AffiliationBackend::TrimCache() {
102 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
103
104 std::vector<AffiliatedFacetsWithUpdateTime> all_affiliations;
105 cache_->GetAllAffiliations(&all_affiliations);
106 for (const auto& affiliation : all_affiliations)
107 DiscardCachedDataIfNoLongerNeeded(affiliation.facets);
108 }
109
110 void AffiliationBackend::TrimCacheForFacet(const FacetURI& facet_uri) {
111 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
112
113 AffiliatedFacetsWithUpdateTime affiliation;
114 if (cache_->GetAffiliationsForFacet(facet_uri, &affiliation))
115 DiscardCachedDataIfNoLongerNeeded(affiliation.facets);
116 }
117
118 // static
119 void AffiliationBackend::DeleteCache(const base::FilePath& db_path) {
120 AffiliationDatabase::Delete(db_path);
121 }
122
123 FacetManager* AffiliationBackend::GetOrCreateFacetManager(
124 const FacetURI& facet_uri) {
125 std::unique_ptr<FacetManager>& facet_manager = facet_managers_[facet_uri];
126 if (!facet_manager) {
127 facet_manager =
128 base::MakeUnique<FacetManager>(facet_uri, this, clock_.get());
129 }
130 return facet_manager.get();
131 }
132
133 void AffiliationBackend::DiscardCachedDataIfNoLongerNeeded(
134 const AffiliatedFacets& affiliated_facets) {
135 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
136
137 // Discard the equivalence class if there is no facet in the class whose
138 // FacetManager claims that it needs to keep the data.
139 for (const auto& facet_uri : affiliated_facets) {
140 auto facet_manager_it = facet_managers_.find(facet_uri);
141 if (facet_manager_it != facet_managers_.end() &&
142 !facet_manager_it->second->CanCachedDataBeDiscarded()) {
143 return;
144 }
145 }
146
147 CHECK(!affiliated_facets.empty());
148 cache_->DeleteAffiliationsForFacet(affiliated_facets[0]);
149 }
150
151 void AffiliationBackend::OnSendNotification(const FacetURI& facet_uri) {
152 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
153
154 auto facet_manager_it = facet_managers_.find(facet_uri);
155 if (facet_manager_it == facet_managers_.end())
156 return;
157 facet_manager_it->second->NotifyAtRequestedTime();
158
159 if (facet_manager_it->second->CanBeDiscarded())
160 facet_managers_.erase(facet_uri);
161 }
162
163 bool AffiliationBackend::ReadAffiliationsFromDatabase(
164 const FacetURI& facet_uri,
165 AffiliatedFacetsWithUpdateTime* affiliations) {
166 return cache_->GetAffiliationsForFacet(facet_uri, affiliations);
167 }
168
169 void AffiliationBackend::SignalNeedNetworkRequest() {
170 throttler_->SignalNetworkRequestNeeded();
171 }
172
173 void AffiliationBackend::RequestNotificationAtTime(const FacetURI& facet_uri,
174 base::Time time) {
175 // TODO(engedy): Avoid spamming the task runner; only ever schedule the first
176 // callback. crbug.com/437865.
177 task_runner_->PostDelayedTask(
178 FROM_HERE, base::Bind(&AffiliationBackend::OnSendNotification,
179 weak_ptr_factory_.GetWeakPtr(), facet_uri),
180 time - clock_->Now());
181 }
182
183 void AffiliationBackend::OnFetchSucceeded(
184 std::unique_ptr<AffiliationFetcherDelegate::Result> result) {
185 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
186
187 fetcher_.reset();
188 throttler_->InformOfNetworkRequestComplete(true);
189
190 for (const AffiliatedFacets& affiliated_facets : *result) {
191 AffiliatedFacetsWithUpdateTime affiliation;
192 affiliation.facets = affiliated_facets;
193 affiliation.last_update_time = clock_->Now();
194
195 std::vector<AffiliatedFacetsWithUpdateTime> obsoleted_affiliations;
196 cache_->StoreAndRemoveConflicting(affiliation, &obsoleted_affiliations);
197
198 // Cached data in contradiction with newly stored data automatically gets
199 // removed from the DB, and will be stored into |obsoleted_affiliations|.
200 // TODO(engedy): Currently, handling this is entirely meaningless unless in
201 // the edge case when the user has credentials for two Android applications
202 // which are now being de-associated. But even in that case, nothing will
203 // explode and the only symptom will be that credentials for the Android
204 // application that is not being fetched right now, if any, will not be
205 // filled into affiliated applications until the next fetch. Still, this
206 // should be implemented at some point by letting facet managers know if
207 // data. See: https://crbug.com/478832.
208
209 for (const auto& facet_uri : affiliated_facets) {
210 auto facet_manager_it = facet_managers_.find(facet_uri);
211 if (facet_manager_it == facet_managers_.end())
212 continue;
213 FacetManager* facet_manager = facet_manager_it->second.get();
214 facet_manager->OnFetchSucceeded(affiliation);
215 if (facet_manager->CanBeDiscarded())
216 facet_managers_.erase(facet_uri);
217 }
218 }
219
220 // A subsequent fetch may be needed if any additional GetAffiliations()
221 // requests came in while the current fetch was in flight.
222 for (const auto& facet_manager_pair : facet_managers_) {
223 if (facet_manager_pair.second->DoesRequireFetch()) {
224 throttler_->SignalNetworkRequestNeeded();
225 return;
226 }
227 }
228 }
229
230 void AffiliationBackend::OnFetchFailed() {
231 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
232
233 fetcher_.reset();
234 throttler_->InformOfNetworkRequestComplete(false);
235
236 // Trigger a retry if a fetch is still needed.
237 for (const auto& facet_manager_pair : facet_managers_) {
238 if (facet_manager_pair.second->DoesRequireFetch()) {
239 throttler_->SignalNetworkRequestNeeded();
240 return;
241 }
242 }
243 }
244
245 void AffiliationBackend::OnMalformedResponse() {
246 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
247
248 // TODO(engedy): Potentially handle this case differently. crbug.com/437865.
249 OnFetchFailed();
250 }
251
252 bool AffiliationBackend::OnCanSendNetworkRequest() {
253 DCHECK(!fetcher_);
254 std::vector<FacetURI> requested_facet_uris;
255 for (const auto& facet_manager_pair : facet_managers_) {
256 if (facet_manager_pair.second->DoesRequireFetch())
257 requested_facet_uris.push_back(facet_manager_pair.first);
258 }
259
260 // In case a request is no longer needed, return false to indicate this.
261 if (requested_facet_uris.empty())
262 return false;
263
264 fetcher_.reset(AffiliationFetcher::Create(request_context_getter_.get(),
265 requested_facet_uris, this));
266 fetcher_->StartRequest();
267 ReportStatistics(requested_facet_uris.size());
268 return true;
269 }
270
271 void AffiliationBackend::ReportStatistics(size_t requested_facet_uri_count) {
272 UMA_HISTOGRAM_COUNTS_100("PasswordManager.AffiliationBackend.FetchSize",
273 requested_facet_uri_count);
274
275 if (last_request_time_.is_null()) {
276 base::TimeDelta delay = clock_->Now() - construction_time_;
277 UMA_HISTOGRAM_CUSTOM_TIMES(
278 "PasswordManager.AffiliationBackend.FirstFetchDelay", delay,
279 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(3), 50);
280 } else {
281 base::TimeDelta delay = clock_->Now() - last_request_time_;
282 UMA_HISTOGRAM_CUSTOM_TIMES(
283 "PasswordManager.AffiliationBackend.SubsequentFetchDelay", delay,
284 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(3), 50);
285 }
286 last_request_time_ = clock_->Now();
287 }
288
289 void AffiliationBackend::SetThrottlerForTesting(
290 std::unique_ptr<AffiliationFetchThrottler> throttler) {
291 throttler_ = std::move(throttler);
292 }
293
294 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698