Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / extensions / browser / event_router.cc
blobd006d1e9a7588f049faf243e26c7097c71f47b25
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/message_loop/message_loop.h"
12 #include "base/stl_util.h"
13 #include "base/values.h"
14 #include "content/public/browser/child_process_security_policy.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "extensions/browser/api_activity_monitor.h"
18 #include "extensions/browser/extension_host.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/browser/extensions_browser_client.h"
23 #include "extensions/browser/lazy_background_task_queue.h"
24 #include "extensions/browser/notification_types.h"
25 #include "extensions/browser/process_manager.h"
26 #include "extensions/browser/process_map.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/extension_api.h"
29 #include "extensions/common/extension_messages.h"
30 #include "extensions/common/extension_urls.h"
31 #include "extensions/common/manifest_handlers/background_info.h"
32 #include "extensions/common/manifest_handlers/incognito_info.h"
33 #include "extensions/common/permissions/permissions_data.h"
35 using base::DictionaryValue;
36 using base::ListValue;
37 using content::BrowserContext;
38 using content::BrowserThread;
40 namespace extensions {
42 namespace {
44 void DoNothing(ExtensionHost* host) {}
46 // A dictionary of event names to lists of filters that this extension has
47 // registered from its lazy background page.
48 const char kFilteredEvents[] = "filtered_events";
50 // Sends a notification about an event to the API activity monitor on the
51 // UI thread. Can be called from any thread.
52 void NotifyApiEventDispatched(void* browser_context_id,
53 const std::string& extension_id,
54 const std::string& event_name,
55 scoped_ptr<ListValue> args) {
56 // The ApiActivityMonitor can only be accessed from the UI thread.
57 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
58 BrowserThread::PostTask(
59 BrowserThread::UI,
60 FROM_HERE,
61 base::Bind(&NotifyApiEventDispatched,
62 browser_context_id,
63 extension_id,
64 event_name,
65 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 } // namespace
81 const char EventRouter::kRegisteredEvents[] = "events";
83 struct EventRouter::ListenerProcess {
84 content::RenderProcessHost* process;
85 std::string extension_id;
87 ListenerProcess(content::RenderProcessHost* process,
88 const std::string& extension_id)
89 : process(process), extension_id(extension_id) {}
91 bool operator<(const ListenerProcess& that) const {
92 if (process < that.process)
93 return true;
94 if (process == that.process && extension_id < that.extension_id)
95 return true;
96 return false;
100 // static
101 void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
102 void* browser_context_id,
103 const std::string& extension_id,
104 const std::string& event_name,
105 ListValue* event_args,
106 UserGestureState user_gesture,
107 const EventFilteringInfo& info) {
108 NotifyApiEventDispatched(browser_context_id,
109 extension_id,
110 event_name,
111 make_scoped_ptr(event_args->DeepCopy()));
113 ListValue args;
114 args.Set(0, new base::StringValue(event_name));
115 args.Set(1, event_args);
116 args.Set(2, info.AsValue().release());
117 ipc_sender->Send(new ExtensionMsg_MessageInvoke(
118 MSG_ROUTING_CONTROL,
119 extension_id,
120 kEventBindings,
121 "dispatchEvent",
122 args,
123 user_gesture == USER_GESTURE_ENABLED));
125 // DispatchExtensionMessage does _not_ take ownership of event_args, so we
126 // must ensure that the destruction of args does not attempt to free it.
127 scoped_ptr<base::Value> removed_event_args;
128 args.Remove(1, &removed_event_args);
129 ignore_result(removed_event_args.release());
132 // static
133 EventRouter* EventRouter::Get(content::BrowserContext* browser_context) {
134 return ExtensionSystem::Get(browser_context)->event_router();
137 // static
138 std::string EventRouter::GetBaseEventName(const std::string& full_event_name) {
139 size_t slash_sep = full_event_name.find('/');
140 return full_event_name.substr(0, slash_sep);
143 // static
144 void EventRouter::DispatchEvent(IPC::Sender* ipc_sender,
145 void* browser_context_id,
146 const std::string& extension_id,
147 const std::string& event_name,
148 scoped_ptr<ListValue> event_args,
149 UserGestureState user_gesture,
150 const EventFilteringInfo& info) {
151 DispatchExtensionMessage(ipc_sender,
152 browser_context_id,
153 extension_id,
154 event_name,
155 event_args.get(),
156 user_gesture,
157 info);
159 BrowserThread::PostTask(
160 BrowserThread::UI,
161 FROM_HERE,
162 base::Bind(&EventRouter::IncrementInFlightEventsOnUI,
163 browser_context_id,
164 extension_id));
167 EventRouter::EventRouter(BrowserContext* browser_context,
168 ExtensionPrefs* extension_prefs)
169 : browser_context_(browser_context),
170 extension_prefs_(extension_prefs),
171 extension_registry_observer_(this),
172 listeners_(this) {
173 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
174 content::NotificationService::AllSources());
175 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
176 content::NotificationService::AllSources());
177 registrar_.Add(this,
178 extensions::NOTIFICATION_EXTENSION_ENABLED,
179 content::Source<BrowserContext>(browser_context_));
180 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
183 EventRouter::~EventRouter() {}
185 void EventRouter::AddEventListener(const std::string& event_name,
186 content::RenderProcessHost* process,
187 const std::string& extension_id) {
188 listeners_.AddListener(EventListener::ForExtension(
189 event_name, extension_id, process, scoped_ptr<DictionaryValue>()));
192 void EventRouter::RemoveEventListener(const std::string& event_name,
193 content::RenderProcessHost* process,
194 const std::string& extension_id) {
195 scoped_ptr<EventListener> listener = EventListener::ForExtension(
196 event_name, extension_id, process, scoped_ptr<DictionaryValue>());
197 listeners_.RemoveListener(listener.get());
200 void EventRouter::AddEventListenerForURL(const std::string& event_name,
201 content::RenderProcessHost* process,
202 const GURL& listener_url) {
203 listeners_.AddListener(EventListener::ForURL(
204 event_name, listener_url, process, scoped_ptr<DictionaryValue>()));
207 void EventRouter::RemoveEventListenerForURL(const std::string& event_name,
208 content::RenderProcessHost* process,
209 const GURL& listener_url) {
210 scoped_ptr<EventListener> listener = EventListener::ForURL(
211 event_name, listener_url, process, scoped_ptr<DictionaryValue>());
212 listeners_.RemoveListener(listener.get());
215 void EventRouter::RegisterObserver(Observer* observer,
216 const std::string& event_name) {
217 // Observing sub-event names like "foo.onBar/123" is not allowed.
218 DCHECK(event_name.find('/') == std::string::npos);
219 observers_[event_name] = observer;
222 void EventRouter::UnregisterObserver(Observer* observer) {
223 std::vector<ObserverMap::iterator> iters_to_remove;
224 for (ObserverMap::iterator iter = observers_.begin();
225 iter != observers_.end(); ++iter) {
226 if (iter->second == observer)
227 iters_to_remove.push_back(iter);
229 for (size_t i = 0; i < iters_to_remove.size(); ++i)
230 observers_.erase(iters_to_remove[i]);
233 void EventRouter::OnListenerAdded(const EventListener* listener) {
234 const EventListenerInfo details(listener->event_name(),
235 listener->extension_id(),
236 listener->listener_url(),
237 listener->GetBrowserContext());
238 std::string base_event_name = GetBaseEventName(listener->event_name());
239 ObserverMap::iterator observer = observers_.find(base_event_name);
240 if (observer != observers_.end())
241 observer->second->OnListenerAdded(details);
244 void EventRouter::OnListenerRemoved(const EventListener* listener) {
245 const EventListenerInfo details(listener->event_name(),
246 listener->extension_id(),
247 listener->listener_url(),
248 listener->GetBrowserContext());
249 std::string base_event_name = GetBaseEventName(listener->event_name());
250 ObserverMap::iterator observer = observers_.find(base_event_name);
251 if (observer != observers_.end())
252 observer->second->OnListenerRemoved(details);
255 void EventRouter::AddLazyEventListener(const std::string& event_name,
256 const std::string& extension_id) {
257 bool is_new = listeners_.AddListener(EventListener::ForExtension(
258 event_name, extension_id, NULL, scoped_ptr<DictionaryValue>()));
260 if (is_new) {
261 std::set<std::string> events = GetRegisteredEvents(extension_id);
262 bool prefs_is_new = events.insert(event_name).second;
263 if (prefs_is_new)
264 SetRegisteredEvents(extension_id, events);
268 void EventRouter::RemoveLazyEventListener(const std::string& event_name,
269 const std::string& extension_id) {
270 scoped_ptr<EventListener> listener = EventListener::ForExtension(
271 event_name, extension_id, NULL, scoped_ptr<DictionaryValue>());
272 bool did_exist = listeners_.RemoveListener(listener.get());
274 if (did_exist) {
275 std::set<std::string> events = GetRegisteredEvents(extension_id);
276 bool prefs_did_exist = events.erase(event_name) > 0;
277 DCHECK(prefs_did_exist);
278 SetRegisteredEvents(extension_id, events);
282 void EventRouter::AddFilteredEventListener(const std::string& event_name,
283 content::RenderProcessHost* process,
284 const std::string& extension_id,
285 const base::DictionaryValue& filter,
286 bool add_lazy_listener) {
287 listeners_.AddListener(EventListener::ForExtension(
288 event_name,
289 extension_id,
290 process,
291 scoped_ptr<DictionaryValue>(filter.DeepCopy())));
293 if (add_lazy_listener) {
294 bool added = listeners_.AddListener(EventListener::ForExtension(
295 event_name,
296 extension_id,
297 NULL,
298 scoped_ptr<DictionaryValue>(filter.DeepCopy())));
300 if (added)
301 AddFilterToEvent(event_name, extension_id, &filter);
305 void EventRouter::RemoveFilteredEventListener(
306 const std::string& event_name,
307 content::RenderProcessHost* process,
308 const std::string& extension_id,
309 const base::DictionaryValue& filter,
310 bool remove_lazy_listener) {
311 scoped_ptr<EventListener> listener = EventListener::ForExtension(
312 event_name,
313 extension_id,
314 process,
315 scoped_ptr<DictionaryValue>(filter.DeepCopy()));
317 listeners_.RemoveListener(listener.get());
319 if (remove_lazy_listener) {
320 listener->MakeLazy();
321 bool removed = listeners_.RemoveListener(listener.get());
323 if (removed)
324 RemoveFilterFromEvent(event_name, extension_id, &filter);
328 bool EventRouter::HasEventListener(const std::string& event_name) {
329 return listeners_.HasListenerForEvent(event_name);
332 bool EventRouter::ExtensionHasEventListener(const std::string& extension_id,
333 const std::string& event_name) {
334 return listeners_.HasListenerForExtension(extension_id, event_name);
337 bool EventRouter::HasEventListenerImpl(const ListenerMap& listener_map,
338 const std::string& extension_id,
339 const std::string& event_name) {
340 ListenerMap::const_iterator it = listener_map.find(event_name);
341 if (it == listener_map.end())
342 return false;
344 const std::set<ListenerProcess>& listeners = it->second;
345 if (extension_id.empty())
346 return !listeners.empty();
348 for (std::set<ListenerProcess>::const_iterator listener = listeners.begin();
349 listener != listeners.end(); ++listener) {
350 if (listener->extension_id == extension_id)
351 return true;
353 return false;
356 std::set<std::string> EventRouter::GetRegisteredEvents(
357 const std::string& extension_id) {
358 std::set<std::string> events;
359 const ListValue* events_value = NULL;
361 if (!extension_prefs_ ||
362 !extension_prefs_->ReadPrefAsList(
363 extension_id, kRegisteredEvents, &events_value)) {
364 return events;
367 for (size_t i = 0; i < events_value->GetSize(); ++i) {
368 std::string event;
369 if (events_value->GetString(i, &event))
370 events.insert(event);
372 return events;
375 void EventRouter::SetRegisteredEvents(const std::string& extension_id,
376 const std::set<std::string>& events) {
377 ListValue* events_value = new ListValue;
378 for (std::set<std::string>::const_iterator iter = events.begin();
379 iter != events.end(); ++iter) {
380 events_value->Append(new base::StringValue(*iter));
382 extension_prefs_->UpdateExtensionPref(
383 extension_id, kRegisteredEvents, events_value);
386 void EventRouter::AddFilterToEvent(const std::string& event_name,
387 const std::string& extension_id,
388 const DictionaryValue* filter) {
389 ExtensionPrefs::ScopedDictionaryUpdate update(
390 extension_prefs_, extension_id, kFilteredEvents);
391 DictionaryValue* filtered_events = update.Get();
392 if (!filtered_events)
393 filtered_events = update.Create();
395 ListValue* filter_list = NULL;
396 if (!filtered_events->GetList(event_name, &filter_list)) {
397 filter_list = new ListValue;
398 filtered_events->SetWithoutPathExpansion(event_name, filter_list);
401 filter_list->Append(filter->DeepCopy());
404 void EventRouter::RemoveFilterFromEvent(const std::string& event_name,
405 const std::string& extension_id,
406 const DictionaryValue* filter) {
407 ExtensionPrefs::ScopedDictionaryUpdate update(
408 extension_prefs_, extension_id, kFilteredEvents);
409 DictionaryValue* filtered_events = update.Get();
410 ListValue* filter_list = NULL;
411 if (!filtered_events ||
412 !filtered_events->GetListWithoutPathExpansion(event_name, &filter_list)) {
413 return;
416 for (size_t i = 0; i < filter_list->GetSize(); i++) {
417 DictionaryValue* filter = NULL;
418 CHECK(filter_list->GetDictionary(i, &filter));
419 if (filter->Equals(filter)) {
420 filter_list->Remove(i, NULL);
421 break;
426 const DictionaryValue* EventRouter::GetFilteredEvents(
427 const std::string& extension_id) {
428 const DictionaryValue* events = NULL;
429 extension_prefs_->ReadPrefAsDictionary(
430 extension_id, kFilteredEvents, &events);
431 return events;
434 void EventRouter::BroadcastEvent(scoped_ptr<Event> event) {
435 DispatchEventImpl(std::string(), linked_ptr<Event>(event.release()));
438 void EventRouter::DispatchEventToExtension(const std::string& extension_id,
439 scoped_ptr<Event> event) {
440 DCHECK(!extension_id.empty());
441 DispatchEventImpl(extension_id, linked_ptr<Event>(event.release()));
444 void EventRouter::DispatchEventWithLazyListener(const std::string& extension_id,
445 scoped_ptr<Event> event) {
446 DCHECK(!extension_id.empty());
447 std::string event_name = event->event_name;
448 bool has_listener = ExtensionHasEventListener(extension_id, event_name);
449 if (!has_listener)
450 AddLazyEventListener(event_name, extension_id);
451 DispatchEventToExtension(extension_id, event.Pass());
452 if (!has_listener)
453 RemoveLazyEventListener(event_name, extension_id);
456 void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id,
457 const linked_ptr<Event>& event) {
458 // We don't expect to get events from a completely different browser context.
459 DCHECK(!event->restrict_to_browser_context ||
460 ExtensionsBrowserClient::Get()->IsSameContext(
461 browser_context_, event->restrict_to_browser_context));
463 std::set<const EventListener*> listeners(
464 listeners_.GetEventListeners(*event));
466 std::set<EventDispatchIdentifier> already_dispatched;
468 // We dispatch events for lazy background pages first because attempting to do
469 // so will cause those that are being suspended to cancel that suspension.
470 // As canceling a suspension entails sending an event to the affected
471 // background page, and as that event needs to be delivered before we dispatch
472 // the event we are dispatching here, we dispatch to the lazy listeners here
473 // first.
474 for (std::set<const EventListener*>::iterator it = listeners.begin();
475 it != listeners.end(); it++) {
476 const EventListener* listener = *it;
477 if (restrict_to_extension_id.empty() ||
478 restrict_to_extension_id == listener->extension_id()) {
479 if (listener->IsLazy()) {
480 DispatchLazyEvent(listener->extension_id(), event, &already_dispatched);
485 for (std::set<const EventListener*>::iterator it = listeners.begin();
486 it != listeners.end(); it++) {
487 const EventListener* listener = *it;
488 if (restrict_to_extension_id.empty() ||
489 restrict_to_extension_id == listener->extension_id()) {
490 if (listener->process()) {
491 EventDispatchIdentifier dispatch_id(listener->GetBrowserContext(),
492 listener->extension_id());
493 if (!ContainsKey(already_dispatched, dispatch_id)) {
494 DispatchEventToProcess(listener->extension_id(),
495 listener->listener_url(),
496 listener->process(),
497 event);
504 void EventRouter::DispatchLazyEvent(
505 const std::string& extension_id,
506 const linked_ptr<Event>& event,
507 std::set<EventDispatchIdentifier>* already_dispatched) {
508 // Check both the original and the incognito browser context to see if we
509 // should load a lazy bg page to handle the event. The latter case
510 // occurs in the case of split-mode extensions.
511 const Extension* extension =
512 ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID(
513 extension_id);
514 if (!extension)
515 return;
517 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
518 browser_context_, extension, event)) {
519 already_dispatched->insert(std::make_pair(browser_context_, extension_id));
522 ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get();
523 if (browser_client->HasOffTheRecordContext(browser_context_) &&
524 IncognitoInfo::IsSplitMode(extension)) {
525 BrowserContext* incognito_context =
526 browser_client->GetOffTheRecordContext(browser_context_);
527 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
528 incognito_context, extension, event)) {
529 already_dispatched->insert(
530 std::make_pair(incognito_context, extension_id));
535 void EventRouter::DispatchEventToProcess(const std::string& extension_id,
536 const GURL& listener_url,
537 content::RenderProcessHost* process,
538 const linked_ptr<Event>& event) {
539 BrowserContext* listener_context = process->GetBrowserContext();
540 ProcessMap* process_map = ProcessMap::Get(listener_context);
542 // TODO(kalman): Convert this method to use
543 // ProcessMap::GetMostLikelyContextType.
545 const Extension* extension =
546 ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID(
547 extension_id);
548 // NOTE: |extension| being NULL does not necessarily imply that this event
549 // shouldn't be dispatched. Events can be dispatched to WebUI as well.
551 if (!extension && !extension_id.empty()) {
552 // Trying to dispatch an event to an extension that doesn't exist. The
553 // extension could have been removed, but we do not unregister it until the
554 // extension process is unloaded.
555 return;
558 if (extension) {
559 // Dispatching event to an extension.
560 // If the event is privileged, only send to extension processes. Otherwise,
561 // it's OK to send to normal renderers (e.g., for content scripts).
562 if (!process_map->Contains(extension->id(), process->GetID()) &&
563 !ExtensionAPI::GetSharedInstance()->IsAvailableInUntrustedContext(
564 event->event_name, extension)) {
565 return;
568 // If the event is restricted to a URL, only dispatch if the extension has
569 // permission for it (or if the event originated from itself).
570 if (!event->event_url.is_empty() &&
571 event->event_url.host() != extension->id() &&
572 !extension->permissions_data()
573 ->active_permissions()
574 ->HasEffectiveAccessToURL(event->event_url)) {
575 return;
578 if (!CanDispatchEventToBrowserContext(listener_context, extension, event)) {
579 return;
581 } else if (content::ChildProcessSecurityPolicy::GetInstance()
582 ->HasWebUIBindings(process->GetID())) {
583 // Dispatching event to WebUI.
584 if (!ExtensionAPI::GetSharedInstance()->IsAvailableToWebUI(
585 event->event_name, listener_url)) {
586 return;
588 } else {
589 // Dispatching event to a webpage - however, all such events (e.g.
590 // messaging) don't go through EventRouter so this should be impossible.
591 NOTREACHED();
592 return;
595 if (!event->will_dispatch_callback.is_null()) {
596 event->will_dispatch_callback.Run(
597 listener_context, extension, event->event_args.get());
600 DispatchExtensionMessage(process,
601 listener_context,
602 extension_id,
603 event->event_name,
604 event->event_args.get(),
605 event->user_gesture,
606 event->filter_info);
608 if (extension)
609 IncrementInFlightEvents(listener_context, extension);
612 bool EventRouter::CanDispatchEventToBrowserContext(
613 BrowserContext* context,
614 const Extension* extension,
615 const linked_ptr<Event>& event) {
616 // Is this event from a different browser context than the renderer (ie, an
617 // incognito tab event sent to a normal process, or vice versa).
618 bool cross_incognito = event->restrict_to_browser_context &&
619 context != event->restrict_to_browser_context;
620 if (!cross_incognito)
621 return true;
622 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
623 extension, context);
626 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent(
627 BrowserContext* context,
628 const Extension* extension,
629 const linked_ptr<Event>& event) {
630 if (!CanDispatchEventToBrowserContext(context, extension, event))
631 return false;
633 LazyBackgroundTaskQueue* queue = ExtensionSystem::Get(
634 context)->lazy_background_task_queue();
635 if (queue->ShouldEnqueueTask(context, extension)) {
636 linked_ptr<Event> dispatched_event(event);
638 // If there's a dispatch callback, call it now (rather than dispatch time)
639 // to avoid lifetime issues. Use a separate copy of the event args, so they
640 // last until the event is dispatched.
641 if (!event->will_dispatch_callback.is_null()) {
642 dispatched_event.reset(event->DeepCopy());
643 dispatched_event->will_dispatch_callback.Run(
644 context, extension, dispatched_event->event_args.get());
645 // Ensure we don't call it again at dispatch time.
646 dispatched_event->will_dispatch_callback.Reset();
649 queue->AddPendingTask(context, extension->id(),
650 base::Bind(&EventRouter::DispatchPendingEvent,
651 base::Unretained(this), dispatched_event));
652 return true;
655 return false;
658 // static
659 void EventRouter::IncrementInFlightEventsOnUI(
660 void* browser_context_id,
661 const std::string& extension_id) {
662 DCHECK_CURRENTLY_ON(BrowserThread::UI);
663 BrowserContext* browser_context =
664 reinterpret_cast<BrowserContext*>(browser_context_id);
665 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
666 return;
667 EventRouter* event_router = EventRouter::Get(browser_context);
668 if (!event_router)
669 return;
670 const Extension* extension =
671 ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID(
672 extension_id);
673 if (!extension)
674 return;
675 event_router->IncrementInFlightEvents(browser_context, extension);
678 void EventRouter::IncrementInFlightEvents(BrowserContext* context,
679 const Extension* extension) {
680 // Only increment in-flight events if the lazy background page is active,
681 // because that's the only time we'll get an ACK.
682 if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
683 ProcessManager* pm = ExtensionSystem::Get(context)->process_manager();
684 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension->id());
685 if (host)
686 pm->IncrementLazyKeepaliveCount(extension);
690 void EventRouter::OnEventAck(BrowserContext* context,
691 const std::string& extension_id) {
692 ProcessManager* pm = ExtensionSystem::Get(context)->process_manager();
693 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id);
694 // The event ACK is routed to the background host, so this should never be
695 // NULL.
696 CHECK(host);
697 // TODO(mpcomplete): We should never get this message unless
698 // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
699 if (host->extension() &&
700 BackgroundInfo::HasLazyBackgroundPage(host->extension()))
701 pm->DecrementLazyKeepaliveCount(host->extension());
704 void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event,
705 ExtensionHost* host) {
706 if (!host)
707 return;
709 if (listeners_.HasProcessListener(host->render_process_host(),
710 host->extension()->id())) {
711 // URL events cannot be lazy therefore can't be pending, hence the GURL().
712 DispatchEventToProcess(
713 host->extension()->id(), GURL(), host->render_process_host(), event);
717 void EventRouter::Observe(int type,
718 const content::NotificationSource& source,
719 const content::NotificationDetails& details) {
720 switch (type) {
721 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
722 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
723 content::RenderProcessHost* renderer =
724 content::Source<content::RenderProcessHost>(source).ptr();
725 // Remove all event listeners associated with this renderer.
726 listeners_.RemoveListenersForProcess(renderer);
727 break;
729 case extensions::NOTIFICATION_EXTENSION_ENABLED: {
730 // If the extension has a lazy background page, make sure it gets loaded
731 // to register the events the extension is interested in.
732 const Extension* extension =
733 content::Details<const Extension>(details).ptr();
734 if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
735 LazyBackgroundTaskQueue* queue = ExtensionSystem::Get(
736 browser_context_)->lazy_background_task_queue();
737 queue->AddPendingTask(browser_context_, extension->id(),
738 base::Bind(&DoNothing));
740 break;
742 default:
743 NOTREACHED();
747 void EventRouter::OnExtensionLoaded(content::BrowserContext* browser_context,
748 const Extension* extension) {
749 // Add all registered lazy listeners to our cache.
750 std::set<std::string> registered_events =
751 GetRegisteredEvents(extension->id());
752 listeners_.LoadUnfilteredLazyListeners(extension->id(), registered_events);
753 const DictionaryValue* filtered_events = GetFilteredEvents(extension->id());
754 if (filtered_events)
755 listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events);
758 void EventRouter::OnExtensionUnloaded(content::BrowserContext* browser_context,
759 const Extension* extension,
760 UnloadedExtensionInfo::Reason reason) {
761 // Remove all registered lazy listeners from our cache.
762 listeners_.RemoveLazyListenersForExtension(extension->id());
765 Event::Event(const std::string& event_name,
766 scoped_ptr<base::ListValue> event_args)
767 : event_name(event_name),
768 event_args(event_args.Pass()),
769 restrict_to_browser_context(NULL),
770 user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
771 DCHECK(this->event_args.get());
774 Event::Event(const std::string& event_name,
775 scoped_ptr<base::ListValue> event_args,
776 BrowserContext* restrict_to_browser_context)
777 : event_name(event_name),
778 event_args(event_args.Pass()),
779 restrict_to_browser_context(restrict_to_browser_context),
780 user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
781 DCHECK(this->event_args.get());
784 Event::Event(const std::string& event_name,
785 scoped_ptr<ListValue> event_args,
786 BrowserContext* restrict_to_browser_context,
787 const GURL& event_url,
788 EventRouter::UserGestureState user_gesture,
789 const EventFilteringInfo& filter_info)
790 : event_name(event_name),
791 event_args(event_args.Pass()),
792 restrict_to_browser_context(restrict_to_browser_context),
793 event_url(event_url),
794 user_gesture(user_gesture),
795 filter_info(filter_info) {
796 DCHECK(this->event_args.get());
799 Event::~Event() {}
801 Event* Event::DeepCopy() {
802 Event* copy = new Event(event_name,
803 scoped_ptr<base::ListValue>(event_args->DeepCopy()),
804 restrict_to_browser_context,
805 event_url,
806 user_gesture,
807 filter_info);
808 copy->will_dispatch_callback = will_dispatch_callback;
809 return copy;
812 EventListenerInfo::EventListenerInfo(const std::string& event_name,
813 const std::string& extension_id,
814 const GURL& listener_url,
815 content::BrowserContext* browser_context)
816 : event_name(event_name),
817 extension_id(extension_id),
818 listener_url(listener_url),
819 browser_context(browser_context) {
822 } // namespace extensions