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