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.
5 #ifndef EXTENSIONS_BROWSER_EVENT_ROUTER_H_
6 #define EXTENSIONS_BROWSER_EVENT_ROUTER_H_
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"
31 class RenderProcessHost;
34 namespace extensions {
41 struct EventDispatchInfo;
42 struct EventListenerInfo;
44 class EventRouter : public content::NotificationObserver,
45 public EventListenerMap::Delegate {
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,
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[];
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").
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) {}
71 // Converts event names like "foo.onBar/123" into "foo.onBar". Event names
72 // without a "/" are returned unchanged.
73 static std::string GetBaseEventName(const std::string& full_event_name);
75 // Sends an event via ipc_sender to the given extension. Can be called on any
77 static void DispatchEvent(IPC::Sender* ipc_sender,
78 void* browser_context_id,
79 const std::string& extension_id,
80 const std::string& event_name,
81 scoped_ptr<base::ListValue> event_args,
82 UserGestureState user_gesture,
83 const EventFilteringInfo& info);
85 // An EventRouter is shared between |browser_context| and its associated
86 // incognito context. |extension_prefs| may be NULL in tests.
87 EventRouter(content::BrowserContext* browser_context,
88 ExtensionPrefs* extension_prefs);
89 virtual ~EventRouter();
91 // Add or remove the process/extension pair as a listener for |event_name|.
92 // Note that multiple extensions can share a process due to process
93 // collapsing. Also, a single extension can have 2 processes if it is a split
95 void AddEventListener(const std::string& event_name,
96 content::RenderProcessHost* process,
97 const std::string& extension_id);
98 void RemoveEventListener(const std::string& event_name,
99 content::RenderProcessHost* process,
100 const std::string& extension_id);
102 EventListenerMap& listeners() { return listeners_; }
104 // Registers an observer to be notified when an event listener for
105 // |event_name| is added or removed. There can currently be only one observer
106 // for each distinct |event_name|.
107 void RegisterObserver(Observer* observer,
108 const std::string& event_name);
110 // Unregisters an observer from all events.
111 void UnregisterObserver(Observer* observer);
113 // Add or remove the extension as having a lazy background page that listens
114 // to the event. The difference from the above methods is that these will be
115 // remembered even after the process goes away. We use this list to decide
116 // which extension pages to load when dispatching an event.
117 void AddLazyEventListener(const std::string& event_name,
118 const std::string& extension_id);
119 void RemoveLazyEventListener(const std::string& event_name,
120 const std::string& extension_id);
122 // If |add_lazy_listener| is true also add the lazy version of this listener.
123 void AddFilteredEventListener(const std::string& event_name,
124 content::RenderProcessHost* process,
125 const std::string& extension_id,
126 const base::DictionaryValue& filter,
127 bool add_lazy_listener);
129 // If |remove_lazy_listener| is true also remove the lazy version of this
131 void RemoveFilteredEventListener(const std::string& event_name,
132 content::RenderProcessHost* process,
133 const std::string& extension_id,
134 const base::DictionaryValue& filter,
135 bool remove_lazy_listener);
137 // Returns true if there is at least one listener for the given event.
138 bool HasEventListener(const std::string& event_name);
140 // Returns true if the extension is listening to the given event.
141 bool ExtensionHasEventListener(const std::string& extension_id,
142 const std::string& event_name);
144 // Return or set the list of events for which the given extension has
146 std::set<std::string> GetRegisteredEvents(const std::string& extension_id);
147 void SetRegisteredEvents(const std::string& extension_id,
148 const std::set<std::string>& events);
150 // Broadcasts an event to every listener registered for that event.
151 virtual void BroadcastEvent(scoped_ptr<Event> event);
153 // Dispatches an event to the given extension.
154 virtual void DispatchEventToExtension(const std::string& extension_id,
155 scoped_ptr<Event> event);
157 // Dispatches |event| to the given extension as if the extension has a lazy
158 // listener for it. NOTE: This should be used rarely, for dispatching events
159 // to extensions that haven't had a chance to add their own listeners yet, eg:
160 // newly installed extensions.
161 void DispatchEventWithLazyListener(const std::string& extension_id,
162 scoped_ptr<Event> event);
164 // Record the Event Ack from the renderer. (One less event in-flight.)
165 void OnEventAck(content::BrowserContext* context,
166 const std::string& extension_id);
169 FRIEND_TEST_ALL_PREFIXES(EventRouterTest, EventRouterObserver);
171 // The extension and process that contains the event listener for a given
173 struct ListenerProcess;
175 // A map between an event name and a set of extensions that are listening
177 typedef std::map<std::string, std::set<ListenerProcess> > ListenerMap;
179 // An identifier for an event dispatch that is used to prevent double dispatch
180 // due to race conditions between the direct and lazy dispatch paths.
181 typedef std::pair<const content::BrowserContext*, std::string>
182 EventDispatchIdentifier;
184 // TODO(gdk): Document this.
185 static void DispatchExtensionMessage(
186 IPC::Sender* ipc_sender,
187 void* browser_context_id,
188 const std::string& extension_id,
189 const std::string& event_name,
190 base::ListValue* event_args,
191 UserGestureState user_gesture,
192 const extensions::EventFilteringInfo& info);
194 virtual void Observe(int type,
195 const content::NotificationSource& source,
196 const content::NotificationDetails& details) OVERRIDE;
198 // Returns true if the given listener map contains a event listeners for
199 // the given event. If |extension_id| is non-empty, we also check that that
200 // extension is one of the listeners.
201 bool HasEventListenerImpl(const ListenerMap& listeners,
202 const std::string& extension_id,
203 const std::string& event_name);
205 // Shared by DispatchEvent*. If |restrict_to_extension_id| is empty, the
206 // event is broadcast.
207 // An event that just came off the pending list may not be delayed again.
208 void DispatchEventImpl(const std::string& restrict_to_extension_id,
209 const linked_ptr<Event>& event);
211 // Ensures that all lazy background pages that are interested in the given
212 // event are loaded, and queues the event if the page is not ready yet.
213 // Inserts an EventDispatchIdentifier into |already_dispatched| for each lazy
214 // event dispatch that is queued.
215 void DispatchLazyEvent(const std::string& extension_id,
216 const linked_ptr<Event>& event,
217 std::set<EventDispatchIdentifier>* already_dispatched);
219 // Dispatches the event to the specified extension running in |process|.
220 void DispatchEventToProcess(const std::string& extension_id,
221 content::RenderProcessHost* process,
222 const linked_ptr<Event>& event);
224 // Returns false when the event is scoped to a context and the listening
225 // extension does not have access to events from that context. Also fills
226 // |event_args| with the proper arguments to send, which may differ if
227 // the event crosses the incognito boundary.
228 bool CanDispatchEventToBrowserContext(content::BrowserContext* context,
229 const Extension* extension,
230 const linked_ptr<Event>& event);
232 // Possibly loads given extension's background page in preparation to
233 // dispatch an event. Returns true if the event was queued for subsequent
234 // dispatch, false otherwise.
235 bool MaybeLoadLazyBackgroundPageToDispatchEvent(
236 content::BrowserContext* context,
237 const Extension* extension,
238 const linked_ptr<Event>& event);
240 // Adds a filter to an event.
241 void AddFilterToEvent(const std::string& event_name,
242 const std::string& extension_id,
243 const base::DictionaryValue* filter);
245 // Removes a filter from an event.
246 void RemoveFilterFromEvent(const std::string& event_name,
247 const std::string& extension_id,
248 const base::DictionaryValue* filter);
250 // Returns the dictionary of event filters that the given extension has
252 const base::DictionaryValue* GetFilteredEvents(
253 const std::string& extension_id);
255 // Track of the number of dispatched events that have not yet sent an
256 // ACK from the renderer.
257 void IncrementInFlightEvents(content::BrowserContext* context,
258 const Extension* extension);
261 static void IncrementInFlightEventsOnUI(
262 void* browser_context_id,
263 const std::string& extension_id);
265 void DispatchPendingEvent(const linked_ptr<Event>& event,
266 ExtensionHost* host);
268 // Implementation of EventListenerMap::Delegate.
269 virtual void OnListenerAdded(const EventListener* listener) OVERRIDE;
270 virtual void OnListenerRemoved(const EventListener* listener) OVERRIDE;
272 content::BrowserContext* browser_context_;
274 // The ExtensionPrefs associated with |browser_context_|. May be NULL in
276 ExtensionPrefs* extension_prefs_;
278 content::NotificationRegistrar registrar_;
280 EventListenerMap listeners_;
282 // Map from base event name to observer.
283 typedef base::hash_map<std::string, Observer*> ObserverMap;
284 ObserverMap observers_;
286 DISALLOW_COPY_AND_ASSIGN(EventRouter);
290 typedef base::Callback<void(content::BrowserContext*,
292 base::ListValue*)> WillDispatchCallback;
294 // The event to dispatch.
295 std::string event_name;
297 // Arguments to send to the event listener.
298 scoped_ptr<base::ListValue> event_args;
300 // If non-NULL, then the event will not be sent to other BrowserContexts
301 // unless the extension has permission (e.g. incognito tab update -> normal
302 // tab only works if extension is allowed incognito access).
303 content::BrowserContext* restrict_to_browser_context;
305 // If not empty, the event is only sent to extensions with host permissions
309 // Whether a user gesture triggered the event.
310 EventRouter::UserGestureState user_gesture;
312 // Extra information used to filter which events are sent to the listener.
313 EventFilteringInfo filter_info;
315 // If specified, this is called before dispatching an event to each
316 // extension. The third argument is a mutable reference to event_args,
317 // allowing the caller to provide different arguments depending on the
318 // extension and profile. This is guaranteed to be called synchronously with
319 // DispatchEvent, so callers don't need to worry about lifetime.
320 WillDispatchCallback will_dispatch_callback;
322 // If true, this event will always be dispatched to ephemeral apps, regardless
323 // of whether they are running or inactive. Defaults to false.
324 // Most events can only be dispatched to ephemeral apps that are already
325 // running. Cached ephemeral apps are inactive until launched by the user.
326 bool can_load_ephemeral_apps;
328 Event(const std::string& event_name,
329 scoped_ptr<base::ListValue> event_args);
331 Event(const std::string& event_name,
332 scoped_ptr<base::ListValue> event_args,
333 content::BrowserContext* restrict_to_browser_context);
335 Event(const std::string& event_name,
336 scoped_ptr<base::ListValue> event_args,
337 content::BrowserContext* restrict_to_browser_context,
338 const GURL& event_url,
339 EventRouter::UserGestureState user_gesture,
340 const EventFilteringInfo& info);
344 // Makes a deep copy of this instance. Ownership is transferred to the
349 struct EventListenerInfo {
350 EventListenerInfo(const std::string& event_name,
351 const std::string& extension_id,
352 content::BrowserContext* browser_context);
353 // The event name including any sub-event, e.g. "runtime.onStartup" or
354 // "webRequest.onCompleted/123".
355 const std::string event_name;
357 const std::string extension_id;
358 content::BrowserContext* browser_context;
361 } // namespace extensions
363 #endif // EXTENSIONS_BROWSER_EVENT_ROUTER_H_