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