Stack sampling profiler: add fire-and-forget interface
[chromium-blink-merge.git] / components / signin / core / browser / account_fetcher_service.cc
blob73abe8b58c28395ea4bc098e0592492ccf92422a
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.
5 #include "components/signin/core/browser/account_fetcher_service.h"
7 #include "base/command_line.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/trace_event/trace_event.h"
12 #include "components/signin/core/browser/account_info_fetcher.h"
13 #include "components/signin/core/browser/account_tracker_service.h"
14 #include "components/signin/core/browser/child_account_info_fetcher.h"
15 #include "components/signin/core/browser/refresh_token_annotation_request.h"
16 #include "components/signin/core/browser/signin_client.h"
17 #include "components/signin/core/common/signin_switches.h"
18 #include "net/url_request/url_request_context_getter.h"
20 namespace {
22 const base::TimeDelta kRefreshFromTokenServiceDelay =
23 base::TimeDelta::FromHours(24);
25 bool AccountSupportsUserInfo(const std::string& account_id) {
26 // Supervised users use a specially scoped token which when used for general
27 // purposes causes the token service to raise spurious auth errors.
28 // TODO(treib): this string is also used in supervised_user_constants.cc.
29 // Should put in a common place.
30 return account_id != "managed_user@localhost";
33 #if !defined(OS_ANDROID) && !defined(OS_IOS)
34 // IsRefreshTokenDeviceIdExperimentEnabled is called from
35 // SendRefreshTokenAnnotationRequest only on desktop platforms.
36 bool IsRefreshTokenDeviceIdExperimentEnabled() {
37 const std::string group_name =
38 base::FieldTrialList::FindFullName("RefreshTokenDeviceId");
39 return group_name == "Enabled";
41 #endif
45 // This pref used to be in the AccountTrackerService, hence its string value.
46 const char AccountFetcherService::kLastUpdatePref[] =
47 "account_tracker_service_last_update";
49 // AccountFetcherService implementation
50 AccountFetcherService::AccountFetcherService()
51 : account_tracker_service_(nullptr),
52 token_service_(nullptr),
53 signin_client_(nullptr),
54 invalidation_service_(nullptr),
55 network_fetches_enabled_(false),
56 shutdown_called_(false),
57 child_info_request_(nullptr) {}
59 AccountFetcherService::~AccountFetcherService() {
60 DCHECK(shutdown_called_);
63 void AccountFetcherService::Initialize(
64 SigninClient* signin_client,
65 OAuth2TokenService* token_service,
66 AccountTrackerService* account_tracker_service,
67 invalidation::InvalidationService* invalidation_service) {
68 DCHECK(signin_client);
69 DCHECK(!signin_client_);
70 signin_client_ = signin_client;
71 invalidation_service_ = invalidation_service;
72 DCHECK(account_tracker_service);
73 DCHECK(!account_tracker_service_);
74 account_tracker_service_ = account_tracker_service;
75 DCHECK(token_service);
76 DCHECK(!token_service_);
77 token_service_ = token_service;
78 token_service_->AddObserver(this);
80 last_updated_ = base::Time::FromInternalValue(
81 signin_client_->GetPrefs()->GetInt64(kLastUpdatePref));
83 RefreshAllAccountInfo(true);
86 void AccountFetcherService::Shutdown() {
87 token_service_->RemoveObserver(this);
88 // child_info_request_ is an invalidation handler and needs to be
89 // unregistered during the lifetime of the invalidation service.
90 child_info_request_.reset();
91 shutdown_called_ = true;
94 void AccountFetcherService::EnableNetworkFetches() {
95 DCHECK(CalledOnValidThread());
96 DCHECK(!network_fetches_enabled_);
97 network_fetches_enabled_ = true;
98 // If there are accounts in |pending_user_info_fetches_|, they were deemed
99 // invalid after being loaded from prefs and need to be fetched now instead of
100 // waiting after the timer.
101 for (std::string account_id : pending_user_info_fetches_)
102 StartFetchingUserInfo(account_id);
103 pending_user_info_fetches_.clear();
105 // Now that network fetches are enabled, schedule the next refresh.
106 ScheduleNextRefresh();
109 bool AccountFetcherService::IsAllUserInfoFetched() const {
110 return user_info_requests_.empty();
113 void AccountFetcherService::RefreshAllAccountInfo(bool only_fetch_if_invalid) {
114 std::vector<std::string> accounts = token_service_->GetAccounts();
115 for (std::vector<std::string>::const_iterator it = accounts.begin();
116 it != accounts.end(); ++it) {
117 RefreshAccountInfo(*it, only_fetch_if_invalid);
121 // Child account status is refreshed through invalidations which are only
122 // available for the primary account. Finding the primary account requires a
123 // dependency on signin_manager which we get around by only allowing a single
124 // account. This is possible since we only support a single account to be a
125 // child anyway.
126 void AccountFetcherService::UpdateChildInfo() {
127 DCHECK(CalledOnValidThread());
128 std::vector<std::string> accounts = token_service_->GetAccounts();
129 if (accounts.size() == 1) {
130 const std::string& candidate = accounts[0];
131 if (candidate == child_request_account_id_)
132 return;
133 if (!child_request_account_id_.empty())
134 ResetChildInfo();
135 if (!AccountSupportsUserInfo(candidate))
136 return;
137 child_request_account_id_ = candidate;
138 StartFetchingChildInfo(candidate);
139 } else {
140 ResetChildInfo();
144 void AccountFetcherService::RefreshAllAccountsAndScheduleNext() {
145 DCHECK(network_fetches_enabled_);
146 RefreshAllAccountInfo(false);
147 last_updated_ = base::Time::Now();
148 signin_client_->GetPrefs()->SetInt64(kLastUpdatePref,
149 last_updated_.ToInternalValue());
150 ScheduleNextRefresh();
153 void AccountFetcherService::ScheduleNextRefresh() {
154 DCHECK(!timer_.IsRunning());
155 DCHECK(network_fetches_enabled_);
157 const base::TimeDelta time_since_update = base::Time::Now() - last_updated_;
158 if(time_since_update > kRefreshFromTokenServiceDelay) {
159 RefreshAllAccountsAndScheduleNext();
160 } else {
161 timer_.Start(FROM_HERE, kRefreshFromTokenServiceDelay - time_since_update,
162 this,
163 &AccountFetcherService::RefreshAllAccountsAndScheduleNext);
167 // Starts fetching user information. This is called periodically to refresh.
168 void AccountFetcherService::StartFetchingUserInfo(
169 const std::string& account_id) {
170 DCHECK(CalledOnValidThread());
171 if (!network_fetches_enabled_) {
172 pending_user_info_fetches_.push_back(account_id);
173 return;
176 if (!ContainsKey(user_info_requests_, account_id)) {
177 DVLOG(1) << "StartFetching " << account_id;
178 scoped_ptr<AccountInfoFetcher> fetcher(new AccountInfoFetcher(
179 token_service_, signin_client_->GetURLRequestContext(), this,
180 account_id));
181 user_info_requests_.set(account_id, fetcher.Pass());
182 user_info_requests_.get(account_id)->Start();
186 // Starts fetching whether this is a child account. Handles refresh internally.
187 void AccountFetcherService::StartFetchingChildInfo(
188 const std::string& account_id) {
189 child_info_request_.reset(ChildAccountInfoFetcher::CreateFrom(
190 child_request_account_id_, this, token_service_,
191 signin_client_->GetURLRequestContext(), invalidation_service_));
194 void AccountFetcherService::ResetChildInfo() {
195 if (!child_request_account_id_.empty())
196 SetIsChildAccount(child_request_account_id_, false);
197 child_request_account_id_.clear();
198 child_info_request_.reset();
201 void AccountFetcherService::RefreshAccountInfo(const std::string& account_id,
202 bool only_fetch_if_invalid) {
203 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
204 // fixed.
205 tracked_objects::ScopedTracker tracking_profile(
206 FROM_HERE_WITH_EXPLICIT_FUNCTION(
207 "422460 AccountFetcherService::OnRefreshTokenAvailable"));
209 TRACE_EVENT1("AccountFetcherService",
210 "AccountFetcherService::RefreshAccountInfo",
211 "account_id",
212 account_id);
213 DVLOG(1) << "AVAILABLE " << account_id;
215 account_tracker_service_->StartTrackingAccount(account_id);
216 const AccountTrackerService::AccountInfo& info =
217 account_tracker_service_->GetAccountInfo(account_id);
218 if (!AccountSupportsUserInfo(account_id))
219 return;
221 // |only_fetch_if_invalid| is false when the service is due for a timed update.
222 #if defined(OS_ANDROID)
223 // TODO(mlerman): Change this condition back to info.IsValid() and ensure the
224 // Fetch doesn't occur until after ProfileImpl::OnPrefsLoaded().
225 if (!only_fetch_if_invalid || info.gaia.empty())
226 #else
227 if (!only_fetch_if_invalid || !info.IsValid())
228 #endif
229 StartFetchingUserInfo(account_id);
231 SendRefreshTokenAnnotationRequest(account_id);
234 void AccountFetcherService::SendRefreshTokenAnnotationRequest(
235 const std::string& account_id) {
236 // We only need to send RefreshTokenAnnotationRequest from desktop platforms.
237 #if !defined(OS_ANDROID) && !defined(OS_IOS)
238 if (IsRefreshTokenDeviceIdExperimentEnabled() ||
239 base::CommandLine::ForCurrentProcess()->HasSwitch(
240 switches::kEnableRefreshTokenAnnotationRequest)) {
241 scoped_ptr<RefreshTokenAnnotationRequest> request =
242 RefreshTokenAnnotationRequest::SendIfNeeded(
243 signin_client_->GetPrefs(), token_service_, signin_client_,
244 signin_client_->GetURLRequestContext(), account_id,
245 base::Bind(
246 &AccountFetcherService::RefreshTokenAnnotationRequestDone,
247 base::Unretained(this), account_id));
248 // If request was sent AccountFetcherService needs to own request till it
249 // finishes.
250 if (request)
251 refresh_token_annotation_requests_.set(account_id, request.Pass());
253 #endif
256 void AccountFetcherService::RefreshTokenAnnotationRequestDone(
257 const std::string& account_id) {
258 refresh_token_annotation_requests_.erase(account_id);
261 void AccountFetcherService::OnUserInfoFetchSuccess(
262 const std::string& account_id,
263 scoped_ptr<base::DictionaryValue> user_info) {
264 account_tracker_service_->SetAccountStateFromUserInfo(account_id,
265 user_info.get());
266 user_info_requests_.erase(account_id);
269 void AccountFetcherService::SetIsChildAccount(const std::string& account_id,
270 bool is_child_account) {
271 if (child_request_account_id_ == account_id)
272 account_tracker_service_->SetIsChildAccount(account_id, is_child_account);
275 void AccountFetcherService::OnUserInfoFetchFailure(
276 const std::string& account_id) {
277 LOG(WARNING) << "Failed to get UserInfo for " << account_id;
278 account_tracker_service_->NotifyAccountUpdateFailed(account_id);
279 user_info_requests_.erase(account_id);
282 void AccountFetcherService::OnRefreshTokenAvailable(
283 const std::string& account_id) {
284 // The SigninClient needs a "final init" in order to perform some actions
285 // (such as fetching the signin token "handle" in order to look for password
286 // changes) once everything is initialized and the refresh token is present.
287 signin_client_->DoFinalInit();
288 RefreshAccountInfo(account_id, true);
289 UpdateChildInfo();
292 void AccountFetcherService::OnRefreshTokenRevoked(
293 const std::string& account_id) {
294 TRACE_EVENT1("AccountFetcherService",
295 "AccountFetcherService::OnRefreshTokenRevoked",
296 "account_id",
297 account_id);
299 DVLOG(1) << "REVOKED " << account_id;
300 user_info_requests_.erase(account_id);
301 UpdateChildInfo();
302 account_tracker_service_->StopTrackingAccount(account_id);
305 void AccountFetcherService::OnRefreshTokensLoaded() {
306 // OnRefreshTokenAvailable has been called for all accounts by this point.
307 // Maybe remove this after further investigation.
308 RefreshAllAccountInfo(true);
309 UpdateChildInfo();