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/lazy_instance.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/stl_util.h"
14 #include "base/synchronization/lock.h"
15 #include "base/values.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "extensions/browser/api_activity_monitor.h"
19 #include "extensions/browser/extension_host.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/notification_types.h"
26 #include "extensions/browser/process_manager.h"
27 #include "extensions/browser/process_map.h"
28 #include "extensions/common/extension.h"
29 #include "extensions/common/extension_api.h"
30 #include "extensions/common/extension_messages.h"
31 #include "extensions/common/extension_urls.h"
32 #include "extensions/common/features/feature.h"
33 #include "extensions/common/features/feature_provider.h"
34 #include "extensions/common/manifest_handlers/background_info.h"
35 #include "extensions/common/manifest_handlers/incognito_info.h"
36 #include "extensions/common/permissions/permissions_data.h"
38 using base::DictionaryValue
;
39 using base::ListValue
;
40 using content::BrowserContext
;
41 using content::BrowserThread
;
43 namespace extensions
{
47 void DoNothing(ExtensionHost
* host
) {}
49 // A dictionary of event names to lists of filters that this extension has
50 // registered from its lazy background page.
51 const char kFilteredEvents
[] = "filtered_events";
53 // Sends a notification about an event to the API activity monitor and the
54 // ExtensionHost for |extension_id| on the UI thread. Can be called from any
56 void NotifyEventDispatched(void* browser_context_id
,
57 const std::string
& extension_id
,
58 const std::string
& event_name
,
60 scoped_ptr
<ListValue
> args
) {
61 // The ApiActivityMonitor can only be accessed from the UI thread.
62 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
63 BrowserThread::PostTask(
64 BrowserThread::UI
, FROM_HERE
,
65 base::Bind(&NotifyEventDispatched
, browser_context_id
, extension_id
,
66 event_name
, message_id
, base::Passed(&args
)));
70 // Notify the ApiActivityMonitor about the event dispatch.
71 BrowserContext
* context
= static_cast<BrowserContext
*>(browser_context_id
);
72 if (!ExtensionsBrowserClient::Get()->IsValidContext(context
))
74 ApiActivityMonitor
* monitor
=
75 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(context
);
77 monitor
->OnApiEventDispatched(extension_id
, event_name
, args
.Pass());
80 ProcessManager::Get(context
)->GetBackgroundHostForExtension(extension_id
);
82 host
->OnMessageDispatched(event_name
, message_id
);
85 // A global identifier used to distinguish extension messages that is
86 // incremented every time a message is dispatched.
87 int g_extension_message_id
= 0;
89 // Protects access to |g_extension_message_id|.
90 base::LazyInstance
<base::Lock
>::Leaky g_message_id_lock
=
91 LAZY_INSTANCE_INITIALIZER
;
95 const char EventRouter::kRegisteredEvents
[] = "events";
97 struct EventRouter::ListenerProcess
{
98 content::RenderProcessHost
* process
;
99 std::string extension_id
;
101 ListenerProcess(content::RenderProcessHost
* process
,
102 const std::string
& extension_id
)
103 : process(process
), extension_id(extension_id
) {}
105 bool operator<(const ListenerProcess
& that
) const {
106 if (process
< that
.process
)
108 if (process
== that
.process
&& extension_id
< that
.extension_id
)
115 void EventRouter::DispatchExtensionMessage(IPC::Sender
* ipc_sender
,
116 void* browser_context_id
,
117 const std::string
& extension_id
,
118 const std::string
& event_name
,
119 ListValue
* event_args
,
120 UserGestureState user_gesture
,
121 const EventFilteringInfo
& info
) {
122 // Since this function can be called from any thread we need to protect access
123 // to |g_extension_message_id|.
124 g_message_id_lock
.Get().Acquire();
125 int message_id
= g_extension_message_id
++;
126 g_message_id_lock
.Get().Release();
128 NotifyEventDispatched(browser_context_id
, extension_id
, event_name
,
129 message_id
, make_scoped_ptr(event_args
->DeepCopy()));
132 args
.Set(0, new base::StringValue(event_name
));
133 args
.Set(1, event_args
);
134 args
.Set(2, info
.AsValue().release());
135 args
.Set(3, new base::FundamentalValue(message_id
));
136 ipc_sender
->Send(new ExtensionMsg_MessageInvoke(
142 user_gesture
== USER_GESTURE_ENABLED
));
144 // DispatchExtensionMessage does _not_ take ownership of event_args, so we
145 // must ensure that the destruction of args does not attempt to free it.
146 scoped_ptr
<base::Value
> removed_event_args
;
147 args
.Remove(1, &removed_event_args
);
148 ignore_result(removed_event_args
.release());
152 EventRouter
* EventRouter::Get(content::BrowserContext
* browser_context
) {
153 return ExtensionSystem::Get(browser_context
)->event_router();
157 std::string
EventRouter::GetBaseEventName(const std::string
& full_event_name
) {
158 size_t slash_sep
= full_event_name
.find('/');
159 return full_event_name
.substr(0, slash_sep
);
163 void EventRouter::DispatchEvent(IPC::Sender
* ipc_sender
,
164 void* browser_context_id
,
165 const std::string
& extension_id
,
166 const std::string
& event_name
,
167 scoped_ptr
<ListValue
> event_args
,
168 UserGestureState user_gesture
,
169 const EventFilteringInfo
& info
) {
170 DispatchExtensionMessage(ipc_sender
,
178 BrowserThread::PostTask(
181 base::Bind(&EventRouter::IncrementInFlightEventsOnUI
,
186 EventRouter::EventRouter(BrowserContext
* browser_context
,
187 ExtensionPrefs
* extension_prefs
)
188 : browser_context_(browser_context
),
189 extension_prefs_(extension_prefs
),
190 extension_registry_observer_(this),
192 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
193 content::NotificationService::AllSources());
194 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
195 content::NotificationService::AllSources());
197 extensions::NOTIFICATION_EXTENSION_ENABLED
,
198 content::Source
<BrowserContext
>(browser_context_
));
199 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context_
));
202 EventRouter::~EventRouter() {}
204 void EventRouter::AddEventListener(const std::string
& event_name
,
205 content::RenderProcessHost
* process
,
206 const std::string
& extension_id
) {
207 listeners_
.AddListener(EventListener::ForExtension(
208 event_name
, extension_id
, process
, scoped_ptr
<DictionaryValue
>()));
211 void EventRouter::RemoveEventListener(const std::string
& event_name
,
212 content::RenderProcessHost
* process
,
213 const std::string
& extension_id
) {
214 scoped_ptr
<EventListener
> listener
= EventListener::ForExtension(
215 event_name
, extension_id
, process
, scoped_ptr
<DictionaryValue
>());
216 listeners_
.RemoveListener(listener
.get());
219 void EventRouter::AddEventListenerForURL(const std::string
& event_name
,
220 content::RenderProcessHost
* process
,
221 const GURL
& listener_url
) {
222 listeners_
.AddListener(EventListener::ForURL(
223 event_name
, listener_url
, process
, scoped_ptr
<DictionaryValue
>()));
226 void EventRouter::RemoveEventListenerForURL(const std::string
& event_name
,
227 content::RenderProcessHost
* process
,
228 const GURL
& listener_url
) {
229 scoped_ptr
<EventListener
> listener
= EventListener::ForURL(
230 event_name
, listener_url
, process
, scoped_ptr
<DictionaryValue
>());
231 listeners_
.RemoveListener(listener
.get());
234 void EventRouter::RegisterObserver(Observer
* observer
,
235 const std::string
& event_name
) {
236 // Observing sub-event names like "foo.onBar/123" is not allowed.
237 DCHECK(event_name
.find('/') == std::string::npos
);
238 observers_
[event_name
] = observer
;
241 void EventRouter::UnregisterObserver(Observer
* observer
) {
242 std::vector
<ObserverMap::iterator
> iters_to_remove
;
243 for (ObserverMap::iterator iter
= observers_
.begin();
244 iter
!= observers_
.end(); ++iter
) {
245 if (iter
->second
== observer
)
246 iters_to_remove
.push_back(iter
);
248 for (size_t i
= 0; i
< iters_to_remove
.size(); ++i
)
249 observers_
.erase(iters_to_remove
[i
]);
252 void EventRouter::OnListenerAdded(const EventListener
* listener
) {
253 const EventListenerInfo
details(listener
->event_name(),
254 listener
->extension_id(),
255 listener
->listener_url(),
256 listener
->GetBrowserContext());
257 std::string base_event_name
= GetBaseEventName(listener
->event_name());
258 ObserverMap::iterator observer
= observers_
.find(base_event_name
);
259 if (observer
!= observers_
.end())
260 observer
->second
->OnListenerAdded(details
);
263 void EventRouter::OnListenerRemoved(const EventListener
* listener
) {
264 const EventListenerInfo
details(listener
->event_name(),
265 listener
->extension_id(),
266 listener
->listener_url(),
267 listener
->GetBrowserContext());
268 std::string base_event_name
= GetBaseEventName(listener
->event_name());
269 ObserverMap::iterator observer
= observers_
.find(base_event_name
);
270 if (observer
!= observers_
.end())
271 observer
->second
->OnListenerRemoved(details
);
274 void EventRouter::AddLazyEventListener(const std::string
& event_name
,
275 const std::string
& extension_id
) {
276 bool is_new
= listeners_
.AddListener(EventListener::ForExtension(
277 event_name
, extension_id
, NULL
, scoped_ptr
<DictionaryValue
>()));
280 std::set
<std::string
> events
= GetRegisteredEvents(extension_id
);
281 bool prefs_is_new
= events
.insert(event_name
).second
;
283 SetRegisteredEvents(extension_id
, events
);
287 void EventRouter::RemoveLazyEventListener(const std::string
& event_name
,
288 const std::string
& extension_id
) {
289 scoped_ptr
<EventListener
> listener
= EventListener::ForExtension(
290 event_name
, extension_id
, NULL
, scoped_ptr
<DictionaryValue
>());
291 bool did_exist
= listeners_
.RemoveListener(listener
.get());
294 std::set
<std::string
> events
= GetRegisteredEvents(extension_id
);
295 bool prefs_did_exist
= events
.erase(event_name
) > 0;
296 DCHECK(prefs_did_exist
);
297 SetRegisteredEvents(extension_id
, events
);
301 void EventRouter::AddFilteredEventListener(const std::string
& event_name
,
302 content::RenderProcessHost
* process
,
303 const std::string
& extension_id
,
304 const base::DictionaryValue
& filter
,
305 bool add_lazy_listener
) {
306 listeners_
.AddListener(EventListener::ForExtension(
310 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy())));
312 if (add_lazy_listener
) {
313 bool added
= listeners_
.AddListener(EventListener::ForExtension(
317 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy())));
320 AddFilterToEvent(event_name
, extension_id
, &filter
);
324 void EventRouter::RemoveFilteredEventListener(
325 const std::string
& event_name
,
326 content::RenderProcessHost
* process
,
327 const std::string
& extension_id
,
328 const base::DictionaryValue
& filter
,
329 bool remove_lazy_listener
) {
330 scoped_ptr
<EventListener
> listener
= EventListener::ForExtension(
334 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy()));
336 listeners_
.RemoveListener(listener
.get());
338 if (remove_lazy_listener
) {
339 listener
->MakeLazy();
340 bool removed
= listeners_
.RemoveListener(listener
.get());
343 RemoveFilterFromEvent(event_name
, extension_id
, &filter
);
347 bool EventRouter::HasEventListener(const std::string
& event_name
) {
348 return listeners_
.HasListenerForEvent(event_name
);
351 bool EventRouter::ExtensionHasEventListener(const std::string
& extension_id
,
352 const std::string
& event_name
) {
353 return listeners_
.HasListenerForExtension(extension_id
, event_name
);
356 bool EventRouter::HasEventListenerImpl(const ListenerMap
& listener_map
,
357 const std::string
& extension_id
,
358 const std::string
& event_name
) {
359 ListenerMap::const_iterator it
= listener_map
.find(event_name
);
360 if (it
== listener_map
.end())
363 const std::set
<ListenerProcess
>& listeners
= it
->second
;
364 if (extension_id
.empty())
365 return !listeners
.empty();
367 for (std::set
<ListenerProcess
>::const_iterator listener
= listeners
.begin();
368 listener
!= listeners
.end(); ++listener
) {
369 if (listener
->extension_id
== extension_id
)
375 std::set
<std::string
> EventRouter::GetRegisteredEvents(
376 const std::string
& extension_id
) {
377 std::set
<std::string
> events
;
378 const ListValue
* events_value
= NULL
;
380 if (!extension_prefs_
||
381 !extension_prefs_
->ReadPrefAsList(
382 extension_id
, kRegisteredEvents
, &events_value
)) {
386 for (size_t i
= 0; i
< events_value
->GetSize(); ++i
) {
388 if (events_value
->GetString(i
, &event
))
389 events
.insert(event
);
394 void EventRouter::SetRegisteredEvents(const std::string
& extension_id
,
395 const std::set
<std::string
>& events
) {
396 ListValue
* events_value
= new ListValue
;
397 for (std::set
<std::string
>::const_iterator iter
= events
.begin();
398 iter
!= events
.end(); ++iter
) {
399 events_value
->Append(new base::StringValue(*iter
));
401 extension_prefs_
->UpdateExtensionPref(
402 extension_id
, kRegisteredEvents
, events_value
);
405 void EventRouter::AddFilterToEvent(const std::string
& event_name
,
406 const std::string
& extension_id
,
407 const DictionaryValue
* filter
) {
408 ExtensionPrefs::ScopedDictionaryUpdate
update(
409 extension_prefs_
, extension_id
, kFilteredEvents
);
410 DictionaryValue
* filtered_events
= update
.Get();
411 if (!filtered_events
)
412 filtered_events
= update
.Create();
414 ListValue
* filter_list
= NULL
;
415 if (!filtered_events
->GetList(event_name
, &filter_list
)) {
416 filter_list
= new ListValue
;
417 filtered_events
->SetWithoutPathExpansion(event_name
, filter_list
);
420 filter_list
->Append(filter
->DeepCopy());
423 void EventRouter::RemoveFilterFromEvent(const std::string
& event_name
,
424 const std::string
& extension_id
,
425 const DictionaryValue
* filter
) {
426 ExtensionPrefs::ScopedDictionaryUpdate
update(
427 extension_prefs_
, extension_id
, kFilteredEvents
);
428 DictionaryValue
* filtered_events
= update
.Get();
429 ListValue
* filter_list
= NULL
;
430 if (!filtered_events
||
431 !filtered_events
->GetListWithoutPathExpansion(event_name
, &filter_list
)) {
435 for (size_t i
= 0; i
< filter_list
->GetSize(); i
++) {
436 DictionaryValue
* filter
= NULL
;
437 CHECK(filter_list
->GetDictionary(i
, &filter
));
438 if (filter
->Equals(filter
)) {
439 filter_list
->Remove(i
, NULL
);
445 const DictionaryValue
* EventRouter::GetFilteredEvents(
446 const std::string
& extension_id
) {
447 const DictionaryValue
* events
= NULL
;
448 extension_prefs_
->ReadPrefAsDictionary(
449 extension_id
, kFilteredEvents
, &events
);
453 void EventRouter::BroadcastEvent(scoped_ptr
<Event
> event
) {
454 DispatchEventImpl(std::string(), linked_ptr
<Event
>(event
.release()));
457 void EventRouter::DispatchEventToExtension(const std::string
& extension_id
,
458 scoped_ptr
<Event
> event
) {
459 DCHECK(!extension_id
.empty());
460 DispatchEventImpl(extension_id
, linked_ptr
<Event
>(event
.release()));
463 void EventRouter::DispatchEventWithLazyListener(const std::string
& extension_id
,
464 scoped_ptr
<Event
> event
) {
465 DCHECK(!extension_id
.empty());
466 std::string event_name
= event
->event_name
;
467 bool has_listener
= ExtensionHasEventListener(extension_id
, event_name
);
469 AddLazyEventListener(event_name
, extension_id
);
470 DispatchEventToExtension(extension_id
, event
.Pass());
472 RemoveLazyEventListener(event_name
, extension_id
);
475 void EventRouter::DispatchEventImpl(const std::string
& restrict_to_extension_id
,
476 const linked_ptr
<Event
>& event
) {
477 // We don't expect to get events from a completely different browser context.
478 DCHECK(!event
->restrict_to_browser_context
||
479 ExtensionsBrowserClient::Get()->IsSameContext(
480 browser_context_
, event
->restrict_to_browser_context
));
482 std::set
<const EventListener
*> listeners(
483 listeners_
.GetEventListeners(*event
));
485 std::set
<EventDispatchIdentifier
> already_dispatched
;
487 // We dispatch events for lazy background pages first because attempting to do
488 // so will cause those that are being suspended to cancel that suspension.
489 // As canceling a suspension entails sending an event to the affected
490 // background page, and as that event needs to be delivered before we dispatch
491 // the event we are dispatching here, we dispatch to the lazy listeners here
493 for (std::set
<const EventListener
*>::iterator it
= listeners
.begin();
494 it
!= listeners
.end(); it
++) {
495 const EventListener
* listener
= *it
;
496 if (restrict_to_extension_id
.empty() ||
497 restrict_to_extension_id
== listener
->extension_id()) {
498 if (listener
->IsLazy()) {
499 DispatchLazyEvent(listener
->extension_id(), event
, &already_dispatched
);
504 for (std::set
<const EventListener
*>::iterator it
= listeners
.begin();
505 it
!= listeners
.end(); it
++) {
506 const EventListener
* listener
= *it
;
507 if (restrict_to_extension_id
.empty() ||
508 restrict_to_extension_id
== listener
->extension_id()) {
509 if (listener
->process()) {
510 EventDispatchIdentifier
dispatch_id(listener
->GetBrowserContext(),
511 listener
->extension_id());
512 if (!ContainsKey(already_dispatched
, dispatch_id
)) {
513 DispatchEventToProcess(listener
->extension_id(),
514 listener
->listener_url(),
523 void EventRouter::DispatchLazyEvent(
524 const std::string
& extension_id
,
525 const linked_ptr
<Event
>& event
,
526 std::set
<EventDispatchIdentifier
>* already_dispatched
) {
527 // Check both the original and the incognito browser context to see if we
528 // should load a lazy bg page to handle the event. The latter case
529 // occurs in the case of split-mode extensions.
530 const Extension
* extension
=
531 ExtensionRegistry::Get(browser_context_
)->enabled_extensions().GetByID(
536 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
537 browser_context_
, extension
, event
)) {
538 already_dispatched
->insert(std::make_pair(browser_context_
, extension_id
));
541 ExtensionsBrowserClient
* browser_client
= ExtensionsBrowserClient::Get();
542 if (browser_client
->HasOffTheRecordContext(browser_context_
) &&
543 IncognitoInfo::IsSplitMode(extension
)) {
544 BrowserContext
* incognito_context
=
545 browser_client
->GetOffTheRecordContext(browser_context_
);
546 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
547 incognito_context
, extension
, event
)) {
548 already_dispatched
->insert(
549 std::make_pair(incognito_context
, extension_id
));
554 void EventRouter::DispatchEventToProcess(const std::string
& extension_id
,
555 const GURL
& listener_url
,
556 content::RenderProcessHost
* process
,
557 const linked_ptr
<Event
>& event
) {
558 BrowserContext
* listener_context
= process
->GetBrowserContext();
559 ProcessMap
* process_map
= ProcessMap::Get(listener_context
);
561 // NOTE: |extension| being NULL does not necessarily imply that this event
562 // shouldn't be dispatched. Events can be dispatched to WebUI and webviews as
563 // well. It all depends on what GetMostLikelyContextType returns.
564 const Extension
* extension
=
565 ExtensionRegistry::Get(browser_context_
)->enabled_extensions().GetByID(
568 if (!extension
&& !extension_id
.empty()) {
569 // Trying to dispatch an event to an extension that doesn't exist. The
570 // extension could have been removed, but we do not unregister it until the
571 // extension process is unloaded.
576 // Extension-specific checks.
577 // Firstly, if the event is for a URL, the Extension must have permission
578 // to access that URL.
579 if (!event
->event_url
.is_empty() &&
580 event
->event_url
.host() != extension
->id() && // event for self is ok
581 !extension
->permissions_data()
582 ->active_permissions()
583 ->HasEffectiveAccessToURL(event
->event_url
)) {
586 // Secondly, if the event is for incognito mode, the Extension must be
587 // enabled in incognito mode.
588 if (!CanDispatchEventToBrowserContext(listener_context
, extension
, event
)) {
593 Feature::Context target_context
=
594 process_map
->GetMostLikelyContextType(extension
, process
->GetID());
596 // We shouldn't be dispatching an event to a webpage, since all such events
597 // (e.g. messaging) don't go through EventRouter.
598 DCHECK_NE(Feature::WEB_PAGE_CONTEXT
, target_context
)
599 << "Trying to dispatch event " << event
->event_name
<< " to a webpage,"
600 << " but this shouldn't be possible";
602 Feature::Availability availability
=
603 ExtensionAPI::GetSharedInstance()->IsAvailable(
604 event
->event_name
, extension
, target_context
, listener_url
);
605 if (!availability
.is_available()) {
606 // It shouldn't be possible to reach here, because access is checked on
607 // registration. However, for paranoia, check on dispatch as well.
608 NOTREACHED() << "Trying to dispatch event " << event
->event_name
609 << " which the target does not have access to: "
610 << availability
.message();
614 if (!event
->will_dispatch_callback
.is_null() &&
615 !event
->will_dispatch_callback
.Run(listener_context
, extension
,
616 event
->event_args
.get())) {
620 DispatchExtensionMessage(process
,
624 event
->event_args
.get(),
629 IncrementInFlightEvents(listener_context
, extension
);
632 bool EventRouter::CanDispatchEventToBrowserContext(
633 BrowserContext
* context
,
634 const Extension
* extension
,
635 const linked_ptr
<Event
>& event
) {
636 // Is this event from a different browser context than the renderer (ie, an
637 // incognito tab event sent to a normal process, or vice versa).
638 bool cross_incognito
= event
->restrict_to_browser_context
&&
639 context
!= event
->restrict_to_browser_context
;
640 if (!cross_incognito
)
642 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
646 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent(
647 BrowserContext
* context
,
648 const Extension
* extension
,
649 const linked_ptr
<Event
>& event
) {
650 if (!CanDispatchEventToBrowserContext(context
, extension
, event
))
653 LazyBackgroundTaskQueue
* queue
= ExtensionSystem::Get(
654 context
)->lazy_background_task_queue();
655 if (queue
->ShouldEnqueueTask(context
, extension
)) {
656 linked_ptr
<Event
> dispatched_event(event
);
658 // If there's a dispatch callback, call it now (rather than dispatch time)
659 // to avoid lifetime issues. Use a separate copy of the event args, so they
660 // last until the event is dispatched.
661 if (!event
->will_dispatch_callback
.is_null()) {
662 dispatched_event
.reset(event
->DeepCopy());
663 if (!dispatched_event
->will_dispatch_callback
.Run(
664 context
, extension
, dispatched_event
->event_args
.get())) {
665 // The event has been canceled.
668 // Ensure we don't call it again at dispatch time.
669 dispatched_event
->will_dispatch_callback
.Reset();
672 queue
->AddPendingTask(context
, extension
->id(),
673 base::Bind(&EventRouter::DispatchPendingEvent
,
674 base::Unretained(this), dispatched_event
));
682 void EventRouter::IncrementInFlightEventsOnUI(
683 void* browser_context_id
,
684 const std::string
& extension_id
) {
685 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
686 BrowserContext
* browser_context
=
687 reinterpret_cast<BrowserContext
*>(browser_context_id
);
688 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context
))
690 EventRouter
* event_router
= EventRouter::Get(browser_context
);
693 const Extension
* extension
=
694 ExtensionRegistry::Get(browser_context
)->enabled_extensions().GetByID(
698 event_router
->IncrementInFlightEvents(browser_context
, extension
);
701 void EventRouter::IncrementInFlightEvents(BrowserContext
* context
,
702 const Extension
* extension
) {
703 // Only increment in-flight events if the lazy background page is active,
704 // because that's the only time we'll get an ACK.
705 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
706 ProcessManager
* pm
= ProcessManager::Get(context
);
707 ExtensionHost
* host
= pm
->GetBackgroundHostForExtension(extension
->id());
709 pm
->IncrementLazyKeepaliveCount(extension
);
713 void EventRouter::OnEventAck(BrowserContext
* context
,
714 const std::string
& extension_id
) {
715 ProcessManager
* pm
= ProcessManager::Get(context
);
716 ExtensionHost
* host
= pm
->GetBackgroundHostForExtension(extension_id
);
717 // The event ACK is routed to the background host, so this should never be
720 // TODO(mpcomplete): We should never get this message unless
721 // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
722 if (host
->extension() &&
723 BackgroundInfo::HasLazyBackgroundPage(host
->extension()))
724 pm
->DecrementLazyKeepaliveCount(host
->extension());
727 void EventRouter::DispatchPendingEvent(const linked_ptr
<Event
>& event
,
728 ExtensionHost
* host
) {
732 if (listeners_
.HasProcessListener(host
->render_process_host(),
733 host
->extension()->id())) {
734 // URL events cannot be lazy therefore can't be pending, hence the GURL().
735 DispatchEventToProcess(
736 host
->extension()->id(), GURL(), host
->render_process_host(), event
);
740 void EventRouter::Observe(int type
,
741 const content::NotificationSource
& source
,
742 const content::NotificationDetails
& details
) {
744 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
:
745 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
746 content::RenderProcessHost
* renderer
=
747 content::Source
<content::RenderProcessHost
>(source
).ptr();
748 // Remove all event listeners associated with this renderer.
749 listeners_
.RemoveListenersForProcess(renderer
);
752 case extensions::NOTIFICATION_EXTENSION_ENABLED
: {
753 // If the extension has a lazy background page, make sure it gets loaded
754 // to register the events the extension is interested in.
755 const Extension
* extension
=
756 content::Details
<const Extension
>(details
).ptr();
757 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
758 LazyBackgroundTaskQueue
* queue
= ExtensionSystem::Get(
759 browser_context_
)->lazy_background_task_queue();
760 queue
->AddPendingTask(browser_context_
, extension
->id(),
761 base::Bind(&DoNothing
));
770 void EventRouter::OnExtensionLoaded(content::BrowserContext
* browser_context
,
771 const Extension
* extension
) {
772 // Add all registered lazy listeners to our cache.
773 std::set
<std::string
> registered_events
=
774 GetRegisteredEvents(extension
->id());
775 listeners_
.LoadUnfilteredLazyListeners(extension
->id(), registered_events
);
776 const DictionaryValue
* filtered_events
= GetFilteredEvents(extension
->id());
778 listeners_
.LoadFilteredLazyListeners(extension
->id(), *filtered_events
);
781 void EventRouter::OnExtensionUnloaded(content::BrowserContext
* browser_context
,
782 const Extension
* extension
,
783 UnloadedExtensionInfo::Reason reason
) {
784 // Remove all registered listeners from our cache.
785 listeners_
.RemoveListenersForExtension(extension
->id());
788 Event::Event(const std::string
& event_name
,
789 scoped_ptr
<base::ListValue
> event_args
)
790 : event_name(event_name
),
791 event_args(event_args
.Pass()),
792 restrict_to_browser_context(NULL
),
793 user_gesture(EventRouter::USER_GESTURE_UNKNOWN
) {
794 DCHECK(this->event_args
.get());
797 Event::Event(const std::string
& event_name
,
798 scoped_ptr
<base::ListValue
> event_args
,
799 BrowserContext
* restrict_to_browser_context
)
800 : event_name(event_name
),
801 event_args(event_args
.Pass()),
802 restrict_to_browser_context(restrict_to_browser_context
),
803 user_gesture(EventRouter::USER_GESTURE_UNKNOWN
) {
804 DCHECK(this->event_args
.get());
807 Event::Event(const std::string
& event_name
,
808 scoped_ptr
<ListValue
> event_args
,
809 BrowserContext
* restrict_to_browser_context
,
810 const GURL
& event_url
,
811 EventRouter::UserGestureState user_gesture
,
812 const EventFilteringInfo
& filter_info
)
813 : event_name(event_name
),
814 event_args(event_args
.Pass()),
815 restrict_to_browser_context(restrict_to_browser_context
),
816 event_url(event_url
),
817 user_gesture(user_gesture
),
818 filter_info(filter_info
) {
819 DCHECK(this->event_args
.get());
824 Event
* Event::DeepCopy() {
825 Event
* copy
= new Event(event_name
,
826 scoped_ptr
<base::ListValue
>(event_args
->DeepCopy()),
827 restrict_to_browser_context
,
831 copy
->will_dispatch_callback
= will_dispatch_callback
;
835 EventListenerInfo::EventListenerInfo(const std::string
& event_name
,
836 const std::string
& extension_id
,
837 const GURL
& listener_url
,
838 content::BrowserContext
* browser_context
)
839 : event_name(event_name
),
840 extension_id(extension_id
),
841 listener_url(listener_url
),
842 browser_context(browser_context
) {
845 } // namespace extensions