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.
5 #include "extensions/browser/event_router.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 "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/process_manager.h"
25 #include "extensions/browser/process_map.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/extension_api.h"
28 #include "extensions/common/extension_messages.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"
33 using base::DictionaryValue
;
34 using base::ListValue
;
35 using content::BrowserContext
;
36 using content::BrowserThread
;
38 namespace extensions
{
42 void DoNothing(ExtensionHost
* host
) {}
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";
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(
59 base::Bind(&NotifyApiEventDispatched
,
63 base::Passed(&args
)));
67 // Notify the ApiActivityMonitor about the event dispatch.
68 BrowserContext
* context
= static_cast<BrowserContext
*>(browser_context_id
);
69 if (!ExtensionsBrowserClient::Get()->IsValidContext(context
))
71 ApiActivityMonitor
* monitor
=
72 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(context
);
74 monitor
->OnApiEventDispatched(extension_id
, event_name
, args
.Pass());
79 const char EventRouter::kRegisteredEvents
[] = "events";
81 struct EventRouter::ListenerProcess
{
82 content::RenderProcessHost
* process
;
83 std::string extension_id
;
85 ListenerProcess(content::RenderProcessHost
* process
,
86 const std::string
& extension_id
)
87 : process(process
), extension_id(extension_id
) {}
89 bool operator<(const ListenerProcess
& that
) const {
90 if (process
< that
.process
)
92 if (process
== that
.process
&& extension_id
< that
.extension_id
)
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
,
109 make_scoped_ptr(event_args
->DeepCopy()));
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(
121 user_gesture
== USER_GESTURE_ENABLED
));
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());
131 EventRouter
* EventRouter::Get(content::BrowserContext
* browser_context
) {
132 return ExtensionSystem::Get(browser_context
)->event_router();
136 std::string
EventRouter::GetBaseEventName(const std::string
& full_event_name
) {
137 size_t slash_sep
= full_event_name
.find('/');
138 return full_event_name
.substr(0, slash_sep
);
142 void EventRouter::DispatchEvent(IPC::Sender
* ipc_sender
,
143 void* browser_context_id
,
144 const std::string
& extension_id
,
145 const std::string
& event_name
,
146 scoped_ptr
<ListValue
> event_args
,
147 UserGestureState user_gesture
,
148 const EventFilteringInfo
& info
) {
149 DispatchExtensionMessage(ipc_sender
,
157 BrowserThread::PostTask(
160 base::Bind(&EventRouter::IncrementInFlightEventsOnUI
,
165 EventRouter::EventRouter(BrowserContext
* browser_context
,
166 ExtensionPrefs
* extension_prefs
)
167 : browser_context_(browser_context
),
168 extension_prefs_(extension_prefs
),
170 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
171 content::NotificationService::AllSources());
172 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
173 content::NotificationService::AllSources());
174 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED
,
175 content::Source
<BrowserContext
>(browser_context_
));
176 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED
,
177 content::Source
<BrowserContext
>(browser_context_
));
178 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
,
179 content::Source
<BrowserContext
>(browser_context_
));
182 EventRouter::~EventRouter() {}
184 void EventRouter::AddEventListener(const std::string
& event_name
,
185 content::RenderProcessHost
* process
,
186 const std::string
& extension_id
) {
187 listeners_
.AddListener(scoped_ptr
<EventListener
>(new EventListener(
188 event_name
, extension_id
, process
, scoped_ptr
<DictionaryValue
>())));
191 void EventRouter::RemoveEventListener(const std::string
& event_name
,
192 content::RenderProcessHost
* process
,
193 const std::string
& extension_id
) {
194 EventListener
listener(event_name
, extension_id
, process
,
195 scoped_ptr
<DictionaryValue
>());
196 listeners_
.RemoveListener(&listener
);
199 void EventRouter::RegisterObserver(Observer
* observer
,
200 const std::string
& event_name
) {
201 // Observing sub-event names like "foo.onBar/123" is not allowed.
202 DCHECK(event_name
.find('/') == std::string::npos
);
203 observers_
[event_name
] = observer
;
206 void EventRouter::UnregisterObserver(Observer
* observer
) {
207 std::vector
<ObserverMap::iterator
> iters_to_remove
;
208 for (ObserverMap::iterator iter
= observers_
.begin();
209 iter
!= observers_
.end(); ++iter
) {
210 if (iter
->second
== observer
)
211 iters_to_remove
.push_back(iter
);
213 for (size_t i
= 0; i
< iters_to_remove
.size(); ++i
)
214 observers_
.erase(iters_to_remove
[i
]);
217 void EventRouter::OnListenerAdded(const EventListener
* listener
) {
218 const EventListenerInfo
details(
219 listener
->event_name
,
220 listener
->extension_id
,
221 listener
->process
? listener
->process
->GetBrowserContext() : NULL
);
222 std::string base_event_name
= GetBaseEventName(listener
->event_name
);
223 ObserverMap::iterator observer
= observers_
.find(base_event_name
);
224 if (observer
!= observers_
.end())
225 observer
->second
->OnListenerAdded(details
);
228 void EventRouter::OnListenerRemoved(const EventListener
* listener
) {
229 const EventListenerInfo
details(
230 listener
->event_name
,
231 listener
->extension_id
,
232 listener
->process
? listener
->process
->GetBrowserContext() : NULL
);
233 std::string base_event_name
= GetBaseEventName(listener
->event_name
);
234 ObserverMap::iterator observer
= observers_
.find(base_event_name
);
235 if (observer
!= observers_
.end())
236 observer
->second
->OnListenerRemoved(details
);
239 void EventRouter::AddLazyEventListener(const std::string
& event_name
,
240 const std::string
& extension_id
) {
241 scoped_ptr
<EventListener
> listener(new EventListener(
242 event_name
, extension_id
, NULL
, scoped_ptr
<DictionaryValue
>()));
243 bool is_new
= listeners_
.AddListener(listener
.Pass());
246 std::set
<std::string
> events
= GetRegisteredEvents(extension_id
);
247 bool prefs_is_new
= events
.insert(event_name
).second
;
249 SetRegisteredEvents(extension_id
, events
);
253 void EventRouter::RemoveLazyEventListener(const std::string
& event_name
,
254 const std::string
& extension_id
) {
255 EventListener
listener(event_name
, extension_id
, NULL
,
256 scoped_ptr
<DictionaryValue
>());
257 bool did_exist
= listeners_
.RemoveListener(&listener
);
260 std::set
<std::string
> events
= GetRegisteredEvents(extension_id
);
261 bool prefs_did_exist
= events
.erase(event_name
) > 0;
262 DCHECK(prefs_did_exist
);
263 SetRegisteredEvents(extension_id
, events
);
267 void EventRouter::AddFilteredEventListener(const std::string
& event_name
,
268 content::RenderProcessHost
* process
,
269 const std::string
& extension_id
,
270 const base::DictionaryValue
& filter
,
271 bool add_lazy_listener
) {
272 listeners_
.AddListener(scoped_ptr
<EventListener
>(new EventListener(
273 event_name
, extension_id
, process
,
274 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy()))));
276 if (add_lazy_listener
) {
277 bool added
= listeners_
.AddListener(scoped_ptr
<EventListener
>(
278 new EventListener(event_name
, extension_id
, NULL
,
279 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy()))));
282 AddFilterToEvent(event_name
, extension_id
, &filter
);
286 void EventRouter::RemoveFilteredEventListener(
287 const std::string
& event_name
,
288 content::RenderProcessHost
* process
,
289 const std::string
& extension_id
,
290 const base::DictionaryValue
& filter
,
291 bool remove_lazy_listener
) {
292 EventListener
listener(event_name
, extension_id
, process
,
293 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy()));
295 listeners_
.RemoveListener(&listener
);
297 if (remove_lazy_listener
) {
298 listener
.process
= NULL
;
299 bool removed
= listeners_
.RemoveListener(&listener
);
302 RemoveFilterFromEvent(event_name
, extension_id
, &filter
);
306 bool EventRouter::HasEventListener(const std::string
& event_name
) {
307 return listeners_
.HasListenerForEvent(event_name
);
310 bool EventRouter::ExtensionHasEventListener(const std::string
& extension_id
,
311 const std::string
& event_name
) {
312 return listeners_
.HasListenerForExtension(extension_id
, event_name
);
315 bool EventRouter::HasEventListenerImpl(const ListenerMap
& listener_map
,
316 const std::string
& extension_id
,
317 const std::string
& event_name
) {
318 ListenerMap::const_iterator it
= listener_map
.find(event_name
);
319 if (it
== listener_map
.end())
322 const std::set
<ListenerProcess
>& listeners
= it
->second
;
323 if (extension_id
.empty())
324 return !listeners
.empty();
326 for (std::set
<ListenerProcess
>::const_iterator listener
= listeners
.begin();
327 listener
!= listeners
.end(); ++listener
) {
328 if (listener
->extension_id
== extension_id
)
334 std::set
<std::string
> EventRouter::GetRegisteredEvents(
335 const std::string
& extension_id
) {
336 std::set
<std::string
> events
;
337 const ListValue
* events_value
= NULL
;
339 if (!extension_prefs_
||
340 !extension_prefs_
->ReadPrefAsList(
341 extension_id
, kRegisteredEvents
, &events_value
)) {
345 for (size_t i
= 0; i
< events_value
->GetSize(); ++i
) {
347 if (events_value
->GetString(i
, &event
))
348 events
.insert(event
);
353 void EventRouter::SetRegisteredEvents(const std::string
& extension_id
,
354 const std::set
<std::string
>& events
) {
355 ListValue
* events_value
= new ListValue
;
356 for (std::set
<std::string
>::const_iterator iter
= events
.begin();
357 iter
!= events
.end(); ++iter
) {
358 events_value
->Append(new base::StringValue(*iter
));
360 extension_prefs_
->UpdateExtensionPref(
361 extension_id
, kRegisteredEvents
, events_value
);
364 void EventRouter::AddFilterToEvent(const std::string
& event_name
,
365 const std::string
& extension_id
,
366 const DictionaryValue
* filter
) {
367 ExtensionPrefs::ScopedDictionaryUpdate
update(
368 extension_prefs_
, extension_id
, kFilteredEvents
);
369 DictionaryValue
* filtered_events
= update
.Get();
370 if (!filtered_events
)
371 filtered_events
= update
.Create();
373 ListValue
* filter_list
= NULL
;
374 if (!filtered_events
->GetList(event_name
, &filter_list
)) {
375 filter_list
= new ListValue
;
376 filtered_events
->SetWithoutPathExpansion(event_name
, filter_list
);
379 filter_list
->Append(filter
->DeepCopy());
382 void EventRouter::RemoveFilterFromEvent(const std::string
& event_name
,
383 const std::string
& extension_id
,
384 const DictionaryValue
* filter
) {
385 ExtensionPrefs::ScopedDictionaryUpdate
update(
386 extension_prefs_
, extension_id
, kFilteredEvents
);
387 DictionaryValue
* filtered_events
= update
.Get();
388 ListValue
* filter_list
= NULL
;
389 if (!filtered_events
||
390 !filtered_events
->GetListWithoutPathExpansion(event_name
, &filter_list
)) {
394 for (size_t i
= 0; i
< filter_list
->GetSize(); i
++) {
395 DictionaryValue
* filter
= NULL
;
396 CHECK(filter_list
->GetDictionary(i
, &filter
));
397 if (filter
->Equals(filter
)) {
398 filter_list
->Remove(i
, NULL
);
404 const DictionaryValue
* EventRouter::GetFilteredEvents(
405 const std::string
& extension_id
) {
406 const DictionaryValue
* events
= NULL
;
407 extension_prefs_
->ReadPrefAsDictionary(
408 extension_id
, kFilteredEvents
, &events
);
412 void EventRouter::BroadcastEvent(scoped_ptr
<Event
> event
) {
413 DispatchEventImpl(std::string(), linked_ptr
<Event
>(event
.release()));
416 void EventRouter::DispatchEventToExtension(const std::string
& extension_id
,
417 scoped_ptr
<Event
> event
) {
418 DCHECK(!extension_id
.empty());
419 DispatchEventImpl(extension_id
, linked_ptr
<Event
>(event
.release()));
422 void EventRouter::DispatchEventWithLazyListener(const std::string
& extension_id
,
423 scoped_ptr
<Event
> event
) {
424 DCHECK(!extension_id
.empty());
425 std::string event_name
= event
->event_name
;
426 bool has_listener
= ExtensionHasEventListener(extension_id
, event_name
);
428 AddLazyEventListener(event_name
, extension_id
);
429 DispatchEventToExtension(extension_id
, event
.Pass());
431 RemoveLazyEventListener(event_name
, extension_id
);
434 void EventRouter::DispatchEventImpl(const std::string
& restrict_to_extension_id
,
435 const linked_ptr
<Event
>& event
) {
436 // We don't expect to get events from a completely different browser context.
437 DCHECK(!event
->restrict_to_browser_context
||
438 ExtensionsBrowserClient::Get()->IsSameContext(
439 browser_context_
, event
->restrict_to_browser_context
));
441 std::set
<const EventListener
*> listeners(
442 listeners_
.GetEventListeners(*event
));
444 std::set
<EventDispatchIdentifier
> already_dispatched
;
446 // We dispatch events for lazy background pages first because attempting to do
447 // so will cause those that are being suspended to cancel that suspension.
448 // As canceling a suspension entails sending an event to the affected
449 // background page, and as that event needs to be delivered before we dispatch
450 // the event we are dispatching here, we dispatch to the lazy listeners here
452 for (std::set
<const EventListener
*>::iterator it
= listeners
.begin();
453 it
!= listeners
.end(); it
++) {
454 const EventListener
* listener
= *it
;
455 if (restrict_to_extension_id
.empty() ||
456 restrict_to_extension_id
== listener
->extension_id
) {
457 if (!listener
->process
) {
458 DispatchLazyEvent(listener
->extension_id
, event
, &already_dispatched
);
463 for (std::set
<const EventListener
*>::iterator it
= listeners
.begin();
464 it
!= listeners
.end(); it
++) {
465 const EventListener
* listener
= *it
;
466 if (restrict_to_extension_id
.empty() ||
467 restrict_to_extension_id
== listener
->extension_id
) {
468 if (listener
->process
) {
469 EventDispatchIdentifier
dispatch_id(
470 listener
->process
->GetBrowserContext(), listener
->extension_id
);
471 if (!ContainsKey(already_dispatched
, dispatch_id
)) {
472 DispatchEventToProcess(listener
->extension_id
, listener
->process
,
480 void EventRouter::DispatchLazyEvent(
481 const std::string
& extension_id
,
482 const linked_ptr
<Event
>& event
,
483 std::set
<EventDispatchIdentifier
>* already_dispatched
) {
484 // Check both the original and the incognito browser context to see if we
485 // should load a lazy bg page to handle the event. The latter case
486 // occurs in the case of split-mode extensions.
487 const Extension
* extension
=
488 ExtensionRegistry::Get(browser_context_
)->enabled_extensions().GetByID(
493 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
494 browser_context_
, extension
, event
)) {
495 already_dispatched
->insert(std::make_pair(browser_context_
, extension_id
));
498 ExtensionsBrowserClient
* browser_client
= ExtensionsBrowserClient::Get();
499 if (browser_client
->HasOffTheRecordContext(browser_context_
) &&
500 IncognitoInfo::IsSplitMode(extension
)) {
501 BrowserContext
* incognito_context
=
502 browser_client
->GetOffTheRecordContext(browser_context_
);
503 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
504 incognito_context
, extension
, event
)) {
505 already_dispatched
->insert(
506 std::make_pair(incognito_context
, extension_id
));
511 void EventRouter::DispatchEventToProcess(const std::string
& extension_id
,
512 content::RenderProcessHost
* process
,
513 const linked_ptr
<Event
>& event
) {
514 const Extension
* extension
=
515 ExtensionRegistry::Get(browser_context_
)->enabled_extensions().GetByID(
518 // The extension could have been removed, but we do not unregister it until
519 // the extension process is unloaded.
523 BrowserContext
* listener_context
= process
->GetBrowserContext();
524 ProcessMap
* process_map
= ProcessMap::Get(listener_context
);
525 // If the event is privileged, only send to extension processes. Otherwise,
526 // it's OK to send to normal renderers (e.g., for content scripts).
527 if (ExtensionAPI::GetSharedInstance()->IsPrivileged(event
->event_name
) &&
528 !process_map
->Contains(extension
->id(), process
->GetID())) {
532 // If the event is restricted to a URL, only dispatch if the extension has
533 // permission for it (or if the event originated from itself).
534 if (!event
->event_url
.is_empty() &&
535 event
->event_url
.host() != extension
->id() &&
536 !extension
->GetActivePermissions()->HasEffectiveAccessToURL(
541 if (!CanDispatchEventToBrowserContext(listener_context
, extension
, event
))
544 if (!event
->will_dispatch_callback
.is_null()) {
545 event
->will_dispatch_callback
.Run(listener_context
, extension
,
546 event
->event_args
.get());
549 DispatchExtensionMessage(process
, listener_context
, extension
->id(),
550 event
->event_name
, event
->event_args
.get(),
551 event
->user_gesture
, event
->filter_info
);
552 IncrementInFlightEvents(listener_context
, extension
);
555 bool EventRouter::CanDispatchEventToBrowserContext(
556 BrowserContext
* context
,
557 const Extension
* extension
,
558 const linked_ptr
<Event
>& event
) {
559 // Is this event from a different browser context than the renderer (ie, an
560 // incognito tab event sent to a normal process, or vice versa).
561 bool cross_incognito
= event
->restrict_to_browser_context
&&
562 context
!= event
->restrict_to_browser_context
;
563 if (!cross_incognito
)
565 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
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
576 ProcessManager
* pm
= ExtensionSystem::Get(context
)->process_manager();
577 if (!pm
->GetBackgroundHostForExtension(extension
->id()))
581 if (!CanDispatchEventToBrowserContext(context
, extension
, event
))
584 LazyBackgroundTaskQueue
* queue
= ExtensionSystem::Get(
585 context
)->lazy_background_task_queue();
586 if (queue
->ShouldEnqueueTask(context
, extension
)) {
587 linked_ptr
<Event
> dispatched_event(event
);
589 // If there's a dispatch callback, call it now (rather than dispatch time)
590 // to avoid lifetime issues. Use a separate copy of the event args, so they
591 // last until the event is dispatched.
592 if (!event
->will_dispatch_callback
.is_null()) {
593 dispatched_event
.reset(event
->DeepCopy());
594 dispatched_event
->will_dispatch_callback
.Run(
595 context
, extension
, dispatched_event
->event_args
.get());
596 // Ensure we don't call it again at dispatch time.
597 dispatched_event
->will_dispatch_callback
.Reset();
600 queue
->AddPendingTask(context
, extension
->id(),
601 base::Bind(&EventRouter::DispatchPendingEvent
,
602 base::Unretained(this), dispatched_event
));
610 void EventRouter::IncrementInFlightEventsOnUI(
611 void* browser_context_id
,
612 const std::string
& extension_id
) {
613 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
614 BrowserContext
* browser_context
=
615 reinterpret_cast<BrowserContext
*>(browser_context_id
);
616 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context
))
618 ExtensionSystem
* extension_system
= ExtensionSystem::Get(browser_context
);
619 EventRouter
* event_router
= extension_system
->event_router();
622 const Extension
* extension
=
623 ExtensionRegistry::Get(browser_context
)->enabled_extensions().GetByID(
627 event_router
->IncrementInFlightEvents(browser_context
, extension
);
630 void EventRouter::IncrementInFlightEvents(BrowserContext
* context
,
631 const Extension
* extension
) {
632 // Only increment in-flight events if the lazy background page is active,
633 // because that's the only time we'll get an ACK.
634 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
635 ProcessManager
* pm
= ExtensionSystem::Get(context
)->process_manager();
636 ExtensionHost
* host
= pm
->GetBackgroundHostForExtension(extension
->id());
638 pm
->IncrementLazyKeepaliveCount(extension
);
642 void EventRouter::OnEventAck(BrowserContext
* context
,
643 const std::string
& extension_id
) {
644 ProcessManager
* pm
= ExtensionSystem::Get(context
)->process_manager();
645 ExtensionHost
* host
= pm
->GetBackgroundHostForExtension(extension_id
);
646 // The event ACK is routed to the background host, so this should never be
649 // TODO(mpcomplete): We should never get this message unless
650 // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
651 if (host
->extension() &&
652 BackgroundInfo::HasLazyBackgroundPage(host
->extension()))
653 pm
->DecrementLazyKeepaliveCount(host
->extension());
656 void EventRouter::DispatchPendingEvent(const linked_ptr
<Event
>& event
,
657 ExtensionHost
* host
) {
661 if (listeners_
.HasProcessListener(host
->render_process_host(),
662 host
->extension()->id())) {
663 DispatchEventToProcess(host
->extension()->id(),
664 host
->render_process_host(), event
);
668 void EventRouter::Observe(int type
,
669 const content::NotificationSource
& source
,
670 const content::NotificationDetails
& details
) {
672 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
:
673 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
674 content::RenderProcessHost
* renderer
=
675 content::Source
<content::RenderProcessHost
>(source
).ptr();
676 // Remove all event listeners associated with this renderer.
677 listeners_
.RemoveListenersForProcess(renderer
);
680 case chrome::NOTIFICATION_EXTENSION_ENABLED
: {
681 // If the extension has a lazy background page, make sure it gets loaded
682 // to register the events the extension is interested in.
683 const Extension
* extension
=
684 content::Details
<const Extension
>(details
).ptr();
685 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
686 LazyBackgroundTaskQueue
* queue
= ExtensionSystem::Get(
687 browser_context_
)->lazy_background_task_queue();
688 queue
->AddPendingTask(browser_context_
, extension
->id(),
689 base::Bind(&DoNothing
));
693 case chrome::NOTIFICATION_EXTENSION_LOADED
: {
694 // Add all registered lazy listeners to our cache.
695 const Extension
* extension
=
696 content::Details
<const Extension
>(details
).ptr();
697 std::set
<std::string
> registered_events
=
698 GetRegisteredEvents(extension
->id());
699 listeners_
.LoadUnfilteredLazyListeners(extension
->id(),
701 const DictionaryValue
* filtered_events
=
702 GetFilteredEvents(extension
->id());
704 listeners_
.LoadFilteredLazyListeners(extension
->id(), *filtered_events
);
707 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
: {
708 // Remove all registered lazy listeners from our cache.
709 UnloadedExtensionInfo
* unloaded
=
710 content::Details
<UnloadedExtensionInfo
>(details
).ptr();
711 listeners_
.RemoveLazyListenersForExtension(unloaded
->extension
->id());
720 Event::Event(const std::string
& event_name
,
721 scoped_ptr
<base::ListValue
> event_args
)
722 : event_name(event_name
),
723 event_args(event_args
.Pass()),
724 restrict_to_browser_context(NULL
),
725 user_gesture(EventRouter::USER_GESTURE_UNKNOWN
),
726 can_load_ephemeral_apps(false) {
727 DCHECK(this->event_args
.get());
730 Event::Event(const std::string
& event_name
,
731 scoped_ptr
<base::ListValue
> event_args
,
732 BrowserContext
* restrict_to_browser_context
)
733 : event_name(event_name
),
734 event_args(event_args
.Pass()),
735 restrict_to_browser_context(restrict_to_browser_context
),
736 user_gesture(EventRouter::USER_GESTURE_UNKNOWN
),
737 can_load_ephemeral_apps(false) {
738 DCHECK(this->event_args
.get());
741 Event::Event(const std::string
& event_name
,
742 scoped_ptr
<ListValue
> event_args
,
743 BrowserContext
* restrict_to_browser_context
,
744 const GURL
& event_url
,
745 EventRouter::UserGestureState user_gesture
,
746 const EventFilteringInfo
& filter_info
)
747 : event_name(event_name
),
748 event_args(event_args
.Pass()),
749 restrict_to_browser_context(restrict_to_browser_context
),
750 event_url(event_url
),
751 user_gesture(user_gesture
),
752 filter_info(filter_info
),
753 can_load_ephemeral_apps(false) {
754 DCHECK(this->event_args
.get());
759 Event
* Event::DeepCopy() {
760 Event
* copy
= new Event(event_name
,
761 scoped_ptr
<base::ListValue
>(event_args
->DeepCopy()),
762 restrict_to_browser_context
,
766 copy
->will_dispatch_callback
= will_dispatch_callback
;
770 EventListenerInfo::EventListenerInfo(const std::string
& event_name
,
771 const std::string
& extension_id
,
772 content::BrowserContext
* browser_context
)
773 : event_name(event_name
),
774 extension_id(extension_id
),
775 browser_context(browser_context
) {}
777 } // namespace extensions