OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/invalidation/ticl_invalidation_service.h" | 5 #include "chrome/browser/invalidation/ticl_invalidation_service.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "chrome/browser/invalidation/invalidation_service_util.h" | 8 #include "chrome/browser/invalidation/invalidation_service_util.h" |
9 #include "chrome/browser/managed_mode/managed_user_service.h" | |
10 #include "chrome/browser/profiles/profile.h" | 9 #include "chrome/browser/profiles/profile.h" |
11 #include "chrome/browser/signin/profile_oauth2_token_service.h" | |
12 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" | |
13 #include "chrome/browser/signin/signin_manager.h" | 10 #include "chrome/browser/signin/signin_manager.h" |
| 11 #include "chrome/browser/signin/token_service.h" |
14 #include "chrome/common/chrome_notification_types.h" | 12 #include "chrome/common/chrome_notification_types.h" |
15 #include "content/public/browser/notification_service.h" | 13 #include "content/public/browser/notification_service.h" |
16 #include "google_apis/gaia/gaia_constants.h" | 14 #include "google_apis/gaia/gaia_constants.h" |
17 #include "sync/notifier/invalidator.h" | 15 #include "sync/notifier/invalidator.h" |
18 #include "sync/notifier/invalidator_state.h" | 16 #include "sync/notifier/invalidator_state.h" |
19 #include "sync/notifier/non_blocking_invalidator.h" | 17 #include "sync/notifier/non_blocking_invalidator.h" |
20 | 18 |
21 static const char* kOAuth2Scopes[] = { | |
22 GaiaConstants::kGoogleTalkOAuth2Scope | |
23 }; | |
24 | |
25 static const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = { | |
26 // Number of initial errors (in sequence) to ignore before applying | |
27 // exponential back-off rules. | |
28 0, | |
29 | |
30 // Initial delay for exponential back-off in ms. | |
31 2000, | |
32 | |
33 // Factor by which the waiting time will be multiplied. | |
34 2, | |
35 | |
36 // Fuzzing percentage. ex: 10% will spread requests randomly | |
37 // between 90%-100% of the calculated time. | |
38 0.2, // 20% | |
39 | |
40 // Maximum amount of time we are willing to delay our request in ms. | |
41 // TODO(pavely): crbug.com/246686 ProfileSyncService should retry | |
42 // RequestAccessToken on connection state change after backoff | |
43 1000 * 3600 * 4, // 4 hours. | |
44 | |
45 // Time to keep an entry from being discarded even when it | |
46 // has no significant state, -1 to never discard. | |
47 -1, | |
48 | |
49 // Don't use initial delay unless the last request was an error. | |
50 false, | |
51 }; | |
52 | |
53 namespace invalidation { | 19 namespace invalidation { |
54 | 20 |
55 TiclInvalidationService::TiclInvalidationService( | 21 TiclInvalidationService::TiclInvalidationService(SigninManagerBase* signin, |
56 SigninManagerBase* signin, | 22 TokenService* token_service, |
57 TokenService* token_service, | 23 Profile* profile) |
58 OAuth2TokenService* oauth2_token_service, | 24 : profile_(profile), |
59 Profile* profile) | 25 signin_manager_(signin), |
60 : profile_(profile), | 26 token_service_(token_service), |
61 signin_manager_(signin), | 27 invalidator_registrar_(new syncer::InvalidatorRegistrar()) { } |
62 token_service_(token_service), | |
63 oauth2_token_service_(oauth2_token_service), | |
64 invalidator_registrar_(new syncer::InvalidatorRegistrar()), | |
65 request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy) { | |
66 } | |
67 | 28 |
68 TiclInvalidationService::~TiclInvalidationService() { | 29 TiclInvalidationService::~TiclInvalidationService() { |
69 DCHECK(CalledOnValidThread()); | 30 DCHECK(CalledOnValidThread()); |
70 } | 31 } |
71 | 32 |
72 void TiclInvalidationService::Init() { | 33 void TiclInvalidationService::Init() { |
73 DCHECK(CalledOnValidThread()); | 34 DCHECK(CalledOnValidThread()); |
74 | 35 |
75 invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs())); | 36 invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs())); |
76 if (invalidator_storage_->GetInvalidatorClientId().empty()) { | 37 if (invalidator_storage_->GetInvalidatorClientId().empty()) { |
77 // This also clears any existing state. We can't reuse old invalidator | 38 // This also clears any existing state. We can't reuse old invalidator |
78 // state with the new ID anyway. | 39 // state with the new ID anyway. |
79 invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId()); | 40 invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId()); |
80 } | 41 } |
81 | 42 |
82 if (IsReadyToStart()) { | 43 if (IsReadyToStart()) { |
83 StartInvalidator(); | 44 Start(); |
84 } | 45 } |
85 | 46 |
86 notification_registrar_.Add(this, | 47 notification_registrar_.Add(this, |
| 48 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 49 content::Source<TokenService>(token_service_)); |
| 50 notification_registrar_.Add(this, |
87 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, | 51 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, |
88 content::Source<Profile>(profile_)); | 52 content::Source<Profile>(profile_)); |
89 notification_registrar_.Add(this, | |
90 chrome::NOTIFICATION_TOKEN_LOADING_FINISHED, | |
91 content::Source<TokenService>(token_service_)); | |
92 notification_registrar_.Add(this, | |
93 chrome::NOTIFICATION_TOKENS_CLEARED, | |
94 content::Source<TokenService>(token_service_)); | |
95 } | 53 } |
96 | 54 |
97 void TiclInvalidationService::InitForTest(syncer::Invalidator* invalidator) { | 55 void TiclInvalidationService::InitForTest(syncer::Invalidator* invalidator) { |
98 // Here we perform the equivalent of Init() and StartInvalidator(), but with | 56 // Here we perform the equivalent of Init() and Start(), but with some minor |
99 // some minor changes to account for the fact that we're injecting the | 57 // changes to account for the fact that we're injecting the invalidator. |
100 // invalidator. | |
101 invalidator_.reset(invalidator); | 58 invalidator_.reset(invalidator); |
102 | 59 |
103 invalidator_->RegisterHandler(this); | 60 invalidator_->RegisterHandler(this); |
104 invalidator_->UpdateRegisteredIds( | 61 invalidator_->UpdateRegisteredIds( |
105 this, | 62 this, |
106 invalidator_registrar_->GetAllRegisteredIds()); | 63 invalidator_registrar_->GetAllRegisteredIds()); |
107 } | 64 } |
108 | 65 |
109 void TiclInvalidationService::RegisterInvalidationHandler( | 66 void TiclInvalidationService::RegisterInvalidationHandler( |
110 syncer::InvalidationHandler* handler) { | 67 syncer::InvalidationHandler* handler) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 return invalidator_storage_->GetInvalidatorClientId(); | 121 return invalidator_storage_->GetInvalidatorClientId(); |
165 } | 122 } |
166 | 123 |
167 void TiclInvalidationService::Observe( | 124 void TiclInvalidationService::Observe( |
168 int type, | 125 int type, |
169 const content::NotificationSource& source, | 126 const content::NotificationSource& source, |
170 const content::NotificationDetails& details) { | 127 const content::NotificationDetails& details) { |
171 DCHECK(CalledOnValidThread()); | 128 DCHECK(CalledOnValidThread()); |
172 | 129 |
173 switch (type) { | 130 switch (type) { |
174 case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: { | 131 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { |
175 if (!IsStarted() && IsReadyToStart()) { | 132 const TokenService::TokenAvailableDetails& token_details = |
176 StartInvalidator(); | 133 *(content::Details<const TokenService::TokenAvailableDetails>( |
177 } | 134 details).ptr()); |
178 break; | 135 if (token_details.service() == GaiaConstants::kSyncService) { |
179 } | 136 DCHECK(IsReadyToStart()); |
180 case chrome::NOTIFICATION_TOKENS_CLEARED: { | 137 if (!IsStarted()) { |
181 access_token_.clear(); | 138 Start(); |
182 if (IsStarted()) { | 139 } else { |
183 UpdateInvalidatorCredentials(); | 140 UpdateToken(); |
| 141 } |
184 } | 142 } |
185 break; | 143 break; |
186 } | 144 } |
187 case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: { | 145 case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: { |
188 Logout(); | 146 Logout(); |
189 break; | 147 break; |
190 } | 148 } |
191 default: { | 149 default: { |
192 NOTREACHED(); | 150 NOTREACHED(); |
193 } | 151 } |
194 } | 152 } |
195 } | 153 } |
196 | 154 |
197 void TiclInvalidationService::RequestAccessToken() { | |
198 // Only one active request at a time. | |
199 if (access_token_request_ != NULL) | |
200 return; | |
201 request_access_token_retry_timer_.Stop(); | |
202 OAuth2TokenService::ScopeSet oauth2_scopes; | |
203 for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++) | |
204 oauth2_scopes.insert(kOAuth2Scopes[i]); | |
205 // Invalidate previous token, otherwise token service will return the same | |
206 // token again. | |
207 oauth2_token_service_->InvalidateToken(oauth2_scopes, access_token_); | |
208 access_token_.clear(); | |
209 access_token_request_ = | |
210 oauth2_token_service_->StartRequest(oauth2_scopes, this); | |
211 } | |
212 | |
213 void TiclInvalidationService::OnGetTokenSuccess( | |
214 const OAuth2TokenService::Request* request, | |
215 const std::string& access_token, | |
216 const base::Time& expiration_time) { | |
217 DCHECK_EQ(access_token_request_, request); | |
218 access_token_request_.reset(); | |
219 // Reset backoff time after successful response. | |
220 request_access_token_backoff_.Reset(); | |
221 access_token_ = access_token; | |
222 if (!IsStarted() && IsReadyToStart()) { | |
223 StartInvalidator(); | |
224 } else { | |
225 UpdateInvalidatorCredentials(); | |
226 } | |
227 } | |
228 | |
229 void TiclInvalidationService::OnGetTokenFailure( | |
230 const OAuth2TokenService::Request* request, | |
231 const GoogleServiceAuthError& error) { | |
232 DCHECK_EQ(access_token_request_, request); | |
233 DCHECK_NE(error.state(), GoogleServiceAuthError::NONE); | |
234 access_token_request_.reset(); | |
235 switch (error.state()) { | |
236 case GoogleServiceAuthError::CONNECTION_FAILED: | |
237 case GoogleServiceAuthError::SERVICE_UNAVAILABLE: { | |
238 // Transient error. Retry after some time. | |
239 request_access_token_backoff_.InformOfRequest(false); | |
240 request_access_token_retry_timer_.Start( | |
241 FROM_HERE, | |
242 request_access_token_backoff_.GetTimeUntilRelease(), | |
243 base::Bind(&TiclInvalidationService::RequestAccessToken, | |
244 base::Unretained(this))); | |
245 break; | |
246 } | |
247 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: { | |
248 // This is a real auth error. | |
249 invalidator_registrar_->UpdateInvalidatorState( | |
250 syncer::INVALIDATION_CREDENTIALS_REJECTED); | |
251 break; | |
252 } | |
253 default: { | |
254 // We have no way to notify the user of this. Do nothing. | |
255 } | |
256 } | |
257 } | |
258 | |
259 void TiclInvalidationService::OnInvalidatorStateChange( | 155 void TiclInvalidationService::OnInvalidatorStateChange( |
260 syncer::InvalidatorState state) { | 156 syncer::InvalidatorState state) { |
261 invalidator_registrar_->UpdateInvalidatorState(state); | 157 invalidator_registrar_->UpdateInvalidatorState(state); |
262 } | 158 } |
263 | 159 |
264 void TiclInvalidationService::OnIncomingInvalidation( | 160 void TiclInvalidationService::OnIncomingInvalidation( |
265 const syncer::ObjectIdInvalidationMap& invalidation_map) { | 161 const syncer::ObjectIdInvalidationMap& invalidation_map) { |
266 invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map); | 162 invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map); |
267 } | 163 } |
268 | 164 |
269 void TiclInvalidationService::Shutdown() { | 165 void TiclInvalidationService::Shutdown() { |
270 DCHECK(CalledOnValidThread()); | 166 DCHECK(CalledOnValidThread()); |
271 if (IsStarted()) { | 167 if (IsStarted()) { |
272 StopInvalidator(); | 168 StopInvalidator(); |
273 } | 169 } |
274 invalidator_storage_.reset(); | 170 invalidator_storage_.reset(); |
275 invalidator_registrar_.reset(); | 171 invalidator_registrar_.reset(); |
276 } | 172 } |
277 | 173 |
278 bool TiclInvalidationService::IsReadyToStart() { | 174 bool TiclInvalidationService::IsReadyToStart() { |
279 if (ManagedUserService::ProfileIsManaged(profile_)) { | 175 if (signin_manager_->GetAuthenticatedUsername().empty()) { |
280 DVLOG(2) << "Not starting TiclInvalidationService: User is managed."; | 176 DVLOG(2) << "Not starting TiclInvalidationService: user is not signed in."; |
281 return false; | 177 return false; |
282 } | 178 } |
283 | 179 |
284 if (signin_manager_->GetAuthenticatedUsername().empty()) { | 180 if (!token_service_) { |
285 DVLOG(2) << "Not starting TiclInvalidationService: User is not signed in."; | |
286 return false; | |
287 } | |
288 | |
289 if (!oauth2_token_service_) { | |
290 DVLOG(2) | 181 DVLOG(2) |
291 << "Not starting TiclInvalidationService: TokenService unavailable."; | 182 << "Not starting TiclInvalidationService: TokenService unavailable."; |
292 return false; | 183 return false; |
293 } | 184 } |
294 | 185 |
295 if (!oauth2_token_service_->RefreshTokenIsAvailable()) { | 186 if (!token_service_->HasTokenForService(GaiaConstants::kSyncService)) { |
296 DVLOG(2) | 187 DVLOG(2) << "Not starting TiclInvalidationService: Sync token unavailable."; |
297 << "Not starting TiclInvalidationServce: Waiting for refresh token."; | |
298 return false; | 188 return false; |
299 } | 189 } |
300 | 190 |
301 return true; | 191 return true; |
302 } | 192 } |
303 | 193 |
304 bool TiclInvalidationService::IsStarted() { | 194 bool TiclInvalidationService::IsStarted() { |
305 return invalidator_.get() != NULL; | 195 return invalidator_.get() != NULL; |
306 } | 196 } |
307 | 197 |
308 void TiclInvalidationService::StartInvalidator() { | 198 void TiclInvalidationService::Start() { |
309 DCHECK(CalledOnValidThread()); | 199 DCHECK(CalledOnValidThread()); |
310 DCHECK(!invalidator_); | 200 DCHECK(!invalidator_); |
311 DCHECK(invalidator_storage_); | 201 DCHECK(invalidator_storage_); |
312 DCHECK(!invalidator_storage_->GetInvalidatorClientId().empty()); | 202 DCHECK(!invalidator_storage_->GetInvalidatorClientId().empty()); |
313 | 203 |
314 if (access_token_.empty()) { | |
315 DVLOG(1) | |
316 << "TiclInvalidationService: " | |
317 << "Deferring start until we have an access token."; | |
318 RequestAccessToken(); | |
319 return; | |
320 } | |
321 | |
322 notifier::NotifierOptions options = | 204 notifier::NotifierOptions options = |
323 ParseNotifierOptions(*CommandLine::ForCurrentProcess()); | 205 ParseNotifierOptions(*CommandLine::ForCurrentProcess()); |
324 options.request_context_getter = profile_->GetRequestContext(); | 206 options.request_context_getter = profile_->GetRequestContext(); |
325 options.auth_mechanism = "X-OAUTH2"; | |
326 invalidator_.reset(new syncer::NonBlockingInvalidator( | 207 invalidator_.reset(new syncer::NonBlockingInvalidator( |
327 options, | 208 options, |
328 invalidator_storage_->GetInvalidatorClientId(), | 209 invalidator_storage_->GetInvalidatorClientId(), |
329 invalidator_storage_->GetAllInvalidationStates(), | 210 invalidator_storage_->GetAllInvalidationStates(), |
330 invalidator_storage_->GetBootstrapData(), | 211 invalidator_storage_->GetBootstrapData(), |
331 syncer::WeakHandle<syncer::InvalidationStateTracker>( | 212 syncer::WeakHandle<syncer::InvalidationStateTracker>( |
332 invalidator_storage_->AsWeakPtr()), | 213 invalidator_storage_->AsWeakPtr()), |
333 content::GetUserAgent(GURL()))); | 214 content::GetUserAgent(GURL()))); |
334 | 215 |
335 UpdateInvalidatorCredentials(); | 216 UpdateToken(); |
336 | 217 |
337 invalidator_->RegisterHandler(this); | 218 invalidator_->RegisterHandler(this); |
338 invalidator_->UpdateRegisteredIds( | 219 invalidator_->UpdateRegisteredIds( |
339 this, | 220 this, |
340 invalidator_registrar_->GetAllRegisteredIds()); | 221 invalidator_registrar_->GetAllRegisteredIds()); |
341 } | 222 } |
342 | 223 |
343 void TiclInvalidationService::UpdateInvalidatorCredentials() { | 224 void TiclInvalidationService::UpdateToken() { |
344 std::string email = signin_manager_->GetAuthenticatedUsername(); | 225 std::string email = signin_manager_->GetAuthenticatedUsername(); |
| 226 DCHECK(!email.empty()) << "Expected user to be signed in."; |
| 227 DCHECK(token_service_->HasTokenForService(GaiaConstants::kSyncService)); |
345 | 228 |
346 DCHECK(!email.empty()) << "Expected user to be signed in."; | 229 std::string sync_token = token_service_->GetTokenForService( |
347 DCHECK(!access_token_.empty()); | 230 GaiaConstants::kSyncService); |
348 | 231 |
349 DVLOG(2) << "UpdateCredentials: " << email; | 232 DVLOG(2) << "UpdateCredentials: " << email; |
350 invalidator_->UpdateCredentials(email, access_token_); | 233 invalidator_->UpdateCredentials(email, sync_token); |
351 } | 234 } |
352 | 235 |
353 void TiclInvalidationService::StopInvalidator() { | 236 void TiclInvalidationService::StopInvalidator() { |
354 DCHECK(invalidator_); | 237 DCHECK(invalidator_); |
355 invalidator_->UnregisterHandler(this); | 238 invalidator_->UnregisterHandler(this); |
356 invalidator_.reset(); | 239 invalidator_.reset(); |
357 } | 240 } |
358 | 241 |
359 void TiclInvalidationService::Logout() { | 242 void TiclInvalidationService::Logout() { |
360 request_access_token_retry_timer_.Stop(); | |
361 | |
362 StopInvalidator(); | 243 StopInvalidator(); |
363 | 244 |
364 // This service always expects to have a valid invalidator storage. | 245 // This service always expects to have a valid invalidator storage. |
365 // So we must not only clear the old one, but also start a new one. | 246 // So we must not only clear the old one, but also start a new one. |
366 invalidator_storage_->Clear(); | 247 invalidator_storage_->Clear(); |
367 invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs())); | 248 invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs())); |
368 invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId()); | 249 invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId()); |
369 } | 250 } |
370 | 251 |
371 } // namespace invalidation | 252 } // namespace invalidation |
OLD | NEW |