Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / invalidation / ticl_invalidation_service.cc
blob4f7e152a7f1a4dbcb486b3656e09a739344ba1f9
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
3 // found in the LICENSE file.
5 #include "chrome/browser/invalidation/ticl_invalidation_service.h"
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "chrome/browser/invalidation/gcm_invalidation_bridge.h"
10 #include "chrome/browser/invalidation/invalidation_service_util.h"
11 #include "chrome/browser/services/gcm/gcm_service.h"
12 #include "chrome/common/chrome_content_client.h"
13 #include "google_apis/gaia/gaia_constants.h"
14 #include "net/url_request/url_request_context_getter.h"
15 #include "sync/notifier/gcm_network_channel_delegate.h"
16 #include "sync/notifier/invalidation_util.h"
17 #include "sync/notifier/invalidator.h"
18 #include "sync/notifier/invalidator_state.h"
19 #include "sync/notifier/non_blocking_invalidator.h"
20 #include "sync/notifier/object_id_invalidation_map.h"
22 static const char* kOAuth2Scopes[] = {
23 GaiaConstants::kGoogleTalkOAuth2Scope
26 static const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
27 // Number of initial errors (in sequence) to ignore before applying
28 // exponential back-off rules.
31 // Initial delay for exponential back-off in ms.
32 2000,
34 // Factor by which the waiting time will be multiplied.
37 // Fuzzing percentage. ex: 10% will spread requests randomly
38 // between 90%-100% of the calculated time.
39 0.2, // 20%
41 // Maximum amount of time we are willing to delay our request in ms.
42 // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
43 // RequestAccessToken on connection state change after backoff
44 1000 * 3600 * 4, // 4 hours.
46 // Time to keep an entry from being discarded even when it
47 // has no significant state, -1 to never discard.
48 -1,
50 // Don't use initial delay unless the last request was an error.
51 false,
54 namespace invalidation {
56 TiclInvalidationService::TiclInvalidationService(
57 scoped_ptr<IdentityProvider> identity_provider,
58 scoped_ptr<TiclSettingsProvider> settings_provider,
59 gcm::GCMService* gcm_service,
60 const scoped_refptr<net::URLRequestContextGetter>& request_context)
61 : OAuth2TokenService::Consumer("ticl_invalidation"),
62 identity_provider_(identity_provider.Pass()),
63 settings_provider_(settings_provider.Pass()),
64 invalidator_registrar_(new syncer::InvalidatorRegistrar()),
65 request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
66 network_channel_type_(PUSH_CLIENT_CHANNEL),
67 gcm_service_(gcm_service),
68 request_context_(request_context),
69 logger_() {}
71 TiclInvalidationService::~TiclInvalidationService() {
72 DCHECK(CalledOnValidThread());
75 void TiclInvalidationService::Init(
76 scoped_ptr<syncer::InvalidationStateTracker> invalidation_state_tracker) {
77 DCHECK(CalledOnValidThread());
78 invalidation_state_tracker_ = invalidation_state_tracker.Pass();
80 if (invalidation_state_tracker_->GetInvalidatorClientId().empty()) {
81 invalidation_state_tracker_->ClearAndSetNewClientId(
82 GenerateInvalidatorClientId());
85 UpdateInvalidationNetworkChannel();
86 UMA_HISTOGRAM_ENUMERATION("Invalidations.NetworkChannel",
87 network_channel_type_,
88 NETWORK_CHANNELS_COUNT);
90 if (IsReadyToStart()) {
91 StartInvalidator(network_channel_type_);
94 identity_provider_->AddObserver(this);
95 identity_provider_->AddActiveAccountRefreshTokenObserver(this);
96 settings_provider_->AddObserver(this);
99 void TiclInvalidationService::InitForTest(
100 scoped_ptr<syncer::InvalidationStateTracker> invalidation_state_tracker,
101 syncer::Invalidator* invalidator) {
102 // Here we perform the equivalent of Init() and StartInvalidator(), but with
103 // some minor changes to account for the fact that we're injecting the
104 // invalidator.
105 invalidation_state_tracker_ = invalidation_state_tracker.Pass();
106 invalidator_.reset(invalidator);
108 invalidator_->RegisterHandler(this);
109 invalidator_->UpdateRegisteredIds(
110 this,
111 invalidator_registrar_->GetAllRegisteredIds());
114 void TiclInvalidationService::RegisterInvalidationHandler(
115 syncer::InvalidationHandler* handler) {
116 DCHECK(CalledOnValidThread());
117 DVLOG(2) << "Registering an invalidation handler";
118 invalidator_registrar_->RegisterHandler(handler);
119 logger_.OnRegistration(handler->GetOwnerName());
122 void TiclInvalidationService::UpdateRegisteredInvalidationIds(
123 syncer::InvalidationHandler* handler,
124 const syncer::ObjectIdSet& ids) {
125 DCHECK(CalledOnValidThread());
126 DVLOG(2) << "Registering ids: " << ids.size();
127 invalidator_registrar_->UpdateRegisteredIds(handler, ids);
128 if (invalidator_) {
129 invalidator_->UpdateRegisteredIds(
130 this,
131 invalidator_registrar_->GetAllRegisteredIds());
133 logger_.OnUpdateIds(invalidator_registrar_->GetSanitizedHandlersIdsMap());
136 void TiclInvalidationService::UnregisterInvalidationHandler(
137 syncer::InvalidationHandler* handler) {
138 DCHECK(CalledOnValidThread());
139 DVLOG(2) << "Unregistering";
140 invalidator_registrar_->UnregisterHandler(handler);
141 if (invalidator_) {
142 invalidator_->UpdateRegisteredIds(
143 this,
144 invalidator_registrar_->GetAllRegisteredIds());
146 logger_.OnUnregistration(handler->GetOwnerName());
149 syncer::InvalidatorState TiclInvalidationService::GetInvalidatorState() const {
150 DCHECK(CalledOnValidThread());
151 if (invalidator_) {
152 DVLOG(2) << "GetInvalidatorState returning "
153 << invalidator_->GetInvalidatorState();
154 return invalidator_->GetInvalidatorState();
155 } else {
156 DVLOG(2) << "Invalidator currently stopped";
157 return syncer::TRANSIENT_INVALIDATION_ERROR;
161 std::string TiclInvalidationService::GetInvalidatorClientId() const {
162 DCHECK(CalledOnValidThread());
163 return invalidation_state_tracker_->GetInvalidatorClientId();
166 InvalidationLogger* TiclInvalidationService::GetInvalidationLogger() {
167 return &logger_;
170 IdentityProvider* TiclInvalidationService::GetIdentityProvider() {
171 return identity_provider_.get();
174 void TiclInvalidationService::RequestDetailedStatus(
175 base::Callback<void(const base::DictionaryValue&)> return_callback) const {
176 if (IsStarted()) {
177 return_callback.Run(network_channel_options_);
178 invalidator_->RequestDetailedStatus(return_callback);
182 void TiclInvalidationService::RequestAccessToken() {
183 // Only one active request at a time.
184 if (access_token_request_ != NULL)
185 return;
186 request_access_token_retry_timer_.Stop();
187 OAuth2TokenService::ScopeSet oauth2_scopes;
188 for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++)
189 oauth2_scopes.insert(kOAuth2Scopes[i]);
190 // Invalidate previous token, otherwise token service will return the same
191 // token again.
192 const std::string& account_id = identity_provider_->GetActiveAccountId();
193 OAuth2TokenService* token_service = identity_provider_->GetTokenService();
194 token_service->InvalidateToken(account_id, oauth2_scopes, access_token_);
195 access_token_.clear();
196 access_token_request_ =
197 token_service->StartRequest(account_id, oauth2_scopes, this);
200 void TiclInvalidationService::OnGetTokenSuccess(
201 const OAuth2TokenService::Request* request,
202 const std::string& access_token,
203 const base::Time& expiration_time) {
204 DCHECK_EQ(access_token_request_, request);
205 access_token_request_.reset();
206 // Reset backoff time after successful response.
207 request_access_token_backoff_.Reset();
208 access_token_ = access_token;
209 if (!IsStarted() && IsReadyToStart()) {
210 StartInvalidator(network_channel_type_);
211 } else {
212 UpdateInvalidatorCredentials();
216 void TiclInvalidationService::OnGetTokenFailure(
217 const OAuth2TokenService::Request* request,
218 const GoogleServiceAuthError& error) {
219 DCHECK_EQ(access_token_request_, request);
220 DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
221 access_token_request_.reset();
222 switch (error.state()) {
223 case GoogleServiceAuthError::CONNECTION_FAILED:
224 case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
225 // Transient error. Retry after some time.
226 request_access_token_backoff_.InformOfRequest(false);
227 request_access_token_retry_timer_.Start(
228 FROM_HERE,
229 request_access_token_backoff_.GetTimeUntilRelease(),
230 base::Bind(&TiclInvalidationService::RequestAccessToken,
231 base::Unretained(this)));
232 break;
234 case GoogleServiceAuthError::SERVICE_ERROR:
235 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
236 invalidator_registrar_->UpdateInvalidatorState(
237 syncer::INVALIDATION_CREDENTIALS_REJECTED);
238 break;
240 default: {
241 // We have no way to notify the user of this. Do nothing.
246 void TiclInvalidationService::OnRefreshTokenAvailable(
247 const std::string& account_id) {
248 if (!IsStarted() && IsReadyToStart())
249 StartInvalidator(network_channel_type_);
252 void TiclInvalidationService::OnRefreshTokenRevoked(
253 const std::string& account_id) {
254 access_token_.clear();
255 if (IsStarted())
256 UpdateInvalidatorCredentials();
259 void TiclInvalidationService::OnActiveAccountLogout() {
260 access_token_request_.reset();
261 request_access_token_retry_timer_.Stop();
263 if (IsStarted()) {
264 StopInvalidator();
267 // This service always expects to have a valid invalidation state. Thus, we
268 // must generate a new client ID to replace the existing one. Setting a new
269 // client ID also clears all other state.
270 invalidation_state_tracker_->
271 ClearAndSetNewClientId(GenerateInvalidatorClientId());
274 void TiclInvalidationService::OnUseGCMChannelChanged() {
275 UpdateInvalidationNetworkChannel();
278 void TiclInvalidationService::OnInvalidatorStateChange(
279 syncer::InvalidatorState state) {
280 if (state == syncer::INVALIDATION_CREDENTIALS_REJECTED) {
281 // This may be due to normal OAuth access token expiration. If so, we must
282 // fetch a new one using our refresh token. Resetting the invalidator's
283 // access token will not reset the invalidator's exponential backoff, so
284 // it's safe to try to update the token every time we receive this signal.
286 // We won't be receiving any invalidations while the refresh is in progress,
287 // we set our state to TRANSIENT_INVALIDATION_ERROR. If the credentials
288 // really are invalid, the refresh request should fail and
289 // OnGetTokenFailure() will put us into a INVALIDATION_CREDENTIALS_REJECTED
290 // state.
291 invalidator_registrar_->UpdateInvalidatorState(
292 syncer::TRANSIENT_INVALIDATION_ERROR);
293 RequestAccessToken();
294 } else {
295 invalidator_registrar_->UpdateInvalidatorState(state);
297 logger_.OnStateChange(state);
300 void TiclInvalidationService::OnIncomingInvalidation(
301 const syncer::ObjectIdInvalidationMap& invalidation_map) {
302 invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map);
304 logger_.OnInvalidation(invalidation_map);
307 std::string TiclInvalidationService::GetOwnerName() const { return "TICL"; }
309 void TiclInvalidationService::Shutdown() {
310 DCHECK(CalledOnValidThread());
311 settings_provider_->RemoveObserver(this);
312 identity_provider_->RemoveActiveAccountRefreshTokenObserver(this);
313 identity_provider_->RemoveObserver(this);
314 if (IsStarted()) {
315 StopInvalidator();
317 invalidation_state_tracker_.reset();
318 invalidator_registrar_.reset();
321 bool TiclInvalidationService::IsReadyToStart() {
322 if (identity_provider_->GetActiveAccountId().empty()) {
323 DVLOG(2) << "Not starting TiclInvalidationService: User is not signed in.";
324 return false;
327 OAuth2TokenService* token_service = identity_provider_->GetTokenService();
328 if (!token_service) {
329 DVLOG(2)
330 << "Not starting TiclInvalidationService: "
331 << "OAuth2TokenService unavailable.";
332 return false;
335 if (!token_service->RefreshTokenIsAvailable(
336 identity_provider_->GetActiveAccountId())) {
337 DVLOG(2)
338 << "Not starting TiclInvalidationServce: Waiting for refresh token.";
339 return false;
342 return true;
345 bool TiclInvalidationService::IsStarted() const {
346 return invalidator_.get() != NULL;
349 void TiclInvalidationService::StartInvalidator(
350 InvalidationNetworkChannel network_channel) {
351 DCHECK(CalledOnValidThread());
352 DCHECK(!invalidator_);
353 DCHECK(invalidation_state_tracker_);
354 DCHECK(!invalidation_state_tracker_->GetInvalidatorClientId().empty());
356 // Request access token for PushClientChannel. GCMNetworkChannel will request
357 // access token before sending message to server.
358 if (network_channel == PUSH_CLIENT_CHANNEL && access_token_.empty()) {
359 DVLOG(1)
360 << "TiclInvalidationService: "
361 << "Deferring start until we have an access token.";
362 RequestAccessToken();
363 return;
366 syncer::NetworkChannelCreator network_channel_creator;
368 switch (network_channel) {
369 case PUSH_CLIENT_CHANNEL: {
370 notifier::NotifierOptions options =
371 ParseNotifierOptions(*CommandLine::ForCurrentProcess());
372 options.request_context_getter = request_context_;
373 options.auth_mechanism = "X-OAUTH2";
374 network_channel_options_.SetString("Options.HostPort",
375 options.xmpp_host_port.ToString());
376 network_channel_options_.SetString("Options.AuthMechanism",
377 options.auth_mechanism);
378 DCHECK_EQ(notifier::NOTIFICATION_SERVER, options.notification_method);
379 network_channel_creator =
380 syncer::NonBlockingInvalidator::MakePushClientChannelCreator(options);
381 break;
383 case GCM_NETWORK_CHANNEL: {
384 gcm_invalidation_bridge_.reset(new GCMInvalidationBridge(
385 gcm_service_, identity_provider_.get()));
386 network_channel_creator =
387 syncer::NonBlockingInvalidator::MakeGCMNetworkChannelCreator(
388 request_context_,
389 gcm_invalidation_bridge_->CreateDelegate().Pass());
390 break;
392 default: {
393 NOTREACHED();
394 return;
397 invalidator_.reset(new syncer::NonBlockingInvalidator(
398 network_channel_creator,
399 invalidation_state_tracker_->GetInvalidatorClientId(),
400 invalidation_state_tracker_->GetSavedInvalidations(),
401 invalidation_state_tracker_->GetBootstrapData(),
402 invalidation_state_tracker_.get(),
403 GetUserAgent(),
404 request_context_));
406 UpdateInvalidatorCredentials();
408 invalidator_->RegisterHandler(this);
409 invalidator_->UpdateRegisteredIds(
410 this,
411 invalidator_registrar_->GetAllRegisteredIds());
414 void TiclInvalidationService::UpdateInvalidationNetworkChannel() {
415 const InvalidationNetworkChannel network_channel_type =
416 settings_provider_->UseGCMChannel() ? GCM_NETWORK_CHANNEL
417 : PUSH_CLIENT_CHANNEL;
418 if (network_channel_type_ == network_channel_type)
419 return;
420 network_channel_type_ = network_channel_type;
421 if (IsStarted()) {
422 StopInvalidator();
423 StartInvalidator(network_channel_type_);
427 void TiclInvalidationService::UpdateInvalidatorCredentials() {
428 std::string email = identity_provider_->GetActiveAccountId();
430 DCHECK(!email.empty()) << "Expected user to be signed in.";
432 DVLOG(2) << "UpdateCredentials: " << email;
433 invalidator_->UpdateCredentials(email, access_token_);
436 void TiclInvalidationService::StopInvalidator() {
437 DCHECK(invalidator_);
438 gcm_invalidation_bridge_.reset();
439 invalidator_->UnregisterHandler(this);
440 invalidator_.reset();
443 } // namespace invalidation