Home | History | Annotate | Download | only in browser
      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 EXTENSIONS_BROWSER_EVENT_ROUTER_H_
      6 #define EXTENSIONS_BROWSER_EVENT_ROUTER_H_
      7 
      8 #include <map>
      9 #include <set>
     10 #include <string>
     11 #include <utility>
     12 
     13 #include "base/callback.h"
     14 #include "base/compiler_specific.h"
     15 #include "base/containers/hash_tables.h"
     16 #include "base/gtest_prod_util.h"
     17 #include "base/memory/linked_ptr.h"
     18 #include "base/memory/ref_counted.h"
     19 #include "base/values.h"
     20 #include "content/public/browser/notification_observer.h"
     21 #include "content/public/browser/notification_registrar.h"
     22 #include "extensions/browser/event_listener_map.h"
     23 #include "extensions/common/event_filtering_info.h"
     24 #include "ipc/ipc_sender.h"
     25 
     26 class GURL;
     27 class PrefService;
     28 
     29 namespace content {
     30 class BrowserContext;
     31 class RenderProcessHost;
     32 }
     33 
     34 namespace extensions {
     35 class ActivityLog;
     36 class Extension;
     37 class ExtensionHost;
     38 class ExtensionPrefs;
     39 
     40 struct Event;
     41 struct EventDispatchInfo;
     42 struct EventListenerInfo;
     43 
     44 class EventRouter : public content::NotificationObserver,
     45                     public EventListenerMap::Delegate {
     46  public:
     47   // These constants convey the state of our knowledge of whether we're in
     48   // a user-caused gesture as part of DispatchEvent.
     49   enum UserGestureState {
     50     USER_GESTURE_UNKNOWN = 0,
     51     USER_GESTURE_ENABLED = 1,
     52     USER_GESTURE_NOT_ENABLED = 2,
     53   };
     54 
     55   // The pref key for the list of event names for which an extension has
     56   // registered from its lazy background page.
     57   static const char kRegisteredEvents[];
     58 
     59   // Observers register interest in events with a particular name and are
     60   // notified when a listener is added or removed. Observers are matched by
     61   // the base name of the event (e.g. adding an event listener for event name
     62   // "foo.onBar/123" will trigger observers registered for "foo.onBar").
     63   class Observer {
     64    public:
     65     // Called when a listener is added.
     66     virtual void OnListenerAdded(const EventListenerInfo& details) {}
     67     // Called when a listener is removed.
     68     virtual void OnListenerRemoved(const EventListenerInfo& details) {}
     69   };
     70 
     71   // The EventDispatchObserver is notified on the UI thread whenever
     72   // an event is dispatched. There can be only one EventDispatchObserver.
     73   class EventDispatchObserver {
     74    public:
     75     virtual void OnWillDispatchEvent(scoped_ptr<EventDispatchInfo> details) = 0;
     76   };
     77 
     78   // Converts event names like "foo.onBar/123" into "foo.onBar". Event names
     79   // without a "/" are returned unchanged.
     80   static std::string GetBaseEventName(const std::string& full_event_name);
     81 
     82   // Sends an event via ipc_sender to the given extension. Can be called on any
     83   // thread.
     84   static void DispatchEvent(IPC::Sender* ipc_sender,
     85                             void* browser_context_id,
     86                             const std::string& extension_id,
     87                             const std::string& event_name,
     88                             scoped_ptr<base::ListValue> event_args,
     89                             UserGestureState user_gesture,
     90                             const EventFilteringInfo& info);
     91 
     92   // An EventRouter is shared between |browser_context| and its associated
     93   // incognito context. |extension_prefs| may be NULL in tests.
     94   EventRouter(content::BrowserContext* browser_context,
     95               ExtensionPrefs* extension_prefs);
     96   virtual ~EventRouter();
     97 
     98   // Add or remove the process/extension pair as a listener for |event_name|.
     99   // Note that multiple extensions can share a process due to process
    100   // collapsing. Also, a single extension can have 2 processes if it is a split
    101   // mode extension.
    102   void AddEventListener(const std::string& event_name,
    103                         content::RenderProcessHost* process,
    104                         const std::string& extension_id);
    105   void RemoveEventListener(const std::string& event_name,
    106                            content::RenderProcessHost* process,
    107                            const std::string& extension_id);
    108 
    109   EventListenerMap& listeners() { return listeners_; }
    110 
    111   // Registers an observer to be notified when an event listener for
    112   // |event_name| is added or removed. There can currently be only one observer
    113   // for each distinct |event_name|.
    114   void RegisterObserver(Observer* observer,
    115                         const std::string& event_name);
    116 
    117   // Unregisters an observer from all events.
    118   void UnregisterObserver(Observer* observer);
    119 
    120   // Sets the observer to be notified whenever an event is dispatched to an
    121   // extension.
    122   void SetEventDispatchObserver(EventDispatchObserver* observer);
    123 
    124   // Add or remove the extension as having a lazy background page that listens
    125   // to the event. The difference from the above methods is that these will be
    126   // remembered even after the process goes away. We use this list to decide
    127   // which extension pages to load when dispatching an event.
    128   void AddLazyEventListener(const std::string& event_name,
    129                             const std::string& extension_id);
    130   void RemoveLazyEventListener(const std::string& event_name,
    131                                const std::string& extension_id);
    132 
    133   // If |add_lazy_listener| is true also add the lazy version of this listener.
    134   void AddFilteredEventListener(const std::string& event_name,
    135                                 content::RenderProcessHost* process,
    136                                 const std::string& extension_id,
    137                                 const base::DictionaryValue& filter,
    138                                 bool add_lazy_listener);
    139 
    140   // If |remove_lazy_listener| is true also remove the lazy version of this
    141   // listener.
    142   void RemoveFilteredEventListener(const std::string& event_name,
    143                                    content::RenderProcessHost* process,
    144                                    const std::string& extension_id,
    145                                    const base::DictionaryValue& filter,
    146                                    bool remove_lazy_listener);
    147 
    148   // Returns true if there is at least one listener for the given event.
    149   bool HasEventListener(const std::string& event_name);
    150 
    151   // Returns true if the extension is listening to the given event.
    152   bool ExtensionHasEventListener(const std::string& extension_id,
    153                                  const std::string& event_name);
    154 
    155   // Return or set the list of events for which the given extension has
    156   // registered.
    157   std::set<std::string> GetRegisteredEvents(const std::string& extension_id);
    158   void SetRegisteredEvents(const std::string& extension_id,
    159                            const std::set<std::string>& events);
    160 
    161   // Broadcasts an event to every listener registered for that event.
    162   virtual void BroadcastEvent(scoped_ptr<Event> event);
    163 
    164   // Dispatches an event to the given extension.
    165   virtual void DispatchEventToExtension(const std::string& extension_id,
    166                                         scoped_ptr<Event> event);
    167 
    168   // Dispatches |event| to the given extension as if the extension has a lazy
    169   // listener for it. NOTE: This should be used rarely, for dispatching events
    170   // to extensions that haven't had a chance to add their own listeners yet, eg:
    171   // newly installed extensions.
    172   void DispatchEventWithLazyListener(const std::string& extension_id,
    173                                      scoped_ptr<Event> event);
    174 
    175   // Record the Event Ack from the renderer. (One less event in-flight.)
    176   void OnEventAck(content::BrowserContext* context,
    177                   const std::string& extension_id);
    178 
    179  private:
    180   FRIEND_TEST_ALL_PREFIXES(EventRouterTest, EventRouterObserver);
    181 
    182   // The extension and process that contains the event listener for a given
    183   // event.
    184   struct ListenerProcess;
    185 
    186   // A map between an event name and a set of extensions that are listening
    187   // to that event.
    188   typedef std::map<std::string, std::set<ListenerProcess> > ListenerMap;
    189 
    190   // An identifier for an event dispatch that is used to prevent double dispatch
    191   // due to race conditions between the direct and lazy dispatch paths.
    192   typedef std::pair<const content::BrowserContext*, std::string>
    193       EventDispatchIdentifier;
    194 
    195   // Sends a notification about an event to the event dispatch observer on the
    196   // UI thread. Can be called from any thread.
    197   static void NotifyExtensionDispatchObserverOnUIThread(
    198       void* browser_context_id,
    199       scoped_ptr<EventDispatchInfo> details);
    200 
    201   // TODO(gdk): Document this.
    202   static void DispatchExtensionMessage(
    203       IPC::Sender* ipc_sender,
    204       void* browser_context_id,
    205       const std::string& extension_id,
    206       const std::string& event_name,
    207       base::ListValue* event_args,
    208       UserGestureState user_gesture,
    209       const extensions::EventFilteringInfo& info);
    210 
    211   virtual void Observe(int type,
    212                        const content::NotificationSource& source,
    213                        const content::NotificationDetails& details) OVERRIDE;
    214 
    215   // Returns true if the given listener map contains a event listeners for
    216   // the given event. If |extension_id| is non-empty, we also check that that
    217   // extension is one of the listeners.
    218   bool HasEventListenerImpl(const ListenerMap& listeners,
    219                             const std::string& extension_id,
    220                             const std::string& event_name);
    221 
    222   // Shared by DispatchEvent*. If |restrict_to_extension_id| is empty, the
    223   // event is broadcast.
    224   // An event that just came off the pending list may not be delayed again.
    225   void DispatchEventImpl(const std::string& restrict_to_extension_id,
    226                          const linked_ptr<Event>& event);
    227 
    228   // Ensures that all lazy background pages that are interested in the given
    229   // event are loaded, and queues the event if the page is not ready yet.
    230   // Inserts an EventDispatchIdentifier into |already_dispatched| for each lazy
    231   // event dispatch that is queued.
    232   void DispatchLazyEvent(const std::string& extension_id,
    233                          const linked_ptr<Event>& event,
    234                          std::set<EventDispatchIdentifier>* already_dispatched);
    235 
    236   // Dispatches the event to the specified extension running in |process|.
    237   void DispatchEventToProcess(const std::string& extension_id,
    238                               content::RenderProcessHost* process,
    239                               const linked_ptr<Event>& event);
    240 
    241   // Returns false when the event is scoped to a context and the listening
    242   // extension does not have access to events from that context. Also fills
    243   // |event_args| with the proper arguments to send, which may differ if
    244   // the event crosses the incognito boundary.
    245   bool CanDispatchEventToBrowserContext(content::BrowserContext* context,
    246                                         const Extension* extension,
    247                                         const linked_ptr<Event>& event);
    248 
    249   // Possibly loads given extension's background page in preparation to
    250   // dispatch an event.  Returns true if the event was queued for subsequent
    251   // dispatch, false otherwise.
    252   bool MaybeLoadLazyBackgroundPageToDispatchEvent(
    253       content::BrowserContext* context,
    254       const Extension* extension,
    255       const linked_ptr<Event>& event);
    256 
    257   // Adds a filter to an event.
    258   void AddFilterToEvent(const std::string& event_name,
    259                         const std::string& extension_id,
    260                         const base::DictionaryValue* filter);
    261 
    262   // Removes a filter from an event.
    263   void RemoveFilterFromEvent(const std::string& event_name,
    264                              const std::string& extension_id,
    265                              const base::DictionaryValue* filter);
    266 
    267   // Returns the dictionary of event filters that the given extension has
    268   // registered.
    269   const base::DictionaryValue* GetFilteredEvents(
    270       const std::string& extension_id);
    271 
    272   // Track of the number of dispatched events that have not yet sent an
    273   // ACK from the renderer.
    274   void IncrementInFlightEvents(content::BrowserContext* context,
    275                                const Extension* extension);
    276 
    277   // static
    278   static void IncrementInFlightEventsOnUI(
    279       void* browser_context_id,
    280       const std::string& extension_id);
    281 
    282   void DispatchPendingEvent(const linked_ptr<Event>& event,
    283                             ExtensionHost* host);
    284 
    285   // Implementation of EventListenerMap::Delegate.
    286   virtual void OnListenerAdded(const EventListener* listener) OVERRIDE;
    287   virtual void OnListenerRemoved(const EventListener* listener) OVERRIDE;
    288 
    289   content::BrowserContext* browser_context_;
    290 
    291   // The ExtensionPrefs associated with |browser_context_|. May be NULL in
    292   // tests.
    293   ExtensionPrefs* extension_prefs_;
    294 
    295   content::NotificationRegistrar registrar_;
    296 
    297   EventListenerMap listeners_;
    298 
    299   // Map from base event name to observer.
    300   typedef base::hash_map<std::string, Observer*> ObserverMap;
    301   ObserverMap observers_;
    302 
    303   EventDispatchObserver* event_dispatch_observer_;
    304 
    305   DISALLOW_COPY_AND_ASSIGN(EventRouter);
    306 };
    307 
    308 struct Event {
    309   typedef base::Callback<void(content::BrowserContext*,
    310                               const Extension*,
    311                               base::ListValue*)> WillDispatchCallback;
    312 
    313   // The event to dispatch.
    314   std::string event_name;
    315 
    316   // Arguments to send to the event listener.
    317   scoped_ptr<base::ListValue> event_args;
    318 
    319   // If non-NULL, then the event will not be sent to other BrowserContexts
    320   // unless the extension has permission (e.g. incognito tab update -> normal
    321   // tab only works if extension is allowed incognito access).
    322   content::BrowserContext* restrict_to_browser_context;
    323 
    324   // If not empty, the event is only sent to extensions with host permissions
    325   // for this url.
    326   GURL event_url;
    327 
    328   // Whether a user gesture triggered the event.
    329   EventRouter::UserGestureState user_gesture;
    330 
    331   // Extra information used to filter which events are sent to the listener.
    332   EventFilteringInfo filter_info;
    333 
    334   // If specified, this is called before dispatching an event to each
    335   // extension. The third argument is a mutable reference to event_args,
    336   // allowing the caller to provide different arguments depending on the
    337   // extension and profile. This is guaranteed to be called synchronously with
    338   // DispatchEvent, so callers don't need to worry about lifetime.
    339   WillDispatchCallback will_dispatch_callback;
    340 
    341   Event(const std::string& event_name,
    342         scoped_ptr<base::ListValue> event_args);
    343 
    344   Event(const std::string& event_name,
    345         scoped_ptr<base::ListValue> event_args,
    346         content::BrowserContext* restrict_to_browser_context);
    347 
    348   Event(const std::string& event_name,
    349         scoped_ptr<base::ListValue> event_args,
    350         content::BrowserContext* restrict_to_browser_context,
    351         const GURL& event_url,
    352         EventRouter::UserGestureState user_gesture,
    353         const EventFilteringInfo& info);
    354 
    355   ~Event();
    356 
    357   // Makes a deep copy of this instance. Ownership is transferred to the
    358   // caller.
    359   Event* DeepCopy();
    360 };
    361 
    362 struct EventListenerInfo {
    363   EventListenerInfo(const std::string& event_name,
    364                     const std::string& extension_id,
    365                     content::BrowserContext* browser_context);
    366   // The event name including any sub-event, e.g. "runtime.onStartup" or
    367   // "webRequest.onCompleted/123".
    368   const std::string event_name;
    369 
    370   const std::string extension_id;
    371   content::BrowserContext* browser_context;
    372 };
    373 
    374 struct EventDispatchInfo {
    375   EventDispatchInfo(const std::string& extension_id,
    376                     const std::string& event_name,
    377                     scoped_ptr<ListValue> event_args);
    378   ~EventDispatchInfo();
    379 
    380   const std::string extension_id;
    381   const std::string event_name;
    382   scoped_ptr<ListValue> event_args;
    383 };
    384 
    385 }  // namespace extensions
    386 
    387 #endif  // EXTENSIONS_BROWSER_EVENT_ROUTER_H_
    388