Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / extensions / browser / event_router.cc
blob6a8cf8d31eed7d95978c4d492ef99ad1e1286e80
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/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 {
45 namespace {
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
55 // thread.
56 void NotifyEventDispatched(void* browser_context_id,
57 const std::string& extension_id,
58 const std::string& event_name,
59 scoped_ptr<ListValue> args) {
60 // The ApiActivityMonitor can only be accessed from the UI thread.
61 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
62 BrowserThread::PostTask(
63 BrowserThread::UI, FROM_HERE,
64 base::Bind(&NotifyEventDispatched, browser_context_id, extension_id,
65 event_name, base::Passed(&args)));
66 return;
69 // Notify the ApiActivityMonitor about the event dispatch.
70 BrowserContext* context = static_cast<BrowserContext*>(browser_context_id);
71 if (!ExtensionsBrowserClient::Get()->IsValidContext(context))
72 return;
73 ApiActivityMonitor* monitor =
74 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(context);
75 if (monitor)
76 monitor->OnApiEventDispatched(extension_id, event_name, args.Pass());
79 // A global identifier used to distinguish extension events.
80 base::StaticAtomicSequenceNumber g_extension_event_id;
82 } // namespace
84 const char EventRouter::kRegisteredEvents[] = "events";
86 struct EventRouter::ListenerProcess {
87 content::RenderProcessHost* process;
88 std::string extension_id;
90 ListenerProcess(content::RenderProcessHost* process,
91 const std::string& extension_id)
92 : process(process), extension_id(extension_id) {}
94 bool operator<(const ListenerProcess& that) const {
95 if (process < that.process)
96 return true;
97 if (process == that.process && extension_id < that.extension_id)
98 return true;
99 return false;
103 // static
104 void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
105 void* browser_context_id,
106 const std::string& extension_id,
107 int event_id,
108 const std::string& event_name,
109 ListValue* event_args,
110 UserGestureState user_gesture,
111 const EventFilteringInfo& info) {
112 NotifyEventDispatched(browser_context_id, extension_id, event_name,
113 make_scoped_ptr(event_args->DeepCopy()));
115 // TODO(chirantan): Make event dispatch a separate IPC so that it doesn't
116 // piggyback off MessageInvoke, which is used for other things.
117 ListValue args;
118 args.Set(0, new base::StringValue(event_name));
119 args.Set(1, event_args);
120 args.Set(2, info.AsValue().release());
121 args.Set(3, new base::FundamentalValue(event_id));
122 ipc_sender->Send(new ExtensionMsg_MessageInvoke(
123 MSG_ROUTING_CONTROL,
124 extension_id,
125 kEventBindings,
126 "dispatchEvent",
127 args,
128 user_gesture == USER_GESTURE_ENABLED));
130 // DispatchExtensionMessage does _not_ take ownership of event_args, so we
131 // must ensure that the destruction of args does not attempt to free it.
132 scoped_ptr<base::Value> removed_event_args;
133 args.Remove(1, &removed_event_args);
134 ignore_result(removed_event_args.release());
137 // static
138 EventRouter* EventRouter::Get(content::BrowserContext* browser_context) {
139 return ExtensionSystem::Get(browser_context)->event_router();
142 // static
143 std::string EventRouter::GetBaseEventName(const std::string& full_event_name) {
144 size_t slash_sep = full_event_name.find('/');
145 return full_event_name.substr(0, slash_sep);
148 // static
149 void EventRouter::DispatchEvent(IPC::Sender* ipc_sender,
150 void* browser_context_id,
151 const std::string& extension_id,
152 const std::string& event_name,
153 scoped_ptr<ListValue> event_args,
154 UserGestureState user_gesture,
155 const EventFilteringInfo& info) {
156 int event_id = g_extension_event_id.GetNext();
158 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
159 // This is called from WebRequest API.
160 // TODO(lazyboy): Skip this entirely: http://crbug.com/488747.
161 BrowserThread::PostTask(
162 BrowserThread::UI, FROM_HERE,
163 base::Bind(&EventRouter::IncrementInFlightEventsOnUI,
164 browser_context_id, extension_id, event_id, event_name));
165 } else {
166 IncrementInFlightEventsOnUI(browser_context_id, extension_id, event_id,
167 event_name);
170 DispatchExtensionMessage(ipc_sender, browser_context_id, extension_id,
171 event_id, event_name, event_args.get(), user_gesture,
172 info);
175 EventRouter::EventRouter(BrowserContext* browser_context,
176 ExtensionPrefs* extension_prefs)
177 : browser_context_(browser_context),
178 extension_prefs_(extension_prefs),
179 extension_registry_observer_(this),
180 listeners_(this) {
181 registrar_.Add(this,
182 extensions::NOTIFICATION_EXTENSION_ENABLED,
183 content::Source<BrowserContext>(browser_context_));
184 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
187 EventRouter::~EventRouter() {
188 for (auto process : observed_process_set_)
189 process->RemoveObserver(this);
192 void EventRouter::AddEventListener(const std::string& event_name,
193 content::RenderProcessHost* process,
194 const std::string& extension_id) {
195 listeners_.AddListener(EventListener::ForExtension(
196 event_name, extension_id, process, scoped_ptr<DictionaryValue>()));
199 void EventRouter::RemoveEventListener(const std::string& event_name,
200 content::RenderProcessHost* process,
201 const std::string& extension_id) {
202 scoped_ptr<EventListener> listener = EventListener::ForExtension(
203 event_name, extension_id, process, scoped_ptr<DictionaryValue>());
204 listeners_.RemoveListener(listener.get());
207 void EventRouter::AddEventListenerForURL(const std::string& event_name,
208 content::RenderProcessHost* process,
209 const GURL& listener_url) {
210 listeners_.AddListener(EventListener::ForURL(
211 event_name, listener_url, process, scoped_ptr<DictionaryValue>()));
214 void EventRouter::RemoveEventListenerForURL(const std::string& event_name,
215 content::RenderProcessHost* process,
216 const GURL& listener_url) {
217 scoped_ptr<EventListener> listener = EventListener::ForURL(
218 event_name, listener_url, process, scoped_ptr<DictionaryValue>());
219 listeners_.RemoveListener(listener.get());
222 void EventRouter::RegisterObserver(Observer* observer,
223 const std::string& event_name) {
224 // Observing sub-event names like "foo.onBar/123" is not allowed.
225 DCHECK(event_name.find('/') == std::string::npos);
226 observers_[event_name] = observer;
229 void EventRouter::UnregisterObserver(Observer* observer) {
230 std::vector<ObserverMap::iterator> iters_to_remove;
231 for (ObserverMap::iterator iter = observers_.begin();
232 iter != observers_.end(); ++iter) {
233 if (iter->second == observer)
234 iters_to_remove.push_back(iter);
236 for (size_t i = 0; i < iters_to_remove.size(); ++i)
237 observers_.erase(iters_to_remove[i]);
240 void EventRouter::OnListenerAdded(const EventListener* listener) {
241 const EventListenerInfo details(listener->event_name(),
242 listener->extension_id(),
243 listener->listener_url(),
244 listener->GetBrowserContext());
245 std::string base_event_name = GetBaseEventName(listener->event_name());
246 ObserverMap::iterator observer = observers_.find(base_event_name);
247 if (observer != observers_.end())
248 observer->second->OnListenerAdded(details);
250 content::RenderProcessHost* process = listener->process();
251 if (process) {
252 bool inserted = observed_process_set_.insert(process).second;
253 if (inserted)
254 process->AddObserver(this);
258 void EventRouter::OnListenerRemoved(const EventListener* listener) {
259 const EventListenerInfo details(listener->event_name(),
260 listener->extension_id(),
261 listener->listener_url(),
262 listener->GetBrowserContext());
263 std::string base_event_name = GetBaseEventName(listener->event_name());
264 ObserverMap::iterator observer = observers_.find(base_event_name);
265 if (observer != observers_.end())
266 observer->second->OnListenerRemoved(details);
269 void EventRouter::RenderProcessExited(content::RenderProcessHost* host,
270 base::TerminationStatus status,
271 int exit_code) {
272 listeners_.RemoveListenersForProcess(host);
273 observed_process_set_.erase(host);
274 host->RemoveObserver(this);
277 void EventRouter::RenderProcessHostDestroyed(content::RenderProcessHost* host) {
278 listeners_.RemoveListenersForProcess(host);
279 observed_process_set_.erase(host);
280 host->RemoveObserver(this);
283 void EventRouter::AddLazyEventListener(const std::string& event_name,
284 const std::string& extension_id) {
285 bool is_new = listeners_.AddListener(EventListener::ForExtension(
286 event_name, extension_id, NULL, scoped_ptr<DictionaryValue>()));
288 if (is_new) {
289 std::set<std::string> events = GetRegisteredEvents(extension_id);
290 bool prefs_is_new = events.insert(event_name).second;
291 if (prefs_is_new)
292 SetRegisteredEvents(extension_id, events);
296 void EventRouter::RemoveLazyEventListener(const std::string& event_name,
297 const std::string& extension_id) {
298 scoped_ptr<EventListener> listener = EventListener::ForExtension(
299 event_name, extension_id, NULL, scoped_ptr<DictionaryValue>());
300 bool did_exist = listeners_.RemoveListener(listener.get());
302 if (did_exist) {
303 std::set<std::string> events = GetRegisteredEvents(extension_id);
304 bool prefs_did_exist = events.erase(event_name) > 0;
305 DCHECK(prefs_did_exist);
306 SetRegisteredEvents(extension_id, events);
310 void EventRouter::AddFilteredEventListener(const std::string& event_name,
311 content::RenderProcessHost* process,
312 const std::string& extension_id,
313 const base::DictionaryValue& filter,
314 bool add_lazy_listener) {
315 listeners_.AddListener(EventListener::ForExtension(
316 event_name,
317 extension_id,
318 process,
319 scoped_ptr<DictionaryValue>(filter.DeepCopy())));
321 if (add_lazy_listener) {
322 bool added = listeners_.AddListener(EventListener::ForExtension(
323 event_name,
324 extension_id,
325 NULL,
326 scoped_ptr<DictionaryValue>(filter.DeepCopy())));
328 if (added)
329 AddFilterToEvent(event_name, extension_id, &filter);
333 void EventRouter::RemoveFilteredEventListener(
334 const std::string& event_name,
335 content::RenderProcessHost* process,
336 const std::string& extension_id,
337 const base::DictionaryValue& filter,
338 bool remove_lazy_listener) {
339 scoped_ptr<EventListener> listener = EventListener::ForExtension(
340 event_name,
341 extension_id,
342 process,
343 scoped_ptr<DictionaryValue>(filter.DeepCopy()));
345 listeners_.RemoveListener(listener.get());
347 if (remove_lazy_listener) {
348 listener->MakeLazy();
349 bool removed = listeners_.RemoveListener(listener.get());
351 if (removed)
352 RemoveFilterFromEvent(event_name, extension_id, &filter);
356 bool EventRouter::HasEventListener(const std::string& event_name) {
357 return listeners_.HasListenerForEvent(event_name);
360 bool EventRouter::ExtensionHasEventListener(const std::string& extension_id,
361 const std::string& event_name) {
362 return listeners_.HasListenerForExtension(extension_id, event_name);
365 bool EventRouter::HasEventListenerImpl(const ListenerMap& listener_map,
366 const std::string& extension_id,
367 const std::string& event_name) {
368 ListenerMap::const_iterator it = listener_map.find(event_name);
369 if (it == listener_map.end())
370 return false;
372 const std::set<ListenerProcess>& listeners = it->second;
373 if (extension_id.empty())
374 return !listeners.empty();
376 for (std::set<ListenerProcess>::const_iterator listener = listeners.begin();
377 listener != listeners.end(); ++listener) {
378 if (listener->extension_id == extension_id)
379 return true;
381 return false;
384 std::set<std::string> EventRouter::GetRegisteredEvents(
385 const std::string& extension_id) {
386 std::set<std::string> events;
387 const ListValue* events_value = NULL;
389 if (!extension_prefs_ ||
390 !extension_prefs_->ReadPrefAsList(
391 extension_id, kRegisteredEvents, &events_value)) {
392 return events;
395 for (size_t i = 0; i < events_value->GetSize(); ++i) {
396 std::string event;
397 if (events_value->GetString(i, &event))
398 events.insert(event);
400 return events;
403 void EventRouter::SetRegisteredEvents(const std::string& extension_id,
404 const std::set<std::string>& events) {
405 ListValue* events_value = new ListValue;
406 for (std::set<std::string>::const_iterator iter = events.begin();
407 iter != events.end(); ++iter) {
408 events_value->Append(new base::StringValue(*iter));
410 extension_prefs_->UpdateExtensionPref(
411 extension_id, kRegisteredEvents, events_value);
414 void EventRouter::AddFilterToEvent(const std::string& event_name,
415 const std::string& extension_id,
416 const DictionaryValue* filter) {
417 ExtensionPrefs::ScopedDictionaryUpdate update(
418 extension_prefs_, extension_id, kFilteredEvents);
419 DictionaryValue* filtered_events = update.Get();
420 if (!filtered_events)
421 filtered_events = update.Create();
423 ListValue* filter_list = NULL;
424 if (!filtered_events->GetList(event_name, &filter_list)) {
425 filter_list = new ListValue;
426 filtered_events->SetWithoutPathExpansion(event_name, filter_list);
429 filter_list->Append(filter->DeepCopy());
432 void EventRouter::RemoveFilterFromEvent(const std::string& event_name,
433 const std::string& extension_id,
434 const DictionaryValue* filter) {
435 ExtensionPrefs::ScopedDictionaryUpdate update(
436 extension_prefs_, extension_id, kFilteredEvents);
437 DictionaryValue* filtered_events = update.Get();
438 ListValue* filter_list = NULL;
439 if (!filtered_events ||
440 !filtered_events->GetListWithoutPathExpansion(event_name, &filter_list)) {
441 return;
444 for (size_t i = 0; i < filter_list->GetSize(); i++) {
445 DictionaryValue* filter = NULL;
446 CHECK(filter_list->GetDictionary(i, &filter));
447 if (filter->Equals(filter)) {
448 filter_list->Remove(i, NULL);
449 break;
454 const DictionaryValue* EventRouter::GetFilteredEvents(
455 const std::string& extension_id) {
456 const DictionaryValue* events = NULL;
457 extension_prefs_->ReadPrefAsDictionary(
458 extension_id, kFilteredEvents, &events);
459 return events;
462 void EventRouter::BroadcastEvent(scoped_ptr<Event> event) {
463 DispatchEventImpl(std::string(), linked_ptr<Event>(event.release()));
466 void EventRouter::DispatchEventToExtension(const std::string& extension_id,
467 scoped_ptr<Event> event) {
468 DCHECK(!extension_id.empty());
469 DispatchEventImpl(extension_id, linked_ptr<Event>(event.release()));
472 void EventRouter::DispatchEventWithLazyListener(const std::string& extension_id,
473 scoped_ptr<Event> event) {
474 DCHECK(!extension_id.empty());
475 std::string event_name = event->event_name;
476 bool has_listener = ExtensionHasEventListener(extension_id, event_name);
477 if (!has_listener)
478 AddLazyEventListener(event_name, extension_id);
479 DispatchEventToExtension(extension_id, event.Pass());
480 if (!has_listener)
481 RemoveLazyEventListener(event_name, extension_id);
484 void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id,
485 const linked_ptr<Event>& event) {
486 // We don't expect to get events from a completely different browser context.
487 DCHECK(!event->restrict_to_browser_context ||
488 ExtensionsBrowserClient::Get()->IsSameContext(
489 browser_context_, event->restrict_to_browser_context));
491 std::set<const EventListener*> listeners(
492 listeners_.GetEventListeners(*event));
494 std::set<EventDispatchIdentifier> already_dispatched;
496 // We dispatch events for lazy background pages first because attempting to do
497 // so will cause those that are being suspended to cancel that suspension.
498 // As canceling a suspension entails sending an event to the affected
499 // background page, and as that event needs to be delivered before we dispatch
500 // the event we are dispatching here, we dispatch to the lazy listeners here
501 // first.
502 for (std::set<const EventListener*>::iterator it = listeners.begin();
503 it != listeners.end(); it++) {
504 const EventListener* listener = *it;
505 if (restrict_to_extension_id.empty() ||
506 restrict_to_extension_id == listener->extension_id()) {
507 if (listener->IsLazy()) {
508 DispatchLazyEvent(listener->extension_id(), event, &already_dispatched);
513 for (std::set<const EventListener*>::iterator it = listeners.begin();
514 it != listeners.end(); it++) {
515 const EventListener* listener = *it;
516 if (restrict_to_extension_id.empty() ||
517 restrict_to_extension_id == listener->extension_id()) {
518 if (listener->process()) {
519 EventDispatchIdentifier dispatch_id(listener->GetBrowserContext(),
520 listener->extension_id());
521 if (!ContainsKey(already_dispatched, dispatch_id)) {
522 DispatchEventToProcess(listener->extension_id(),
523 listener->listener_url(),
524 listener->process(),
525 event);
532 void EventRouter::DispatchLazyEvent(
533 const std::string& extension_id,
534 const linked_ptr<Event>& event,
535 std::set<EventDispatchIdentifier>* already_dispatched) {
536 // Check both the original and the incognito browser context to see if we
537 // should load a lazy bg page to handle the event. The latter case
538 // occurs in the case of split-mode extensions.
539 const Extension* extension =
540 ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID(
541 extension_id);
542 if (!extension)
543 return;
545 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
546 browser_context_, extension, event)) {
547 already_dispatched->insert(std::make_pair(browser_context_, extension_id));
550 ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get();
551 if (browser_client->HasOffTheRecordContext(browser_context_) &&
552 IncognitoInfo::IsSplitMode(extension)) {
553 BrowserContext* incognito_context =
554 browser_client->GetOffTheRecordContext(browser_context_);
555 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
556 incognito_context, extension, event)) {
557 already_dispatched->insert(
558 std::make_pair(incognito_context, extension_id));
563 void EventRouter::DispatchEventToProcess(const std::string& extension_id,
564 const GURL& listener_url,
565 content::RenderProcessHost* process,
566 const linked_ptr<Event>& event) {
567 BrowserContext* listener_context = process->GetBrowserContext();
568 ProcessMap* process_map = ProcessMap::Get(listener_context);
570 // NOTE: |extension| being NULL does not necessarily imply that this event
571 // shouldn't be dispatched. Events can be dispatched to WebUI and webviews as
572 // well. It all depends on what GetMostLikelyContextType returns.
573 const Extension* extension =
574 ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID(
575 extension_id);
577 if (!extension && !extension_id.empty()) {
578 // Trying to dispatch an event to an extension that doesn't exist. The
579 // extension could have been removed, but we do not unregister it until the
580 // extension process is unloaded.
581 return;
584 if (extension) {
585 // Extension-specific checks.
586 // Firstly, if the event is for a URL, the Extension must have permission
587 // to access that URL.
588 if (!event->event_url.is_empty() &&
589 event->event_url.host() != extension->id() && // event for self is ok
590 !extension->permissions_data()
591 ->active_permissions()
592 ->HasEffectiveAccessToURL(event->event_url)) {
593 return;
595 // Secondly, if the event is for incognito mode, the Extension must be
596 // enabled in incognito mode.
597 if (!CanDispatchEventToBrowserContext(listener_context, extension, event)) {
598 return;
602 Feature::Context target_context =
603 process_map->GetMostLikelyContextType(extension, process->GetID());
605 // We shouldn't be dispatching an event to a webpage, since all such events
606 // (e.g. messaging) don't go through EventRouter.
607 DCHECK_NE(Feature::WEB_PAGE_CONTEXT, target_context)
608 << "Trying to dispatch event " << event->event_name << " to a webpage,"
609 << " but this shouldn't be possible";
611 Feature::Availability availability =
612 ExtensionAPI::GetSharedInstance()->IsAvailable(
613 event->event_name, extension, target_context, listener_url);
614 if (!availability.is_available()) {
615 // It shouldn't be possible to reach here, because access is checked on
616 // registration. However, for paranoia, check on dispatch as well.
617 NOTREACHED() << "Trying to dispatch event " << event->event_name
618 << " which the target does not have access to: "
619 << availability.message();
620 return;
623 if (!event->will_dispatch_callback.is_null() &&
624 !event->will_dispatch_callback.Run(listener_context, extension,
625 event->event_args.get())) {
626 return;
629 int event_id = g_extension_event_id.GetNext();
630 DispatchExtensionMessage(process, listener_context, extension_id, event_id,
631 event->event_name, event->event_args.get(),
632 event->user_gesture, event->filter_info);
634 if (extension) {
635 IncrementInFlightEvents(listener_context, extension, event_id,
636 event->event_name);
640 bool EventRouter::CanDispatchEventToBrowserContext(
641 BrowserContext* context,
642 const Extension* extension,
643 const linked_ptr<Event>& event) {
644 // Is this event from a different browser context than the renderer (ie, an
645 // incognito tab event sent to a normal process, or vice versa).
646 bool cross_incognito = event->restrict_to_browser_context &&
647 context != event->restrict_to_browser_context;
648 if (!cross_incognito)
649 return true;
650 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
651 extension, context);
654 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent(
655 BrowserContext* context,
656 const Extension* extension,
657 const linked_ptr<Event>& event) {
658 if (!CanDispatchEventToBrowserContext(context, extension, event))
659 return false;
661 LazyBackgroundTaskQueue* queue = LazyBackgroundTaskQueue::Get(context);
662 if (queue->ShouldEnqueueTask(context, extension)) {
663 linked_ptr<Event> dispatched_event(event);
665 // If there's a dispatch callback, call it now (rather than dispatch time)
666 // to avoid lifetime issues. Use a separate copy of the event args, so they
667 // last until the event is dispatched.
668 if (!event->will_dispatch_callback.is_null()) {
669 dispatched_event.reset(event->DeepCopy());
670 if (!dispatched_event->will_dispatch_callback.Run(
671 context, extension, dispatched_event->event_args.get())) {
672 // The event has been canceled.
673 return true;
675 // Ensure we don't call it again at dispatch time.
676 dispatched_event->will_dispatch_callback.Reset();
679 queue->AddPendingTask(context, extension->id(),
680 base::Bind(&EventRouter::DispatchPendingEvent,
681 base::Unretained(this), dispatched_event));
682 return true;
685 return false;
688 // static
689 void EventRouter::IncrementInFlightEventsOnUI(void* browser_context_id,
690 const std::string& extension_id,
691 int event_id,
692 const std::string& event_name) {
693 DCHECK_CURRENTLY_ON(BrowserThread::UI);
694 BrowserContext* browser_context =
695 reinterpret_cast<BrowserContext*>(browser_context_id);
696 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
697 return;
698 EventRouter* event_router = EventRouter::Get(browser_context);
699 if (!event_router)
700 return;
701 const Extension* extension =
702 ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID(
703 extension_id);
704 if (!extension)
705 return;
706 event_router->IncrementInFlightEvents(browser_context, extension, event_id,
707 event_name);
710 void EventRouter::IncrementInFlightEvents(BrowserContext* context,
711 const Extension* extension,
712 int event_id,
713 const std::string& event_name) {
714 // TODO(chirantan): Turn this on once crbug.com/464513 is fixed.
715 // DCHECK_CURRENTLY_ON(BrowserThread::UI);
717 // Only increment in-flight events if the lazy background page is active,
718 // because that's the only time we'll get an ACK.
719 if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
720 ProcessManager* pm = ProcessManager::Get(context);
721 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension->id());
722 if (host) {
723 pm->IncrementLazyKeepaliveCount(extension);
724 host->OnBackgroundEventDispatched(event_name, event_id);
729 void EventRouter::OnEventAck(BrowserContext* context,
730 const std::string& extension_id) {
731 ProcessManager* pm = ProcessManager::Get(context);
732 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id);
733 // The event ACK is routed to the background host, so this should never be
734 // NULL.
735 CHECK(host);
736 // TODO(mpcomplete): We should never get this message unless
737 // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
738 if (host->extension() &&
739 BackgroundInfo::HasLazyBackgroundPage(host->extension()))
740 pm->DecrementLazyKeepaliveCount(host->extension());
743 void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event,
744 ExtensionHost* host) {
745 if (!host)
746 return;
748 if (listeners_.HasProcessListener(host->render_process_host(),
749 host->extension()->id())) {
750 // URL events cannot be lazy therefore can't be pending, hence the GURL().
751 DispatchEventToProcess(
752 host->extension()->id(), GURL(), host->render_process_host(), event);
756 void EventRouter::Observe(int type,
757 const content::NotificationSource& source,
758 const content::NotificationDetails& details) {
759 switch (type) {
760 case extensions::NOTIFICATION_EXTENSION_ENABLED: {
761 // If the extension has a lazy background page, make sure it gets loaded
762 // to register the events the extension is interested in.
763 const Extension* extension =
764 content::Details<const Extension>(details).ptr();
765 if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
766 LazyBackgroundTaskQueue* queue =
767 LazyBackgroundTaskQueue::Get(browser_context_);
768 queue->AddPendingTask(browser_context_, extension->id(),
769 base::Bind(&DoNothing));
771 break;
773 default:
774 NOTREACHED();
778 void EventRouter::OnExtensionLoaded(content::BrowserContext* browser_context,
779 const Extension* extension) {
780 // Add all registered lazy listeners to our cache.
781 std::set<std::string> registered_events =
782 GetRegisteredEvents(extension->id());
783 listeners_.LoadUnfilteredLazyListeners(extension->id(), registered_events);
784 const DictionaryValue* filtered_events = GetFilteredEvents(extension->id());
785 if (filtered_events)
786 listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events);
789 void EventRouter::OnExtensionUnloaded(content::BrowserContext* browser_context,
790 const Extension* extension,
791 UnloadedExtensionInfo::Reason reason) {
792 // Remove all registered listeners from our cache.
793 listeners_.RemoveListenersForExtension(extension->id());
796 Event::Event(const std::string& event_name,
797 scoped_ptr<base::ListValue> event_args)
798 : event_name(event_name),
799 event_args(event_args.Pass()),
800 restrict_to_browser_context(NULL),
801 user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
802 DCHECK(this->event_args.get());
805 Event::Event(const std::string& event_name,
806 scoped_ptr<base::ListValue> event_args,
807 BrowserContext* restrict_to_browser_context)
808 : event_name(event_name),
809 event_args(event_args.Pass()),
810 restrict_to_browser_context(restrict_to_browser_context),
811 user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
812 DCHECK(this->event_args.get());
815 Event::Event(const std::string& event_name,
816 scoped_ptr<ListValue> event_args,
817 BrowserContext* restrict_to_browser_context,
818 const GURL& event_url,
819 EventRouter::UserGestureState user_gesture,
820 const EventFilteringInfo& filter_info)
821 : event_name(event_name),
822 event_args(event_args.Pass()),
823 restrict_to_browser_context(restrict_to_browser_context),
824 event_url(event_url),
825 user_gesture(user_gesture),
826 filter_info(filter_info) {
827 DCHECK(this->event_args.get());
830 Event::~Event() {}
832 Event* Event::DeepCopy() {
833 Event* copy = new Event(event_name,
834 scoped_ptr<base::ListValue>(event_args->DeepCopy()),
835 restrict_to_browser_context,
836 event_url,
837 user_gesture,
838 filter_info);
839 copy->will_dispatch_callback = will_dispatch_callback;
840 return copy;
843 EventListenerInfo::EventListenerInfo(const std::string& event_name,
844 const std::string& extension_id,
845 const GURL& listener_url,
846 content::BrowserContext* browser_context)
847 : event_name(event_name),
848 extension_id(extension_id),
849 listener_url(listener_url),
850 browser_context(browser_context) {
853 } // namespace extensions