fcm_invalidation_service_base.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Copyright 2019 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.
  4. #include "components/invalidation/impl/fcm_invalidation_service_base.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/i18n/time_formatting.h"
  8. #include "base/metrics/histogram_functions.h"
  9. #include "base/strings/strcat.h"
  10. #include "components/gcm_driver/instance_id/instance_id_driver.h"
  11. #include "components/invalidation/impl/fcm_network_handler.h"
  12. #include "components/invalidation/impl/invalidation_prefs.h"
  13. #include "components/invalidation/public/invalidator_state.h"
  14. #include "components/invalidation/public/topic_data.h"
  15. #include "components/invalidation/public/topic_invalidation_map.h"
  16. #include "components/prefs/scoped_user_pref_update.h"
  17. namespace invalidation {
  18. namespace {
  19. const char kApplicationName[] = "com.google.chrome.fcm.invalidations";
  20. // Sender ID coming from the Firebase console.
  21. const char kInvalidationGCMSenderId[] = "8181035976";
  22. // Added in M76.
  23. void MigratePrefs(PrefService* prefs, const std::string& sender_id) {
  24. if (!prefs->HasPrefPath(prefs::kFCMInvalidationClientIDCacheDeprecated)) {
  25. return;
  26. }
  27. DictionaryPrefUpdate update(prefs, prefs::kInvalidationClientIDCache);
  28. update->SetStringKey(
  29. sender_id,
  30. prefs->GetString(prefs::kFCMInvalidationClientIDCacheDeprecated));
  31. prefs->ClearPref(prefs::kFCMInvalidationClientIDCacheDeprecated);
  32. }
  33. } // namespace
  34. FCMInvalidationServiceBase::FCMInvalidationServiceBase(
  35. FCMNetworkHandlerCallback fcm_network_handler_callback,
  36. PerUserTopicSubscriptionManagerCallback
  37. per_user_topic_subscription_manager_callback,
  38. instance_id::InstanceIDDriver* instance_id_driver,
  39. PrefService* pref_service,
  40. const std::string& sender_id)
  41. : sender_id_(sender_id.empty() ? kInvalidationGCMSenderId : sender_id),
  42. invalidator_registrar_(pref_service,
  43. sender_id_,
  44. sender_id_ == kInvalidationGCMSenderId),
  45. fcm_network_handler_callback_(std::move(fcm_network_handler_callback)),
  46. per_user_topic_subscription_manager_callback_(
  47. std::move(per_user_topic_subscription_manager_callback)),
  48. instance_id_driver_(instance_id_driver),
  49. pref_service_(pref_service) {}
  50. FCMInvalidationServiceBase::~FCMInvalidationServiceBase() {
  51. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  52. invalidator_registrar_.UpdateInvalidatorState(INVALIDATOR_SHUTTING_DOWN);
  53. if (IsStarted()) {
  54. StopInvalidator();
  55. }
  56. }
  57. // static
  58. void FCMInvalidationServiceBase::RegisterPrefs(PrefRegistrySimple* registry) {
  59. registry->RegisterStringPref(prefs::kFCMInvalidationClientIDCacheDeprecated,
  60. /*default_value=*/std::string());
  61. registry->RegisterDictionaryPref(prefs::kInvalidationClientIDCache);
  62. }
  63. void FCMInvalidationServiceBase::RegisterInvalidationHandler(
  64. InvalidationHandler* handler) {
  65. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  66. DVLOG(2) << "Registering an invalidation handler";
  67. invalidator_registrar_.RegisterHandler(handler);
  68. // Populate the id for newly registered handlers.
  69. handler->OnInvalidatorClientIdChange(client_id_);
  70. logger_.OnRegistration(handler->GetOwnerName());
  71. }
  72. bool FCMInvalidationServiceBase::UpdateInterestedTopics(
  73. InvalidationHandler* handler,
  74. const TopicSet& legacy_topic_set) {
  75. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  76. update_was_requested_ = true;
  77. DVLOG(2) << "Subscribing to topics: " << legacy_topic_set.size();
  78. std::set<TopicData> topic_set;
  79. for (const auto& topic_name : legacy_topic_set) {
  80. topic_set.insert(TopicData(topic_name, handler->IsPublicTopic(topic_name)));
  81. }
  82. // TODO(crbug.com/1054404): UpdateRegisteredTopics() should be renamed to
  83. // clarify that it actually updates whether topics need subscription (aka
  84. // interested).
  85. if (!invalidator_registrar_.UpdateRegisteredTopics(handler, topic_set)) {
  86. return false;
  87. }
  88. DoUpdateSubscribedTopicsIfNeeded();
  89. logger_.OnUpdatedTopics(invalidator_registrar_.GetHandlerNameToTopicsMap());
  90. return true;
  91. }
  92. void FCMInvalidationServiceBase::UnsubscribeFromUnregisteredTopics(
  93. InvalidationHandler* handler) {
  94. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  95. DVLOG(2) << "Unsubscribing from unregistered topics";
  96. invalidator_registrar_.RemoveUnregisteredTopics(handler);
  97. DoUpdateSubscribedTopicsIfNeeded();
  98. logger_.OnUpdatedTopics(invalidator_registrar_.GetHandlerNameToTopicsMap());
  99. }
  100. void FCMInvalidationServiceBase::UnregisterInvalidationHandler(
  101. InvalidationHandler* handler) {
  102. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  103. DVLOG(2) << "Unregistering";
  104. invalidator_registrar_.UnregisterHandler(handler);
  105. logger_.OnUnregistration(handler->GetOwnerName());
  106. }
  107. InvalidatorState FCMInvalidationServiceBase::GetInvalidatorState() const {
  108. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  109. if (invalidation_listener_) {
  110. DVLOG(2) << "GetInvalidatorState returning "
  111. << invalidator_registrar_.GetInvalidatorState();
  112. return invalidator_registrar_.GetInvalidatorState();
  113. }
  114. DVLOG(2) << "Invalidator currently stopped";
  115. return STOPPED;
  116. }
  117. std::string FCMInvalidationServiceBase::GetInvalidatorClientId() const {
  118. return client_id_;
  119. }
  120. InvalidationLogger* FCMInvalidationServiceBase::GetInvalidationLogger() {
  121. return &logger_;
  122. }
  123. void FCMInvalidationServiceBase::RequestDetailedStatus(
  124. base::RepeatingCallback<void(base::Value::Dict)> return_callback) const {
  125. return_callback.Run(CollectDebugData());
  126. invalidator_registrar_.RequestDetailedStatus(return_callback);
  127. if (IsStarted()) {
  128. invalidation_listener_->RequestDetailedStatus(return_callback);
  129. }
  130. }
  131. void FCMInvalidationServiceBase::OnInvalidate(
  132. const TopicInvalidationMap& invalidation_map) {
  133. invalidator_registrar_.DispatchInvalidationsToHandlers(invalidation_map);
  134. logger_.OnInvalidation(invalidation_map);
  135. }
  136. void FCMInvalidationServiceBase::OnInvalidatorStateChange(
  137. InvalidatorState state) {
  138. invalidator_registrar_.UpdateInvalidatorState(state);
  139. logger_.OnStateChange(state);
  140. }
  141. void FCMInvalidationServiceBase::InitForTest(
  142. std::unique_ptr<FCMInvalidationListener> invalidation_listener) {
  143. // Here we perform the equivalent of Init() and StartInvalidator(), but with
  144. // some minor changes to account for the fact that we're injecting the
  145. // invalidation_listener.
  146. // StartInvalidator initializes the invalidation_listener and starts it.
  147. invalidation_listener_ = std::move(invalidation_listener);
  148. invalidation_listener_->StartForTest(this);
  149. PopulateClientID();
  150. DoUpdateSubscribedTopicsIfNeeded();
  151. }
  152. base::Value::Dict FCMInvalidationServiceBase::CollectDebugData() const {
  153. base::Value::Dict status;
  154. status.SetByDottedPath(
  155. "InvalidationService.IID-requested",
  156. base::TimeFormatShortDateAndTime(diagnostic_info_.instance_id_requested));
  157. status.SetByDottedPath(
  158. "InvalidationService.IID-received",
  159. base::TimeFormatShortDateAndTime(diagnostic_info_.instance_id_received));
  160. status.SetByDottedPath(
  161. "InvalidationService.IID-cleared",
  162. base::TimeFormatShortDateAndTime(diagnostic_info_.instance_id_cleared));
  163. status.SetByDottedPath(
  164. "InvalidationService.Service-stopped",
  165. base::TimeFormatShortDateAndTime(diagnostic_info_.service_was_stopped));
  166. status.SetByDottedPath(
  167. "InvalidationService.Service-started",
  168. base::TimeFormatShortDateAndTime(diagnostic_info_.service_was_started));
  169. return status;
  170. }
  171. bool FCMInvalidationServiceBase::IsStarted() const {
  172. return invalidation_listener_ != nullptr;
  173. }
  174. void FCMInvalidationServiceBase::StartInvalidator() {
  175. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  176. DCHECK(!invalidation_listener_);
  177. diagnostic_info_.service_was_started = base::Time::Now();
  178. auto network =
  179. fcm_network_handler_callback_.Run(sender_id_, GetApplicationName());
  180. // The order of calls is important. Do not change.
  181. // We should start listening before requesting the id, because
  182. // valid id is only generated, once there is an app handler
  183. // for the app. StartListening registers the app handler.
  184. // We should create InvalidationListener first, because it registers the
  185. // handler for the incoming messages, which is crucial on Android, because on
  186. // the startup cached messages might exists.
  187. invalidation_listener_ =
  188. std::make_unique<FCMInvalidationListener>(std::move(network));
  189. auto subscription_manager = per_user_topic_subscription_manager_callback_.Run(
  190. sender_id_, /*migrate_prefs=*/sender_id_ == kInvalidationGCMSenderId);
  191. invalidation_listener_->Start(this, std::move(subscription_manager));
  192. PopulateClientID();
  193. DoUpdateSubscribedTopicsIfNeeded();
  194. }
  195. void FCMInvalidationServiceBase::StopInvalidator() {
  196. DCHECK(invalidation_listener_);
  197. diagnostic_info_.service_was_stopped = base::Time::Now();
  198. invalidation_listener_.reset();
  199. }
  200. void FCMInvalidationServiceBase::StopInvalidatorPermanently() {
  201. // Reset the client ID (aka InstanceID) *before* stopping, so that
  202. // FCMInvalidationListener gets notified about the cleared ID (the listener
  203. // gets destroyed during StopInvalidator()).
  204. if (!client_id_.empty()) {
  205. ResetClientID();
  206. }
  207. StopInvalidator();
  208. }
  209. void FCMInvalidationServiceBase::PopulateClientID() {
  210. diagnostic_info_.instance_id_requested = base::Time::Now();
  211. if (sender_id_ == kInvalidationGCMSenderId) {
  212. MigratePrefs(pref_service_, sender_id_);
  213. }
  214. // Retrieve any client ID (aka Instance ID) from a previous run, which was
  215. // cached in prefs.
  216. const std::string* client_id_pref =
  217. pref_service_->GetValueDict(prefs::kInvalidationClientIDCache)
  218. .FindString(sender_id_);
  219. client_id_ = client_id_pref ? *client_id_pref : "";
  220. // There might already be clients (handlers) registered, so tell them about
  221. // the client ID.
  222. invalidator_registrar_.UpdateInvalidatorInstanceId(client_id_);
  223. // Also retrieve a fresh (or validated) client ID. If the |client_id_| just
  224. // retrieved from prefs is non-empty, then the fresh/validated one will
  225. // typically be equal to it, but it's not completely guaranteed. OTOH, if
  226. // |client_id_| is empty, i.e. we didn't have one previously, then this will
  227. // generate/retrieve a new one.
  228. instance_id::InstanceID* instance_id =
  229. instance_id_driver_->GetInstanceID(GetApplicationName());
  230. instance_id->GetID(
  231. base::BindOnce(&FCMInvalidationServiceBase::OnInstanceIDReceived,
  232. base::Unretained(this)));
  233. }
  234. void FCMInvalidationServiceBase::ResetClientID() {
  235. instance_id::InstanceID* instance_id =
  236. instance_id_driver_->GetInstanceID(GetApplicationName());
  237. instance_id->DeleteID(
  238. base::BindOnce(&FCMInvalidationServiceBase::OnDeleteInstanceIDCompleted,
  239. base::Unretained(this)));
  240. // Immediately clear our cached values (before we get confirmation of the
  241. // deletion), since they shouldn't be used anymore. Lower layers are the
  242. // source of truth, and are responsible for ensuring that the deletion
  243. // actually happens.
  244. client_id_.clear();
  245. DictionaryPrefUpdate update(pref_service_, prefs::kInvalidationClientIDCache);
  246. update->RemoveKey(sender_id_);
  247. // Also let the registrar (and its observers) know that the instance ID is
  248. // gone.
  249. invalidator_registrar_.UpdateInvalidatorInstanceId(std::string());
  250. // This will also delete all Instance ID *tokens*; we need to let the
  251. // FCMInvalidationListener know.
  252. if (invalidation_listener_) {
  253. invalidation_listener_->ClearInstanceIDToken();
  254. }
  255. }
  256. void FCMInvalidationServiceBase::OnInstanceIDReceived(
  257. const std::string& instance_id) {
  258. diagnostic_info_.instance_id_received = base::Time::Now();
  259. if (client_id_ != instance_id) {
  260. client_id_ = instance_id;
  261. DictionaryPrefUpdate update(pref_service_,
  262. prefs::kInvalidationClientIDCache);
  263. update->SetStringKey(sender_id_, instance_id);
  264. invalidator_registrar_.UpdateInvalidatorInstanceId(instance_id);
  265. }
  266. }
  267. void FCMInvalidationServiceBase::OnDeleteInstanceIDCompleted(
  268. instance_id::InstanceID::Result) {
  269. // Note: |client_id_| and the pref were already cleared when we initiated the
  270. // deletion.
  271. diagnostic_info_.instance_id_cleared = base::Time::Now();
  272. }
  273. void FCMInvalidationServiceBase::DoUpdateSubscribedTopicsIfNeeded() {
  274. if (!invalidation_listener_ || !update_was_requested_) {
  275. return;
  276. }
  277. auto subscribed_topics = invalidator_registrar_.GetAllSubscribedTopics();
  278. invalidation_listener_->UpdateInterestedTopics(subscribed_topics);
  279. update_was_requested_ = false;
  280. }
  281. const std::string FCMInvalidationServiceBase::GetApplicationName() {
  282. // If using the default |sender_id_|, use the bare |kApplicationName|, so the
  283. // old app name is maintained.
  284. if (sender_id_ == kInvalidationGCMSenderId) {
  285. return kApplicationName;
  286. }
  287. return base::StrCat({kApplicationName, "-", sender_id_});
  288. }
  289. } // namespace invalidation