Home | History | Annotate | Download | only in browser
      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 "extensions/browser/event_router.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/bind.h"
     10 #include "base/command_line.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/profiler/scoped_profile.h"
     13 #include "base/stl_util.h"
     14 #include "base/values.h"
     15 #include "content/public/browser/child_process_security_policy.h"
     16 #include "content/public/browser/notification_service.h"
     17 #include "content/public/browser/render_process_host.h"
     18 #include "extensions/browser/api_activity_monitor.h"
     19 #include "extensions/browser/extension_host.h"
     20 #include "extensions/browser/extension_prefs.h"
     21 #include "extensions/browser/extension_registry.h"
     22 #include "extensions/browser/extension_system.h"
     23 #include "extensions/browser/extensions_browser_client.h"
     24 #include "extensions/browser/lazy_background_task_queue.h"
     25 #include "extensions/browser/notification_types.h"
     26 #include "extensions/browser/process_manager.h"
     27 #include "extensions/browser/process_map.h"
     28 #include "extensions/common/extension.h"
     29 #include "extensions/common/extension_api.h"
     30 #include "extensions/common/extension_messages.h"
     31 #include "extensions/common/extension_urls.h"
     32 #include "extensions/common/manifest_handlers/background_info.h"
     33 #include "extensions/common/manifest_handlers/incognito_info.h"
     34 #include "extensions/common/permissions/permissions_data.h"
     35 
     36 using base::DictionaryValue;
     37 using base::ListValue;
     38 using content::BrowserContext;
     39 using content::BrowserThread;
     40 
     41 namespace extensions {
     42 
     43 namespace {
     44 
     45 void DoNothing(ExtensionHost* host) {}
     46 
     47 // A dictionary of event names to lists of filters that this extension has
     48 // registered from its lazy background page.
     49 const char kFilteredEvents[] = "filtered_events";
     50 
     51 // Sends a notification about an event to the API activity monitor on the
     52 // UI thread. Can be called from any thread.
     53 void NotifyApiEventDispatched(void* browser_context_id,
     54                               const std::string& extension_id,
     55                               const std::string& event_name,
     56                               scoped_ptr<ListValue> args) {
     57   // The ApiActivityMonitor can only be accessed from the UI thread.
     58   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     59     BrowserThread::PostTask(
     60         BrowserThread::UI,
     61         FROM_HERE,
     62         base::Bind(&NotifyApiEventDispatched,
     63                    browser_context_id,
     64                    extension_id,
     65                    event_name,
     66                    base::Passed(&args)));
     67     return;
     68   }
     69 
     70   // Notify the ApiActivityMonitor about the event dispatch.
     71   BrowserContext* context = static_cast<BrowserContext*>(browser_context_id);
     72   if (!ExtensionsBrowserClient::Get()->IsValidContext(context))
     73     return;
     74   ApiActivityMonitor* monitor =
     75       ExtensionsBrowserClient::Get()->GetApiActivityMonitor(context);
     76   if (monitor)
     77     monitor->OnApiEventDispatched(extension_id, event_name, args.Pass());
     78 }
     79 
     80 }  // namespace
     81 
     82 const char EventRouter::kRegisteredEvents[] = "events";
     83 
     84 struct EventRouter::ListenerProcess {
     85   content::RenderProcessHost* process;
     86   std::string extension_id;
     87 
     88   ListenerProcess(content::RenderProcessHost* process,
     89                   const std::string& extension_id)
     90       : process(process), extension_id(extension_id) {}
     91 
     92   bool operator<(const ListenerProcess& that) const {
     93     if (process < that.process)
     94       return true;
     95     if (process == that.process && extension_id < that.extension_id)
     96       return true;
     97     return false;
     98   }
     99 };
    100 
    101 // static
    102 void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
    103                                            void* browser_context_id,
    104                                            const std::string& extension_id,
    105                                            const std::string& event_name,
    106                                            ListValue* event_args,
    107                                            UserGestureState user_gesture,
    108                                            const EventFilteringInfo& info) {
    109   NotifyApiEventDispatched(browser_context_id,
    110                            extension_id,
    111                            event_name,
    112                            make_scoped_ptr(event_args->DeepCopy()));
    113 
    114   ListValue args;
    115   args.Set(0, new base::StringValue(event_name));
    116   args.Set(1, event_args);
    117   args.Set(2, info.AsValue().release());
    118   ipc_sender->Send(new ExtensionMsg_MessageInvoke(
    119       MSG_ROUTING_CONTROL,
    120       extension_id,
    121       kEventBindings,
    122       "dispatchEvent",
    123       args,
    124       user_gesture == USER_GESTURE_ENABLED));
    125 
    126   // DispatchExtensionMessage does _not_ take ownership of event_args, so we
    127   // must ensure that the destruction of args does not attempt to free it.
    128   scoped_ptr<base::Value> removed_event_args;
    129   args.Remove(1, &removed_event_args);
    130   ignore_result(removed_event_args.release());
    131 }
    132 
    133 // static
    134 EventRouter* EventRouter::Get(content::BrowserContext* browser_context) {
    135   return ExtensionSystem::Get(browser_context)->event_router();
    136 }
    137 
    138 // static
    139 std::string EventRouter::GetBaseEventName(const std::string& full_event_name) {
    140   size_t slash_sep = full_event_name.find('/');
    141   return full_event_name.substr(0, slash_sep);
    142 }
    143 
    144 // static
    145 void EventRouter::DispatchEvent(IPC::Sender* ipc_sender,
    146                                 void* browser_context_id,
    147                                 const std::string& extension_id,
    148                                 const std::string& event_name,
    149                                 scoped_ptr<ListValue> event_args,
    150                                 UserGestureState user_gesture,
    151                                 const EventFilteringInfo& info) {
    152   DispatchExtensionMessage(ipc_sender,
    153                            browser_context_id,
    154                            extension_id,
    155                            event_name,
    156                            event_args.get(),
    157                            user_gesture,
    158                            info);
    159 
    160   BrowserThread::PostTask(
    161       BrowserThread::UI,
    162       FROM_HERE,
    163       base::Bind(&EventRouter::IncrementInFlightEventsOnUI,
    164                   browser_context_id,
    165                   extension_id));
    166 }
    167 
    168 EventRouter::EventRouter(BrowserContext* browser_context,
    169                          ExtensionPrefs* extension_prefs)
    170     : browser_context_(browser_context),
    171       extension_prefs_(extension_prefs),
    172       extension_registry_observer_(this),
    173       listeners_(this) {
    174   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
    175                  content::NotificationService::AllSources());
    176   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
    177                  content::NotificationService::AllSources());
    178   registrar_.Add(this,
    179                  extensions::NOTIFICATION_EXTENSION_ENABLED,
    180                  content::Source<BrowserContext>(browser_context_));
    181   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
    182 }
    183 
    184 EventRouter::~EventRouter() {}
    185 
    186 void EventRouter::AddEventListener(const std::string& event_name,
    187                                    content::RenderProcessHost* process,
    188                                    const std::string& extension_id) {
    189   listeners_.AddListener(EventListener::ForExtension(
    190       event_name, extension_id, process, scoped_ptr<DictionaryValue>()));
    191 }
    192 
    193 void EventRouter::RemoveEventListener(const std::string& event_name,
    194                                       content::RenderProcessHost* process,
    195                                       const std::string& extension_id) {
    196   scoped_ptr<EventListener> listener = EventListener::ForExtension(
    197       event_name, extension_id, process, scoped_ptr<DictionaryValue>());
    198   listeners_.RemoveListener(listener.get());
    199 }
    200 
    201 void EventRouter::AddEventListenerForURL(const std::string& event_name,
    202                                          content::RenderProcessHost* process,
    203                                          const GURL& listener_url) {
    204   listeners_.AddListener(EventListener::ForURL(
    205       event_name, listener_url, process, scoped_ptr<DictionaryValue>()));
    206 }
    207 
    208 void EventRouter::RemoveEventListenerForURL(const std::string& event_name,
    209                                             content::RenderProcessHost* process,
    210                                             const GURL& listener_url) {
    211   scoped_ptr<EventListener> listener = EventListener::ForURL(
    212       event_name, listener_url, process, scoped_ptr<DictionaryValue>());
    213   listeners_.RemoveListener(listener.get());
    214 }
    215 
    216 void EventRouter::RegisterObserver(Observer* observer,
    217                                    const std::string& event_name) {
    218   // Observing sub-event names like "foo.onBar/123" is not allowed.
    219   DCHECK(event_name.find('/') == std::string::npos);
    220   observers_[event_name] = observer;
    221 }
    222 
    223 void EventRouter::UnregisterObserver(Observer* observer) {
    224   std::vector<ObserverMap::iterator> iters_to_remove;
    225   for (ObserverMap::iterator iter = observers_.begin();
    226        iter != observers_.end(); ++iter) {
    227     if (iter->second == observer)
    228       iters_to_remove.push_back(iter);
    229   }
    230   for (size_t i = 0; i < iters_to_remove.size(); ++i)
    231     observers_.erase(iters_to_remove[i]);
    232 }
    233 
    234 void EventRouter::OnListenerAdded(const EventListener* listener) {
    235   const EventListenerInfo details(listener->event_name(),
    236                                   listener->extension_id(),
    237                                   listener->listener_url(),
    238                                   listener->GetBrowserContext());
    239   std::string base_event_name = GetBaseEventName(listener->event_name());
    240   ObserverMap::iterator observer = observers_.find(base_event_name);
    241   if (observer != observers_.end()) {
    242     // TODO(vadimt): Remove ScopedProfile below once crbug.com/417106 is fixed.
    243     tracked_objects::ScopedProfile tracking_profile(
    244         FROM_HERE_WITH_EXPLICIT_FUNCTION(
    245             "EventRouter_OnListenerAdded_ObserverCall"));
    246     observer->second->OnListenerAdded(details);
    247   }
    248 }
    249 
    250 void EventRouter::OnListenerRemoved(const EventListener* listener) {
    251   const EventListenerInfo details(listener->event_name(),
    252                                   listener->extension_id(),
    253                                   listener->listener_url(),
    254                                   listener->GetBrowserContext());
    255   std::string base_event_name = GetBaseEventName(listener->event_name());
    256   ObserverMap::iterator observer = observers_.find(base_event_name);
    257   if (observer != observers_.end())
    258     observer->second->OnListenerRemoved(details);
    259 }
    260 
    261 void EventRouter::AddLazyEventListener(const std::string& event_name,
    262                                        const std::string& extension_id) {
    263   bool is_new = listeners_.AddListener(EventListener::ForExtension(
    264       event_name, extension_id, NULL, scoped_ptr<DictionaryValue>()));
    265 
    266   if (is_new) {
    267     std::set<std::string> events = GetRegisteredEvents(extension_id);
    268     bool prefs_is_new = events.insert(event_name).second;
    269     if (prefs_is_new)
    270       SetRegisteredEvents(extension_id, events);
    271   }
    272 }
    273 
    274 void EventRouter::RemoveLazyEventListener(const std::string& event_name,
    275                                           const std::string& extension_id) {
    276   scoped_ptr<EventListener> listener = EventListener::ForExtension(
    277       event_name, extension_id, NULL, scoped_ptr<DictionaryValue>());
    278   bool did_exist = listeners_.RemoveListener(listener.get());
    279 
    280   if (did_exist) {
    281     std::set<std::string> events = GetRegisteredEvents(extension_id);
    282     bool prefs_did_exist = events.erase(event_name) > 0;
    283     DCHECK(prefs_did_exist);
    284     SetRegisteredEvents(extension_id, events);
    285   }
    286 }
    287 
    288 void EventRouter::AddFilteredEventListener(const std::string& event_name,
    289                                            content::RenderProcessHost* process,
    290                                            const std::string& extension_id,
    291                                            const base::DictionaryValue& filter,
    292                                            bool add_lazy_listener) {
    293   listeners_.AddListener(EventListener::ForExtension(
    294       event_name,
    295       extension_id,
    296       process,
    297       scoped_ptr<DictionaryValue>(filter.DeepCopy())));
    298 
    299   if (add_lazy_listener) {
    300     bool added = listeners_.AddListener(EventListener::ForExtension(
    301         event_name,
    302         extension_id,
    303         NULL,
    304         scoped_ptr<DictionaryValue>(filter.DeepCopy())));
    305 
    306     if (added)
    307       AddFilterToEvent(event_name, extension_id, &filter);
    308   }
    309 }
    310 
    311 void EventRouter::RemoveFilteredEventListener(
    312     const std::string& event_name,
    313     content::RenderProcessHost* process,
    314     const std::string& extension_id,
    315     const base::DictionaryValue& filter,
    316     bool remove_lazy_listener) {
    317   scoped_ptr<EventListener> listener = EventListener::ForExtension(
    318       event_name,
    319       extension_id,
    320       process,
    321       scoped_ptr<DictionaryValue>(filter.DeepCopy()));
    322 
    323   listeners_.RemoveListener(listener.get());
    324 
    325   if (remove_lazy_listener) {
    326     listener->MakeLazy();
    327     bool removed = listeners_.RemoveListener(listener.get());
    328 
    329     if (removed)
    330       RemoveFilterFromEvent(event_name, extension_id, &filter);
    331   }
    332 }
    333 
    334 bool EventRouter::HasEventListener(const std::string& event_name) {
    335   return listeners_.HasListenerForEvent(event_name);
    336 }
    337 
    338 bool EventRouter::ExtensionHasEventListener(const std::string& extension_id,
    339                                             const std::string& event_name) {
    340   return listeners_.HasListenerForExtension(extension_id, event_name);
    341 }
    342 
    343 bool EventRouter::HasEventListenerImpl(const ListenerMap& listener_map,
    344                                        const std::string& extension_id,
    345                                        const std::string& event_name) {
    346   ListenerMap::const_iterator it = listener_map.find(event_name);
    347   if (it == listener_map.end())
    348     return false;
    349 
    350   const std::set<ListenerProcess>& listeners = it->second;
    351   if (extension_id.empty())
    352     return !listeners.empty();
    353 
    354   for (std::set<ListenerProcess>::const_iterator listener = listeners.begin();
    355        listener != listeners.end(); ++listener) {
    356     if (listener->extension_id == extension_id)
    357       return true;
    358   }
    359   return false;
    360 }
    361 
    362 std::set<std::string> EventRouter::GetRegisteredEvents(
    363     const std::string& extension_id) {
    364   std::set<std::string> events;
    365   const ListValue* events_value = NULL;
    366 
    367   if (!extension_prefs_ ||
    368       !extension_prefs_->ReadPrefAsList(
    369            extension_id, kRegisteredEvents, &events_value)) {
    370     return events;
    371   }
    372 
    373   for (size_t i = 0; i < events_value->GetSize(); ++i) {
    374     std::string event;
    375     if (events_value->GetString(i, &event))
    376       events.insert(event);
    377   }
    378   return events;
    379 }
    380 
    381 void EventRouter::SetRegisteredEvents(const std::string& extension_id,
    382                                       const std::set<std::string>& events) {
    383   ListValue* events_value = new ListValue;
    384   for (std::set<std::string>::const_iterator iter = events.begin();
    385        iter != events.end(); ++iter) {
    386     events_value->Append(new base::StringValue(*iter));
    387   }
    388   extension_prefs_->UpdateExtensionPref(
    389       extension_id, kRegisteredEvents, events_value);
    390 }
    391 
    392 void EventRouter::AddFilterToEvent(const std::string& event_name,
    393                                    const std::string& extension_id,
    394                                    const DictionaryValue* filter) {
    395   ExtensionPrefs::ScopedDictionaryUpdate update(
    396       extension_prefs_, extension_id, kFilteredEvents);
    397   DictionaryValue* filtered_events = update.Get();
    398   if (!filtered_events)
    399     filtered_events = update.Create();
    400 
    401   ListValue* filter_list = NULL;
    402   if (!filtered_events->GetList(event_name, &filter_list)) {
    403     filter_list = new ListValue;
    404     filtered_events->SetWithoutPathExpansion(event_name, filter_list);
    405   }
    406 
    407   filter_list->Append(filter->DeepCopy());
    408 }
    409 
    410 void EventRouter::RemoveFilterFromEvent(const std::string& event_name,
    411                                         const std::string& extension_id,
    412                                         const DictionaryValue* filter) {
    413   ExtensionPrefs::ScopedDictionaryUpdate update(
    414       extension_prefs_, extension_id, kFilteredEvents);
    415   DictionaryValue* filtered_events = update.Get();
    416   ListValue* filter_list = NULL;
    417   if (!filtered_events ||
    418       !filtered_events->GetListWithoutPathExpansion(event_name, &filter_list)) {
    419     return;
    420   }
    421 
    422   for (size_t i = 0; i < filter_list->GetSize(); i++) {
    423     DictionaryValue* filter = NULL;
    424     CHECK(filter_list->GetDictionary(i, &filter));
    425     if (filter->Equals(filter)) {
    426       filter_list->Remove(i, NULL);
    427       break;
    428     }
    429   }
    430 }
    431 
    432 const DictionaryValue* EventRouter::GetFilteredEvents(
    433     const std::string& extension_id) {
    434   const DictionaryValue* events = NULL;
    435   extension_prefs_->ReadPrefAsDictionary(
    436       extension_id, kFilteredEvents, &events);
    437   return events;
    438 }
    439 
    440 void EventRouter::BroadcastEvent(scoped_ptr<Event> event) {
    441   DispatchEventImpl(std::string(), linked_ptr<Event>(event.release()));
    442 }
    443 
    444 void EventRouter::DispatchEventToExtension(const std::string& extension_id,
    445                                            scoped_ptr<Event> event) {
    446   DCHECK(!extension_id.empty());
    447   DispatchEventImpl(extension_id, linked_ptr<Event>(event.release()));
    448 }
    449 
    450 void EventRouter::DispatchEventWithLazyListener(const std::string& extension_id,
    451                                                 scoped_ptr<Event> event) {
    452   DCHECK(!extension_id.empty());
    453   std::string event_name = event->event_name;
    454   bool has_listener = ExtensionHasEventListener(extension_id, event_name);
    455   if (!has_listener)
    456     AddLazyEventListener(event_name, extension_id);
    457   DispatchEventToExtension(extension_id, event.Pass());
    458   if (!has_listener)
    459     RemoveLazyEventListener(event_name, extension_id);
    460 }
    461 
    462 void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id,
    463                                     const linked_ptr<Event>& event) {
    464   // We don't expect to get events from a completely different browser context.
    465   DCHECK(!event->restrict_to_browser_context ||
    466          ExtensionsBrowserClient::Get()->IsSameContext(
    467              browser_context_, event->restrict_to_browser_context));
    468 
    469   std::set<const EventListener*> listeners(
    470       listeners_.GetEventListeners(*event));
    471 
    472   std::set<EventDispatchIdentifier> already_dispatched;
    473 
    474   // We dispatch events for lazy background pages first because attempting to do
    475   // so will cause those that are being suspended to cancel that suspension.
    476   // As canceling a suspension entails sending an event to the affected
    477   // background page, and as that event needs to be delivered before we dispatch
    478   // the event we are dispatching here, we dispatch to the lazy listeners here
    479   // first.
    480   for (std::set<const EventListener*>::iterator it = listeners.begin();
    481        it != listeners.end(); it++) {
    482     const EventListener* listener = *it;
    483     if (restrict_to_extension_id.empty() ||
    484         restrict_to_extension_id == listener->extension_id()) {
    485       if (listener->IsLazy()) {
    486         DispatchLazyEvent(listener->extension_id(), event, &already_dispatched);
    487       }
    488     }
    489   }
    490 
    491   for (std::set<const EventListener*>::iterator it = listeners.begin();
    492        it != listeners.end(); it++) {
    493     const EventListener* listener = *it;
    494     if (restrict_to_extension_id.empty() ||
    495         restrict_to_extension_id == listener->extension_id()) {
    496       if (listener->process()) {
    497         EventDispatchIdentifier dispatch_id(listener->GetBrowserContext(),
    498                                             listener->extension_id());
    499         if (!ContainsKey(already_dispatched, dispatch_id)) {
    500           DispatchEventToProcess(listener->extension_id(),
    501                                  listener->listener_url(),
    502                                  listener->process(),
    503                                  event);
    504         }
    505       }
    506     }
    507   }
    508 }
    509 
    510 void EventRouter::DispatchLazyEvent(
    511     const std::string& extension_id,
    512     const linked_ptr<Event>& event,
    513     std::set<EventDispatchIdentifier>* already_dispatched) {
    514   // Check both the original and the incognito browser context to see if we
    515   // should load a lazy bg page to handle the event. The latter case
    516   // occurs in the case of split-mode extensions.
    517   const Extension* extension =
    518       ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID(
    519           extension_id);
    520   if (!extension)
    521     return;
    522 
    523   if (MaybeLoadLazyBackgroundPageToDispatchEvent(
    524           browser_context_, extension, event)) {
    525     already_dispatched->insert(std::make_pair(browser_context_, extension_id));
    526   }
    527 
    528   ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get();
    529   if (browser_client->HasOffTheRecordContext(browser_context_) &&
    530       IncognitoInfo::IsSplitMode(extension)) {
    531     BrowserContext* incognito_context =
    532         browser_client->GetOffTheRecordContext(browser_context_);
    533     if (MaybeLoadLazyBackgroundPageToDispatchEvent(
    534             incognito_context, extension, event)) {
    535       already_dispatched->insert(
    536           std::make_pair(incognito_context, extension_id));
    537     }
    538   }
    539 }
    540 
    541 void EventRouter::DispatchEventToProcess(const std::string& extension_id,
    542                                          const GURL& listener_url,
    543                                          content::RenderProcessHost* process,
    544                                          const linked_ptr<Event>& event) {
    545   BrowserContext* listener_context = process->GetBrowserContext();
    546   ProcessMap* process_map = ProcessMap::Get(listener_context);
    547 
    548   // TODO(kalman): Convert this method to use
    549   // ProcessMap::GetMostLikelyContextType.
    550 
    551   const Extension* extension =
    552       ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID(
    553           extension_id);
    554   // NOTE: |extension| being NULL does not necessarily imply that this event
    555   // shouldn't be dispatched. Events can be dispatched to WebUI as well.
    556 
    557   if (!extension && !extension_id.empty()) {
    558     // Trying to dispatch an event to an extension that doesn't exist. The
    559     // extension could have been removed, but we do not unregister it until the
    560     // extension process is unloaded.
    561     return;
    562   }
    563 
    564   if (extension) {
    565     // Dispatching event to an extension.
    566     // If the event is privileged, only send to extension processes. Otherwise,
    567     // it's OK to send to normal renderers (e.g., for content scripts).
    568     if (!process_map->Contains(extension->id(), process->GetID()) &&
    569         !ExtensionAPI::GetSharedInstance()->IsAvailableInUntrustedContext(
    570             event->event_name, extension)) {
    571       return;
    572     }
    573 
    574     // If the event is restricted to a URL, only dispatch if the extension has
    575     // permission for it (or if the event originated from itself).
    576     if (!event->event_url.is_empty() &&
    577         event->event_url.host() != extension->id() &&
    578         !extension->permissions_data()
    579              ->active_permissions()
    580              ->HasEffectiveAccessToURL(event->event_url)) {
    581       return;
    582     }
    583 
    584     if (!CanDispatchEventToBrowserContext(listener_context, extension, event)) {
    585       return;
    586     }
    587   } else if (content::ChildProcessSecurityPolicy::GetInstance()
    588                  ->HasWebUIBindings(process->GetID())) {
    589     // Dispatching event to WebUI.
    590     if (!ExtensionAPI::GetSharedInstance()->IsAvailableToWebUI(
    591             event->event_name, listener_url)) {
    592       return;
    593     }
    594   } else {
    595     // Dispatching event to a webpage - however, all such events (e.g.
    596     // messaging) don't go through EventRouter so this should be impossible.
    597     NOTREACHED();
    598     return;
    599   }
    600 
    601   if (!event->will_dispatch_callback.is_null()) {
    602     event->will_dispatch_callback.Run(
    603         listener_context, extension, event->event_args.get());
    604   }
    605 
    606   DispatchExtensionMessage(process,
    607                            listener_context,
    608                            extension_id,
    609                            event->event_name,
    610                            event->event_args.get(),
    611                            event->user_gesture,
    612                            event->filter_info);
    613 
    614   if (extension)
    615     IncrementInFlightEvents(listener_context, extension);
    616 }
    617 
    618 bool EventRouter::CanDispatchEventToBrowserContext(
    619     BrowserContext* context,
    620     const Extension* extension,
    621     const linked_ptr<Event>& event) {
    622   // Is this event from a different browser context than the renderer (ie, an
    623   // incognito tab event sent to a normal process, or vice versa).
    624   bool cross_incognito = event->restrict_to_browser_context &&
    625                          context != event->restrict_to_browser_context;
    626   if (!cross_incognito)
    627     return true;
    628   return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
    629       extension, context);
    630 }
    631 
    632 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent(
    633     BrowserContext* context,
    634     const Extension* extension,
    635     const linked_ptr<Event>& event) {
    636   if (!CanDispatchEventToBrowserContext(context, extension, event))
    637     return false;
    638 
    639   LazyBackgroundTaskQueue* queue = ExtensionSystem::Get(
    640       context)->lazy_background_task_queue();
    641   if (queue->ShouldEnqueueTask(context, extension)) {
    642     linked_ptr<Event> dispatched_event(event);
    643 
    644     // If there's a dispatch callback, call it now (rather than dispatch time)
    645     // to avoid lifetime issues. Use a separate copy of the event args, so they
    646     // last until the event is dispatched.
    647     if (!event->will_dispatch_callback.is_null()) {
    648       dispatched_event.reset(event->DeepCopy());
    649       dispatched_event->will_dispatch_callback.Run(
    650           context, extension, dispatched_event->event_args.get());
    651       // Ensure we don't call it again at dispatch time.
    652       dispatched_event->will_dispatch_callback.Reset();
    653     }
    654 
    655     queue->AddPendingTask(context, extension->id(),
    656                           base::Bind(&EventRouter::DispatchPendingEvent,
    657                                      base::Unretained(this), dispatched_event));
    658     return true;
    659   }
    660 
    661   return false;
    662 }
    663 
    664 // static
    665 void EventRouter::IncrementInFlightEventsOnUI(
    666     void* browser_context_id,
    667     const std::string& extension_id) {
    668   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    669   BrowserContext* browser_context =
    670       reinterpret_cast<BrowserContext*>(browser_context_id);
    671   if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
    672     return;
    673   EventRouter* event_router = EventRouter::Get(browser_context);
    674   if (!event_router)
    675     return;
    676   const Extension* extension =
    677       ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID(
    678           extension_id);
    679   if (!extension)
    680     return;
    681   event_router->IncrementInFlightEvents(browser_context, extension);
    682 }
    683 
    684 void EventRouter::IncrementInFlightEvents(BrowserContext* context,
    685                                           const Extension* extension) {
    686   // Only increment in-flight events if the lazy background page is active,
    687   // because that's the only time we'll get an ACK.
    688   if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
    689     ProcessManager* pm = ExtensionSystem::Get(context)->process_manager();
    690     ExtensionHost* host = pm->GetBackgroundHostForExtension(extension->id());
    691     if (host)
    692       pm->IncrementLazyKeepaliveCount(extension);
    693   }
    694 }
    695 
    696 void EventRouter::OnEventAck(BrowserContext* context,
    697                              const std::string& extension_id) {
    698   ProcessManager* pm = ExtensionSystem::Get(context)->process_manager();
    699   ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id);
    700   // The event ACK is routed to the background host, so this should never be
    701   // NULL.
    702   CHECK(host);
    703   // TODO(mpcomplete): We should never get this message unless
    704   // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
    705   if (host->extension() &&
    706       BackgroundInfo::HasLazyBackgroundPage(host->extension()))
    707     pm->DecrementLazyKeepaliveCount(host->extension());
    708 }
    709 
    710 void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event,
    711                                        ExtensionHost* host) {
    712   if (!host)
    713     return;
    714 
    715   if (listeners_.HasProcessListener(host->render_process_host(),
    716                                     host->extension()->id())) {
    717     // URL events cannot be lazy therefore can't be pending, hence the GURL().
    718     DispatchEventToProcess(
    719         host->extension()->id(), GURL(), host->render_process_host(), event);
    720   }
    721 }
    722 
    723 void EventRouter::Observe(int type,
    724                           const content::NotificationSource& source,
    725                           const content::NotificationDetails& details) {
    726   switch (type) {
    727     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
    728     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
    729       content::RenderProcessHost* renderer =
    730           content::Source<content::RenderProcessHost>(source).ptr();
    731       // Remove all event listeners associated with this renderer.
    732       listeners_.RemoveListenersForProcess(renderer);
    733       break;
    734     }
    735     case extensions::NOTIFICATION_EXTENSION_ENABLED: {
    736       // If the extension has a lazy background page, make sure it gets loaded
    737       // to register the events the extension is interested in.
    738       const Extension* extension =
    739           content::Details<const Extension>(details).ptr();
    740       if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
    741         LazyBackgroundTaskQueue* queue = ExtensionSystem::Get(
    742             browser_context_)->lazy_background_task_queue();
    743         queue->AddPendingTask(browser_context_, extension->id(),
    744                               base::Bind(&DoNothing));
    745       }
    746       break;
    747     }
    748     default:
    749       NOTREACHED();
    750   }
    751 }
    752 
    753 void EventRouter::OnExtensionLoaded(content::BrowserContext* browser_context,
    754                                     const Extension* extension) {
    755   // Add all registered lazy listeners to our cache.
    756   std::set<std::string> registered_events =
    757       GetRegisteredEvents(extension->id());
    758   listeners_.LoadUnfilteredLazyListeners(extension->id(), registered_events);
    759   const DictionaryValue* filtered_events = GetFilteredEvents(extension->id());
    760   if (filtered_events)
    761     listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events);
    762 }
    763 
    764 void EventRouter::OnExtensionUnloaded(content::BrowserContext* browser_context,
    765                                       const Extension* extension,
    766                                       UnloadedExtensionInfo::Reason reason) {
    767   // Remove all registered lazy listeners from our cache.
    768   listeners_.RemoveLazyListenersForExtension(extension->id());
    769 }
    770 
    771 Event::Event(const std::string& event_name,
    772              scoped_ptr<base::ListValue> event_args)
    773     : event_name(event_name),
    774       event_args(event_args.Pass()),
    775       restrict_to_browser_context(NULL),
    776       user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
    777   DCHECK(this->event_args.get());
    778 }
    779 
    780 Event::Event(const std::string& event_name,
    781              scoped_ptr<base::ListValue> event_args,
    782              BrowserContext* restrict_to_browser_context)
    783     : event_name(event_name),
    784       event_args(event_args.Pass()),
    785       restrict_to_browser_context(restrict_to_browser_context),
    786       user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
    787   DCHECK(this->event_args.get());
    788 }
    789 
    790 Event::Event(const std::string& event_name,
    791              scoped_ptr<ListValue> event_args,
    792              BrowserContext* restrict_to_browser_context,
    793              const GURL& event_url,
    794              EventRouter::UserGestureState user_gesture,
    795              const EventFilteringInfo& filter_info)
    796     : event_name(event_name),
    797       event_args(event_args.Pass()),
    798       restrict_to_browser_context(restrict_to_browser_context),
    799       event_url(event_url),
    800       user_gesture(user_gesture),
    801       filter_info(filter_info) {
    802   DCHECK(this->event_args.get());
    803 }
    804 
    805 Event::~Event() {}
    806 
    807 Event* Event::DeepCopy() {
    808   Event* copy = new Event(event_name,
    809                           scoped_ptr<base::ListValue>(event_args->DeepCopy()),
    810                           restrict_to_browser_context,
    811                           event_url,
    812                           user_gesture,
    813                           filter_info);
    814   copy->will_dispatch_callback = will_dispatch_callback;
    815   return copy;
    816 }
    817 
    818 EventListenerInfo::EventListenerInfo(const std::string& event_name,
    819                                      const std::string& extension_id,
    820                                      const GURL& listener_url,
    821                                      content::BrowserContext* browser_context)
    822     : event_name(event_name),
    823       extension_id(extension_id),
    824       listener_url(listener_url),
    825       browser_context(browser_context) {
    826 }
    827 
    828 }  // namespace extensions
    829