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
|
// Copyright (c) 2012 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.
#ifndef CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_
#define CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_
#include <stddef.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/containers/hash_tables.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/extensions/api/dial/dial_service.h"
#include "chrome/browser/profiles/profile.h"
#include "net/base/network_change_notifier.h"
namespace extensions {
namespace api {
namespace dial {
// Keeps track of devices that have responded to discovery requests and notifies
// the observer with an updated, complete set of active devices. The registry's
// observer (i.e., the Dial API) owns the registry instance.
// DialRegistry lives on the IO thread.
class DialRegistry : public DialService::Observer,
public net::NetworkChangeNotifier::NetworkChangeObserver {
public:
using DeviceList = std::vector<DialDeviceData>;
enum DialErrorCode {
DIAL_NO_LISTENERS = 0,
DIAL_NO_INTERFACES,
DIAL_NETWORK_DISCONNECTED,
DIAL_CELLULAR_NETWORK,
DIAL_SOCKET_ERROR,
DIAL_UNKNOWN
};
class Observer {
public:
// Methods invoked on the IO thread when a new device is discovered, an
// update is triggered by dial.discoverNow or an error occured.
virtual void OnDialDeviceEvent(const DeviceList& devices) = 0;
virtual void OnDialError(DialErrorCode type) = 0;
protected:
virtual ~Observer() {}
};
// Create the DIAL registry and pass a reference to allow it to notify on
// DIAL device events.
DialRegistry(Observer* dial_api,
const base::TimeDelta& refresh_interval,
const base::TimeDelta& expiration,
const size_t max_devices);
~DialRegistry() override;
// Called by the DIAL API when event listeners are added or removed. The dial
// service is started after the first listener is added and stopped after the
// last listener is removed.
void OnListenerAdded();
void OnListenerRemoved();
// Called by the DIAL API to try to kickoff a discovery if there is not one
// already active.
bool DiscoverNow();
// 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);
protected:
// Returns a new instance of the DIAL service. Overridden by tests.
virtual std::unique_ptr<DialService> CreateDialService();
virtual void ClearDialService();
// Returns the current time. Overridden by tests.
virtual base::Time Now() const;
// The DIAL service. Periodic discovery is active when this is not NULL.
std::unique_ptr<DialService> dial_;
private:
using DeviceByIdMap =
base::hash_map<std::string, std::unique_ptr<DialDeviceData>>;
using DeviceByLabelMap = std::map<std::string, DialDeviceData*>;
// DialService::Observer:
void OnDiscoveryRequest(DialService* service) override;
void OnDeviceDiscovered(DialService* service,
const DialDeviceData& device) override;
void OnDiscoveryFinished(DialService* service) override;
void OnError(DialService* service,
const DialService::DialServiceErrorCode& code) override;
// net::NetworkChangeObserver:
void OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) override;
// Starts and stops periodic discovery. Periodic discovery is done when there
// are registered event listeners.
void StartPeriodicDiscovery();
void StopPeriodicDiscovery();
// 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 listeners with the current device list if the list has changed.
void MaybeSendEvent();
// Notify listeners with the current device list.
void SendEvent();
// Returns the next label to use for a newly-seen device.
std::string NextLabel();
// The current number of event listeners attached to this registry.
int num_listeners_;
// 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.
base::RepeatingTimer repeating_timer_;
// Interface from which the DIAL API is notified of DIAL device events. the
// DIAL API owns this DIAL registry.
Observer* const dial_api_;
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);
DISALLOW_COPY_AND_ASSIGN(DialRegistry);
};
} // namespace dial
} // namespace api
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_
|