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