123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- // Copyright 2019 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 "components/invalidation/impl/fcm_invalidation_service_base.h"
- #include <memory>
- #include "base/bind.h"
- #include "base/i18n/time_formatting.h"
- #include "base/metrics/histogram_functions.h"
- #include "base/strings/strcat.h"
- #include "components/gcm_driver/instance_id/instance_id_driver.h"
- #include "components/invalidation/impl/fcm_network_handler.h"
- #include "components/invalidation/impl/invalidation_prefs.h"
- #include "components/invalidation/public/invalidator_state.h"
- #include "components/invalidation/public/topic_data.h"
- #include "components/invalidation/public/topic_invalidation_map.h"
- #include "components/prefs/scoped_user_pref_update.h"
- namespace invalidation {
- namespace {
- const char kApplicationName[] = "com.google.chrome.fcm.invalidations";
- // Sender ID coming from the Firebase console.
- const char kInvalidationGCMSenderId[] = "8181035976";
- // Added in M76.
- void MigratePrefs(PrefService* prefs, const std::string& sender_id) {
- if (!prefs->HasPrefPath(prefs::kFCMInvalidationClientIDCacheDeprecated)) {
- return;
- }
- DictionaryPrefUpdate update(prefs, prefs::kInvalidationClientIDCache);
- update->SetStringKey(
- sender_id,
- prefs->GetString(prefs::kFCMInvalidationClientIDCacheDeprecated));
- prefs->ClearPref(prefs::kFCMInvalidationClientIDCacheDeprecated);
- }
- } // namespace
- FCMInvalidationServiceBase::FCMInvalidationServiceBase(
- FCMNetworkHandlerCallback fcm_network_handler_callback,
- PerUserTopicSubscriptionManagerCallback
- per_user_topic_subscription_manager_callback,
- instance_id::InstanceIDDriver* instance_id_driver,
- PrefService* pref_service,
- const std::string& sender_id)
- : sender_id_(sender_id.empty() ? kInvalidationGCMSenderId : sender_id),
- invalidator_registrar_(pref_service,
- sender_id_,
- sender_id_ == kInvalidationGCMSenderId),
- fcm_network_handler_callback_(std::move(fcm_network_handler_callback)),
- per_user_topic_subscription_manager_callback_(
- std::move(per_user_topic_subscription_manager_callback)),
- instance_id_driver_(instance_id_driver),
- pref_service_(pref_service) {}
- FCMInvalidationServiceBase::~FCMInvalidationServiceBase() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- invalidator_registrar_.UpdateInvalidatorState(INVALIDATOR_SHUTTING_DOWN);
- if (IsStarted()) {
- StopInvalidator();
- }
- }
- // static
- void FCMInvalidationServiceBase::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterStringPref(prefs::kFCMInvalidationClientIDCacheDeprecated,
- /*default_value=*/std::string());
- registry->RegisterDictionaryPref(prefs::kInvalidationClientIDCache);
- }
- void FCMInvalidationServiceBase::RegisterInvalidationHandler(
- InvalidationHandler* handler) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DVLOG(2) << "Registering an invalidation handler";
- invalidator_registrar_.RegisterHandler(handler);
- // Populate the id for newly registered handlers.
- handler->OnInvalidatorClientIdChange(client_id_);
- logger_.OnRegistration(handler->GetOwnerName());
- }
- bool FCMInvalidationServiceBase::UpdateInterestedTopics(
- InvalidationHandler* handler,
- const TopicSet& legacy_topic_set) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- update_was_requested_ = true;
- DVLOG(2) << "Subscribing to topics: " << legacy_topic_set.size();
- std::set<TopicData> topic_set;
- for (const auto& topic_name : legacy_topic_set) {
- topic_set.insert(TopicData(topic_name, handler->IsPublicTopic(topic_name)));
- }
- // TODO(crbug.com/1054404): UpdateRegisteredTopics() should be renamed to
- // clarify that it actually updates whether topics need subscription (aka
- // interested).
- if (!invalidator_registrar_.UpdateRegisteredTopics(handler, topic_set)) {
- return false;
- }
- DoUpdateSubscribedTopicsIfNeeded();
- logger_.OnUpdatedTopics(invalidator_registrar_.GetHandlerNameToTopicsMap());
- return true;
- }
- void FCMInvalidationServiceBase::UnsubscribeFromUnregisteredTopics(
- InvalidationHandler* handler) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DVLOG(2) << "Unsubscribing from unregistered topics";
- invalidator_registrar_.RemoveUnregisteredTopics(handler);
- DoUpdateSubscribedTopicsIfNeeded();
- logger_.OnUpdatedTopics(invalidator_registrar_.GetHandlerNameToTopicsMap());
- }
- void FCMInvalidationServiceBase::UnregisterInvalidationHandler(
- InvalidationHandler* handler) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DVLOG(2) << "Unregistering";
- invalidator_registrar_.UnregisterHandler(handler);
- logger_.OnUnregistration(handler->GetOwnerName());
- }
- InvalidatorState FCMInvalidationServiceBase::GetInvalidatorState() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (invalidation_listener_) {
- DVLOG(2) << "GetInvalidatorState returning "
- << invalidator_registrar_.GetInvalidatorState();
- return invalidator_registrar_.GetInvalidatorState();
- }
- DVLOG(2) << "Invalidator currently stopped";
- return STOPPED;
- }
- std::string FCMInvalidationServiceBase::GetInvalidatorClientId() const {
- return client_id_;
- }
- InvalidationLogger* FCMInvalidationServiceBase::GetInvalidationLogger() {
- return &logger_;
- }
- void FCMInvalidationServiceBase::RequestDetailedStatus(
- base::RepeatingCallback<void(base::Value::Dict)> return_callback) const {
- return_callback.Run(CollectDebugData());
- invalidator_registrar_.RequestDetailedStatus(return_callback);
- if (IsStarted()) {
- invalidation_listener_->RequestDetailedStatus(return_callback);
- }
- }
- void FCMInvalidationServiceBase::OnInvalidate(
- const TopicInvalidationMap& invalidation_map) {
- invalidator_registrar_.DispatchInvalidationsToHandlers(invalidation_map);
- logger_.OnInvalidation(invalidation_map);
- }
- void FCMInvalidationServiceBase::OnInvalidatorStateChange(
- InvalidatorState state) {
- invalidator_registrar_.UpdateInvalidatorState(state);
- logger_.OnStateChange(state);
- }
- void FCMInvalidationServiceBase::InitForTest(
- std::unique_ptr<FCMInvalidationListener> invalidation_listener) {
- // Here we perform the equivalent of Init() and StartInvalidator(), but with
- // some minor changes to account for the fact that we're injecting the
- // invalidation_listener.
- // StartInvalidator initializes the invalidation_listener and starts it.
- invalidation_listener_ = std::move(invalidation_listener);
- invalidation_listener_->StartForTest(this);
- PopulateClientID();
- DoUpdateSubscribedTopicsIfNeeded();
- }
- base::Value::Dict FCMInvalidationServiceBase::CollectDebugData() const {
- base::Value::Dict status;
- status.SetByDottedPath(
- "InvalidationService.IID-requested",
- base::TimeFormatShortDateAndTime(diagnostic_info_.instance_id_requested));
- status.SetByDottedPath(
- "InvalidationService.IID-received",
- base::TimeFormatShortDateAndTime(diagnostic_info_.instance_id_received));
- status.SetByDottedPath(
- "InvalidationService.IID-cleared",
- base::TimeFormatShortDateAndTime(diagnostic_info_.instance_id_cleared));
- status.SetByDottedPath(
- "InvalidationService.Service-stopped",
- base::TimeFormatShortDateAndTime(diagnostic_info_.service_was_stopped));
- status.SetByDottedPath(
- "InvalidationService.Service-started",
- base::TimeFormatShortDateAndTime(diagnostic_info_.service_was_started));
- return status;
- }
- bool FCMInvalidationServiceBase::IsStarted() const {
- return invalidation_listener_ != nullptr;
- }
- void FCMInvalidationServiceBase::StartInvalidator() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!invalidation_listener_);
- diagnostic_info_.service_was_started = base::Time::Now();
- auto network =
- fcm_network_handler_callback_.Run(sender_id_, GetApplicationName());
- // The order of calls is important. Do not change.
- // We should start listening before requesting the id, because
- // valid id is only generated, once there is an app handler
- // for the app. StartListening registers the app handler.
- // We should create InvalidationListener first, because it registers the
- // handler for the incoming messages, which is crucial on Android, because on
- // the startup cached messages might exists.
- invalidation_listener_ =
- std::make_unique<FCMInvalidationListener>(std::move(network));
- auto subscription_manager = per_user_topic_subscription_manager_callback_.Run(
- sender_id_, /*migrate_prefs=*/sender_id_ == kInvalidationGCMSenderId);
- invalidation_listener_->Start(this, std::move(subscription_manager));
- PopulateClientID();
- DoUpdateSubscribedTopicsIfNeeded();
- }
- void FCMInvalidationServiceBase::StopInvalidator() {
- DCHECK(invalidation_listener_);
- diagnostic_info_.service_was_stopped = base::Time::Now();
- invalidation_listener_.reset();
- }
- void FCMInvalidationServiceBase::StopInvalidatorPermanently() {
- // Reset the client ID (aka InstanceID) *before* stopping, so that
- // FCMInvalidationListener gets notified about the cleared ID (the listener
- // gets destroyed during StopInvalidator()).
- if (!client_id_.empty()) {
- ResetClientID();
- }
- StopInvalidator();
- }
- void FCMInvalidationServiceBase::PopulateClientID() {
- diagnostic_info_.instance_id_requested = base::Time::Now();
- if (sender_id_ == kInvalidationGCMSenderId) {
- MigratePrefs(pref_service_, sender_id_);
- }
- // Retrieve any client ID (aka Instance ID) from a previous run, which was
- // cached in prefs.
- const std::string* client_id_pref =
- pref_service_->GetValueDict(prefs::kInvalidationClientIDCache)
- .FindString(sender_id_);
- client_id_ = client_id_pref ? *client_id_pref : "";
- // There might already be clients (handlers) registered, so tell them about
- // the client ID.
- invalidator_registrar_.UpdateInvalidatorInstanceId(client_id_);
- // Also retrieve a fresh (or validated) client ID. If the |client_id_| just
- // retrieved from prefs is non-empty, then the fresh/validated one will
- // typically be equal to it, but it's not completely guaranteed. OTOH, if
- // |client_id_| is empty, i.e. we didn't have one previously, then this will
- // generate/retrieve a new one.
- instance_id::InstanceID* instance_id =
- instance_id_driver_->GetInstanceID(GetApplicationName());
- instance_id->GetID(
- base::BindOnce(&FCMInvalidationServiceBase::OnInstanceIDReceived,
- base::Unretained(this)));
- }
- void FCMInvalidationServiceBase::ResetClientID() {
- instance_id::InstanceID* instance_id =
- instance_id_driver_->GetInstanceID(GetApplicationName());
- instance_id->DeleteID(
- base::BindOnce(&FCMInvalidationServiceBase::OnDeleteInstanceIDCompleted,
- base::Unretained(this)));
- // Immediately clear our cached values (before we get confirmation of the
- // deletion), since they shouldn't be used anymore. Lower layers are the
- // source of truth, and are responsible for ensuring that the deletion
- // actually happens.
- client_id_.clear();
- DictionaryPrefUpdate update(pref_service_, prefs::kInvalidationClientIDCache);
- update->RemoveKey(sender_id_);
- // Also let the registrar (and its observers) know that the instance ID is
- // gone.
- invalidator_registrar_.UpdateInvalidatorInstanceId(std::string());
- // This will also delete all Instance ID *tokens*; we need to let the
- // FCMInvalidationListener know.
- if (invalidation_listener_) {
- invalidation_listener_->ClearInstanceIDToken();
- }
- }
- void FCMInvalidationServiceBase::OnInstanceIDReceived(
- const std::string& instance_id) {
- diagnostic_info_.instance_id_received = base::Time::Now();
- if (client_id_ != instance_id) {
- client_id_ = instance_id;
- DictionaryPrefUpdate update(pref_service_,
- prefs::kInvalidationClientIDCache);
- update->SetStringKey(sender_id_, instance_id);
- invalidator_registrar_.UpdateInvalidatorInstanceId(instance_id);
- }
- }
- void FCMInvalidationServiceBase::OnDeleteInstanceIDCompleted(
- instance_id::InstanceID::Result) {
- // Note: |client_id_| and the pref were already cleared when we initiated the
- // deletion.
- diagnostic_info_.instance_id_cleared = base::Time::Now();
- }
- void FCMInvalidationServiceBase::DoUpdateSubscribedTopicsIfNeeded() {
- if (!invalidation_listener_ || !update_was_requested_) {
- return;
- }
- auto subscribed_topics = invalidator_registrar_.GetAllSubscribedTopics();
- invalidation_listener_->UpdateInterestedTopics(subscribed_topics);
- update_was_requested_ = false;
- }
- const std::string FCMInvalidationServiceBase::GetApplicationName() {
- // If using the default |sender_id_|, use the bare |kApplicationName|, so the
- // old app name is maintained.
- if (sender_id_ == kInvalidationGCMSenderId) {
- return kApplicationName;
- }
- return base::StrCat({kApplicationName, "-", sender_id_});
- }
- } // namespace invalidation
|