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"
9 #include "base/atomic_sequence_num.h"
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/lazy_instance.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/stl_util.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/event_router_factory.h"
20 #include "extensions/browser/extension_host.h"
21 #include "extensions/browser/extension_prefs.h"
22 #include "extensions/browser/extension_registry.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/browser/extensions_browser_client.h"
25 #include "extensions/browser/lazy_background_task_queue.h"
26 #include "extensions/browser/notification_types.h"
27 #include "extensions/browser/process_manager.h"
28 #include "extensions/browser/process_map.h"
29 #include "extensions/common/extension.h"
30 #include "extensions/common/extension_api.h"
31 #include "extensions/common/extension_messages.h"
32 #include "extensions/common/extension_urls.h"
33 #include "extensions/common/features/feature.h"
34 #include "extensions/common/features/feature_provider.h"
35 #include "extensions/common/manifest_handlers/background_info.h"
36 #include "extensions/common/manifest_handlers/incognito_info.h"
37 #include "extensions/common/permissions/permissions_data.h"
39 using base::DictionaryValue
;
40 using base::ListValue
;
41 using content::BrowserContext
;
42 using content::BrowserThread
;
44 namespace extensions
{
48 void DoNothing(ExtensionHost
* host
) {}
50 // A dictionary of event names to lists of filters that this extension has
51 // registered from its lazy background page.
52 const char kFilteredEvents
[] = "filtered_events";
54 // Sends a notification about an event to the API activity monitor and the
55 // ExtensionHost for |extension_id| on the UI thread. Can be called from any
57 void NotifyEventDispatched(void* browser_context_id
,
58 const std::string
& extension_id
,
59 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
, 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 // A global identifier used to distinguish extension events.
81 base::StaticAtomicSequenceNumber g_extension_event_id
;
85 const char EventRouter::kRegisteredEvents
[] = "events";
87 struct EventRouter::ListenerProcess
{
88 content::RenderProcessHost
* process
;
89 std::string extension_id
;
91 ListenerProcess(content::RenderProcessHost
* process
,
92 const std::string
& extension_id
)
93 : process(process
), extension_id(extension_id
) {}
95 bool operator<(const ListenerProcess
& that
) const {
96 if (process
< that
.process
)
98 if (process
== that
.process
&& extension_id
< that
.extension_id
)
105 void EventRouter::DispatchExtensionMessage(IPC::Sender
* ipc_sender
,
106 void* browser_context_id
,
107 const std::string
& extension_id
,
109 const std::string
& event_name
,
110 ListValue
* event_args
,
111 UserGestureState user_gesture
,
112 const EventFilteringInfo
& info
) {
113 NotifyEventDispatched(browser_context_id
, extension_id
, event_name
,
114 make_scoped_ptr(event_args
->DeepCopy()));
116 // TODO(chirantan): Make event dispatch a separate IPC so that it doesn't
117 // piggyback off MessageInvoke, which is used for other things.
119 args
.Set(0, new base::StringValue(event_name
));
120 args
.Set(1, event_args
);
121 args
.Set(2, info
.AsValue().release());
122 args
.Set(3, new base::FundamentalValue(event_id
));
123 ipc_sender
->Send(new ExtensionMsg_MessageInvoke(
129 user_gesture
== USER_GESTURE_ENABLED
));
131 // DispatchExtensionMessage does _not_ take ownership of event_args, so we
132 // must ensure that the destruction of args does not attempt to free it.
133 scoped_ptr
<base::Value
> removed_event_args
;
134 args
.Remove(1, &removed_event_args
);
135 ignore_result(removed_event_args
.release());
139 EventRouter
* EventRouter::Get(content::BrowserContext
* browser_context
) {
140 return EventRouterFactory::GetForBrowserContext(browser_context
);
144 std::string
EventRouter::GetBaseEventName(const std::string
& full_event_name
) {
145 size_t slash_sep
= full_event_name
.find('/');
146 return full_event_name
.substr(0, slash_sep
);
150 void EventRouter::DispatchEvent(IPC::Sender
* ipc_sender
,
151 void* browser_context_id
,
152 const std::string
& extension_id
,
153 const std::string
& event_name
,
154 scoped_ptr
<ListValue
> event_args
,
155 UserGestureState user_gesture
,
156 const EventFilteringInfo
& info
) {
157 int event_id
= g_extension_event_id
.GetNext();
159 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
160 // This is called from WebRequest API.
161 // TODO(lazyboy): Skip this entirely: http://crbug.com/488747.
162 BrowserThread::PostTask(
163 BrowserThread::UI
, FROM_HERE
,
164 base::Bind(&EventRouter::IncrementInFlightEventsOnUI
,
165 browser_context_id
, extension_id
, event_id
, event_name
));
167 IncrementInFlightEventsOnUI(browser_context_id
, extension_id
, event_id
,
171 DispatchExtensionMessage(ipc_sender
, browser_context_id
, extension_id
,
172 event_id
, event_name
, event_args
.get(), user_gesture
,
176 EventRouter::EventRouter(BrowserContext
* browser_context
,
177 ExtensionPrefs
* extension_prefs
)
178 : browser_context_(browser_context
),
179 extension_prefs_(extension_prefs
),
180 extension_registry_observer_(this),
183 extensions::NOTIFICATION_EXTENSION_ENABLED
,
184 content::Source
<BrowserContext
>(browser_context_
));
185 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context_
));
188 EventRouter::~EventRouter() {
189 for (auto process
: observed_process_set_
)
190 process
->RemoveObserver(this);
193 void EventRouter::AddEventListener(const std::string
& event_name
,
194 content::RenderProcessHost
* process
,
195 const std::string
& extension_id
) {
196 listeners_
.AddListener(EventListener::ForExtension(
197 event_name
, extension_id
, process
, scoped_ptr
<DictionaryValue
>()));
200 void EventRouter::RemoveEventListener(const std::string
& event_name
,
201 content::RenderProcessHost
* process
,
202 const std::string
& extension_id
) {
203 scoped_ptr
<EventListener
> listener
= EventListener::ForExtension(
204 event_name
, extension_id
, process
, scoped_ptr
<DictionaryValue
>());
205 listeners_
.RemoveListener(listener
.get());
208 void EventRouter::AddEventListenerForURL(const std::string
& event_name
,
209 content::RenderProcessHost
* process
,
210 const GURL
& listener_url
) {
211 listeners_
.AddListener(EventListener::ForURL(
212 event_name
, listener_url
, process
, scoped_ptr
<DictionaryValue
>()));
215 void EventRouter::RemoveEventListenerForURL(const std::string
& event_name
,
216 content::RenderProcessHost
* process
,
217 const GURL
& listener_url
) {
218 scoped_ptr
<EventListener
> listener
= EventListener::ForURL(
219 event_name
, listener_url
, process
, scoped_ptr
<DictionaryValue
>());
220 listeners_
.RemoveListener(listener
.get());
223 void EventRouter::RegisterObserver(Observer
* observer
,
224 const std::string
& event_name
) {
225 // Observing sub-event names like "foo.onBar/123" is not allowed.
226 DCHECK(event_name
.find('/') == std::string::npos
);
227 observers_
[event_name
] = observer
;
230 void EventRouter::UnregisterObserver(Observer
* observer
) {
231 std::vector
<ObserverMap::iterator
> iters_to_remove
;
232 for (ObserverMap::iterator iter
= observers_
.begin();
233 iter
!= observers_
.end(); ++iter
) {
234 if (iter
->second
== observer
)
235 iters_to_remove
.push_back(iter
);
237 for (size_t i
= 0; i
< iters_to_remove
.size(); ++i
)
238 observers_
.erase(iters_to_remove
[i
]);
241 void EventRouter::OnListenerAdded(const EventListener
* listener
) {
242 const EventListenerInfo
details(listener
->event_name(),
243 listener
->extension_id(),
244 listener
->listener_url(),
245 listener
->GetBrowserContext());
246 std::string base_event_name
= GetBaseEventName(listener
->event_name());
247 ObserverMap::iterator observer
= observers_
.find(base_event_name
);
248 if (observer
!= observers_
.end())
249 observer
->second
->OnListenerAdded(details
);
251 content::RenderProcessHost
* process
= listener
->process();
253 bool inserted
= observed_process_set_
.insert(process
).second
;
255 process
->AddObserver(this);
259 void EventRouter::OnListenerRemoved(const EventListener
* listener
) {
260 const EventListenerInfo
details(listener
->event_name(),
261 listener
->extension_id(),
262 listener
->listener_url(),
263 listener
->GetBrowserContext());
264 std::string base_event_name
= GetBaseEventName(listener
->event_name());
265 ObserverMap::iterator observer
= observers_
.find(base_event_name
);
266 if (observer
!= observers_
.end())
267 observer
->second
->OnListenerRemoved(details
);
270 void EventRouter::RenderProcessExited(content::RenderProcessHost
* host
,
271 base::TerminationStatus status
,
273 listeners_
.RemoveListenersForProcess(host
);
274 observed_process_set_
.erase(host
);
275 host
->RemoveObserver(this);
278 void EventRouter::RenderProcessHostDestroyed(content::RenderProcessHost
* host
) {
279 listeners_
.RemoveListenersForProcess(host
);
280 observed_process_set_
.erase(host
);
281 host
->RemoveObserver(this);
284 void EventRouter::AddLazyEventListener(const std::string
& event_name
,
285 const std::string
& extension_id
) {
286 bool is_new
= listeners_
.AddListener(EventListener::ForExtension(
287 event_name
, extension_id
, NULL
, scoped_ptr
<DictionaryValue
>()));
290 std::set
<std::string
> events
= GetRegisteredEvents(extension_id
);
291 bool prefs_is_new
= events
.insert(event_name
).second
;
293 SetRegisteredEvents(extension_id
, events
);
297 void EventRouter::RemoveLazyEventListener(const std::string
& event_name
,
298 const std::string
& extension_id
) {
299 scoped_ptr
<EventListener
> listener
= EventListener::ForExtension(
300 event_name
, extension_id
, NULL
, scoped_ptr
<DictionaryValue
>());
301 bool did_exist
= listeners_
.RemoveListener(listener
.get());
304 std::set
<std::string
> events
= GetRegisteredEvents(extension_id
);
305 bool prefs_did_exist
= events
.erase(event_name
) > 0;
306 DCHECK(prefs_did_exist
);
307 SetRegisteredEvents(extension_id
, events
);
311 void EventRouter::AddFilteredEventListener(const std::string
& event_name
,
312 content::RenderProcessHost
* process
,
313 const std::string
& extension_id
,
314 const base::DictionaryValue
& filter
,
315 bool add_lazy_listener
) {
316 listeners_
.AddListener(EventListener::ForExtension(
320 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy())));
322 if (add_lazy_listener
) {
323 bool added
= listeners_
.AddListener(EventListener::ForExtension(
327 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy())));
330 AddFilterToEvent(event_name
, extension_id
, &filter
);
334 void EventRouter::RemoveFilteredEventListener(
335 const std::string
& event_name
,
336 content::RenderProcessHost
* process
,
337 const std::string
& extension_id
,
338 const base::DictionaryValue
& filter
,
339 bool remove_lazy_listener
) {
340 scoped_ptr
<EventListener
> listener
= EventListener::ForExtension(
344 scoped_ptr
<DictionaryValue
>(filter
.DeepCopy()));
346 listeners_
.RemoveListener(listener
.get());
348 if (remove_lazy_listener
) {
349 listener
->MakeLazy();
350 bool removed
= listeners_
.RemoveListener(listener
.get());
353 RemoveFilterFromEvent(event_name
, extension_id
, &filter
);
357 bool EventRouter::HasEventListener(const std::string
& event_name
) {
358 return listeners_
.HasListenerForEvent(event_name
);
361 bool EventRouter::ExtensionHasEventListener(const std::string
& extension_id
,
362 const std::string
& event_name
) {
363 return listeners_
.HasListenerForExtension(extension_id
, event_name
);
366 bool EventRouter::HasEventListenerImpl(const ListenerMap
& listener_map
,
367 const std::string
& extension_id
,
368 const std::string
& event_name
) {
369 ListenerMap::const_iterator it
= listener_map
.find(event_name
);
370 if (it
== listener_map
.end())
373 const std::set
<ListenerProcess
>& listeners
= it
->second
;
374 if (extension_id
.empty())
375 return !listeners
.empty();
377 for (std::set
<ListenerProcess
>::const_iterator listener
= listeners
.begin();
378 listener
!= listeners
.end(); ++listener
) {
379 if (listener
->extension_id
== extension_id
)
385 std::set
<std::string
> EventRouter::GetRegisteredEvents(
386 const std::string
& extension_id
) {
387 std::set
<std::string
> events
;
388 const ListValue
* events_value
= NULL
;
390 if (!extension_prefs_
||
391 !extension_prefs_
->ReadPrefAsList(
392 extension_id
, kRegisteredEvents
, &events_value
)) {
396 for (size_t i
= 0; i
< events_value
->GetSize(); ++i
) {
398 if (events_value
->GetString(i
, &event
))
399 events
.insert(event
);
404 void EventRouter::SetRegisteredEvents(const std::string
& extension_id
,
405 const std::set
<std::string
>& events
) {
406 ListValue
* events_value
= new ListValue
;
407 for (std::set
<std::string
>::const_iterator iter
= events
.begin();
408 iter
!= events
.end(); ++iter
) {
409 events_value
->Append(new base::StringValue(*iter
));
411 extension_prefs_
->UpdateExtensionPref(
412 extension_id
, kRegisteredEvents
, events_value
);
415 void EventRouter::AddFilterToEvent(const std::string
& event_name
,
416 const std::string
& extension_id
,
417 const DictionaryValue
* filter
) {
418 ExtensionPrefs::ScopedDictionaryUpdate
update(
419 extension_prefs_
, extension_id
, kFilteredEvents
);
420 DictionaryValue
* filtered_events
= update
.Get();
421 if (!filtered_events
)
422 filtered_events
= update
.Create();
424 ListValue
* filter_list
= NULL
;
425 if (!filtered_events
->GetList(event_name
, &filter_list
)) {
426 filter_list
= new ListValue
;
427 filtered_events
->SetWithoutPathExpansion(event_name
, filter_list
);
430 filter_list
->Append(filter
->DeepCopy());
433 void EventRouter::RemoveFilterFromEvent(const std::string
& event_name
,
434 const std::string
& extension_id
,
435 const DictionaryValue
* filter
) {
436 ExtensionPrefs::ScopedDictionaryUpdate
update(
437 extension_prefs_
, extension_id
, kFilteredEvents
);
438 DictionaryValue
* filtered_events
= update
.Get();
439 ListValue
* filter_list
= NULL
;
440 if (!filtered_events
||
441 !filtered_events
->GetListWithoutPathExpansion(event_name
, &filter_list
)) {
445 for (size_t i
= 0; i
< filter_list
->GetSize(); i
++) {
446 DictionaryValue
* filter
= NULL
;
447 CHECK(filter_list
->GetDictionary(i
, &filter
));
448 if (filter
->Equals(filter
)) {
449 filter_list
->Remove(i
, NULL
);
455 const DictionaryValue
* EventRouter::GetFilteredEvents(
456 const std::string
& extension_id
) {
457 const DictionaryValue
* events
= NULL
;
458 extension_prefs_
->ReadPrefAsDictionary(
459 extension_id
, kFilteredEvents
, &events
);
463 void EventRouter::BroadcastEvent(scoped_ptr
<Event
> event
) {
464 DispatchEventImpl(std::string(), linked_ptr
<Event
>(event
.release()));
467 void EventRouter::DispatchEventToExtension(const std::string
& extension_id
,
468 scoped_ptr
<Event
> event
) {
469 DCHECK(!extension_id
.empty());
470 DispatchEventImpl(extension_id
, linked_ptr
<Event
>(event
.release()));
473 void EventRouter::DispatchEventWithLazyListener(const std::string
& extension_id
,
474 scoped_ptr
<Event
> event
) {
475 DCHECK(!extension_id
.empty());
476 std::string event_name
= event
->event_name
;
477 bool has_listener
= ExtensionHasEventListener(extension_id
, event_name
);
479 AddLazyEventListener(event_name
, extension_id
);
480 DispatchEventToExtension(extension_id
, event
.Pass());
482 RemoveLazyEventListener(event_name
, extension_id
);
485 void EventRouter::DispatchEventImpl(const std::string
& restrict_to_extension_id
,
486 const linked_ptr
<Event
>& event
) {
487 // We don't expect to get events from a completely different browser context.
488 DCHECK(!event
->restrict_to_browser_context
||
489 ExtensionsBrowserClient::Get()->IsSameContext(
490 browser_context_
, event
->restrict_to_browser_context
));
492 std::set
<const EventListener
*> listeners(
493 listeners_
.GetEventListeners(*event
));
495 std::set
<EventDispatchIdentifier
> already_dispatched
;
497 // We dispatch events for lazy background pages first because attempting to do
498 // so will cause those that are being suspended to cancel that suspension.
499 // As canceling a suspension entails sending an event to the affected
500 // background page, and as that event needs to be delivered before we dispatch
501 // the event we are dispatching here, we dispatch to the lazy listeners here
503 for (std::set
<const EventListener
*>::iterator it
= listeners
.begin();
504 it
!= listeners
.end(); it
++) {
505 const EventListener
* listener
= *it
;
506 if (restrict_to_extension_id
.empty() ||
507 restrict_to_extension_id
== listener
->extension_id()) {
508 if (listener
->IsLazy()) {
509 DispatchLazyEvent(listener
->extension_id(), event
, &already_dispatched
,
515 for (std::set
<const EventListener
*>::iterator it
= listeners
.begin();
516 it
!= listeners
.end(); it
++) {
517 const EventListener
* listener
= *it
;
518 if (restrict_to_extension_id
.empty() ||
519 restrict_to_extension_id
== listener
->extension_id()) {
520 if (listener
->process()) {
521 EventDispatchIdentifier
dispatch_id(listener
->GetBrowserContext(),
522 listener
->extension_id());
523 if (!ContainsKey(already_dispatched
, dispatch_id
)) {
524 DispatchEventToProcess(listener
->extension_id(),
525 listener
->listener_url(), listener
->process(),
526 event
, listener
->filter());
533 void EventRouter::DispatchLazyEvent(
534 const std::string
& extension_id
,
535 const linked_ptr
<Event
>& event
,
536 std::set
<EventDispatchIdentifier
>* already_dispatched
,
537 const base::DictionaryValue
* listener_filter
) {
538 // Check both the original and the incognito browser context to see if we
539 // should load a lazy bg page to handle the event. The latter case
540 // occurs in the case of split-mode extensions.
541 const Extension
* extension
=
542 ExtensionRegistry::Get(browser_context_
)->enabled_extensions().GetByID(
547 if (MaybeLoadLazyBackgroundPageToDispatchEvent(browser_context_
, extension
,
548 event
, listener_filter
)) {
549 already_dispatched
->insert(std::make_pair(browser_context_
, extension_id
));
552 ExtensionsBrowserClient
* browser_client
= ExtensionsBrowserClient::Get();
553 if (browser_client
->HasOffTheRecordContext(browser_context_
) &&
554 IncognitoInfo::IsSplitMode(extension
)) {
555 BrowserContext
* incognito_context
=
556 browser_client
->GetOffTheRecordContext(browser_context_
);
557 if (MaybeLoadLazyBackgroundPageToDispatchEvent(incognito_context
, extension
,
558 event
, listener_filter
)) {
559 already_dispatched
->insert(
560 std::make_pair(incognito_context
, extension_id
));
565 void EventRouter::DispatchEventToProcess(
566 const std::string
& extension_id
,
567 const GURL
& listener_url
,
568 content::RenderProcessHost
* process
,
569 const linked_ptr
<Event
>& event
,
570 const base::DictionaryValue
* listener_filter
) {
571 BrowserContext
* listener_context
= process
->GetBrowserContext();
572 ProcessMap
* process_map
= ProcessMap::Get(listener_context
);
574 // NOTE: |extension| being NULL does not necessarily imply that this event
575 // shouldn't be dispatched. Events can be dispatched to WebUI and webviews as
576 // well. It all depends on what GetMostLikelyContextType returns.
577 const Extension
* extension
=
578 ExtensionRegistry::Get(browser_context_
)->enabled_extensions().GetByID(
581 if (!extension
&& !extension_id
.empty()) {
582 // Trying to dispatch an event to an extension that doesn't exist. The
583 // extension could have been removed, but we do not unregister it until the
584 // extension process is unloaded.
589 // Extension-specific checks.
590 // Firstly, if the event is for a URL, the Extension must have permission
591 // to access that URL.
592 if (!event
->event_url
.is_empty() &&
593 event
->event_url
.host() != extension
->id() && // event for self is ok
594 !extension
->permissions_data()
595 ->active_permissions()
596 ->HasEffectiveAccessToURL(event
->event_url
)) {
599 // Secondly, if the event is for incognito mode, the Extension must be
600 // enabled in incognito mode.
601 if (!CanDispatchEventToBrowserContext(listener_context
, extension
, event
)) {
606 Feature::Context target_context
=
607 process_map
->GetMostLikelyContextType(extension
, process
->GetID());
609 // We shouldn't be dispatching an event to a webpage, since all such events
610 // (e.g. messaging) don't go through EventRouter.
611 DCHECK_NE(Feature::WEB_PAGE_CONTEXT
, target_context
)
612 << "Trying to dispatch event " << event
->event_name
<< " to a webpage,"
613 << " but this shouldn't be possible";
615 Feature::Availability availability
=
616 ExtensionAPI::GetSharedInstance()->IsAvailable(
617 event
->event_name
, extension
, target_context
, listener_url
);
618 if (!availability
.is_available()) {
619 // It shouldn't be possible to reach here, because access is checked on
620 // registration. However, for paranoia, check on dispatch as well.
621 NOTREACHED() << "Trying to dispatch event " << event
->event_name
622 << " which the target does not have access to: "
623 << availability
.message();
627 if (!event
->will_dispatch_callback
.is_null() &&
628 !event
->will_dispatch_callback
.Run(listener_context
, extension
,
629 event
->event_args
.get(),
634 int event_id
= g_extension_event_id
.GetNext();
635 DispatchExtensionMessage(process
, listener_context
, extension_id
, event_id
,
636 event
->event_name
, event
->event_args
.get(),
637 event
->user_gesture
, event
->filter_info
);
640 IncrementInFlightEvents(listener_context
, extension
, event_id
,
645 bool EventRouter::CanDispatchEventToBrowserContext(
646 BrowserContext
* context
,
647 const Extension
* extension
,
648 const linked_ptr
<Event
>& event
) {
649 // Is this event from a different browser context than the renderer (ie, an
650 // incognito tab event sent to a normal process, or vice versa).
651 bool cross_incognito
= event
->restrict_to_browser_context
&&
652 context
!= event
->restrict_to_browser_context
;
653 if (!cross_incognito
)
655 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
659 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent(
660 BrowserContext
* context
,
661 const Extension
* extension
,
662 const linked_ptr
<Event
>& event
,
663 const base::DictionaryValue
* listener_filter
) {
664 if (!CanDispatchEventToBrowserContext(context
, extension
, event
))
667 LazyBackgroundTaskQueue
* queue
= LazyBackgroundTaskQueue::Get(context
);
668 if (queue
->ShouldEnqueueTask(context
, extension
)) {
669 linked_ptr
<Event
> dispatched_event(event
);
671 // If there's a dispatch callback, call it now (rather than dispatch time)
672 // to avoid lifetime issues. Use a separate copy of the event args, so they
673 // last until the event is dispatched.
674 if (!event
->will_dispatch_callback
.is_null()) {
675 dispatched_event
.reset(event
->DeepCopy());
676 if (!dispatched_event
->will_dispatch_callback
.Run(
677 context
, extension
, dispatched_event
->event_args
.get(),
679 // The event has been canceled.
682 // Ensure we don't call it again at dispatch time.
683 dispatched_event
->will_dispatch_callback
.Reset();
686 queue
->AddPendingTask(context
, extension
->id(),
687 base::Bind(&EventRouter::DispatchPendingEvent
,
688 base::Unretained(this), dispatched_event
));
696 void EventRouter::IncrementInFlightEventsOnUI(void* browser_context_id
,
697 const std::string
& extension_id
,
699 const std::string
& event_name
) {
700 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
701 BrowserContext
* browser_context
=
702 reinterpret_cast<BrowserContext
*>(browser_context_id
);
703 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context
))
705 EventRouter
* event_router
= EventRouter::Get(browser_context
);
708 const Extension
* extension
=
709 ExtensionRegistry::Get(browser_context
)->enabled_extensions().GetByID(
713 event_router
->IncrementInFlightEvents(browser_context
, extension
, event_id
,
717 void EventRouter::IncrementInFlightEvents(BrowserContext
* context
,
718 const Extension
* extension
,
720 const std::string
& event_name
) {
721 // TODO(chirantan): Turn this on once crbug.com/464513 is fixed.
722 // DCHECK_CURRENTLY_ON(BrowserThread::UI);
724 // Only increment in-flight events if the lazy background page is active,
725 // because that's the only time we'll get an ACK.
726 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
727 ProcessManager
* pm
= ProcessManager::Get(context
);
728 ExtensionHost
* host
= pm
->GetBackgroundHostForExtension(extension
->id());
730 pm
->IncrementLazyKeepaliveCount(extension
);
731 host
->OnBackgroundEventDispatched(event_name
, event_id
);
736 void EventRouter::OnEventAck(BrowserContext
* context
,
737 const std::string
& extension_id
) {
738 ProcessManager
* pm
= ProcessManager::Get(context
);
739 ExtensionHost
* host
= pm
->GetBackgroundHostForExtension(extension_id
);
740 // The event ACK is routed to the background host, so this should never be
743 // TODO(mpcomplete): We should never get this message unless
744 // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
745 if (host
->extension() &&
746 BackgroundInfo::HasLazyBackgroundPage(host
->extension()))
747 pm
->DecrementLazyKeepaliveCount(host
->extension());
750 void EventRouter::DispatchPendingEvent(const linked_ptr
<Event
>& event
,
751 ExtensionHost
* host
) {
755 if (listeners_
.HasProcessListener(host
->render_process_host(),
756 host
->extension()->id())) {
757 // URL events cannot be lazy therefore can't be pending, hence the GURL().
758 DispatchEventToProcess(host
->extension()->id(), GURL(),
759 host
->render_process_host(), event
, nullptr);
763 void EventRouter::Observe(int type
,
764 const content::NotificationSource
& source
,
765 const content::NotificationDetails
& details
) {
767 case extensions::NOTIFICATION_EXTENSION_ENABLED
: {
768 // If the extension has a lazy background page, make sure it gets loaded
769 // to register the events the extension is interested in.
770 const Extension
* extension
=
771 content::Details
<const Extension
>(details
).ptr();
772 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
773 LazyBackgroundTaskQueue
* queue
=
774 LazyBackgroundTaskQueue::Get(browser_context_
);
775 queue
->AddPendingTask(browser_context_
, extension
->id(),
776 base::Bind(&DoNothing
));
785 void EventRouter::OnExtensionLoaded(content::BrowserContext
* browser_context
,
786 const Extension
* extension
) {
787 // Add all registered lazy listeners to our cache.
788 std::set
<std::string
> registered_events
=
789 GetRegisteredEvents(extension
->id());
790 listeners_
.LoadUnfilteredLazyListeners(extension
->id(), registered_events
);
791 const DictionaryValue
* filtered_events
= GetFilteredEvents(extension
->id());
793 listeners_
.LoadFilteredLazyListeners(extension
->id(), *filtered_events
);
796 void EventRouter::OnExtensionUnloaded(content::BrowserContext
* browser_context
,
797 const Extension
* extension
,
798 UnloadedExtensionInfo::Reason reason
) {
799 // Remove all registered listeners from our cache.
800 listeners_
.RemoveListenersForExtension(extension
->id());
803 Event::Event(events::HistogramValue histogram_value
,
804 const std::string
& event_name
,
805 scoped_ptr
<base::ListValue
> event_args
)
806 : Event(histogram_value
, event_name
, event_args
.Pass(), nullptr) {}
808 Event::Event(events::HistogramValue histogram_value
,
809 const std::string
& event_name
,
810 scoped_ptr
<base::ListValue
> event_args
,
811 BrowserContext
* restrict_to_browser_context
)
812 : Event(histogram_value
,
815 restrict_to_browser_context
,
817 EventRouter::USER_GESTURE_UNKNOWN
,
818 EventFilteringInfo()) {}
820 Event::Event(events::HistogramValue histogram_value
,
821 const std::string
& event_name
,
822 scoped_ptr
<ListValue
> event_args_tmp
,
823 BrowserContext
* restrict_to_browser_context
,
824 const GURL
& event_url
,
825 EventRouter::UserGestureState user_gesture
,
826 const EventFilteringInfo
& filter_info
)
827 : histogram_value(histogram_value
),
828 event_name(event_name
),
829 event_args(event_args_tmp
.Pass()),
830 restrict_to_browser_context(restrict_to_browser_context
),
831 event_url(event_url
),
832 user_gesture(user_gesture
),
833 filter_info(filter_info
) {
835 DCHECK_NE(events::UNKNOWN
, histogram_value
)
836 << "events::UNKNOWN cannot be used as a histogram value.\n"
837 << "If this is a test, use events::FOR_TEST.\n"
838 << "If this is production code, it is important that you use a realistic "
839 << "value so that we can accurately track event usage. "
840 << "See extension_event_histogram_value.h for inspiration.";
845 Event
* Event::DeepCopy() {
846 Event
* copy
= new Event(histogram_value
, event_name
,
847 scoped_ptr
<base::ListValue
>(event_args
->DeepCopy()),
848 restrict_to_browser_context
, event_url
, user_gesture
,
850 copy
->will_dispatch_callback
= will_dispatch_callback
;
854 EventListenerInfo::EventListenerInfo(const std::string
& event_name
,
855 const std::string
& extension_id
,
856 const GURL
& listener_url
,
857 content::BrowserContext
* browser_context
)
858 : event_name(event_name
),
859 extension_id(extension_id
),
860 listener_url(listener_url
),
861 browser_context(browser_context
) {
864 } // namespace extensions