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
|
// 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 <map>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/gtest_prod_util.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.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 {
// 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.
class DialRegistry : public DialService::Observer,
public net::NetworkChangeNotifier::NetworkChangeObserver {
public:
typedef std::vector<DialDeviceData> DeviceList;
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();
protected:
// Returns a new instance of the DIAL service. Overridden by tests.
virtual DialService* CreateDialService();
virtual void ClearDialService();
// Returns the current time. Overridden by tests.
virtual base::Time Now() const;
protected:
// The DIAL service. Periodic discovery is active when this is not NULL.
scoped_ptr<DialService> dial_;
private:
typedef base::hash_map<std::string, linked_ptr<DialDeviceData> >
DeviceByIdMap;
typedef std::map<std::string, linked_ptr<DialDeviceData> > DeviceByLabelMap;
// 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(const linked_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 clients with the current device list if necessary.
void MaybeSendEvent();
// 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 DoDiscovery().
int discovery_generation_;
// Incremented each time we modify the registry of active devices.
int registry_generation_;
// The discovery generation associated with the last time we sent an event.
// Used to ensure that we generate at least one event per round of discovery.
int last_event_discovery_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
base::TimeDelta refresh_interval_delta_;
base::TimeDelta expiration_delta_;
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<DialRegistry> 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_;
// Thread checker.
base::ThreadChecker thread_checker_;
FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestAddRemoveListeners);
FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestNoDevicesDiscovered);
FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestDevicesDiscovered);
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 extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_
|