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 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 29 EventListener::~EventListener() {} 30 31 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 41 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 49 bool EventListener::IsLazy() const { 50 return !process_; 51 } 52 53 void EventListener::MakeLazy() { 54 process_ = NULL; 55 } 56 57 content::BrowserContext* EventListener::GetBrowserContext() const { 58 return process_ ? process_->GetBrowserContext() : NULL; 59 } 60 61 EventListenerMap::EventListenerMap(Delegate* delegate) 62 : delegate_(delegate) { 63 } 64 65 EventListenerMap::~EventListenerMap() {} 66 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 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 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 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 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 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 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 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 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 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 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 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 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 252 bool EventListenerMap::IsFilteredEvent(const Event& event) const { 253 return filtered_events_.count(event.event_name) > 0u; 254 } 255 256 } // namespace extensions 257