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
36using base::DictionaryValue;
37using base::ListValue;
38using content::BrowserContext;
39using content::BrowserThread;
40
41namespace extensions {
42
43namespace {
44
45void 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.
49const 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.
53void 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
82const char EventRouter::kRegisteredEvents[] = "events";
83
84struct 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
102void 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
134EventRouter* EventRouter::Get(content::BrowserContext* browser_context) {
135  return ExtensionSystem::Get(browser_context)->event_router();
136}
137
138// static
139std::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
145void 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
168EventRouter::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
184EventRouter::~EventRouter() {}
185
186void 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
193void 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
201void 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
208void 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
216void 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
223void 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
234void 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
250void 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
261void 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
274void 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
288void 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
311void 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
334bool EventRouter::HasEventListener(const std::string& event_name) {
335  return listeners_.HasListenerForEvent(event_name);
336}
337
338bool EventRouter::ExtensionHasEventListener(const std::string& extension_id,
339                                            const std::string& event_name) {
340  return listeners_.HasListenerForExtension(extension_id, event_name);
341}
342
343bool 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
362std::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
381void 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
392void 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
410void 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
432const 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
440void EventRouter::BroadcastEvent(scoped_ptr<Event> event) {
441  DispatchEventImpl(std::string(), linked_ptr<Event>(event.release()));
442}
443
444void 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
450void 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
462void 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
510void 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
541void 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
618bool 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
632bool 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
665void 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
684void 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
696void 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
710void 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
723void 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
753void 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
764void 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
771Event::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
780Event::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
790Event::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
805Event::~Event() {}
806
807Event* 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
818EventListenerInfo::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