summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension_event_router.h
blob: daef5543e4f0e983d392206dcb0f9b3693fb7249 (plain)
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
// 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_EXTENSION_EVENT_ROUTER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_EVENT_ROUTER_H_
#pragma once

#include <map>
#include <set>
#include <string>

#include "base/compiler_specific.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "ipc/ipc_message.h"

class GURL;
class Extension;
class ExtensionDevToolsManager;
class Profile;

namespace content {
class RenderProcessHost;
}

class ExtensionEventRouter : public content::NotificationObserver {
 public:
  // Sends an event via ipc_sender to the given extension. Can be called on
  // any thread.
  static void DispatchEvent(IPC::Message::Sender* ipc_sender,
                            const std::string& extension_id,
                            const std::string& event_name,
                            const std::string& event_args,
                            const GURL& event_url);

  explicit ExtensionEventRouter(Profile* profile);
  virtual ~ExtensionEventRouter();

  // Add or remove the process/extension pair as a listener for |event_name|.
  // Note that multiple extensions can share a process due to process
  // collapsing. Also, a single extension can have 2 processes if it is a split
  // mode extension.
  void AddEventListener(const std::string& event_name,
                        content::RenderProcessHost* process,
                        const std::string& extension_id);
  void RemoveEventListener(const std::string& event_name,
                           content::RenderProcessHost* process,
                           const std::string& extension_id);

  // Add or remove the extension as having a lazy background page that listens
  // to the event. The difference from the above methods is that these will be
  // remembered even after the process goes away. We use this list to decide
  // which extension pages to load when dispatching an event.
  void AddLazyEventListener(const std::string& event_name,
                            const std::string& extension_id);
  void RemoveLazyEventListener(const std::string& event_name,
                               const std::string& extension_id);

  // Returns true if there is at least one listener for the given event.
  bool HasEventListener(const std::string& event_name);

  // Returns true if the extension is listening to the given event.
  bool ExtensionHasEventListener(const std::string& extension_id,
                                 const std::string& event_name);

  // Send an event to every registered extension renderer. If
  // |restrict_to_profile| is non-NULL, then the event will not be sent to other
  // profiles unless the extension has permission (e.g. incognito tab update ->
  // normal profile only works if extension is allowed incognito access). If
  // |event_url| is not empty, the event is only sent to extension with host
  // permissions for this url.
  void DispatchEventToRenderers(
      const std::string& event_name,
      const std::string& event_args,
      Profile* restrict_to_profile,
      const GURL& event_url);

  // Same as above, except only send the event to the given extension.
  virtual void DispatchEventToExtension(
      const std::string& extension_id,
      const std::string& event_name,
      const std::string& event_args,
      Profile* restrict_to_profile,
      const GURL& event_url);

  // Send different versions of an event to extensions in different profiles.
  // This is used in the case of sending one event to extensions that have
  // incognito access, and another event to extensions that don't (here),
  // in order to avoid sending 2 events to "spanning" extensions.
  // If |cross_incognito_profile| is non-NULL and different from
  // restrict_to_profile, send the event with cross_incognito_args to the
  // extensions in that profile that can't cross incognito.
  void DispatchEventsToRenderersAcrossIncognito(
      const std::string& event_name,
      const std::string& event_args,
      Profile* restrict_to_profile,
      const std::string& cross_incognito_args,
      const GURL& event_url);

  // Record the Event Ack from the renderer. (One less event in-flight.)
  void OnExtensionEventAck(const std::string& extension_id);

  // Check if there are any Extension Events that have not yet been acked by
  // the renderer.
  bool HasInFlightEvents(const std::string& extension_id);

 protected:
  // The details of an event to be dispatched.
  struct ExtensionEvent;

  // Shared by DispatchEvent*. If |extension_id| is empty, the event is
  // broadcast.
  // An event that just came off the pending list may not be delayed again.
  void DispatchEventImpl(const std::string& extension_id,
                         const linked_ptr<ExtensionEvent>& event,
                         bool was_pending);

  // Ensures that all lazy background pages that are interested in the given
  // event are loaded, and queues the event if the page is not ready yet.
  // If |extension_id| is non-empty, we load only that extension's page
  // (assuming it is interested in the event).
  void LoadLazyBackgroundPagesForEvent(
      const std::string& extension_id,
      const linked_ptr<ExtensionEvent>& event);

  // Dispatch may be delayed if the extension has a lazy background page.
  bool CanDispatchEventNow(const Extension* extension);

  // Store the event so that it can be dispatched (in order received)
  // when the background page is done loading.
  void AppendEvent(const std::string& extension_id,
                   const linked_ptr<ExtensionEvent>& event);
  void DispatchPendingEvents(const std::string& extension_id);

 private:
  // The extension and process that contains the event listener for a given
  // event.
  struct ListenerProcess;

  // A map between an event name and a set of extensions that are listening
  // to that event.
  typedef std::map<std::string, std::set<ListenerProcess> > ListenerMap;

  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

  // Returns true if the given listener map contains a event listeners for
  // the given event. If |extension_id| is non-empty, we also check that that
  // extension is one of the listeners.
  bool HasEventListenerImpl(const ListenerMap& listeners,
                            const std::string& extension_id,
                            const std::string& event_name);

  Profile* profile_;

  content::NotificationRegistrar registrar_;

  scoped_refptr<ExtensionDevToolsManager> extension_devtools_manager_;

  // The list of active extension processes that are listening to events.
  ListenerMap listeners_;

  // The list of all the lazy (non-persistent) background pages that are
  // listening to events. This is just a cache of the real list, which is
  // stored on disk in the extension prefs.
  ListenerMap lazy_listeners_;

  // A map between an extension id and the queue of events pending
  // the load of it's background page.
  typedef std::vector<linked_ptr<ExtensionEvent> > PendingEventsList;
  typedef std::map<std::string,
                   linked_ptr<PendingEventsList> > PendingEventsPerExtMap;
  PendingEventsPerExtMap pending_events_;

  // Track of the number of dispatched events that have not yet sent an
  // ACK from the renderer.
  void IncrementInFlightEvents(const Extension* extension);
  std::map<std::string, int> in_flight_events_;

  DISALLOW_COPY_AND_ASSIGN(ExtensionEventRouter);
};

#endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_EVENT_ROUTER_H_