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