File: dial_registry.h

package info (click to toggle)
chromium 139.0.7258.127-1~deb13u1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,096 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 (221 lines) | stat: -rw-r--r-- 7,735 bytes parent folder | download | duplicates (8)
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_REGISTRY_H_
#define CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_REGISTRY_H_

#include <stddef.h>

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/media/router/discovery/dial/dial_service.h"
#include "services/network/public/cpp/network_connection_tracker.h"
#include "url/gurl.h"

namespace base {
class Clock;
}

namespace net {
class NetLog;
}

namespace media_router {

// Keeps track of devices that have responded to discovery requests and notifies
// the client with the current device list. It is indirectly owned by a
// singleton that is never freed. All APIs should be called on the sequence
// bound to |task_runner_|.
class DialRegistry
    : public DialService::Client,
      public network::NetworkConnectionTracker::NetworkConnectionObserver {
 public:
  using DeviceList = std::vector<DialDeviceData>;

  enum DialErrorCode {
    DIAL_NO_LISTENERS = 0,  // Deprecated
    DIAL_NO_INTERFACES,
    DIAL_NETWORK_DISCONNECTED,
    DIAL_CELLULAR_NETWORK,
    DIAL_SOCKET_ERROR,
    DIAL_UNKNOWN
  };

  class Client {
   public:
    // Called when the list of DIAL devices has changed.  Will be called
    // multiple times.
    virtual void OnDialDeviceList(const DeviceList& devices) = 0;
    // Called when an error has occurred.
    virtual void OnDialError(DialErrorCode type) = 0;

   protected:
    virtual ~Client() = default;
  };

  DialRegistry(DialRegistry::Client& client,
               const scoped_refptr<base::SequencedTaskRunner>& task_runner);
  DialRegistry(const DialRegistry&) = delete;
  DialRegistry(DialRegistry&&) = delete;
  DialRegistry& operator=(const DialRegistry&) = delete;
  DialRegistry& operator=(DialRegistry&&) = delete;
  ~DialRegistry() override;

  // Sets the NetLog object used for logging. If the registry already has a
  // NetLog, does nothing. The NetLog should live at least as long as the IO
  // Thread.
  void SetNetLog(net::NetLog* net_log);

  // Waits for a suitable network interface to be up and then starts periodic
  // discovery.  Must be called before DiscoverNow() or
  // StartPeriodicDiscovery().
  void Start();

  // Starts a discovery cycle immediately.
  bool DiscoverNow();

  // Starts and stops periodic background discovery.
  void StartPeriodicDiscovery();
  void StopPeriodicDiscovery();

  // Returns the URL of the device description for the device identified by
  // |label|, or an empty GURL if no such device exists.
  GURL GetDeviceDescriptionURL(const std::string& label) const;

  // Adds a device directly to the registry as if it was discovered.  For tests
  // only.  Note that if discovery is actually started, this device will be
  // removed by PruneExpiredDevices().
  void AddDeviceForTest(const DialDeviceData& device_data);

  // Allows tests to swap in a fake clock.
  void SetClockForTest(base::Clock* clock);

 protected:
  // Returns a new instance of the DIAL service.  Overridden by tests.
  virtual std::unique_ptr<DialService> CreateDialService();
  virtual void ClearDialService();

  // The DIAL service. Periodic discovery is active when this is not NULL.
  std::unique_ptr<DialService> dial_;

 private:
  using DeviceByIdMap = std::map<std::string, std::unique_ptr<DialDeviceData>>;
  using DeviceByLabelMap =
      std::map<std::string, raw_ptr<DialDeviceData, CtnExperimental>>;

  friend class MockDialRegistry;
  friend class TestDialRegistry;

  // Called when we've gotten the NetworkConnectionTracker from the UI thread.
  void SetNetworkConnectionTracker(network::NetworkConnectionTracker* tracker);

  // DialService::Client:
  void OnDiscoveryRequest() override;
  void OnDeviceDiscovered(const DialDeviceData& device) override;
  void OnDiscoveryFinished() override;
  void OnError(DialService::DialServiceErrorCode code) override;

  // network::NetworkConnectionTracker::NetworkConnectionObserver:
  void OnConnectionChanged(network::mojom::ConnectionType type) override;

  // Check whether we are in a state ready to discover and dispatch error
  // notifications if not.
  bool ReadyToDiscover();

  // Purge our whole registry. We may need to do this occasionally, e.g. when
  // the network status changes.  Increments the registry generation.
  void Clear();

  // The repeating timer schedules discoveries with this method.
  void DoDiscovery();

  // Attempts to add a newly discovered device to the registry.  Returns true if
  // successful.
  bool MaybeAddDevice(std::unique_ptr<DialDeviceData> device_data);

  // Remove devices from the registry that have expired, i.e. not responded
  // after some time.  Returns true if the registry was modified.
  bool PruneExpiredDevices();

  // Returns true if the device has expired and should be removed from the
  // active set.
  bool IsDeviceExpired(const DialDeviceData& device) const;

  // Notify the client with the current device list if the list has changed.
  void MaybeSendDeviceList();

  // Returns the next label to use for a newly-seen device.
  std::string NextLabel();

  // Unowned reference to the DialRegistry::Client.
  const raw_ref<Client> client_;

  // Task runner for the DialRegistry.
  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  // Incremented each time we modify the registry of active devices.
  int registry_generation_;

  // The registry generation associated with the last time we sent an event.
  // Used to suppress events with duplicate device lists.
  int last_event_registry_generation_;

  // Counter to generate device labels.
  int label_count_;

  // Registry parameters
  const base::TimeDelta refresh_interval_delta_;
  const base::TimeDelta expiration_delta_;
  const size_t max_devices_;

  // A map used to track known devices by their device_id.
  DeviceByIdMap device_by_id_map_;

  // A map used to track known devices sorted by label.  We iterate over this to
  // construct the device list sent to API clients.
  DeviceByLabelMap device_by_label_map_;

  // Timer used to manage periodic discovery requests.
  std::unique_ptr<base::RepeatingTimer> repeating_timer_;

  // Set just after construction.
  raw_ptr<net::NetLog> net_log_ = nullptr;

  raw_ptr<network::NetworkConnectionTracker> network_connection_tracker_ =
      nullptr;

  raw_ptr<base::Clock> clock_;

  SEQUENCE_CHECKER(sequence_checker_);

  friend class DialMediaSinkServiceImplTest;
  friend class DialRegistryTest;
  FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestAddRemoveListeners);
  FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestNoDevicesDiscovered);
  FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestDevicesDiscovered);
  FRIEND_TEST_ALL_PREFIXES(DialRegistryTest,
                           TestDevicesDiscoveredWithTwoListeners);
  FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestDeviceExpires);
  FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestExpiredDeviceIsRediscovered);
  FRIEND_TEST_ALL_PREFIXES(DialRegistryTest,
                           TestRemovingListenerDoesNotClearList);
  FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestNetworkEventConnectionLost);
  FRIEND_TEST_ALL_PREFIXES(DialRegistryTest,
                           TestNetworkEventConnectionRestored);
};

}  // namespace media_router

#endif  // CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_REGISTRY_H_