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 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. 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 88 ListenerProcess(content::RenderProcessHost* process, 89 const std::string& extension_id) 90 : process(process), extension_id(extension_id) {} 91 92 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 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 134 EventRouter* EventRouter::Get(content::BrowserContext* browser_context) { 135 return ExtensionSystem::Get(browser_context)->event_router(); 136 } 137 138 // static 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 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 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 184 EventRouter::~EventRouter() {} 185 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 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 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 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 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 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 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 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 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 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 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 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 334 bool EventRouter::HasEventListener(const std::string& event_name) { 335 return listeners_.HasListenerForEvent(event_name); 336 } 337 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 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 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 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 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 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 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 440 void EventRouter::BroadcastEvent(scoped_ptr<Event> event) { 441 DispatchEventImpl(std::string(), linked_ptr<Event>(event.release())); 442 } 443 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 805 Event::~Event() {} 806 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 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