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