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 "chrome/browser/extensions/extension_host.h"
     16 #include "chrome/browser/extensions/extension_prefs.h"
     17 #include "chrome/browser/extensions/extension_service.h"
     18 #include "chrome/browser/extensions/extension_system.h"
     19 #include "chrome/browser/extensions/extension_util.h"
     20 #include "chrome/common/extensions/extension_messages.h"
     21 #include "content/public/browser/notification_service.h"
     22 #include "content/public/browser/render_process_host.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_urls.h"
     30 #include "extensions/common/manifest_handlers/background_info.h"
     31 #include "extensions/common/manifest_handlers/incognito_info.h"
     32 
     33 using base::DictionaryValue;
     34 using base::ListValue;
     35 using content::BrowserContext;
     36 using content::BrowserThread;
     37 
     38 namespace extensions {
     39 
     40 namespace {
     41 
     42 void DoNothing(ExtensionHost* host) {}
     43 
     44 // A dictionary of event names to lists of filters that this extension has
     45 // registered from its lazy background page.
     46 const char kFilteredEvents[] = "filtered_events";
     47 
     48 }  // namespace
     49 
     50 const char EventRouter::kRegisteredEvents[] = "events";
     51 
     52 struct EventRouter::ListenerProcess {
     53   content::RenderProcessHost* process;
     54   std::string extension_id;
     55 
     56   ListenerProcess(content::RenderProcessHost* process,
     57                   const std::string& extension_id)
     58       : process(process), extension_id(extension_id) {}
     59 
     60   bool operator<(const ListenerProcess& that) const {
     61     if (process < that.process)
     62       return true;
     63     if (process == that.process && extension_id < that.extension_id)
     64       return true;
     65     return false;
     66   }
     67 };
     68 
     69 // static
     70 void EventRouter::NotifyExtensionDispatchObserverOnUIThread(
     71     void* browser_context_id,
     72     scoped_ptr<EventDispatchInfo> details) {
     73   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     74     BrowserThread::PostTask(
     75         BrowserThread::UI,
     76         FROM_HERE,
     77         base::Bind(&NotifyExtensionDispatchObserverOnUIThread,
     78                    browser_context_id, base::Passed(&details)));
     79   } else {
     80     BrowserContext* context =
     81         reinterpret_cast<BrowserContext*>(browser_context_id);
     82     if (!ExtensionsBrowserClient::Get()->IsValidContext(context))
     83       return;
     84     ExtensionSystem* extension_system =
     85         ExtensionSystem::GetForBrowserContext(context);
     86     EventRouter* event_router = extension_system->event_router();
     87     if (!event_router)
     88       return;
     89     if (event_router->event_dispatch_observer_) {
     90       event_router->event_dispatch_observer_->OnWillDispatchEvent(
     91           details.Pass());
     92     }
     93   }
     94 }
     95 
     96 // static
     97 void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
     98                                            void* browser_context_id,
     99                                            const std::string& extension_id,
    100                                            const std::string& event_name,
    101                                            ListValue* event_args,
    102                                            UserGestureState user_gesture,
    103                                            const EventFilteringInfo& info) {
    104   NotifyExtensionDispatchObserverOnUIThread(
    105       browser_context_id,
    106       make_scoped_ptr(new EventDispatchInfo(
    107           extension_id,
    108           event_name,
    109           make_scoped_ptr(event_args->DeepCopy()))));
    110 
    111   ListValue args;
    112   args.Set(0, new base::StringValue(event_name));
    113   args.Set(1, event_args);
    114   args.Set(2, info.AsValue().release());
    115   ipc_sender->Send(new ExtensionMsg_MessageInvoke(
    116       MSG_ROUTING_CONTROL,
    117       extension_id,
    118       kEventBindings,
    119       "dispatchEvent",
    120       args,
    121       user_gesture == USER_GESTURE_ENABLED));
    122 
    123   // DispatchExtensionMessage does _not_ take ownership of event_args, so we
    124   // must ensure that the destruction of args does not attempt to free it.
    125   scoped_ptr<Value> removed_event_args;
    126   args.Remove(1, &removed_event_args);
    127   ignore_result(removed_event_args.release());
    128 }
    129 
    130 // static
    131 std::string EventRouter::GetBaseEventName(const std::string& full_event_name) {
    132   size_t slash_sep = full_event_name.find('/');
    133   return full_event_name.substr(0, slash_sep);
    134 }
    135 
    136 // static
    137 void EventRouter::DispatchEvent(IPC::Sender* ipc_sender,
    138                                 void* browser_context_id,
    139                                 const std::string& extension_id,
    140                                 const std::string& event_name,
    141                                 scoped_ptr<ListValue> event_args,
    142                                 UserGestureState user_gesture,
    143                                 const EventFilteringInfo& info) {
    144   DispatchExtensionMessage(ipc_sender,
    145                            browser_context_id,
    146                            extension_id,
    147                            event_name,
    148                            event_args.get(),
    149                            user_gesture,
    150                            info);
    151 
    152   BrowserThread::PostTask(
    153       BrowserThread::UI,
    154       FROM_HERE,
    155       base::Bind(&EventRouter::IncrementInFlightEventsOnUI,
    156                   browser_context_id,
    157                   extension_id));
    158 }
    159 
    160 EventRouter::EventRouter(BrowserContext* browser_context,
    161                          ExtensionPrefs* extension_prefs)
    162     : browser_context_(browser_context),
    163       extension_prefs_(extension_prefs),
    164       listeners_(this),
    165       event_dispatch_observer_(NULL) {
    166   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
    167                  content::NotificationService::AllSources());
    168   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
    169                  content::NotificationService::AllSources());
    170   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED,
    171                  content::Source<BrowserContext>(browser_context_));
    172   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
    173                  content::Source<BrowserContext>(browser_context_));
    174   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
    175                  content::Source<BrowserContext>(browser_context_));
    176 }
    177 
    178 EventRouter::~EventRouter() {}
    179 
    180 void EventRouter::AddEventListener(const std::string& event_name,
    181                                    content::RenderProcessHost* process,
    182                                    const std::string& extension_id) {
    183   listeners_.AddListener(scoped_ptr<EventListener>(new EventListener(
    184       event_name, extension_id, process, scoped_ptr<DictionaryValue>())));
    185 }
    186 
    187 void EventRouter::RemoveEventListener(const std::string& event_name,
    188                                       content::RenderProcessHost* process,
    189                                       const std::string& extension_id) {
    190   EventListener listener(event_name, extension_id, process,
    191                          scoped_ptr<DictionaryValue>());
    192   listeners_.RemoveListener(&listener);
    193 }
    194 
    195 void EventRouter::RegisterObserver(Observer* observer,
    196                                    const std::string& event_name) {
    197   // Observing sub-event names like "foo.onBar/123" is not allowed.
    198   DCHECK(event_name.find('/') == std::string::npos);
    199   observers_[event_name] = observer;
    200 }
    201 
    202 void EventRouter::UnregisterObserver(Observer* observer) {
    203   std::vector<ObserverMap::iterator> iters_to_remove;
    204   for (ObserverMap::iterator iter = observers_.begin();
    205        iter != observers_.end(); ++iter) {
    206     if (iter->second == observer)
    207       iters_to_remove.push_back(iter);
    208   }
    209   for (size_t i = 0; i < iters_to_remove.size(); ++i)
    210     observers_.erase(iters_to_remove[i]);
    211 }
    212 
    213 void EventRouter::SetEventDispatchObserver(EventDispatchObserver* observer) {
    214   CHECK(!event_dispatch_observer_);
    215   event_dispatch_observer_ = observer;
    216 }
    217 
    218 void EventRouter::OnListenerAdded(const EventListener* listener) {
    219   const EventListenerInfo details(
    220       listener->event_name,
    221       listener->extension_id,
    222       listener->process ? listener->process->GetBrowserContext() : NULL);
    223   std::string base_event_name = GetBaseEventName(listener->event_name);
    224   ObserverMap::iterator observer = observers_.find(base_event_name);
    225   if (observer != observers_.end())
    226     observer->second->OnListenerAdded(details);
    227 }
    228 
    229 void EventRouter::OnListenerRemoved(const EventListener* listener) {
    230   const EventListenerInfo details(
    231       listener->event_name,
    232       listener->extension_id,
    233       listener->process ? listener->process->GetBrowserContext() : NULL);
    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.process = NULL;
    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 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->process) {
    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(
    471             listener->process->GetBrowserContext(), listener->extension_id);
    472         if (!ContainsKey(already_dispatched, dispatch_id)) {
    473           DispatchEventToProcess(listener->extension_id, listener->process,
    474               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   ExtensionService* service = ExtensionSystem::GetForBrowserContext(
    486       browser_context_)->extension_service();
    487   // Check both the original and the incognito browser context to see if we
    488   // should load a lazy bg page to handle the event. The latter case
    489   // occurs in the case of split-mode extensions.
    490   const Extension* extension = service->extensions()->GetByID(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   ExtensionService* service = ExtensionSystem::GetForBrowserContext(
    516       browser_context_)->extension_service();
    517   const Extension* extension = service->extensions()->GetByID(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 =
    526       ExtensionSystem::GetForBrowserContext(listener_context)
    527           ->extension_service()
    528           ->process_map();
    529   // If the event is privileged, only send to extension processes. Otherwise,
    530   // it's OK to send to normal renderers (e.g., for content scripts).
    531   if (ExtensionAPI::GetSharedInstance()->IsPrivileged(event->event_name) &&
    532       !process_map->Contains(extension->id(), process->GetID())) {
    533     return;
    534   }
    535 
    536   // If the event is restricted to a URL, only dispatch if the extension has
    537   // permission for it (or if the event originated from itself).
    538   if (!event->event_url.is_empty() &&
    539       event->event_url.host() != extension->id() &&
    540       !extension->GetActivePermissions()->HasEffectiveAccessToURL(
    541           event->event_url)) {
    542     return;
    543   }
    544 
    545   if (!CanDispatchEventToBrowserContext(listener_context, extension, event))
    546     return;
    547 
    548   if (!event->will_dispatch_callback.is_null()) {
    549     event->will_dispatch_callback.Run(listener_context, extension,
    550                                       event->event_args.get());
    551   }
    552 
    553   DispatchExtensionMessage(process, listener_context, extension->id(),
    554                            event->event_name, event->event_args.get(),
    555                            event->user_gesture, event->filter_info);
    556   IncrementInFlightEvents(listener_context, extension);
    557 }
    558 
    559 bool EventRouter::CanDispatchEventToBrowserContext(
    560     BrowserContext* context,
    561     const Extension* extension,
    562     const linked_ptr<Event>& event) {
    563   // Is this event from a different browser context than the renderer (ie, an
    564   // incognito tab event sent to a normal process, or vice versa).
    565   bool cross_incognito = event->restrict_to_browser_context &&
    566                          context != event->restrict_to_browser_context;
    567   if (!cross_incognito)
    568     return true;
    569   ExtensionService* service =
    570       ExtensionSystem::GetForBrowserContext(context)->extension_service();
    571   return extension_util::CanCrossIncognito(extension, service);
    572 }
    573 
    574 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent(
    575     BrowserContext* context,
    576     const Extension* extension,
    577     const linked_ptr<Event>& event) {
    578   if (!CanDispatchEventToBrowserContext(context, extension, event))
    579     return false;
    580 
    581   LazyBackgroundTaskQueue* queue = ExtensionSystem::GetForBrowserContext(
    582       context)->lazy_background_task_queue();
    583   if (queue->ShouldEnqueueTask(context, extension)) {
    584     linked_ptr<Event> dispatched_event(event);
    585 
    586     // If there's a dispatch callback, call it now (rather than dispatch time)
    587     // to avoid lifetime issues. Use a separate copy of the event args, so they
    588     // last until the event is dispatched.
    589     if (!event->will_dispatch_callback.is_null()) {
    590       dispatched_event.reset(event->DeepCopy());
    591       dispatched_event->will_dispatch_callback.Run(
    592           context, extension, dispatched_event->event_args.get());
    593       // Ensure we don't call it again at dispatch time.
    594       dispatched_event->will_dispatch_callback.Reset();
    595     }
    596 
    597     queue->AddPendingTask(context, extension->id(),
    598                           base::Bind(&EventRouter::DispatchPendingEvent,
    599                                      base::Unretained(this), dispatched_event));
    600     return true;
    601   }
    602 
    603   return false;
    604 }
    605 
    606 // static
    607 void EventRouter::IncrementInFlightEventsOnUI(
    608     void* browser_context_id,
    609     const std::string& extension_id) {
    610   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    611   BrowserContext* browser_context =
    612       reinterpret_cast<BrowserContext*>(browser_context_id);
    613   if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
    614     return;
    615   ExtensionSystem* extension_system =
    616       ExtensionSystem::GetForBrowserContext(browser_context);
    617   EventRouter* event_router = extension_system->event_router();
    618   if (!event_router)
    619     return;
    620   ExtensionService* extension_service = extension_system->extension_service();
    621   const Extension* extension =
    622       extension_service->extensions()->GetByID(extension_id);
    623   if (!extension)
    624     return;
    625   event_router->IncrementInFlightEvents(browser_context, extension);
    626 }
    627 
    628 void EventRouter::IncrementInFlightEvents(BrowserContext* context,
    629                                           const Extension* extension) {
    630   // Only increment in-flight events if the lazy background page is active,
    631   // because that's the only time we'll get an ACK.
    632   if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
    633     ProcessManager* pm =
    634         ExtensionSystem::GetForBrowserContext(context)->process_manager();
    635     ExtensionHost* host = pm->GetBackgroundHostForExtension(extension->id());
    636     if (host)
    637       pm->IncrementLazyKeepaliveCount(extension);
    638   }
    639 }
    640 
    641 void EventRouter::OnEventAck(BrowserContext* context,
    642                              const std::string& extension_id) {
    643   ProcessManager* pm =
    644       ExtensionSystem::GetForBrowserContext(context)->process_manager();
    645   ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id);
    646   // The event ACK is routed to the background host, so this should never be
    647   // NULL.
    648   CHECK(host);
    649   // TODO(mpcomplete): We should never get this message unless
    650   // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
    651   if (host->extension() &&
    652       BackgroundInfo::HasLazyBackgroundPage(host->extension()))
    653     pm->DecrementLazyKeepaliveCount(host->extension());
    654 }
    655 
    656 void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event,
    657                                        ExtensionHost* host) {
    658   if (!host)
    659     return;
    660 
    661   if (listeners_.HasProcessListener(host->render_process_host(),
    662                                     host->extension()->id())) {
    663     DispatchEventToProcess(host->extension()->id(),
    664                            host->render_process_host(), event);
    665   }
    666 }
    667 
    668 void EventRouter::Observe(int type,
    669                           const content::NotificationSource& source,
    670                           const content::NotificationDetails& details) {
    671   switch (type) {
    672     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
    673     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
    674       content::RenderProcessHost* renderer =
    675           content::Source<content::RenderProcessHost>(source).ptr();
    676       // Remove all event listeners associated with this renderer.
    677       listeners_.RemoveListenersForProcess(renderer);
    678       break;
    679     }
    680     case chrome::NOTIFICATION_EXTENSION_ENABLED: {
    681       // If the extension has a lazy background page, make sure it gets loaded
    682       // to register the events the extension is interested in.
    683       const Extension* extension =
    684           content::Details<const Extension>(details).ptr();
    685       if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
    686         LazyBackgroundTaskQueue* queue = ExtensionSystem::GetForBrowserContext(
    687             browser_context_)->lazy_background_task_queue();
    688         queue->AddPendingTask(browser_context_, extension->id(),
    689                               base::Bind(&DoNothing));
    690       }
    691       break;
    692     }
    693     case chrome::NOTIFICATION_EXTENSION_LOADED: {
    694       // Add all registered lazy listeners to our cache.
    695       const Extension* extension =
    696           content::Details<const Extension>(details).ptr();
    697       std::set<std::string> registered_events =
    698           GetRegisteredEvents(extension->id());
    699       listeners_.LoadUnfilteredLazyListeners(extension->id(),
    700                                              registered_events);
    701       const DictionaryValue* filtered_events =
    702           GetFilteredEvents(extension->id());
    703       if (filtered_events)
    704         listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events);
    705       break;
    706     }
    707     case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
    708       // Remove all registered lazy listeners from our cache.
    709       UnloadedExtensionInfo* unloaded =
    710           content::Details<UnloadedExtensionInfo>(details).ptr();
    711       listeners_.RemoveLazyListenersForExtension(unloaded->extension->id());
    712       break;
    713     }
    714     default:
    715       NOTREACHED();
    716       return;
    717   }
    718 }
    719 
    720 Event::Event(const std::string& event_name,
    721              scoped_ptr<base::ListValue> event_args)
    722     : event_name(event_name),
    723       event_args(event_args.Pass()),
    724       restrict_to_browser_context(NULL),
    725       user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
    726   DCHECK(this->event_args.get());
    727 }
    728 
    729 Event::Event(const std::string& event_name,
    730              scoped_ptr<base::ListValue> event_args,
    731              BrowserContext* restrict_to_browser_context)
    732     : event_name(event_name),
    733       event_args(event_args.Pass()),
    734       restrict_to_browser_context(restrict_to_browser_context),
    735       user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
    736   DCHECK(this->event_args.get());
    737 }
    738 
    739 Event::Event(const std::string& event_name,
    740              scoped_ptr<ListValue> event_args,
    741              BrowserContext* restrict_to_browser_context,
    742              const GURL& event_url,
    743              EventRouter::UserGestureState user_gesture,
    744              const EventFilteringInfo& filter_info)
    745     : event_name(event_name),
    746       event_args(event_args.Pass()),
    747       restrict_to_browser_context(restrict_to_browser_context),
    748       event_url(event_url),
    749       user_gesture(user_gesture),
    750       filter_info(filter_info) {
    751   DCHECK(this->event_args.get());
    752 }
    753 
    754 Event::~Event() {}
    755 
    756 Event* Event::DeepCopy() {
    757   Event* copy = new Event(event_name,
    758                           scoped_ptr<base::ListValue>(event_args->DeepCopy()),
    759                           restrict_to_browser_context,
    760                           event_url,
    761                           user_gesture,
    762                           filter_info);
    763   copy->will_dispatch_callback = will_dispatch_callback;
    764   return copy;
    765 }
    766 
    767 EventListenerInfo::EventListenerInfo(const std::string& event_name,
    768                                      const std::string& extension_id,
    769                                      content::BrowserContext* browser_context)
    770     : event_name(event_name),
    771       extension_id(extension_id),
    772       browser_context(browser_context) {}
    773 
    774 EventDispatchInfo::EventDispatchInfo(const std::string& extension_id,
    775                                      const std::string& event_name,
    776                                      scoped_ptr<ListValue> event_args)
    777     : extension_id(extension_id),
    778       event_name(event_name),
    779       event_args(event_args.Pass()) {}
    780 
    781 EventDispatchInfo::~EventDispatchInfo() {}
    782 
    783 }  // namespace extensions
    784