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 "content/public/browser/notification_service.h" 16 #include "content/public/browser/render_process_host.h" 17 #include "extensions/browser/api_activity_monitor.h" 18 #include "extensions/browser/extension_host.h" 19 #include "extensions/browser/extension_prefs.h" 20 #include "extensions/browser/extension_registry.h" 21 #include "extensions/browser/extension_system.h" 22 #include "extensions/browser/extension_util.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_messages.h" 30 #include "extensions/common/extension_urls.h" 31 #include "extensions/common/manifest_handlers/background_info.h" 32 #include "extensions/common/manifest_handlers/incognito_info.h" 33 #include "extensions/common/permissions/permissions_data.h" 34 35 using base::DictionaryValue; 36 using base::ListValue; 37 using content::BrowserContext; 38 using content::BrowserThread; 39 40 namespace extensions { 41 42 namespace { 43 44 void DoNothing(ExtensionHost* host) {} 45 46 // A dictionary of event names to lists of filters that this extension has 47 // registered from its lazy background page. 48 const char kFilteredEvents[] = "filtered_events"; 49 50 // Sends a notification about an event to the API activity monitor on the 51 // UI thread. Can be called from any thread. 52 void NotifyApiEventDispatched(void* browser_context_id, 53 const std::string& extension_id, 54 const std::string& event_name, 55 scoped_ptr<ListValue> args) { 56 // The ApiActivityMonitor can only be accessed from the UI thread. 57 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 58 BrowserThread::PostTask( 59 BrowserThread::UI, 60 FROM_HERE, 61 base::Bind(&NotifyApiEventDispatched, 62 browser_context_id, 63 extension_id, 64 event_name, 65 base::Passed(&args))); 66 return; 67 } 68 69 // Notify the ApiActivityMonitor about the event dispatch. 70 BrowserContext* context = static_cast<BrowserContext*>(browser_context_id); 71 if (!ExtensionsBrowserClient::Get()->IsValidContext(context)) 72 return; 73 ApiActivityMonitor* monitor = 74 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(context); 75 if (monitor) 76 monitor->OnApiEventDispatched(extension_id, event_name, args.Pass()); 77 } 78 79 } // namespace 80 81 const char EventRouter::kRegisteredEvents[] = "events"; 82 83 struct EventRouter::ListenerProcess { 84 content::RenderProcessHost* process; 85 std::string extension_id; 86 87 ListenerProcess(content::RenderProcessHost* process, 88 const std::string& extension_id) 89 : process(process), extension_id(extension_id) {} 90 91 bool operator<(const ListenerProcess& that) const { 92 if (process < that.process) 93 return true; 94 if (process == that.process && extension_id < that.extension_id) 95 return true; 96 return false; 97 } 98 }; 99 100 // static 101 void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender, 102 void* browser_context_id, 103 const std::string& extension_id, 104 const std::string& event_name, 105 ListValue* event_args, 106 UserGestureState user_gesture, 107 const EventFilteringInfo& info) { 108 NotifyApiEventDispatched(browser_context_id, 109 extension_id, 110 event_name, 111 make_scoped_ptr(event_args->DeepCopy())); 112 113 ListValue args; 114 args.Set(0, new base::StringValue(event_name)); 115 args.Set(1, event_args); 116 args.Set(2, info.AsValue().release()); 117 ipc_sender->Send(new ExtensionMsg_MessageInvoke( 118 MSG_ROUTING_CONTROL, 119 extension_id, 120 kEventBindings, 121 "dispatchEvent", 122 args, 123 user_gesture == USER_GESTURE_ENABLED)); 124 125 // DispatchExtensionMessage does _not_ take ownership of event_args, so we 126 // must ensure that the destruction of args does not attempt to free it. 127 scoped_ptr<base::Value> removed_event_args; 128 args.Remove(1, &removed_event_args); 129 ignore_result(removed_event_args.release()); 130 } 131 132 // static 133 EventRouter* EventRouter::Get(content::BrowserContext* browser_context) { 134 return ExtensionSystem::Get(browser_context)->event_router(); 135 } 136 137 // static 138 std::string EventRouter::GetBaseEventName(const std::string& full_event_name) { 139 size_t slash_sep = full_event_name.find('/'); 140 return full_event_name.substr(0, slash_sep); 141 } 142 143 // static 144 void EventRouter::DispatchEvent(IPC::Sender* ipc_sender, 145 void* browser_context_id, 146 const std::string& extension_id, 147 const std::string& event_name, 148 scoped_ptr<ListValue> event_args, 149 UserGestureState user_gesture, 150 const EventFilteringInfo& info) { 151 DispatchExtensionMessage(ipc_sender, 152 browser_context_id, 153 extension_id, 154 event_name, 155 event_args.get(), 156 user_gesture, 157 info); 158 159 BrowserThread::PostTask( 160 BrowserThread::UI, 161 FROM_HERE, 162 base::Bind(&EventRouter::IncrementInFlightEventsOnUI, 163 browser_context_id, 164 extension_id)); 165 } 166 167 EventRouter::EventRouter(BrowserContext* browser_context, 168 ExtensionPrefs* extension_prefs) 169 : browser_context_(browser_context), 170 extension_prefs_(extension_prefs), 171 listeners_(this) { 172 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 173 content::NotificationService::AllSources()); 174 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 175 content::NotificationService::AllSources()); 176 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, 177 content::Source<BrowserContext>(browser_context_)); 178 registrar_.Add(this, 179 chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, 180 content::Source<BrowserContext>(browser_context_)); 181 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, 182 content::Source<BrowserContext>(browser_context_)); 183 } 184 185 EventRouter::~EventRouter() {} 186 187 void EventRouter::AddEventListener(const std::string& event_name, 188 content::RenderProcessHost* process, 189 const std::string& extension_id) { 190 listeners_.AddListener(scoped_ptr<EventListener>(new EventListener( 191 event_name, extension_id, process, scoped_ptr<DictionaryValue>()))); 192 } 193 194 void EventRouter::RemoveEventListener(const std::string& event_name, 195 content::RenderProcessHost* process, 196 const std::string& extension_id) { 197 EventListener listener(event_name, extension_id, process, 198 scoped_ptr<DictionaryValue>()); 199 listeners_.RemoveListener(&listener); 200 } 201 202 void EventRouter::RegisterObserver(Observer* observer, 203 const std::string& event_name) { 204 // Observing sub-event names like "foo.onBar/123" is not allowed. 205 DCHECK(event_name.find('/') == std::string::npos); 206 observers_[event_name] = observer; 207 } 208 209 void EventRouter::UnregisterObserver(Observer* observer) { 210 std::vector<ObserverMap::iterator> iters_to_remove; 211 for (ObserverMap::iterator iter = observers_.begin(); 212 iter != observers_.end(); ++iter) { 213 if (iter->second == observer) 214 iters_to_remove.push_back(iter); 215 } 216 for (size_t i = 0; i < iters_to_remove.size(); ++i) 217 observers_.erase(iters_to_remove[i]); 218 } 219 220 void EventRouter::OnListenerAdded(const EventListener* listener) { 221 const EventListenerInfo details(listener->event_name(), 222 listener->extension_id(), 223 listener->GetBrowserContext()); 224 std::string base_event_name = GetBaseEventName(listener->event_name()); 225 ObserverMap::iterator observer = observers_.find(base_event_name); 226 if (observer != observers_.end()) 227 observer->second->OnListenerAdded(details); 228 } 229 230 void EventRouter::OnListenerRemoved(const EventListener* listener) { 231 const EventListenerInfo details(listener->event_name(), 232 listener->extension_id(), 233 listener->GetBrowserContext()); 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 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 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 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 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.MakeLazy(); 300 bool removed = listeners_.RemoveListener(&listener); 301 302 if (removed) 303 RemoveFilterFromEvent(event_name, extension_id, &filter); 304 } 305 } 306 307 bool EventRouter::HasEventListener(const std::string& event_name) { 308 return listeners_.HasListenerForEvent(event_name); 309 } 310 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 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 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 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 base::StringValue(*iter)); 360 } 361 extension_prefs_->UpdateExtensionPref( 362 extension_id, kRegisteredEvents, events_value); 363 } 364 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 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 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 413 void EventRouter::BroadcastEvent(scoped_ptr<Event> event) { 414 DispatchEventImpl(std::string(), linked_ptr<Event>(event.release())); 415 } 416 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 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 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->IsLazy()) { 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(listener->GetBrowserContext(), 471 listener->extension_id()); 472 if (!ContainsKey(already_dispatched, dispatch_id)) { 473 DispatchEventToProcess( 474 listener->extension_id(), listener->process(), event); 475 } 476 } 477 } 478 } 479 } 480 481 void EventRouter::DispatchLazyEvent( 482 const std::string& extension_id, 483 const linked_ptr<Event>& event, 484 std::set<EventDispatchIdentifier>* already_dispatched) { 485 // Check both the original and the incognito browser context to see if we 486 // should load a lazy bg page to handle the event. The latter case 487 // occurs in the case of split-mode extensions. 488 const Extension* extension = 489 ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID( 490 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 512 void EventRouter::DispatchEventToProcess(const std::string& extension_id, 513 content::RenderProcessHost* process, 514 const linked_ptr<Event>& event) { 515 const Extension* extension = 516 ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID( 517 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 = ProcessMap::Get(listener_context); 526 // If the event is privileged, only send to extension processes. Otherwise, 527 // it's OK to send to normal renderers (e.g., for content scripts). 528 if (ExtensionAPI::GetSharedInstance()->IsPrivileged(event->event_name) && 529 !process_map->Contains(extension->id(), process->GetID())) { 530 return; 531 } 532 533 // If the event is restricted to a URL, only dispatch if the extension has 534 // permission for it (or if the event originated from itself). 535 if (!event->event_url.is_empty() && 536 event->event_url.host() != extension->id() && 537 !extension->permissions_data() 538 ->active_permissions() 539 ->HasEffectiveAccessToURL(event->event_url)) { 540 return; 541 } 542 543 if (!CanDispatchEventToBrowserContext(listener_context, extension, event)) 544 return; 545 546 if (!event->will_dispatch_callback.is_null()) { 547 event->will_dispatch_callback.Run(listener_context, extension, 548 event->event_args.get()); 549 } 550 551 DispatchExtensionMessage(process, listener_context, extension->id(), 552 event->event_name, event->event_args.get(), 553 event->user_gesture, event->filter_info); 554 IncrementInFlightEvents(listener_context, extension); 555 } 556 557 bool EventRouter::CanDispatchEventToBrowserContext( 558 BrowserContext* context, 559 const Extension* extension, 560 const linked_ptr<Event>& event) { 561 // Is this event from a different browser context than the renderer (ie, an 562 // incognito tab event sent to a normal process, or vice versa). 563 bool cross_incognito = event->restrict_to_browser_context && 564 context != event->restrict_to_browser_context; 565 if (!cross_incognito) 566 return true; 567 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito( 568 extension, context); 569 } 570 571 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent( 572 BrowserContext* context, 573 const Extension* extension, 574 const linked_ptr<Event>& event) { 575 if (util::IsEphemeralApp(extension->id(), context) && 576 !event->can_load_ephemeral_apps) { 577 // Most events can only be dispatched to ephemeral apps that are already 578 // running. 579 ProcessManager* pm = ExtensionSystem::Get(context)->process_manager(); 580 if (!pm->GetBackgroundHostForExtension(extension->id())) 581 return false; 582 } 583 584 if (!CanDispatchEventToBrowserContext(context, extension, event)) 585 return false; 586 587 LazyBackgroundTaskQueue* queue = ExtensionSystem::Get( 588 context)->lazy_background_task_queue(); 589 if (queue->ShouldEnqueueTask(context, extension)) { 590 linked_ptr<Event> dispatched_event(event); 591 592 // If there's a dispatch callback, call it now (rather than dispatch time) 593 // to avoid lifetime issues. Use a separate copy of the event args, so they 594 // last until the event is dispatched. 595 if (!event->will_dispatch_callback.is_null()) { 596 dispatched_event.reset(event->DeepCopy()); 597 dispatched_event->will_dispatch_callback.Run( 598 context, extension, dispatched_event->event_args.get()); 599 // Ensure we don't call it again at dispatch time. 600 dispatched_event->will_dispatch_callback.Reset(); 601 } 602 603 queue->AddPendingTask(context, extension->id(), 604 base::Bind(&EventRouter::DispatchPendingEvent, 605 base::Unretained(this), dispatched_event)); 606 return true; 607 } 608 609 return false; 610 } 611 612 // static 613 void EventRouter::IncrementInFlightEventsOnUI( 614 void* browser_context_id, 615 const std::string& extension_id) { 616 DCHECK_CURRENTLY_ON(BrowserThread::UI); 617 BrowserContext* browser_context = 618 reinterpret_cast<BrowserContext*>(browser_context_id); 619 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context)) 620 return; 621 EventRouter* event_router = EventRouter::Get(browser_context); 622 if (!event_router) 623 return; 624 const Extension* extension = 625 ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID( 626 extension_id); 627 if (!extension) 628 return; 629 event_router->IncrementInFlightEvents(browser_context, extension); 630 } 631 632 void EventRouter::IncrementInFlightEvents(BrowserContext* context, 633 const Extension* extension) { 634 // Only increment in-flight events if the lazy background page is active, 635 // because that's the only time we'll get an ACK. 636 if (BackgroundInfo::HasLazyBackgroundPage(extension)) { 637 ProcessManager* pm = ExtensionSystem::Get(context)->process_manager(); 638 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension->id()); 639 if (host) 640 pm->IncrementLazyKeepaliveCount(extension); 641 } 642 } 643 644 void EventRouter::OnEventAck(BrowserContext* context, 645 const std::string& extension_id) { 646 ProcessManager* pm = ExtensionSystem::Get(context)->process_manager(); 647 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id); 648 // The event ACK is routed to the background host, so this should never be 649 // NULL. 650 CHECK(host); 651 // TODO(mpcomplete): We should never get this message unless 652 // HasLazyBackgroundPage is true. Find out why we're getting it anyway. 653 if (host->extension() && 654 BackgroundInfo::HasLazyBackgroundPage(host->extension())) 655 pm->DecrementLazyKeepaliveCount(host->extension()); 656 } 657 658 void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event, 659 ExtensionHost* host) { 660 if (!host) 661 return; 662 663 if (listeners_.HasProcessListener(host->render_process_host(), 664 host->extension()->id())) { 665 DispatchEventToProcess(host->extension()->id(), 666 host->render_process_host(), event); 667 } 668 } 669 670 void EventRouter::Observe(int type, 671 const content::NotificationSource& source, 672 const content::NotificationDetails& details) { 673 switch (type) { 674 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: 675 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 676 content::RenderProcessHost* renderer = 677 content::Source<content::RenderProcessHost>(source).ptr(); 678 // Remove all event listeners associated with this renderer. 679 listeners_.RemoveListenersForProcess(renderer); 680 break; 681 } 682 case chrome::NOTIFICATION_EXTENSION_ENABLED: { 683 // If the extension has a lazy background page, make sure it gets loaded 684 // to register the events the extension is interested in. 685 const Extension* extension = 686 content::Details<const Extension>(details).ptr(); 687 if (BackgroundInfo::HasLazyBackgroundPage(extension)) { 688 LazyBackgroundTaskQueue* queue = ExtensionSystem::Get( 689 browser_context_)->lazy_background_task_queue(); 690 queue->AddPendingTask(browser_context_, extension->id(), 691 base::Bind(&DoNothing)); 692 } 693 break; 694 } 695 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: { 696 // Add all registered lazy listeners to our cache. 697 const Extension* extension = 698 content::Details<const Extension>(details).ptr(); 699 std::set<std::string> registered_events = 700 GetRegisteredEvents(extension->id()); 701 listeners_.LoadUnfilteredLazyListeners(extension->id(), 702 registered_events); 703 const DictionaryValue* filtered_events = 704 GetFilteredEvents(extension->id()); 705 if (filtered_events) 706 listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events); 707 break; 708 } 709 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: { 710 // Remove all registered lazy listeners from our cache. 711 UnloadedExtensionInfo* unloaded = 712 content::Details<UnloadedExtensionInfo>(details).ptr(); 713 listeners_.RemoveLazyListenersForExtension(unloaded->extension->id()); 714 break; 715 } 716 default: 717 NOTREACHED(); 718 return; 719 } 720 } 721 722 Event::Event(const std::string& event_name, 723 scoped_ptr<base::ListValue> event_args) 724 : event_name(event_name), 725 event_args(event_args.Pass()), 726 restrict_to_browser_context(NULL), 727 user_gesture(EventRouter::USER_GESTURE_UNKNOWN), 728 can_load_ephemeral_apps(false) { 729 DCHECK(this->event_args.get()); 730 } 731 732 Event::Event(const std::string& event_name, 733 scoped_ptr<base::ListValue> event_args, 734 BrowserContext* restrict_to_browser_context) 735 : event_name(event_name), 736 event_args(event_args.Pass()), 737 restrict_to_browser_context(restrict_to_browser_context), 738 user_gesture(EventRouter::USER_GESTURE_UNKNOWN), 739 can_load_ephemeral_apps(false) { 740 DCHECK(this->event_args.get()); 741 } 742 743 Event::Event(const std::string& event_name, 744 scoped_ptr<ListValue> event_args, 745 BrowserContext* restrict_to_browser_context, 746 const GURL& event_url, 747 EventRouter::UserGestureState user_gesture, 748 const EventFilteringInfo& filter_info) 749 : event_name(event_name), 750 event_args(event_args.Pass()), 751 restrict_to_browser_context(restrict_to_browser_context), 752 event_url(event_url), 753 user_gesture(user_gesture), 754 filter_info(filter_info), 755 can_load_ephemeral_apps(false) { 756 DCHECK(this->event_args.get()); 757 } 758 759 Event::~Event() {} 760 761 Event* Event::DeepCopy() { 762 Event* copy = new Event(event_name, 763 scoped_ptr<base::ListValue>(event_args->DeepCopy()), 764 restrict_to_browser_context, 765 event_url, 766 user_gesture, 767 filter_info); 768 copy->will_dispatch_callback = will_dispatch_callback; 769 return copy; 770 } 771 772 EventListenerInfo::EventListenerInfo(const std::string& event_name, 773 const std::string& extension_id, 774 content::BrowserContext* browser_context) 775 : event_name(event_name), 776 extension_id(extension_id), 777 browser_context(browser_context) {} 778 779 } // namespace extensions 780