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