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