Home | History | Annotate | Download | only in browser
      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