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 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 56 ListenerProcess(content::RenderProcessHost* process, 57 const std::string& extension_id) 58 : process(process), extension_id(extension_id) {} 59 60 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 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 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 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 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 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 178 EventRouter::~EventRouter() {} 179 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 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 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 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 213 void EventRouter::SetEventDispatchObserver(EventDispatchObserver* observer) { 214 CHECK(!event_dispatch_observer_); 215 event_dispatch_observer_ = observer; 216 } 217 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 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 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.process = NULL; 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 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->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 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 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 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 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 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 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 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 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 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 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 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 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 754 Event::~Event() {} 755 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 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 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 781 EventDispatchInfo::~EventDispatchInfo() {} 782 783 } // namespace extensions 784