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