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