This source file includes following definitions.
- logger_
- Init
- InitForTest
- RegisterInvalidationHandler
- UpdateRegisteredInvalidationIds
- UnregisterInvalidationHandler
- GetInvalidatorState
- GetInvalidatorClientId
- GetInvalidationLogger
- GetInvalidationAuthProvider
- RequestDetailedStatus
- RequestAccessToken
- OnGetTokenSuccess
- OnGetTokenFailure
- OnRefreshTokenAvailable
- OnRefreshTokenRevoked
- OnInvalidationAuthLogout
- OnInvalidatorStateChange
- OnIncomingInvalidation
- GetOwnerName
- Shutdown
- IsReadyToStart
- IsStarted
- StartInvalidator
- UpdateInvalidationNetworkChannel
- UpdateInvalidatorCredentials
- StopInvalidator
#include "chrome/browser/invalidation/ticl_invalidation_service.h"
#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/invalidation/gcm_invalidation_bridge.h"
#include "chrome/browser/invalidation/invalidation_auth_provider.h"
#include "chrome/browser/invalidation/invalidation_logger.h"
#include "chrome/browser/invalidation/invalidation_service_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/services/gcm/gcm_profile_service.h"
#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "google_apis/gaia/gaia_constants.h"
#include "sync/notifier/gcm_network_channel_delegate.h"
#include "sync/notifier/invalidation_util.h"
#include "sync/notifier/invalidator.h"
#include "sync/notifier/invalidator_state.h"
#include "sync/notifier/non_blocking_invalidator.h"
#include "sync/notifier/object_id_invalidation_map.h"
static const char* kOAuth2Scopes[] = {
GaiaConstants::kGoogleTalkOAuth2Scope
};
static const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
0,
2000,
2,
0.2,
1000 * 3600 * 4,
-1,
false,
};
namespace invalidation {
TiclInvalidationService::TiclInvalidationService(
scoped_ptr<InvalidationAuthProvider> auth_provider,
Profile* profile)
: OAuth2TokenService::Consumer("ticl_invalidation"),
profile_(profile),
auth_provider_(auth_provider.Pass()),
invalidator_registrar_(new syncer::InvalidatorRegistrar()),
request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
network_channel_type_(PUSH_CLIENT_CHANNEL),
logger_() {}
TiclInvalidationService::~TiclInvalidationService() {
DCHECK(CalledOnValidThread());
}
void TiclInvalidationService::Init() {
DCHECK(CalledOnValidThread());
invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs()));
if (invalidator_storage_->GetInvalidatorClientId().empty()) {
invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId());
}
pref_change_registrar_.Init(profile_->GetPrefs());
pref_change_registrar_.Add(
prefs::kInvalidationServiceUseGCMChannel,
base::Bind(&TiclInvalidationService::UpdateInvalidationNetworkChannel,
base::Unretained(this)));
pref_change_registrar_.Add(
prefs::kGCMChannelEnabled,
base::Bind(&TiclInvalidationService::UpdateInvalidationNetworkChannel,
base::Unretained(this)));
UpdateInvalidationNetworkChannel();
UMA_HISTOGRAM_ENUMERATION("Invalidations.NetworkChannel",
network_channel_type_,
NETWORK_CHANNELS_COUNT);
if (IsReadyToStart()) {
StartInvalidator(network_channel_type_);
}
auth_provider_->AddObserver(this);
auth_provider_->GetTokenService()->AddObserver(this);
}
void TiclInvalidationService::InitForTest(syncer::Invalidator* invalidator) {
invalidator_.reset(invalidator);
invalidator_->RegisterHandler(this);
invalidator_->UpdateRegisteredIds(
this,
invalidator_registrar_->GetAllRegisteredIds());
}
void TiclInvalidationService::RegisterInvalidationHandler(
syncer::InvalidationHandler* handler) {
DCHECK(CalledOnValidThread());
DVLOG(2) << "Registering an invalidation handler";
invalidator_registrar_->RegisterHandler(handler);
logger_.OnRegistration(handler->GetOwnerName());
}
void TiclInvalidationService::UpdateRegisteredInvalidationIds(
syncer::InvalidationHandler* handler,
const syncer::ObjectIdSet& ids) {
DCHECK(CalledOnValidThread());
DVLOG(2) << "Registering ids: " << ids.size();
invalidator_registrar_->UpdateRegisteredIds(handler, ids);
if (invalidator_) {
invalidator_->UpdateRegisteredIds(
this,
invalidator_registrar_->GetAllRegisteredIds());
}
logger_.OnUpdateIds(invalidator_registrar_->GetSanitizedHandlersIdsMap());
}
void TiclInvalidationService::UnregisterInvalidationHandler(
syncer::InvalidationHandler* handler) {
DCHECK(CalledOnValidThread());
DVLOG(2) << "Unregistering";
invalidator_registrar_->UnregisterHandler(handler);
if (invalidator_) {
invalidator_->UpdateRegisteredIds(
this,
invalidator_registrar_->GetAllRegisteredIds());
}
logger_.OnUnregistration(handler->GetOwnerName());
}
syncer::InvalidatorState TiclInvalidationService::GetInvalidatorState() const {
DCHECK(CalledOnValidThread());
if (invalidator_) {
DVLOG(2) << "GetInvalidatorState returning "
<< invalidator_->GetInvalidatorState();
return invalidator_->GetInvalidatorState();
} else {
DVLOG(2) << "Invalidator currently stopped";
return syncer::TRANSIENT_INVALIDATION_ERROR;
}
}
std::string TiclInvalidationService::GetInvalidatorClientId() const {
DCHECK(CalledOnValidThread());
return invalidator_storage_->GetInvalidatorClientId();
}
InvalidationLogger* TiclInvalidationService::GetInvalidationLogger() {
return &logger_;
}
InvalidationAuthProvider*
TiclInvalidationService::GetInvalidationAuthProvider() {
return auth_provider_.get();
}
void TiclInvalidationService::RequestDetailedStatus(
base::Callback<void(const base::DictionaryValue&)> return_callback) const {
if (IsStarted()) {
return_callback.Run(network_channel_options_);
invalidator_->RequestDetailedStatus(return_callback);
}
}
void TiclInvalidationService::RequestAccessToken() {
if (access_token_request_ != NULL)
return;
request_access_token_retry_timer_.Stop();
OAuth2TokenService::ScopeSet oauth2_scopes;
for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++)
oauth2_scopes.insert(kOAuth2Scopes[i]);
const std::string& account_id = auth_provider_->GetAccountId();
OAuth2TokenService* token_service = auth_provider_->GetTokenService();
token_service->InvalidateToken(account_id, oauth2_scopes, access_token_);
access_token_.clear();
access_token_request_ =
token_service->StartRequest(account_id, oauth2_scopes, this);
}
void TiclInvalidationService::OnGetTokenSuccess(
const OAuth2TokenService::Request* request,
const std::string& access_token,
const base::Time& expiration_time) {
DCHECK_EQ(access_token_request_, request);
access_token_request_.reset();
request_access_token_backoff_.Reset();
access_token_ = access_token;
if (!IsStarted() && IsReadyToStart()) {
StartInvalidator(network_channel_type_);
} else {
UpdateInvalidatorCredentials();
}
}
void TiclInvalidationService::OnGetTokenFailure(
const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) {
DCHECK_EQ(access_token_request_, request);
DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
access_token_request_.reset();
switch (error.state()) {
case GoogleServiceAuthError::CONNECTION_FAILED:
case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
request_access_token_backoff_.InformOfRequest(false);
request_access_token_retry_timer_.Start(
FROM_HERE,
request_access_token_backoff_.GetTimeUntilRelease(),
base::Bind(&TiclInvalidationService::RequestAccessToken,
base::Unretained(this)));
break;
}
case GoogleServiceAuthError::SERVICE_ERROR:
case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
invalidator_registrar_->UpdateInvalidatorState(
syncer::INVALIDATION_CREDENTIALS_REJECTED);
break;
}
default: {
}
}
}
void TiclInvalidationService::OnRefreshTokenAvailable(
const std::string& account_id) {
if (auth_provider_->GetAccountId() == account_id) {
if (!IsStarted() && IsReadyToStart()) {
StartInvalidator(network_channel_type_);
}
}
}
void TiclInvalidationService::OnRefreshTokenRevoked(
const std::string& account_id) {
if (auth_provider_->GetAccountId() == account_id) {
access_token_.clear();
if (IsStarted()) {
UpdateInvalidatorCredentials();
}
}
}
void TiclInvalidationService::OnInvalidationAuthLogout() {
access_token_request_.reset();
request_access_token_retry_timer_.Stop();
if (IsStarted()) {
StopInvalidator();
}
invalidator_storage_->Clear();
invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs()));
invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId());
}
void TiclInvalidationService::OnInvalidatorStateChange(
syncer::InvalidatorState state) {
if (state == syncer::INVALIDATION_CREDENTIALS_REJECTED) {
invalidator_registrar_->UpdateInvalidatorState(
syncer::TRANSIENT_INVALIDATION_ERROR);
RequestAccessToken();
} else {
invalidator_registrar_->UpdateInvalidatorState(state);
}
logger_.OnStateChange(state);
}
void TiclInvalidationService::OnIncomingInvalidation(
const syncer::ObjectIdInvalidationMap& invalidation_map) {
invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map);
logger_.OnInvalidation(invalidation_map);
}
std::string TiclInvalidationService::GetOwnerName() const { return "TICL"; }
void TiclInvalidationService::Shutdown() {
DCHECK(CalledOnValidThread());
auth_provider_->GetTokenService()->RemoveObserver(this);
auth_provider_->RemoveObserver(this);
if (IsStarted()) {
StopInvalidator();
}
invalidator_storage_.reset();
invalidator_registrar_.reset();
}
bool TiclInvalidationService::IsReadyToStart() {
if (profile_->IsManaged()) {
DVLOG(2) << "Not starting TiclInvalidationService: User is managed.";
return false;
}
if (auth_provider_->GetAccountId().empty()) {
DVLOG(2) << "Not starting TiclInvalidationService: User is not signed in.";
return false;
}
OAuth2TokenService* token_service = auth_provider_->GetTokenService();
if (!token_service) {
DVLOG(2)
<< "Not starting TiclInvalidationService: "
<< "OAuth2TokenService unavailable.";
return false;
}
if (!token_service->RefreshTokenIsAvailable(auth_provider_->GetAccountId())) {
DVLOG(2)
<< "Not starting TiclInvalidationServce: Waiting for refresh token.";
return false;
}
return true;
}
bool TiclInvalidationService::IsStarted() const {
return invalidator_.get() != NULL;
}
void TiclInvalidationService::StartInvalidator(
InvalidationNetworkChannel network_channel) {
DCHECK(CalledOnValidThread());
DCHECK(!invalidator_);
DCHECK(invalidator_storage_);
DCHECK(!invalidator_storage_->GetInvalidatorClientId().empty());
if (network_channel == PUSH_CLIENT_CHANNEL && access_token_.empty()) {
DVLOG(1)
<< "TiclInvalidationService: "
<< "Deferring start until we have an access token.";
RequestAccessToken();
return;
}
syncer::NetworkChannelCreator network_channel_creator;
switch (network_channel) {
case PUSH_CLIENT_CHANNEL: {
notifier::NotifierOptions options =
ParseNotifierOptions(*CommandLine::ForCurrentProcess());
options.request_context_getter = profile_->GetRequestContext();
options.auth_mechanism = "X-OAUTH2";
network_channel_options_.SetString("Options.HostPort",
options.xmpp_host_port.ToString());
network_channel_options_.SetString("Options.AuthMechanism",
options.auth_mechanism);
DCHECK_EQ(notifier::NOTIFICATION_SERVER, options.notification_method);
network_channel_creator =
syncer::NonBlockingInvalidator::MakePushClientChannelCreator(options);
break;
}
case GCM_NETWORK_CHANNEL: {
gcm::GCMProfileService* gcm_profile_service =
gcm::GCMProfileServiceFactory::GetForProfile(profile_);
gcm_invalidation_bridge_.reset(
new GCMInvalidationBridge(gcm_profile_service, auth_provider_.get()));
network_channel_creator =
syncer::NonBlockingInvalidator::MakeGCMNetworkChannelCreator(
profile_->GetRequestContext(),
gcm_invalidation_bridge_->CreateDelegate().Pass());
break;
}
default: {
NOTREACHED();
return;
}
}
invalidator_.reset(new syncer::NonBlockingInvalidator(
network_channel_creator,
invalidator_storage_->GetInvalidatorClientId(),
invalidator_storage_->GetSavedInvalidations(),
invalidator_storage_->GetBootstrapData(),
syncer::WeakHandle<syncer::InvalidationStateTracker>(
invalidator_storage_->AsWeakPtr()),
GetUserAgent(),
profile_->GetRequestContext()));
UpdateInvalidatorCredentials();
invalidator_->RegisterHandler(this);
invalidator_->UpdateRegisteredIds(
this,
invalidator_registrar_->GetAllRegisteredIds());
}
void TiclInvalidationService::UpdateInvalidationNetworkChannel() {
InvalidationNetworkChannel network_channel_type = PUSH_CLIENT_CHANNEL;
if (gcm::GCMProfileService::GetGCMEnabledState(profile_) ==
gcm::GCMProfileService::ALWAYS_ENABLED &&
(profile_->GetPrefs()->GetBoolean(
prefs::kInvalidationServiceUseGCMChannel) ||
CommandLine::ForCurrentProcess()->HasSwitch(
switches::kInvalidationUseGCMChannel))) {
network_channel_type = GCM_NETWORK_CHANNEL;
}
if (network_channel_type_ == network_channel_type)
return;
network_channel_type_ = network_channel_type;
if (IsStarted()) {
StopInvalidator();
StartInvalidator(network_channel_type_);
}
}
void TiclInvalidationService::UpdateInvalidatorCredentials() {
std::string email = auth_provider_->GetAccountId();
DCHECK(!email.empty()) << "Expected user to be signed in.";
DVLOG(2) << "UpdateCredentials: " << email;
invalidator_->UpdateCredentials(email, access_token_);
}
void TiclInvalidationService::StopInvalidator() {
DCHECK(invalidator_);
gcm_invalidation_bridge_.reset();
invalidator_->UnregisterHandler(this);
invalidator_.reset();
}
}