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