Home | History | Annotate | Download | only in dial
      1 // Copyright (c) 2012 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 
      5 #ifndef CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_
      6 #define CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_
      7 
      8 #include <map>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/containers/hash_tables.h"
     14 #include "base/gtest_prod_util.h"
     15 #include "base/memory/linked_ptr.h"
     16 #include "base/memory/ref_counted.h"
     17 #include "base/threading/thread_checker.h"
     18 #include "base/time/time.h"
     19 #include "base/timer/timer.h"
     20 #include "chrome/browser/extensions/api/dial/dial_service.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "net/base/network_change_notifier.h"
     23 
     24 namespace extensions {
     25 
     26 // Keeps track of devices that have responded to discovery requests and notifies
     27 // the observer with an updated, complete set of active devices.  The registry's
     28 // observer (i.e., the Dial API) owns the registry instance.
     29 class DialRegistry : public DialService::Observer,
     30                      public net::NetworkChangeNotifier::NetworkChangeObserver {
     31  public:
     32   typedef std::vector<DialDeviceData> DeviceList;
     33 
     34   enum DialErrorCode {
     35     DIAL_NO_LISTENERS = 0,
     36     DIAL_NO_INTERFACES,
     37     DIAL_NETWORK_DISCONNECTED,
     38     DIAL_CELLULAR_NETWORK,
     39     DIAL_SOCKET_ERROR,
     40     DIAL_UNKNOWN
     41   };
     42 
     43   class Observer {
     44    public:
     45     // Methods invoked on the IO thread when a new device is discovered, an
     46     // update is triggered by dial.discoverNow or an error occured.
     47     virtual void OnDialDeviceEvent(const DeviceList& devices) = 0;
     48     virtual void OnDialError(DialErrorCode type) = 0;
     49 
     50    protected:
     51     virtual ~Observer() {}
     52   };
     53 
     54   // Create the DIAL registry and pass a reference to allow it to notify on
     55   // DIAL device events.
     56   DialRegistry(Observer* dial_api,
     57                const base::TimeDelta& refresh_interval,
     58                const base::TimeDelta& expiration,
     59                const size_t max_devices);
     60 
     61   virtual ~DialRegistry();
     62 
     63   // Called by the DIAL API when event listeners are added or removed. The dial
     64   // service is started after the first listener is added and stopped after the
     65   // last listener is removed.
     66   void OnListenerAdded();
     67   void OnListenerRemoved();
     68 
     69   // Called by the DIAL API to try to kickoff a discovery if there is not one
     70   // already active.
     71   bool DiscoverNow();
     72 
     73  protected:
     74   // Returns a new instance of the DIAL service.  Overridden by tests.
     75   virtual DialService* CreateDialService();
     76   virtual void ClearDialService();
     77 
     78   // Returns the current time.  Overridden by tests.
     79   virtual base::Time Now() const;
     80 
     81  protected:
     82   // The DIAL service. Periodic discovery is active when this is not NULL.
     83   scoped_ptr<DialService> dial_;
     84 
     85  private:
     86   typedef base::hash_map<std::string, linked_ptr<DialDeviceData> >
     87       DeviceByIdMap;
     88   typedef std::map<std::string, linked_ptr<DialDeviceData> > DeviceByLabelMap;
     89 
     90   // DialService::Observer:
     91   virtual void OnDiscoveryRequest(DialService* service) OVERRIDE;
     92   virtual void OnDeviceDiscovered(DialService* service,
     93                                   const DialDeviceData& device) OVERRIDE;
     94   virtual void OnDiscoveryFinished(DialService* service) OVERRIDE;
     95   virtual void OnError(DialService* service,
     96                        const DialService::DialServiceErrorCode& code) OVERRIDE;
     97 
     98   // net::NetworkChangeObserver:
     99   virtual void OnNetworkChanged(
    100       net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
    101 
    102   // Starts and stops periodic discovery.  Periodic discovery is done when there
    103   // are registered event listeners.
    104   void StartPeriodicDiscovery();
    105   void StopPeriodicDiscovery();
    106 
    107   // Check whether we are in a state ready to discover and dispatch error
    108   // notifications if not.
    109   bool ReadyToDiscover();
    110 
    111   // Purge our whole registry. We may need to do this occasionally, e.g. when
    112   // the network status changes.  Increments the registry generation.
    113   void Clear();
    114 
    115   // The repeating timer schedules discoveries with this method.
    116   void DoDiscovery();
    117 
    118   // Attempts to add a newly discovered device to the registry.  Returns true if
    119   // successful.
    120   bool MaybeAddDevice(const linked_ptr<DialDeviceData>& device_data);
    121 
    122   // Remove devices from the registry that have expired, i.e. not responded
    123   // after some time.  Returns true if the registry was modified.
    124   bool PruneExpiredDevices();
    125 
    126   // Returns true if the device has expired and should be removed from the
    127   // active set.
    128   bool IsDeviceExpired(const DialDeviceData& device) const;
    129 
    130   // Notify clients with the current device list if necessary.
    131   void MaybeSendEvent();
    132 
    133   // Returns the next label to use for a newly-seen device.
    134   std::string NextLabel();
    135 
    136   // The current number of event listeners attached to this registry.
    137   int num_listeners_;
    138 
    139   // Incremented each time we DoDiscovery().
    140   int discovery_generation_;
    141 
    142   // Incremented each time we modify the registry of active devices.
    143   int registry_generation_;
    144 
    145   // The discovery generation associated with the last time we sent an event.
    146   // Used to ensure that we generate at least one event per round of discovery.
    147   int last_event_discovery_generation_;
    148 
    149   // The registry generation associated with the last time we sent an event.
    150   // Used to suppress events with duplicate device lists.
    151   int last_event_registry_generation_;
    152 
    153   // Counter to generate device labels.
    154   int label_count_;
    155 
    156   // Registry parameters
    157   base::TimeDelta refresh_interval_delta_;
    158   base::TimeDelta expiration_delta_;
    159   size_t max_devices_;
    160 
    161   // A map used to track known devices by their device_id.
    162   DeviceByIdMap device_by_id_map_;
    163 
    164   // A map used to track known devices sorted by label.  We iterate over this to
    165   // construct the device list sent to API clients.
    166   DeviceByLabelMap device_by_label_map_;
    167 
    168   // Timer used to manage periodic discovery requests.
    169   base::RepeatingTimer<DialRegistry> repeating_timer_;
    170 
    171   // Interface from which the DIAL API is notified of DIAL device events. the
    172   // DIAL API owns this DIAL registry.
    173   Observer* const dial_api_;
    174 
    175   // Thread checker.
    176   base::ThreadChecker thread_checker_;
    177 
    178   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestAddRemoveListeners);
    179   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestNoDevicesDiscovered);
    180   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestDevicesDiscovered);
    181   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestDeviceExpires);
    182   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestExpiredDeviceIsRediscovered);
    183   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest,
    184                            TestRemovingListenerDoesNotClearList);
    185   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestNetworkEventConnectionLost);
    186   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest,
    187                            TestNetworkEventConnectionRestored);
    188   DISALLOW_COPY_AND_ASSIGN(DialRegistry);
    189 };
    190 
    191 }  // namespace extensions
    192 
    193 #endif  // CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_
    194