File: per_user_topic_subscription_manager.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (196 lines) | stat: -rw-r--r-- 7,635 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_INVALIDATION_IMPL_PER_USER_TOPIC_SUBSCRIPTION_MANAGER_H_
#define COMPONENTS_INVALIDATION_IMPL_PER_USER_TOPIC_SUBSCRIPTION_MANAGER_H_

#include <map>
#include <memory>
#include <optional>

#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "components/invalidation/impl/channels_states.h"
#include "components/invalidation/impl/per_user_topic_subscription_request.h"
#include "components/invalidation/public/identity_provider.h"
#include "components/invalidation/public/invalidation_export.h"
#include "components/invalidation/public/invalidation_util.h"
#include "components/invalidation/public/invalidator_state.h"
#include "net/base/backoff_entry.h"

class PrefRegistrySimple;
class PrefService;

namespace invalidation {
class ActiveAccountAccessTokenFetcher;
class IdentityProvider;
}  // namespace invalidation

namespace invalidation {

// A class that manages the subscription to topics for server-issued
// notifications.
// Manages the details of subscribing to topics for invalidations. For example,
// Chrome Sync uses the ModelTypes (bookmarks, passwords, autofill data) as
// topics.
class INVALIDATION_EXPORT PerUserTopicSubscriptionManager {
 public:
  using RequestType = PerUserTopicSubscriptionRequest::RequestType;
  class Observer {
   public:
    virtual ~Observer() = default;

    virtual void OnSubscriptionChannelStateChanged(
        SubscriptionChannelState state) = 0;
    virtual void OnSubscriptionRequestFinished(Topic topic,
                                               RequestType request_type,
                                               Status code) = 0;
  };

  PerUserTopicSubscriptionManager(
      IdentityProvider* identity_provider,
      PrefService* pref_service,
      network::mojom::URLLoaderFactory* url_loader_factory,
      const std::string& project_id);
  PerUserTopicSubscriptionManager(
      const PerUserTopicSubscriptionManager& other) = delete;
  PerUserTopicSubscriptionManager& operator=(
      const PerUserTopicSubscriptionManager& other) = delete;
  virtual ~PerUserTopicSubscriptionManager();

  // Just calls std::make_unique. For ease of base::Bind'ing
  static std::unique_ptr<PerUserTopicSubscriptionManager> Create(
      network::mojom::URLLoaderFactory* url_loader_factory,
      IdentityProvider* identity_provider,
      PrefService* pref_service,
      const std::string& project_id);

  // RegisterProfilePrefs and RegisterPrefs register the same prefs, because on
  // device level (sign in screen, device local account) we spin up separate
  // InvalidationService and on profile level (when user signed in) we have
  // another InvalidationService, and we want to keep profile data in an
  // encrypted area of disk. While device data which is public can be kept in an
  // unencrypted area.
  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
  static void RegisterPrefs(PrefRegistrySimple* registry);

  virtual void Init();

  // Triggers subscription and/or unsubscription requests so that the set of
  // subscribed topics matches |topics|. If the |new_instance_id_token| has
  // changed, triggers re-subscription for all topics.
  virtual void UpdateSubscribedTopics(const TopicMap& topics,
                                      const std::string& new_instance_id_token);

  // Called when the InstanceID token (previously passed to
  // UpdateSubscribedTopics()) is deleted or revoked. Clears the cached token
  // and any subscribed topics, since the subscriptions will not be valid
  // anymore.
  void ClearInstanceIDToken();

  // Classes interested in subscription channel state changes should implement
  // PerUserTopicSubscriptionManager::Observer and register here.
  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  virtual std::optional<Topic> LookupSubscribedPublicTopicByPrivateTopic(
      const std::string& private_topic) const;

  TopicSet GetSubscribedTopicsForTest() const;

  bool HaveAllRequestsFinishedForTest() const {
    return pending_subscriptions_.empty();
  }

  size_t GetPendingSubscriptionsCountForTest() const {
    return pending_subscriptions_.size();
  }

 protected:
  // These are protected so that the mock can access them.
  void NotifySubscriptionChannelStateChange(
      SubscriptionChannelState invalidator_state);
  void NotifySubscriptionRequestFinished(Topic topic,
                                         RequestType request_type,
                                         Status code);

 private:
  struct SubscriptionEntry;

  void StartPendingSubscriptions();

  // Tries to (un)subscribe to |topic|. No retry in case of failure.
  // Effectively no-op if (un)subscription request is backed off or already in
  // flight with the same access token.
  void StartPendingSubscriptionRequest(const Topic& topic);

  void ActOnSuccessfulSubscription(
      const Topic& topic,
      const std::string& private_topic_name,
      PerUserTopicSubscriptionRequest::RequestType type);
  void ScheduleRequestForRepetition(const Topic& topic);
  void SubscriptionFinishedForTopic(
      Topic topic,
      Status code,
      std::string private_topic_name,
      PerUserTopicSubscriptionRequest::RequestType type);

  void RequestAccessToken();

  void OnAccessTokenRequestCompleted(GoogleServiceAuthError error,
                                     std::string access_token);
  void OnAccessTokenRequestSucceeded(const std::string& access_token);
  void OnAccessTokenRequestFailed(GoogleServiceAuthError error);

  // Compares `new_instance_id_token` and `instance_id_token_` to report the
  // nature of the change (if any) to UMA.
  void ReportNewInstanceIdTokenState(
      const std::string& new_instance_id_token) const;

  // In case `new_instance_id_token` differs from `instance_id_token_`, this
  // drops subscriptions from memory and `pref_service_`.
  void DropAllSavedSubscriptionsOnTokenChange(
      const std::string& new_instance_id_token);

  // Stores `new_instance_id_token` as `instance_id_token_` and persists it in
  // `pref_service_`.
  void StoreNewToken(const std::string& new_instance_id_token);

  const raw_ptr<PrefService> pref_service_;
  const raw_ptr<IdentityProvider> identity_provider_;
  const raw_ptr<network::mojom::URLLoaderFactory> url_loader_factory_;

  const std::string project_id_;

  // Subscription or unsubscription requests that are either scheduled or
  // started, but not finished yet.
  std::map<Topic, std::unique_ptr<SubscriptionEntry>> pending_subscriptions_;

  // For subscribed topics, these map from the topic to the private topic name
  // and vice versa.
  std::map<Topic, std::string> topic_to_private_topic_;
  std::map<std::string, Topic> private_topic_to_topic_;

  // Token derived from GCM IID.
  std::string instance_id_token_;

  // Cached OAuth2 access token, and/or pending request to fetch one.
  std::string access_token_;
  std::unique_ptr<ActiveAccountAccessTokenFetcher> access_token_fetcher_;
  base::OneShotTimer request_access_token_retry_timer_;
  net::BackoffEntry request_access_token_backoff_;

  base::ObserverList<Observer>::Unchecked observers_;
  SubscriptionChannelState last_issued_state_ =
      SubscriptionChannelState::NOT_STARTED;

  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace invalidation

#endif  // COMPONENTS_INVALIDATION_IMPL_PER_USER_TOPIC_SUBSCRIPTION_MANAGER_H_