• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 #include "extensions/browser/event_listener_map.h"
6 
7 #include "base/values.h"
8 #include "content/public/browser/render_process_host.h"
9 #include "extensions/browser/event_router.h"
10 #include "ipc/ipc_message.h"
11 
12 using base::DictionaryValue;
13 
14 namespace extensions {
15 
16 typedef EventFilter::MatcherID MatcherID;
17 
EventListener(const std::string & event_name,const std::string & extension_id,content::RenderProcessHost * process,scoped_ptr<DictionaryValue> filter)18 EventListener::EventListener(const std::string& event_name,
19                              const std::string& extension_id,
20                              content::RenderProcessHost* process,
21                              scoped_ptr<DictionaryValue> filter)
22     : event_name_(event_name),
23       extension_id_(extension_id),
24       process_(process),
25       filter_(filter.Pass()),
26       matcher_id_(-1) {
27 }
28 
~EventListener()29 EventListener::~EventListener() {}
30 
Equals(const EventListener * other) const31 bool EventListener::Equals(const EventListener* other) const {
32   // We don't check matcher_id equality because we want a listener with a
33   // filter that hasn't been added to EventFilter to match one that is
34   // equivalent but has.
35   return event_name_ == other->event_name_ &&
36          extension_id_ == other->extension_id_ && process_ == other->process_ &&
37          ((!!filter_.get()) == (!!other->filter_.get())) &&
38          (!filter_.get() || filter_->Equals(other->filter_.get()));
39 }
40 
Copy() const41 scoped_ptr<EventListener> EventListener::Copy() const {
42   scoped_ptr<DictionaryValue> filter_copy;
43   if (filter_)
44     filter_copy.reset(filter_->DeepCopy());
45   return scoped_ptr<EventListener>(new EventListener(
46       event_name_, extension_id_, process_, filter_copy.Pass()));
47 }
48 
IsLazy() const49 bool EventListener::IsLazy() const {
50   return !process_;
51 }
52 
MakeLazy()53 void EventListener::MakeLazy() {
54   process_ = NULL;
55 }
56 
GetBrowserContext() const57 content::BrowserContext* EventListener::GetBrowserContext() const {
58   return process_ ? process_->GetBrowserContext() : NULL;
59 }
60 
EventListenerMap(Delegate * delegate)61 EventListenerMap::EventListenerMap(Delegate* delegate)
62     : delegate_(delegate) {
63 }
64 
~EventListenerMap()65 EventListenerMap::~EventListenerMap() {}
66 
AddListener(scoped_ptr<EventListener> listener)67 bool EventListenerMap::AddListener(scoped_ptr<EventListener> listener) {
68   if (HasListener(listener.get()))
69     return false;
70   if (listener->filter()) {
71     scoped_ptr<EventMatcher> matcher(ParseEventMatcher(listener->filter()));
72     MatcherID id =
73         event_filter_.AddEventMatcher(listener->event_name(), matcher.Pass());
74     listener->set_matcher_id(id);
75     listeners_by_matcher_id_[id] = listener.get();
76     filtered_events_.insert(listener->event_name());
77   }
78   linked_ptr<EventListener> listener_ptr(listener.release());
79   listeners_[listener_ptr->event_name()].push_back(listener_ptr);
80 
81   delegate_->OnListenerAdded(listener_ptr.get());
82 
83   return true;
84 }
85 
ParseEventMatcher(DictionaryValue * filter_dict)86 scoped_ptr<EventMatcher> EventListenerMap::ParseEventMatcher(
87     DictionaryValue* filter_dict) {
88   return scoped_ptr<EventMatcher>(new EventMatcher(
89       scoped_ptr<DictionaryValue>(filter_dict->DeepCopy()), MSG_ROUTING_NONE));
90 }
91 
RemoveListener(const EventListener * listener)92 bool EventListenerMap::RemoveListener(const EventListener* listener) {
93   ListenerList& listeners = listeners_[listener->event_name()];
94   for (ListenerList::iterator it = listeners.begin(); it != listeners.end();
95        it++) {
96     if ((*it)->Equals(listener)) {
97       CleanupListener(it->get());
98       // Popping from the back should be cheaper than erase(it).
99       std::swap(*it, listeners.back());
100       listeners.pop_back();
101       delegate_->OnListenerRemoved(listener);
102       return true;
103     }
104   }
105   return false;
106 }
107 
HasListenerForEvent(const std::string & event_name)108 bool EventListenerMap::HasListenerForEvent(const std::string& event_name) {
109   ListenerMap::iterator it = listeners_.find(event_name);
110   return it != listeners_.end() && !it->second.empty();
111 }
112 
HasListenerForExtension(const std::string & extension_id,const std::string & event_name)113 bool EventListenerMap::HasListenerForExtension(
114     const std::string& extension_id,
115     const std::string& event_name) {
116   ListenerMap::iterator it = listeners_.find(event_name);
117   if (it == listeners_.end())
118     return false;
119 
120   for (ListenerList::iterator it2 = it->second.begin();
121        it2 != it->second.end(); it2++) {
122     if ((*it2)->extension_id() == extension_id)
123       return true;
124   }
125   return false;
126 }
127 
HasListener(const EventListener * listener)128 bool EventListenerMap::HasListener(const EventListener* listener) {
129   ListenerMap::iterator it = listeners_.find(listener->event_name());
130   if (it == listeners_.end())
131     return false;
132   for (ListenerList::iterator it2 = it->second.begin();
133        it2 != it->second.end(); it2++) {
134     if ((*it2)->Equals(listener)) {
135       return true;
136     }
137   }
138   return false;
139 }
140 
HasProcessListener(content::RenderProcessHost * process,const std::string & extension_id)141 bool EventListenerMap::HasProcessListener(content::RenderProcessHost* process,
142                                           const std::string& extension_id) {
143   for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
144        it++) {
145     for (ListenerList::iterator it2 = it->second.begin();
146          it2 != it->second.end(); it2++) {
147       if ((*it2)->process() == process &&
148           (*it2)->extension_id() == extension_id)
149         return true;
150     }
151   }
152   return false;
153 }
154 
RemoveLazyListenersForExtension(const std::string & extension_id)155 void EventListenerMap::RemoveLazyListenersForExtension(
156     const std::string& extension_id) {
157   for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
158        it++) {
159     for (ListenerList::iterator it2 = it->second.begin();
160          it2 != it->second.end();) {
161       if ((*it2)->IsLazy() && (*it2)->extension_id() == extension_id) {
162         CleanupListener(it2->get());
163         it2 = it->second.erase(it2);
164       } else {
165         it2++;
166       }
167     }
168   }
169 }
170 
LoadUnfilteredLazyListeners(const std::string & extension_id,const std::set<std::string> & event_names)171 void EventListenerMap::LoadUnfilteredLazyListeners(
172     const std::string& extension_id,
173     const std::set<std::string>& event_names) {
174   for (std::set<std::string>::const_iterator it = event_names.begin();
175        it != event_names.end(); ++it) {
176     AddListener(scoped_ptr<EventListener>(new EventListener(
177         *it, extension_id, NULL, scoped_ptr<DictionaryValue>())));
178   }
179 }
180 
LoadFilteredLazyListeners(const std::string & extension_id,const DictionaryValue & filtered)181 void EventListenerMap::LoadFilteredLazyListeners(
182     const std::string& extension_id,
183     const DictionaryValue& filtered) {
184   for (DictionaryValue::Iterator it(filtered); !it.IsAtEnd(); it.Advance()) {
185     // We skip entries if they are malformed.
186     const base::ListValue* filter_list = NULL;
187     if (!it.value().GetAsList(&filter_list))
188       continue;
189     for (size_t i = 0; i < filter_list->GetSize(); i++) {
190       const DictionaryValue* filter = NULL;
191       if (!filter_list->GetDictionary(i, &filter))
192         continue;
193       AddListener(scoped_ptr<EventListener>(new EventListener(
194           it.key(), extension_id, NULL,
195           scoped_ptr<DictionaryValue>(filter->DeepCopy()))));
196     }
197   }
198 }
199 
GetEventListeners(const Event & event)200 std::set<const EventListener*> EventListenerMap::GetEventListeners(
201     const Event& event) {
202   std::set<const EventListener*> interested_listeners;
203   if (IsFilteredEvent(event)) {
204     // Look up the interested listeners via the EventFilter.
205     std::set<MatcherID> ids =
206         event_filter_.MatchEvent(event.event_name, event.filter_info,
207             MSG_ROUTING_NONE);
208     for (std::set<MatcherID>::iterator id = ids.begin(); id != ids.end();
209          id++) {
210       EventListener* listener = listeners_by_matcher_id_[*id];
211       CHECK(listener);
212       interested_listeners.insert(listener);
213     }
214   } else {
215     ListenerList& listeners = listeners_[event.event_name];
216     for (ListenerList::const_iterator it = listeners.begin();
217          it != listeners.end(); it++) {
218       interested_listeners.insert(it->get());
219     }
220   }
221 
222   return interested_listeners;
223 }
224 
RemoveListenersForProcess(const content::RenderProcessHost * process)225 void EventListenerMap::RemoveListenersForProcess(
226     const content::RenderProcessHost* process) {
227   CHECK(process);
228   for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
229        it++) {
230     for (ListenerList::iterator it2 = it->second.begin();
231          it2 != it->second.end();) {
232       if ((*it2)->process() == process) {
233         linked_ptr<EventListener> listener(*it2);
234         CleanupListener(it2->get());
235         it2 = it->second.erase(it2);
236         delegate_->OnListenerRemoved(listener.get());
237       } else {
238         it2++;
239       }
240     }
241   }
242 }
243 
CleanupListener(EventListener * listener)244 void EventListenerMap::CleanupListener(EventListener* listener) {
245   // If the listener doesn't have a filter then we have nothing to clean up.
246   if (listener->matcher_id() == -1)
247     return;
248   event_filter_.RemoveEventMatcher(listener->matcher_id());
249   CHECK_EQ(1u, listeners_by_matcher_id_.erase(listener->matcher_id()));
250 }
251 
IsFilteredEvent(const Event & event) const252 bool EventListenerMap::IsFilteredEvent(const Event& event) const {
253   return filtered_events_.count(event.event_name) > 0u;
254 }
255 
256 }  // namespace extensions
257