Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / signin / core / browser / account_fetcher_service.cc
blob139ad28b4dccbfbc995725ae2f2ad7731bcc1275
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/pref_registry/pref_registry_syncable.h"
13 #include "components/signin/core/browser/account_info_fetcher.h"
14 #include "components/signin/core/browser/account_tracker_service.h"
15 #include "components/signin/core/browser/child_account_info_fetcher.h"
16 #include "components/signin/core/browser/refresh_token_annotation_request.h"
17 #include "components/signin/core/browser/signin_client.h"
18 #include "components/signin/core/common/signin_switches.h"
19 #include "net/url_request/url_request_context_getter.h"
21 namespace {
23 const base::TimeDelta kRefreshFromTokenServiceDelay =
24 base::TimeDelta::FromHours(24);
26 bool AccountSupportsUserInfo(const std::string& account_id) {
27 // Supervised users use a specially scoped token which when used for general
28 // purposes causes the token service to raise spurious auth errors.
29 // TODO(treib): this string is also used in supervised_user_constants.cc.
30 // Should put in a common place.
31 return account_id != "managed_user@localhost";
34 #if !defined(OS_ANDROID) && !defined(OS_IOS)
35 // IsRefreshTokenDeviceIdExperimentEnabled is called from
36 // SendRefreshTokenAnnotationRequest only on desktop platforms.
37 bool IsRefreshTokenDeviceIdExperimentEnabled() {
38 const std::string group_name =
39 base::FieldTrialList::FindFullName("RefreshTokenDeviceId");
40 return group_name == "Enabled";
42 #endif
46 // This pref used to be in the AccountTrackerService, hence its string value.
47 const char AccountFetcherService::kLastUpdatePref[] =
48 "account_tracker_service_last_update";
50 // AccountFetcherService implementation
51 AccountFetcherService::AccountFetcherService()
52 : account_tracker_service_(nullptr),
53 token_service_(nullptr),
54 signin_client_(nullptr),
55 invalidation_service_(nullptr),
56 network_fetches_enabled_(false),
57 shutdown_called_(false),
58 child_info_request_(nullptr) {}
60 AccountFetcherService::~AccountFetcherService() {
61 DCHECK(shutdown_called_);
64 // static
65 void AccountFetcherService::RegisterPrefs(
66 user_prefs::PrefRegistrySyncable* user_prefs) {
67 user_prefs->RegisterInt64Pref(kLastUpdatePref, 0);
70 void AccountFetcherService::Initialize(
71 SigninClient* signin_client,
72 OAuth2TokenService* token_service,
73 AccountTrackerService* account_tracker_service,
74 invalidation::InvalidationService* invalidation_service) {
75 DCHECK(signin_client);
76 DCHECK(!signin_client_);
77 signin_client_ = signin_client;
78 invalidation_service_ = invalidation_service;
79 DCHECK(account_tracker_service);
80 DCHECK(!account_tracker_service_);
81 account_tracker_service_ = account_tracker_service;
82 DCHECK(token_service);
83 DCHECK(!token_service_);
84 token_service_ = token_service;
85 token_service_->AddObserver(this);
87 last_updated_ = base::Time::FromInternalValue(
88 signin_client_->GetPrefs()->GetInt64(kLastUpdatePref));
90 RefreshAllAccountInfo(true);
93 void AccountFetcherService::Shutdown() {
94 token_service_->RemoveObserver(this);
95 // child_info_request_ is an invalidation handler and needs to be
96 // unregistered during the lifetime of the invalidation service.
97 child_info_request_.reset();
98 shutdown_called_ = true;
101 void AccountFetcherService::EnableNetworkFetches() {
102 DCHECK(CalledOnValidThread());
103 DCHECK(!network_fetches_enabled_);
104 network_fetches_enabled_ = true;
105 // If there are accounts in |pending_user_info_fetches_|, they were deemed
106 // invalid after being loaded from prefs and need to be fetched now instead of
107 // waiting after the timer.
108 for (std::string account_id : pending_user_info_fetches_)
109 StartFetchingUserInfo(account_id);
110 pending_user_info_fetches_.clear();
112 // Now that network fetches are enabled, schedule the next refresh.
113 ScheduleNextRefresh();
116 bool AccountFetcherService::IsAllUserInfoFetched() const {
117 return user_info_requests_.empty();
120 void AccountFetcherService::FetchUserInfoBeforeSignin(
121 const std::string& account_id) {
122 RefreshAccountInfo(account_id, false);
125 void AccountFetcherService::RefreshAllAccountInfo(bool only_fetch_if_invalid) {
126 std::vector<std::string> accounts = token_service_->GetAccounts();
127 for (std::vector<std::string>::const_iterator it = accounts.begin();
128 it != accounts.end(); ++it) {
129 RefreshAccountInfo(*it, only_fetch_if_invalid);
133 // Child account status is refreshed through invalidations which are only
134 // available for the primary account. Finding the primary account requires a
135 // dependency on signin_manager which we get around by only allowing a single
136 // account. This is possible since we only support a single account to be a
137 // child anyway.
138 void AccountFetcherService::UpdateChildInfo() {
139 DCHECK(CalledOnValidThread());
140 std::vector<std::string> accounts = token_service_->GetAccounts();
141 if (accounts.size() == 1) {
142 const std::string& candidate = accounts[0];
143 if (candidate == child_request_account_id_)
144 return;
145 if (!child_request_account_id_.empty())
146 ResetChildInfo();
147 if (!AccountSupportsUserInfo(candidate))
148 return;
149 child_request_account_id_ = candidate;
150 StartFetchingChildInfo(candidate);
151 } else {
152 ResetChildInfo();
156 void AccountFetcherService::RefreshAllAccountsAndScheduleNext() {
157 DCHECK(network_fetches_enabled_);
158 RefreshAllAccountInfo(false);
159 last_updated_ = base::Time::Now();
160 signin_client_->GetPrefs()->SetInt64(kLastUpdatePref,
161 last_updated_.ToInternalValue());
162 ScheduleNextRefresh();
165 void AccountFetcherService::ScheduleNextRefresh() {
166 DCHECK(!timer_.IsRunning());
167 DCHECK(network_fetches_enabled_);
169 const base::TimeDelta time_since_update = base::Time::Now() - last_updated_;
170 if(time_since_update > kRefreshFromTokenServiceDelay) {
171 RefreshAllAccountsAndScheduleNext();
172 } else {
173 timer_.Start(FROM_HERE, kRefreshFromTokenServiceDelay - time_since_update,
174 this,
175 &AccountFetcherService::RefreshAllAccountsAndScheduleNext);
179 // Starts fetching user information. This is called periodically to refresh.
180 void AccountFetcherService::StartFetchingUserInfo(
181 const std::string& account_id) {
182 DCHECK(CalledOnValidThread());
183 if (!network_fetches_enabled_) {
184 pending_user_info_fetches_.push_back(account_id);
185 return;
188 if (!ContainsKey(user_info_requests_, account_id)) {
189 DVLOG(1) << "StartFetching " << account_id;
190 scoped_ptr<AccountInfoFetcher> fetcher(new AccountInfoFetcher(
191 token_service_, signin_client_->GetURLRequestContext(), this,
192 account_id));
193 user_info_requests_.set(account_id, fetcher.Pass());
194 user_info_requests_.get(account_id)->Start();
198 // Starts fetching whether this is a child account. Handles refresh internally.
199 void AccountFetcherService::StartFetchingChildInfo(
200 const std::string& account_id) {
201 child_info_request_.reset(ChildAccountInfoFetcher::CreateFrom(
202 child_request_account_id_, this, token_service_,
203 signin_client_->GetURLRequestContext(), invalidation_service_));
206 void AccountFetcherService::ResetChildInfo() {
207 if (!child_request_account_id_.empty())
208 SetIsChildAccount(child_request_account_id_, false);
209 child_request_account_id_.clear();
210 child_info_request_.reset();
213 void AccountFetcherService::RefreshAccountInfo(const std::string& account_id,
214 bool only_fetch_if_invalid) {
215 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
216 // fixed.
217 tracked_objects::ScopedTracker tracking_profile(
218 FROM_HERE_WITH_EXPLICIT_FUNCTION(
219 "422460 AccountFetcherService::OnRefreshTokenAvailable"));
221 TRACE_EVENT1("AccountFetcherService",
222 "AccountFetcherService::RefreshAccountInfo",
223 "account_id",
224 account_id);
225 DVLOG(1) << "AVAILABLE " << account_id;
227 account_tracker_service_->StartTrackingAccount(account_id);
228 const AccountInfo& info =
229 account_tracker_service_->GetAccountInfo(account_id);
230 if (!AccountSupportsUserInfo(account_id))
231 return;
233 // |only_fetch_if_invalid| is false when the service is due for a timed update.
234 #if defined(OS_ANDROID)
235 // TODO(mlerman): Change this condition back to info.IsValid() and ensure the
236 // Fetch doesn't occur until after ProfileImpl::OnPrefsLoaded().
237 if (!only_fetch_if_invalid || info.gaia.empty())
238 #else
239 if (!only_fetch_if_invalid || !info.IsValid())
240 #endif
241 StartFetchingUserInfo(account_id);
243 SendRefreshTokenAnnotationRequest(account_id);
246 void AccountFetcherService::SendRefreshTokenAnnotationRequest(
247 const std::string& account_id) {
248 // We only need to send RefreshTokenAnnotationRequest from desktop platforms.
249 #if !defined(OS_ANDROID) && !defined(OS_IOS)
250 if (IsRefreshTokenDeviceIdExperimentEnabled() ||
251 base::CommandLine::ForCurrentProcess()->HasSwitch(
252 switches::kEnableRefreshTokenAnnotationRequest)) {
253 scoped_ptr<RefreshTokenAnnotationRequest> request =
254 RefreshTokenAnnotationRequest::SendIfNeeded(
255 signin_client_->GetPrefs(), token_service_, signin_client_,
256 signin_client_->GetURLRequestContext(), account_id,
257 base::Bind(
258 &AccountFetcherService::RefreshTokenAnnotationRequestDone,
259 base::Unretained(this), account_id));
260 // If request was sent AccountFetcherService needs to own request till it
261 // finishes.
262 if (request)
263 refresh_token_annotation_requests_.set(account_id, request.Pass());
265 #endif
268 void AccountFetcherService::RefreshTokenAnnotationRequestDone(
269 const std::string& account_id) {
270 refresh_token_annotation_requests_.erase(account_id);
273 void AccountFetcherService::OnUserInfoFetchSuccess(
274 const std::string& account_id,
275 scoped_ptr<base::DictionaryValue> user_info) {
276 account_tracker_service_->SetAccountStateFromUserInfo(account_id,
277 user_info.get());
278 user_info_requests_.erase(account_id);
281 void AccountFetcherService::SetIsChildAccount(const std::string& account_id,
282 bool is_child_account) {
283 if (child_request_account_id_ == account_id)
284 account_tracker_service_->SetIsChildAccount(account_id, is_child_account);
287 void AccountFetcherService::OnUserInfoFetchFailure(
288 const std::string& account_id) {
289 LOG(WARNING) << "Failed to get UserInfo for " << account_id;
290 account_tracker_service_->NotifyAccountUpdateFailed(account_id);
291 user_info_requests_.erase(account_id);
294 void AccountFetcherService::OnRefreshTokenAvailable(
295 const std::string& account_id) {
296 // The SigninClient needs a "final init" in order to perform some actions
297 // (such as fetching the signin token "handle" in order to look for password
298 // changes) once everything is initialized and the refresh token is present.
299 signin_client_->DoFinalInit();
300 RefreshAccountInfo(account_id, true);
301 UpdateChildInfo();
304 void AccountFetcherService::OnRefreshTokenRevoked(
305 const std::string& account_id) {
306 TRACE_EVENT1("AccountFetcherService",
307 "AccountFetcherService::OnRefreshTokenRevoked",
308 "account_id",
309 account_id);
311 DVLOG(1) << "REVOKED " << account_id;
312 user_info_requests_.erase(account_id);
313 UpdateChildInfo();
314 account_tracker_service_->StopTrackingAccount(account_id);
317 void AccountFetcherService::OnRefreshTokensLoaded() {
318 // OnRefreshTokenAvailable has been called for all accounts by this point.
319 // Maybe remove this after further investigation.
320 RefreshAllAccountInfo(true);
321 UpdateChildInfo();