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