Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1663)

Unified Diff: chrome/browser/invalidation_service.cc

Issue 13197004: Draft: InvalidationService (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Passes tests Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/invalidation_service.cc
diff --git a/chrome/browser/invalidation_service.cc b/chrome/browser/invalidation_service.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ab8e1ee37c531f1a4dea01f185b7bd11cf34e94e
--- /dev/null
+++ b/chrome/browser/invalidation_service.cc
@@ -0,0 +1,286 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/invalidation_service.h"
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/rand_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/token_service.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/notification_service.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "sync/notifier/invalidator.h"
+#include "sync/notifier/invalidator_state.h"
+#include "sync/notifier/non_blocking_invalidator.h"
+
+namespace {
+// Parses the given command line for notifier options.
+notifier::NotifierOptions ParseNotifierOptions(
+ const CommandLine& command_line,
+ const scoped_refptr<net::URLRequestContextGetter>&
+ request_context_getter) {
+ notifier::NotifierOptions notifier_options;
+ notifier_options.request_context_getter = request_context_getter;
+
+ if (command_line.HasSwitch(switches::kSyncNotificationHostPort)) {
+ notifier_options.xmpp_host_port =
+ net::HostPortPair::FromString(
+ command_line.GetSwitchValueASCII(
+ switches::kSyncNotificationHostPort));
+ DVLOG(1) << "Using " << notifier_options.xmpp_host_port.ToString()
+ << " for test sync notification server.";
+ }
+
+ notifier_options.try_ssltcp_first =
+ command_line.HasSwitch(switches::kSyncTrySsltcpFirstForXmpp);
+ DVLOG_IF(1, notifier_options.try_ssltcp_first)
+ << "Trying SSL/TCP port before XMPP port for notifications.";
+
+ notifier_options.invalidate_xmpp_login =
+ command_line.HasSwitch(switches::kSyncInvalidateXmppLogin);
+ DVLOG_IF(1, notifier_options.invalidate_xmpp_login)
+ << "Invalidating sync XMPP login.";
+
+ notifier_options.allow_insecure_connection =
+ command_line.HasSwitch(switches::kSyncAllowInsecureXmppConnection);
+ DVLOG_IF(1, notifier_options.allow_insecure_connection)
+ << "Allowing insecure XMPP connections.";
+
+ if (command_line.HasSwitch(switches::kSyncNotificationMethod)) {
+ const std::string notification_method_str(
+ command_line.GetSwitchValueASCII(switches::kSyncNotificationMethod));
+ notifier_options.notification_method =
+ notifier::StringToNotificationMethod(notification_method_str);
+ }
+
+ return notifier_options;
+}
+
+std::string GenerateInvalidatorClientId() {
+ // Generate a GUID with 128 bits worth of base64-encoded randomness.
+ // This format is similar to that of sync's cache_guid.
+ const int kGuidBytes = 128 / 8;
+ std::string guid;
+ base::Base64Encode(base::RandBytesAsString(kGuidBytes), &guid);
+ return guid;
+}
+
+} // namespace
+
+InvalidationService::InvalidationService(SigninManager* signin,
+ TokenService* token_service)
+ : signin_manager_(signin),
+ token_service_(token_service),
+ invalidator_registrar_(new syncer::InvalidatorRegistrar()) { }
+
+InvalidationService::~InvalidationService() {
+ DCHECK(CalledOnValidThread());
+}
+
+void InvalidationService::Init(Profile* profile) {
+ DCHECK(CalledOnValidThread());
+
+ profile_ = profile;
+
+ invalidator_storage_.reset(
+ new browser_sync::InvalidatorStorage(profile_->GetPrefs()));
+ if (invalidator_storage_->GetInvalidatorClientId().empty()) {
+ // This also clears any existing state. We can't reuse old invalidator
+ // state with the new ID anyway.
+ invalidator_storage_->SetInvalidatorClientId(
+ GenerateInvalidatorClientId());
+ }
+
+ if (IsReadyToStart()) {
+ Start();
+ }
+
+ notification_registrar_.Add(this,
+ chrome::NOTIFICATION_TOKEN_AVAILABLE,
+ content::Source<TokenService>(token_service_));
+ notification_registrar_.Add(this,
+ chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
+ content::NotificationService::AllSources());
+}
+
+void InvalidationService::RegisterInvalidationHandler(
+ syncer::InvalidationHandler* handler) {
+ DCHECK(CalledOnValidThread());
+ DVLOG(2) << "Registering";
+ invalidator_registrar_->RegisterHandler(handler);
+}
+
+void InvalidationService::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());
+ }
+}
+
+void InvalidationService::UnregisterInvalidationHandler(
+ syncer::InvalidationHandler* handler) {
+ DCHECK(CalledOnValidThread());
+ DVLOG(2) << "Unregistering";
+ invalidator_registrar_->UnregisterHandler(handler);
+ // FIXME: Should unregistering the handler also unregister the IDs?
+ // I don't see why not...
+ if (invalidator_) {
+ invalidator_->UpdateRegisteredIds(
+ this,
+ invalidator_registrar_->GetAllRegisteredIds());
+ }
+}
+
+void InvalidationService::AcknowledgeInvalidation(
+ const invalidation::ObjectId& id,
+ const syncer::AckHandle& ack_handle) {
+ DCHECK(CalledOnValidThread());
+ if (invalidator_) {
+ invalidator_->Acknowledge(id, ack_handle);
+ }
+}
+
+syncer::InvalidatorState InvalidationService::GetInvalidatorState() const {
+ DCHECK(CalledOnValidThread());
+ if (invalidator_) {
+ DVLOG(2) << "GetInvalidatorState returning " << GetInvalidatorState();
+ return invalidator_->GetInvalidatorState();
+ } else {
+ DVLOG(2) << "Invalidator currently stopped";
+ return syncer::TRANSIENT_INVALIDATION_ERROR;
+ }
+}
+
+std::string InvalidationService::GetInvalidatorClientId() const {
+ DCHECK(CalledOnValidThread());
+ if (!invalidator_storage_) { // NULL in some unit tests.
+ return "TESTING_ONLY_ID";
+ }
+
+ return invalidator_storage_->GetInvalidatorClientId();
+}
+
+void InvalidationService::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK(CalledOnValidThread());
+
+ switch (type) {
+ case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
tim (not reviewing) 2013/04/15 16:48:24 I forget, do we always send TOKEN_AVAILABLE from T
rlarocque 2013/04/22 21:47:15 I think that's always guaranteed. I was a bit sus
tim (not reviewing) 2013/04/22 22:13:56 More likely is at one time TOKEN_AVAILABLE was act
+ const TokenService::TokenAvailableDetails& token_details =
+ *(content::Details<const TokenService::TokenAvailableDetails>(
+ details).ptr());
+ if (token_details.service() == GaiaConstants::kSyncService) {
+ DCHECK(IsReadyToStart());
+ if (!IsStarted()) {
+ Start();
tim (not reviewing) 2013/04/15 16:48:24 You should check with atwilson@ and rogerta@ about
rlarocque 2013/04/22 21:47:15 I'm not sure that we want to go in that direction.
tim (not reviewing) 2013/04/22 22:13:56 As I said, just make sure you check with Drew (at
+ } else {
+ UpdateToken();
+ }
+ }
+ break;
+ }
+ case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
tim (not reviewing) 2013/04/15 16:48:24 This may get interesting when we have service acco
+ Stop();
+ break;
+ }
+}
+
+void InvalidationService::OnInvalidatorStateChange(
+ syncer::InvalidatorState state) {
+ invalidator_registrar_->UpdateInvalidatorState(state);
+}
+
+void InvalidationService::OnIncomingInvalidation(
+ const syncer::ObjectIdInvalidationMap& invalidation_map) {
+ invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map);
+}
+
+void InvalidationService::Shutdown() {
+ DCHECK(CalledOnValidThread());
+ Stop();
+ invalidator_registrar_.reset();
+}
+
+bool InvalidationService::IsReadyToStart() {
+ if (signin_manager_->GetAuthenticatedUsername().empty()) {
+ DVLOG(2) << "Not starting InvalidationService: user is not signed in.";
+ return false;
+ }
+
+ if (!token_service_) {
+ DVLOG(2) << "Not starting InvalidationService: TokenService unavailable.";
+ return false;
+ }
+
+ if (!token_service_->HasTokenForService(GaiaConstants::kSyncService)) {
+ DVLOG(2) << "Not starting InvalidationService: Sync token unavailable.";
+ return false;
+ }
+
+ return true;
+}
+
+bool InvalidationService::IsStarted() {
+ return !!invalidator_;
+}
+
+void InvalidationService::Start() {
+ DCHECK(CalledOnValidThread());
+
+ DCHECK(!invalidator_);
+
+ invalidator_.reset(new syncer::NonBlockingInvalidator(
+ ParseNotifierOptions(*CommandLine::ForCurrentProcess(),
+ profile_->GetRequestContext()),
+ invalidator_storage_->GetInvalidatorClientId(),
+ invalidator_storage_->GetAllInvalidationStates(),
+ invalidator_storage_->GetBootstrapData(),
+ syncer::WeakHandle<syncer::InvalidationStateTracker>(
+ invalidator_storage_->AsWeakPtr()),
+ content::GetUserAgent(GURL())));
+
+ UpdateToken();
+
+ invalidator_->RegisterHandler(this);
+ invalidator_->UpdateRegisteredIds(
+ this,
+ invalidator_registrar_->GetAllRegisteredIds());
+}
+
+void InvalidationService::UpdateToken() {
+ std::string email = signin_manager_->GetAuthenticatedUsername();
+ DCHECK(!email.empty()) << "Expected user to be signed in.";
+
+ // FIXME: Is it right to use the sync token here?
tim (not reviewing) 2013/04/15 16:48:24 Yes, this seems correct and equivalent to before t
rlarocque 2013/04/22 21:47:15 OK. Just to be clear, my intent with this patch i
tim (not reviewing) 2013/04/22 22:13:56 So, yes. I think we're in agreement? In the futur
+ DCHECK(token_service_->HasTokenForService(GaiaConstants::kSyncService));
+ std::string sync_token = token_service_->GetTokenForService(
+ GaiaConstants::kSyncService);
+
+ DVLOG(2) << "UpdateCredentials: " << email;
+ invalidator_->UpdateCredentials(email, sync_token);
+}
+
+void InvalidationService::Stop() {
+ if (invalidator_) {
+ invalidator_->UnregisterHandler(this);
+ invalidator_.reset();
+ }
+ if (invalidator_storage_) {
+ invalidator_storage_->Clear();
+ invalidator_storage_.reset();
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698