Add ICU message format support
[chromium-blink-merge.git] / extensions / browser / event_router.cc
blobe70d02b65a88c5d2cb1ee5cd19904d5958413246
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"
7 #include <utility>
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 {
46 namespace {
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
56 // thread.
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)));
67 return;
70 // Notify the ApiActivityMonitor about the event dispatch.
71 BrowserContext* context = static_cast<BrowserContext*>(browser_context_id);
72 if (!ExtensionsBrowserClient::Get()->IsValidContext(context))
73 return;
74 ApiActivityMonitor* monitor =
75 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(context);
76 if (monitor)
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;
83 } // namespace
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)
97 return true;
98 if (process == that.process && extension_id < that.extension_id)
99 return true;
100 return false;
104 // static
105 void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
106 void* browser_context_id,
107 const std::string& extension_id,
108 int event_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.
118 ListValue args;
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(
124 MSG_ROUTING_CONTROL,
125 extension_id,
126 kEventBindings,
127 "dispatchEvent",
128 args,
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());
138 // static
139 EventRouter* EventRouter::Get(content::BrowserContext* browser_context) {
140 return EventRouterFactory::GetForBrowserContext(browser_context);
143 // static
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);
149 // static
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));
166 } else {
167 IncrementInFlightEventsOnUI(browser_context_id, extension_id, event_id,
168 event_name);
171 DispatchExtensionMessage(ipc_sender, browser_context_id, extension_id,
172 event_id, event_name, event_args.get(), user_gesture,
173 info);
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),
181 listeners_(this) {
182 registrar_.Add(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();
252 if (process) {
253 bool inserted = observed_process_set_.insert(process).second;
254 if (inserted)
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,
272 int exit_code) {
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>()));
289 if (is_new) {
290 std::set<std::string> events = GetRegisteredEvents(extension_id);
291 bool prefs_is_new = events.insert(event_name).second;
292 if (prefs_is_new)
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());
303 if (did_exist) {
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(
317 event_name,
318 extension_id,
319 process,
320 scoped_ptr<DictionaryValue>(filter.DeepCopy())));
322 if (add_lazy_listener) {
323 bool added = listeners_.AddListener(EventListener::ForExtension(
324 event_name,
325 extension_id,
326 NULL,
327 scoped_ptr<DictionaryValue>(filter.DeepCopy())));
329 if (added)
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(
341 event_name,
342 extension_id,
343 process,
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());
352 if (removed)
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())
371 return false;
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)
380 return true;
382 return false;
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)) {
393 return events;
396 for (size_t i = 0; i < events_value->GetSize(); ++i) {
397 std::string event;
398 if (events_value->GetString(i, &event))
399 events.insert(event);
401 return events;
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)) {
442 return;
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);
450 break;
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);
460 return 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);
478 if (!has_listener)
479 AddLazyEventListener(event_name, extension_id);
480 DispatchEventToExtension(extension_id, event.Pass());
481 if (!has_listener)
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
502 // first.
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,
510 listener->filter());
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(
543 extension_id);
544 if (!extension)
545 return;
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(
579 extension_id);
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.
585 return;
588 if (extension) {
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)) {
597 return;
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)) {
602 return;
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();
624 return;
627 if (!event->will_dispatch_callback.is_null() &&
628 !event->will_dispatch_callback.Run(listener_context, extension,
629 event->event_args.get(),
630 listener_filter)) {
631 return;
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);
639 if (extension) {
640 IncrementInFlightEvents(listener_context, extension, event_id,
641 event->event_name);
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)
654 return true;
655 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
656 extension, context);
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))
665 return false;
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(),
678 listener_filter)) {
679 // The event has been canceled.
680 return true;
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));
689 return true;
692 return false;
695 // static
696 void EventRouter::IncrementInFlightEventsOnUI(void* browser_context_id,
697 const std::string& extension_id,
698 int event_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))
704 return;
705 EventRouter* event_router = EventRouter::Get(browser_context);
706 if (!event_router)
707 return;
708 const Extension* extension =
709 ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID(
710 extension_id);
711 if (!extension)
712 return;
713 event_router->IncrementInFlightEvents(browser_context, extension, event_id,
714 event_name);
717 void EventRouter::IncrementInFlightEvents(BrowserContext* context,
718 const Extension* extension,
719 int event_id,
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());
729 if (host) {
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
741 // NULL.
742 CHECK(host);
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) {
752 if (!host)
753 return;
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) {
766 switch (type) {
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));
778 break;
780 default:
781 NOTREACHED();
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());
792 if (filtered_events)
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,
813 event_name,
814 event_args.Pass(),
815 restrict_to_browser_context,
816 GURL(),
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) {
834 DCHECK(event_args);
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.";
843 Event::~Event() {}
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,
849 filter_info);
850 copy->will_dispatch_callback = will_dispatch_callback;
851 return copy;
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