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 "content/public/browser/child_process_security_policy.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "extensions/browser/api_activity_monitor.h"
18 #include "extensions/browser/extension_host.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/browser/extensions_browser_client.h"
23 #include "extensions/browser/lazy_background_task_queue.h"
24 #include "extensions/browser/notification_types.h"
25 #include "extensions/browser/process_manager.h"
26 #include "extensions/browser/process_map.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/extension_api.h"
29 #include "extensions/common/extension_messages.h"
30 #include "extensions/common/extension_urls.h"
31 #include "extensions/common/manifest_handlers/background_info.h"
32 #include "extensions/common/manifest_handlers/incognito_info.h"
33 #include "extensions/common/permissions/permissions_data.h"
35 using base::DictionaryValue
;
36 using base::ListValue
;
37 using content::BrowserContext
;
38 using content::BrowserThread
;
40 namespace extensions
{
44 void DoNothing(ExtensionHost
* host
) {}
46 // A dictionary of event names to lists of filters that this extension has
47 // registered from its lazy background page.
48 const char kFilteredEvents
[] = "filtered_events";
50 // Sends a notification about an event to the API activity monitor on the
51 // UI thread. Can be called from any thread.
52 void NotifyApiEventDispatched(void* browser_context_id
,
53 const std::string
& extension_id
,
54 const std::string
& event_name
,
55 scoped_ptr
<ListValue
> args
) {
56 // The ApiActivityMonitor can only be accessed from the UI thread.
57 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
58 BrowserThread::PostTask(
61 base::Bind(&NotifyApiEventDispatched
,
65 base::Passed(&args
)));
69 // Notify the ApiActivityMonitor about the event dispatch.
70 BrowserContext
* context
= static_cast<BrowserContext
*>(browser_context_id
);
71 if (!ExtensionsBrowserClient::Get()->IsValidContext(context
))
73 ApiActivityMonitor
* monitor
=
74 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(context
);
76 monitor
->OnApiEventDispatched(extension_id
, event_name
, args
.Pass());
81 const char EventRouter::kRegisteredEvents
[] = "events";
83 struct EventRouter::ListenerProcess
{
84 content::RenderProcessHost
* process
;
85 std::string extension_id
;
87 ListenerProcess(content::RenderProcessHost
* process
,
88 const std::string
& extension_id
)
89 : process(process
), extension_id(extension_id
) {}
91 bool operator<(const ListenerProcess
& that
) const {
92 if (process
< that
.process
)
94 if (process
== that
.process
&& extension_id
< that
.extension_id
)
101 void EventRouter::DispatchExtensionMessage(IPC::Sender
* ipc_sender
,
102 void* browser_context_id
,
103 const std::string
& extension_id
,
104 const std::string
& event_name
,
105 ListValue
* event_args
,
106 UserGestureState user_gesture
,
107 const EventFilteringInfo
& info
) {
108 NotifyApiEventDispatched(browser_context_id
,
111 make_scoped_ptr(event_args
->DeepCopy()));
114 args
.Set(0, new base::StringValue(event_name
));
115 args
.Set(1, event_args
);
116 args
.Set(2, info
.AsValue().release());
117 ipc_sender
->Send(new ExtensionMsg_MessageInvoke(
123 user_gesture
== USER_GESTURE_ENABLED
));
125 // DispatchExtensionMessage does _not_ take ownership of event_args, so we
126 // must ensure that the destruction of args does not attempt to free it.
127 scoped_ptr
<base::Value
> removed_event_args
;
128 args
.Remove(1, &removed_event_args
);
129 ignore_result(removed_event_args
.release());
133 EventRouter
* EventRouter::Get(content::BrowserContext
* browser_context
) {
134 return ExtensionSystem::Get(browser_context
)->event_router();
138 std::string
EventRouter::GetBaseEventName(const std::string
& full_event_name
) {
139 size_t slash_sep
= full_event_name
.find('/');
140 return full_event_name
.substr(0, slash_sep
);
144 void EventRouter::DispatchEvent(IPC::Sender
* ipc_sender
,
145 void* browser_context_id
,
146 const std::string
& extension_id
,
147 const std::string
& event_name
,
148 scoped_ptr
<ListValue
> event_args
,
149 UserGestureState user_gesture
,
150 const EventFilteringInfo
& info
) {
151 DispatchExtensionMessage(ipc_sender
,
159 BrowserThread::PostTask(
162 base::Bind(&EventRouter::IncrementInFlightEventsOnUI
,
167 EventRouter::EventRouter(BrowserContext
* browser_context
,
168 ExtensionPrefs
* extension_prefs
)
169 : browser_context_(browser_context
),
170 extension_prefs_(extension_prefs
),
171 extension_registry_observer_(this),
173 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
174 content::NotificationService::AllSources());
175 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
176 content::NotificationService::AllSources());
178 extensions::NOTIFICATION_EXTENSION_ENABLED
,
179 content::Source
<BrowserContext
>(browser_context_
));
180 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context_
));
183 EventRouter::~EventRouter() {}
185 void EventRouter::AddEventListener(const std::string
& event_name
,
186 content::RenderProcessHost
* process
,
187 const std::string
& extension_id
) {
188 listeners_
.AddListener(EventListener::ForExtension(
189 event_name
, extension_id
, process
, scoped_ptr
<DictionaryValue
>()));
192 void EventRouter::RemoveEventListener(const std::string
& event_name
,
193 content::RenderProcessHost
* process
,
194 const std::string
& extension_id
) {
195 scoped_ptr
<EventListener
> listener
= EventListener::ForExtension(
196 event_name
, extension_id
, process
, scoped_ptr
<DictionaryValue
>());
197 listeners_
.RemoveListener(listener
.get());
200 void EventRouter::AddEventListenerForURL(const std::string
& event_name
,
201 content::RenderProcessHost
* process
,
202 const GURL
& listener_url
) {
203 listeners_
.AddListener(EventListener::ForURL(
204 event_name
, listener_url
, process
, scoped_ptr
<DictionaryValue
>()));
207 void EventRouter::RemoveEventListenerForURL(const std::string
& event_name
,
208 content::RenderProcessHost
* process
,
209 const GURL
& listener_url
) {
210 scoped_ptr
<EventListener
> listener
= EventListener::ForURL(
211 event_name
, listener_url
, process
, scoped_ptr
<DictionaryValue
>());
212 listeners_
.RemoveListener(listener
.get());
215 void EventRouter::RegisterObserver(Observer
* observer
,
216 const std::string
& event_name
) {
217 // Observing sub-event names like "foo.onBar/123" is not allowed.
218 DCHECK(event_name
.find('/') == std::string::npos
);
219 observers_
[event_name
] = observer
;
222 void EventRouter::UnregisterObserver(Observer
* observer
) {
223 std::vector
<ObserverMap::iterator
> iters_to_remove
;
224 for (ObserverMap::iterator iter
= observers_
.begin();
225 iter
!= observers_
.end(); ++iter
) {
226 if (iter
->second
== observer
)
227 iters_to_remove
.push_back(iter
);
229 for (size_t i
= 0; i
< iters_to_remove
.size(); ++i
)
230 observers_
.erase(iters_to_remove
[i
]);
233 void EventRouter::OnListenerAdded(const EventListener
* listener
) {
234 const EventListenerInfo
details(listener
->event_name(),
235 listener
->extension_id(),
236 listener
->listener_url(),
237 listener
->GetBrowserContext());
238 std::string base_event_name
= GetBaseEventName(listener
->event_name());
239 ObserverMap::iterator observer
= observers_
.find(base_event_name
);
240 if (observer
!= observers_
.end())
241 observer
->second
->OnListenerAdded(details
);
244 void EventRouter::OnListenerRemoved(const EventListener
* listener
) {
245 const EventListenerInfo
details(listener
->event_name(),
246 listener
->extension_id(),
247 listener
->listener_url(),
248 listener
->GetBrowserContext());
249 std::string base_event_name
= GetBaseEventName(listener
->event_name());
250 ObserverMap::iterator observer
= observers_
.find(base_event_name
);
251 if (observer
!= observers_
.end())
252 observer
->second
->OnListenerRemoved(details
);
255 void EventRouter::AddLazyEventListener(const std::string
& event_name
,
256 const std::string
& extension_id
) {
257 bool is_new
= listeners_
.AddListener(EventListener::ForExtension(
258 event_name
, extension_id
, NULL
, scoped_ptr
<DictionaryValue
>()));
261 std::set
<std::string
> events
= GetRegisteredEvents(extension_id
);
262 bool prefs_is_new
= events
.insert(event_name
).second
;
264 SetRegisteredEvents(extension_id
, events
);
268 void EventRouter::RemoveLazyEventListener(const std::string
& event_name
,
269 const std::string
& extension_id
) {
270 scoped_ptr
<EventListener
> listener
= EventListener::ForExtension(
271 event_name
, extension_id
, NULL
, scoped_ptr
<DictionaryValue
>());
272 bool did_exist
= listeners_
.RemoveListener(listener
.get());
275 std::set
<std::string
> events
= GetRegisteredEvents(extension_id
);
276 bool prefs_did_exist
= events
.erase(event_name
) > 0;
277 DCHECK(prefs_did_exist
);
278 SetRegisteredEvents(extension_id
, events
);
282 void EventRouter::AddFilteredEventListener(const std::string
& event_name
,
283 content::RenderProcessHost
* process
,
284 const std::string
& extension_id
,
285 const base::DictionaryValue
& filter
,
286 bool add_lazy_listener
) {
287 listeners_
.AddListener(EventListener::ForExtension(
291 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy())));
293 if (add_lazy_listener
) {
294 bool added
= listeners_
.AddListener(EventListener::ForExtension(
298 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy())));
301 AddFilterToEvent(event_name
, extension_id
, &filter
);
305 void EventRouter::RemoveFilteredEventListener(
306 const std::string
& event_name
,
307 content::RenderProcessHost
* process
,
308 const std::string
& extension_id
,
309 const base::DictionaryValue
& filter
,
310 bool remove_lazy_listener
) {
311 scoped_ptr
<EventListener
> listener
= EventListener::ForExtension(
315 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy()));
317 listeners_
.RemoveListener(listener
.get());
319 if (remove_lazy_listener
) {
320 listener
->MakeLazy();
321 bool removed
= listeners_
.RemoveListener(listener
.get());
324 RemoveFilterFromEvent(event_name
, extension_id
, &filter
);
328 bool EventRouter::HasEventListener(const std::string
& event_name
) {
329 return listeners_
.HasListenerForEvent(event_name
);
332 bool EventRouter::ExtensionHasEventListener(const std::string
& extension_id
,
333 const std::string
& event_name
) {
334 return listeners_
.HasListenerForExtension(extension_id
, event_name
);
337 bool EventRouter::HasEventListenerImpl(const ListenerMap
& listener_map
,
338 const std::string
& extension_id
,
339 const std::string
& event_name
) {
340 ListenerMap::const_iterator it
= listener_map
.find(event_name
);
341 if (it
== listener_map
.end())
344 const std::set
<ListenerProcess
>& listeners
= it
->second
;
345 if (extension_id
.empty())
346 return !listeners
.empty();
348 for (std::set
<ListenerProcess
>::const_iterator listener
= listeners
.begin();
349 listener
!= listeners
.end(); ++listener
) {
350 if (listener
->extension_id
== extension_id
)
356 std::set
<std::string
> EventRouter::GetRegisteredEvents(
357 const std::string
& extension_id
) {
358 std::set
<std::string
> events
;
359 const ListValue
* events_value
= NULL
;
361 if (!extension_prefs_
||
362 !extension_prefs_
->ReadPrefAsList(
363 extension_id
, kRegisteredEvents
, &events_value
)) {
367 for (size_t i
= 0; i
< events_value
->GetSize(); ++i
) {
369 if (events_value
->GetString(i
, &event
))
370 events
.insert(event
);
375 void EventRouter::SetRegisteredEvents(const std::string
& extension_id
,
376 const std::set
<std::string
>& events
) {
377 ListValue
* events_value
= new ListValue
;
378 for (std::set
<std::string
>::const_iterator iter
= events
.begin();
379 iter
!= events
.end(); ++iter
) {
380 events_value
->Append(new base::StringValue(*iter
));
382 extension_prefs_
->UpdateExtensionPref(
383 extension_id
, kRegisteredEvents
, events_value
);
386 void EventRouter::AddFilterToEvent(const std::string
& event_name
,
387 const std::string
& extension_id
,
388 const DictionaryValue
* filter
) {
389 ExtensionPrefs::ScopedDictionaryUpdate
update(
390 extension_prefs_
, extension_id
, kFilteredEvents
);
391 DictionaryValue
* filtered_events
= update
.Get();
392 if (!filtered_events
)
393 filtered_events
= update
.Create();
395 ListValue
* filter_list
= NULL
;
396 if (!filtered_events
->GetList(event_name
, &filter_list
)) {
397 filter_list
= new ListValue
;
398 filtered_events
->SetWithoutPathExpansion(event_name
, filter_list
);
401 filter_list
->Append(filter
->DeepCopy());
404 void EventRouter::RemoveFilterFromEvent(const std::string
& event_name
,
405 const std::string
& extension_id
,
406 const DictionaryValue
* filter
) {
407 ExtensionPrefs::ScopedDictionaryUpdate
update(
408 extension_prefs_
, extension_id
, kFilteredEvents
);
409 DictionaryValue
* filtered_events
= update
.Get();
410 ListValue
* filter_list
= NULL
;
411 if (!filtered_events
||
412 !filtered_events
->GetListWithoutPathExpansion(event_name
, &filter_list
)) {
416 for (size_t i
= 0; i
< filter_list
->GetSize(); i
++) {
417 DictionaryValue
* filter
= NULL
;
418 CHECK(filter_list
->GetDictionary(i
, &filter
));
419 if (filter
->Equals(filter
)) {
420 filter_list
->Remove(i
, NULL
);
426 const DictionaryValue
* EventRouter::GetFilteredEvents(
427 const std::string
& extension_id
) {
428 const DictionaryValue
* events
= NULL
;
429 extension_prefs_
->ReadPrefAsDictionary(
430 extension_id
, kFilteredEvents
, &events
);
434 void EventRouter::BroadcastEvent(scoped_ptr
<Event
> event
) {
435 DispatchEventImpl(std::string(), linked_ptr
<Event
>(event
.release()));
438 void EventRouter::DispatchEventToExtension(const std::string
& extension_id
,
439 scoped_ptr
<Event
> event
) {
440 DCHECK(!extension_id
.empty());
441 DispatchEventImpl(extension_id
, linked_ptr
<Event
>(event
.release()));
444 void EventRouter::DispatchEventWithLazyListener(const std::string
& extension_id
,
445 scoped_ptr
<Event
> event
) {
446 DCHECK(!extension_id
.empty());
447 std::string event_name
= event
->event_name
;
448 bool has_listener
= ExtensionHasEventListener(extension_id
, event_name
);
450 AddLazyEventListener(event_name
, extension_id
);
451 DispatchEventToExtension(extension_id
, event
.Pass());
453 RemoveLazyEventListener(event_name
, extension_id
);
456 void EventRouter::DispatchEventImpl(const std::string
& restrict_to_extension_id
,
457 const linked_ptr
<Event
>& event
) {
458 // We don't expect to get events from a completely different browser context.
459 DCHECK(!event
->restrict_to_browser_context
||
460 ExtensionsBrowserClient::Get()->IsSameContext(
461 browser_context_
, event
->restrict_to_browser_context
));
463 std::set
<const EventListener
*> listeners(
464 listeners_
.GetEventListeners(*event
));
466 std::set
<EventDispatchIdentifier
> already_dispatched
;
468 // We dispatch events for lazy background pages first because attempting to do
469 // so will cause those that are being suspended to cancel that suspension.
470 // As canceling a suspension entails sending an event to the affected
471 // background page, and as that event needs to be delivered before we dispatch
472 // the event we are dispatching here, we dispatch to the lazy listeners here
474 for (std::set
<const EventListener
*>::iterator it
= listeners
.begin();
475 it
!= listeners
.end(); it
++) {
476 const EventListener
* listener
= *it
;
477 if (restrict_to_extension_id
.empty() ||
478 restrict_to_extension_id
== listener
->extension_id()) {
479 if (listener
->IsLazy()) {
480 DispatchLazyEvent(listener
->extension_id(), event
, &already_dispatched
);
485 for (std::set
<const EventListener
*>::iterator it
= listeners
.begin();
486 it
!= listeners
.end(); it
++) {
487 const EventListener
* listener
= *it
;
488 if (restrict_to_extension_id
.empty() ||
489 restrict_to_extension_id
== listener
->extension_id()) {
490 if (listener
->process()) {
491 EventDispatchIdentifier
dispatch_id(listener
->GetBrowserContext(),
492 listener
->extension_id());
493 if (!ContainsKey(already_dispatched
, dispatch_id
)) {
494 DispatchEventToProcess(listener
->extension_id(),
495 listener
->listener_url(),
504 void EventRouter::DispatchLazyEvent(
505 const std::string
& extension_id
,
506 const linked_ptr
<Event
>& event
,
507 std::set
<EventDispatchIdentifier
>* already_dispatched
) {
508 // Check both the original and the incognito browser context to see if we
509 // should load a lazy bg page to handle the event. The latter case
510 // occurs in the case of split-mode extensions.
511 const Extension
* extension
=
512 ExtensionRegistry::Get(browser_context_
)->enabled_extensions().GetByID(
517 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
518 browser_context_
, extension
, event
)) {
519 already_dispatched
->insert(std::make_pair(browser_context_
, extension_id
));
522 ExtensionsBrowserClient
* browser_client
= ExtensionsBrowserClient::Get();
523 if (browser_client
->HasOffTheRecordContext(browser_context_
) &&
524 IncognitoInfo::IsSplitMode(extension
)) {
525 BrowserContext
* incognito_context
=
526 browser_client
->GetOffTheRecordContext(browser_context_
);
527 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
528 incognito_context
, extension
, event
)) {
529 already_dispatched
->insert(
530 std::make_pair(incognito_context
, extension_id
));
535 void EventRouter::DispatchEventToProcess(const std::string
& extension_id
,
536 const GURL
& listener_url
,
537 content::RenderProcessHost
* process
,
538 const linked_ptr
<Event
>& event
) {
539 BrowserContext
* listener_context
= process
->GetBrowserContext();
540 ProcessMap
* process_map
= ProcessMap::Get(listener_context
);
542 // TODO(kalman): Convert this method to use
543 // ProcessMap::GetMostLikelyContextType.
545 const Extension
* extension
=
546 ExtensionRegistry::Get(browser_context_
)->enabled_extensions().GetByID(
548 // NOTE: |extension| being NULL does not necessarily imply that this event
549 // shouldn't be dispatched. Events can be dispatched to WebUI as well.
551 if (!extension
&& !extension_id
.empty()) {
552 // Trying to dispatch an event to an extension that doesn't exist. The
553 // extension could have been removed, but we do not unregister it until the
554 // extension process is unloaded.
559 // Dispatching event to an extension.
560 // If the event is privileged, only send to extension processes. Otherwise,
561 // it's OK to send to normal renderers (e.g., for content scripts).
562 if (!process_map
->Contains(extension
->id(), process
->GetID()) &&
563 !ExtensionAPI::GetSharedInstance()->IsAvailableInUntrustedContext(
564 event
->event_name
, extension
)) {
568 // If the event is restricted to a URL, only dispatch if the extension has
569 // permission for it (or if the event originated from itself).
570 if (!event
->event_url
.is_empty() &&
571 event
->event_url
.host() != extension
->id() &&
572 !extension
->permissions_data()
573 ->active_permissions()
574 ->HasEffectiveAccessToURL(event
->event_url
)) {
578 if (!CanDispatchEventToBrowserContext(listener_context
, extension
, event
)) {
581 } else if (content::ChildProcessSecurityPolicy::GetInstance()
582 ->HasWebUIBindings(process
->GetID())) {
583 // Dispatching event to WebUI.
584 if (!ExtensionAPI::GetSharedInstance()->IsAvailableToWebUI(
585 event
->event_name
, listener_url
)) {
589 // Dispatching event to a webpage - however, all such events (e.g.
590 // messaging) don't go through EventRouter so this should be impossible.
595 if (!event
->will_dispatch_callback
.is_null()) {
596 event
->will_dispatch_callback
.Run(
597 listener_context
, extension
, event
->event_args
.get());
600 DispatchExtensionMessage(process
,
604 event
->event_args
.get(),
609 IncrementInFlightEvents(listener_context
, extension
);
612 bool EventRouter::CanDispatchEventToBrowserContext(
613 BrowserContext
* context
,
614 const Extension
* extension
,
615 const linked_ptr
<Event
>& event
) {
616 // Is this event from a different browser context than the renderer (ie, an
617 // incognito tab event sent to a normal process, or vice versa).
618 bool cross_incognito
= event
->restrict_to_browser_context
&&
619 context
!= event
->restrict_to_browser_context
;
620 if (!cross_incognito
)
622 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
626 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent(
627 BrowserContext
* context
,
628 const Extension
* extension
,
629 const linked_ptr
<Event
>& event
) {
630 if (!CanDispatchEventToBrowserContext(context
, extension
, event
))
633 LazyBackgroundTaskQueue
* queue
= ExtensionSystem::Get(
634 context
)->lazy_background_task_queue();
635 if (queue
->ShouldEnqueueTask(context
, extension
)) {
636 linked_ptr
<Event
> dispatched_event(event
);
638 // If there's a dispatch callback, call it now (rather than dispatch time)
639 // to avoid lifetime issues. Use a separate copy of the event args, so they
640 // last until the event is dispatched.
641 if (!event
->will_dispatch_callback
.is_null()) {
642 dispatched_event
.reset(event
->DeepCopy());
643 dispatched_event
->will_dispatch_callback
.Run(
644 context
, extension
, dispatched_event
->event_args
.get());
645 // Ensure we don't call it again at dispatch time.
646 dispatched_event
->will_dispatch_callback
.Reset();
649 queue
->AddPendingTask(context
, extension
->id(),
650 base::Bind(&EventRouter::DispatchPendingEvent
,
651 base::Unretained(this), dispatched_event
));
659 void EventRouter::IncrementInFlightEventsOnUI(
660 void* browser_context_id
,
661 const std::string
& extension_id
) {
662 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
663 BrowserContext
* browser_context
=
664 reinterpret_cast<BrowserContext
*>(browser_context_id
);
665 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context
))
667 EventRouter
* event_router
= EventRouter::Get(browser_context
);
670 const Extension
* extension
=
671 ExtensionRegistry::Get(browser_context
)->enabled_extensions().GetByID(
675 event_router
->IncrementInFlightEvents(browser_context
, extension
);
678 void EventRouter::IncrementInFlightEvents(BrowserContext
* context
,
679 const Extension
* extension
) {
680 // Only increment in-flight events if the lazy background page is active,
681 // because that's the only time we'll get an ACK.
682 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
683 ProcessManager
* pm
= ExtensionSystem::Get(context
)->process_manager();
684 ExtensionHost
* host
= pm
->GetBackgroundHostForExtension(extension
->id());
686 pm
->IncrementLazyKeepaliveCount(extension
);
690 void EventRouter::OnEventAck(BrowserContext
* context
,
691 const std::string
& extension_id
) {
692 ProcessManager
* pm
= ExtensionSystem::Get(context
)->process_manager();
693 ExtensionHost
* host
= pm
->GetBackgroundHostForExtension(extension_id
);
694 // The event ACK is routed to the background host, so this should never be
697 // TODO(mpcomplete): We should never get this message unless
698 // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
699 if (host
->extension() &&
700 BackgroundInfo::HasLazyBackgroundPage(host
->extension()))
701 pm
->DecrementLazyKeepaliveCount(host
->extension());
704 void EventRouter::DispatchPendingEvent(const linked_ptr
<Event
>& event
,
705 ExtensionHost
* host
) {
709 if (listeners_
.HasProcessListener(host
->render_process_host(),
710 host
->extension()->id())) {
711 // URL events cannot be lazy therefore can't be pending, hence the GURL().
712 DispatchEventToProcess(
713 host
->extension()->id(), GURL(), host
->render_process_host(), event
);
717 void EventRouter::Observe(int type
,
718 const content::NotificationSource
& source
,
719 const content::NotificationDetails
& details
) {
721 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
:
722 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
723 content::RenderProcessHost
* renderer
=
724 content::Source
<content::RenderProcessHost
>(source
).ptr();
725 // Remove all event listeners associated with this renderer.
726 listeners_
.RemoveListenersForProcess(renderer
);
729 case extensions::NOTIFICATION_EXTENSION_ENABLED
: {
730 // If the extension has a lazy background page, make sure it gets loaded
731 // to register the events the extension is interested in.
732 const Extension
* extension
=
733 content::Details
<const Extension
>(details
).ptr();
734 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
735 LazyBackgroundTaskQueue
* queue
= ExtensionSystem::Get(
736 browser_context_
)->lazy_background_task_queue();
737 queue
->AddPendingTask(browser_context_
, extension
->id(),
738 base::Bind(&DoNothing
));
747 void EventRouter::OnExtensionLoaded(content::BrowserContext
* browser_context
,
748 const Extension
* extension
) {
749 // Add all registered lazy listeners to our cache.
750 std::set
<std::string
> registered_events
=
751 GetRegisteredEvents(extension
->id());
752 listeners_
.LoadUnfilteredLazyListeners(extension
->id(), registered_events
);
753 const DictionaryValue
* filtered_events
= GetFilteredEvents(extension
->id());
755 listeners_
.LoadFilteredLazyListeners(extension
->id(), *filtered_events
);
758 void EventRouter::OnExtensionUnloaded(content::BrowserContext
* browser_context
,
759 const Extension
* extension
,
760 UnloadedExtensionInfo::Reason reason
) {
761 // Remove all registered lazy listeners from our cache.
762 listeners_
.RemoveLazyListenersForExtension(extension
->id());
765 Event::Event(const std::string
& event_name
,
766 scoped_ptr
<base::ListValue
> event_args
)
767 : event_name(event_name
),
768 event_args(event_args
.Pass()),
769 restrict_to_browser_context(NULL
),
770 user_gesture(EventRouter::USER_GESTURE_UNKNOWN
) {
771 DCHECK(this->event_args
.get());
774 Event::Event(const std::string
& event_name
,
775 scoped_ptr
<base::ListValue
> event_args
,
776 BrowserContext
* restrict_to_browser_context
)
777 : event_name(event_name
),
778 event_args(event_args
.Pass()),
779 restrict_to_browser_context(restrict_to_browser_context
),
780 user_gesture(EventRouter::USER_GESTURE_UNKNOWN
) {
781 DCHECK(this->event_args
.get());
784 Event::Event(const std::string
& event_name
,
785 scoped_ptr
<ListValue
> event_args
,
786 BrowserContext
* restrict_to_browser_context
,
787 const GURL
& event_url
,
788 EventRouter::UserGestureState user_gesture
,
789 const EventFilteringInfo
& filter_info
)
790 : event_name(event_name
),
791 event_args(event_args
.Pass()),
792 restrict_to_browser_context(restrict_to_browser_context
),
793 event_url(event_url
),
794 user_gesture(user_gesture
),
795 filter_info(filter_info
) {
796 DCHECK(this->event_args
.get());
801 Event
* Event::DeepCopy() {
802 Event
* copy
= new Event(event_name
,
803 scoped_ptr
<base::ListValue
>(event_args
->DeepCopy()),
804 restrict_to_browser_context
,
808 copy
->will_dispatch_callback
= will_dispatch_callback
;
812 EventListenerInfo::EventListenerInfo(const std::string
& event_name
,
813 const std::string
& extension_id
,
814 const GURL
& listener_url
,
815 content::BrowserContext
* browser_context
)
816 : event_name(event_name
),
817 extension_id(extension_id
),
818 listener_url(listener_url
),
819 browser_context(browser_context
) {
822 } // namespace extensions