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 "chrome/browser/extensions/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 "base/version.h" 15 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/chrome_notification_types.h" 17 #include "chrome/browser/extensions/activity_log/activity_log.h" 18 #include "chrome/browser/extensions/api/runtime/runtime_api.h" 19 #include "chrome/browser/extensions/api/web_request/web_request_api.h" 20 #include "chrome/browser/extensions/event_names.h" 21 #include "chrome/browser/extensions/extension_host.h" 22 #include "chrome/browser/extensions/extension_prefs.h" 23 #include "chrome/browser/extensions/extension_process_manager.h" 24 #include "chrome/browser/extensions/extension_service.h" 25 #include "chrome/browser/extensions/extension_system.h" 26 #include "chrome/browser/extensions/lazy_background_task_queue.h" 27 #include "chrome/browser/extensions/process_map.h" 28 #include "chrome/browser/profiles/profile.h" 29 #include "chrome/browser/profiles/profile_manager.h" 30 #include "chrome/common/chrome_switches.h" 31 #include "chrome/common/chrome_version_info.h" 32 #include "chrome/common/extensions/api/extension_api.h" 33 #include "chrome/common/extensions/background_info.h" 34 #include "chrome/common/extensions/extension.h" 35 #include "chrome/common/extensions/extension_messages.h" 36 #include "chrome/common/extensions/incognito_handler.h" 37 #include "content/public/browser/notification_service.h" 38 #include "content/public/browser/render_process_host.h" 39 40 using base::DictionaryValue; 41 using base::ListValue; 42 using content::BrowserThread; 43 44 namespace extensions { 45 46 namespace { 47 48 void NotifyEventListenerRemovedOnIOThread( 49 void* profile, 50 const std::string& extension_id, 51 const std::string& sub_event_name) { 52 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 53 profile, extension_id, sub_event_name); 54 } 55 56 void DispatchOnInstalledEvent( 57 Profile* profile, 58 const std::string& extension_id, 59 const Version& old_version, 60 bool chrome_updated) { 61 if (!g_browser_process->profile_manager()->IsValidProfile(profile)) 62 return; 63 64 RuntimeEventRouter::DispatchOnInstalledEvent(profile, extension_id, 65 old_version, chrome_updated); 66 } 67 68 void DoNothing(ExtensionHost* host) {} 69 70 // A dictionary of event names to lists of filters that this extension has 71 // registered from its lazy background page. 72 const char kFilteredEvents[] = "filtered_events"; 73 74 } // namespace 75 76 const char EventRouter::kRegisteredEvents[] = "events"; 77 78 struct EventRouter::ListenerProcess { 79 content::RenderProcessHost* process; 80 std::string extension_id; 81 82 ListenerProcess(content::RenderProcessHost* process, 83 const std::string& extension_id) 84 : process(process), extension_id(extension_id) {} 85 86 bool operator<(const ListenerProcess& that) const { 87 if (process < that.process) 88 return true; 89 if (process == that.process && extension_id < that.extension_id) 90 return true; 91 return false; 92 } 93 }; 94 95 // static 96 void EventRouter::LogExtensionEventMessage(void* profile_id, 97 const std::string& extension_id, 98 const std::string& event_name, 99 scoped_ptr<ListValue> event_args) { 100 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 101 BrowserThread::PostTask(BrowserThread::UI, 102 FROM_HERE, 103 base::Bind(&LogExtensionEventMessage, 104 profile_id, 105 extension_id, 106 event_name, 107 base::Passed(&event_args))); 108 } else { 109 Profile* profile = reinterpret_cast<Profile*>(profile_id); 110 if (!g_browser_process->profile_manager()->IsValidProfile(profile)) 111 return; 112 scoped_refptr<Action> action = new Action( 113 extension_id, base::Time::Now(), Action::ACTION_API_EVENT, event_name); 114 action->set_args(event_args.Pass()); 115 ActivityLog::GetInstance(profile)->LogAction(action); 116 } 117 } 118 119 // static 120 void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender, 121 void* profile_id, 122 const std::string& extension_id, 123 const std::string& event_name, 124 ListValue* event_args, 125 UserGestureState user_gesture, 126 const EventFilteringInfo& info) { 127 if (ActivityLog::IsLogEnabledOnAnyProfile()) { 128 LogExtensionEventMessage(profile_id, extension_id, event_name, 129 scoped_ptr<ListValue>(event_args->DeepCopy())); 130 } 131 132 ListValue args; 133 args.Set(0, Value::CreateStringValue(event_name)); 134 args.Set(1, event_args); 135 args.Set(2, info.AsValue().release()); 136 ipc_sender->Send(new ExtensionMsg_MessageInvoke( 137 MSG_ROUTING_CONTROL, 138 extension_id, 139 "event_bindings", 140 "dispatchEvent", 141 args, 142 user_gesture == USER_GESTURE_ENABLED)); 143 144 // DispatchExtensionMessage does _not_ take ownership of event_args, so we 145 // must ensure that the destruction of args does not attempt to free it. 146 scoped_ptr<Value> removed_event_args; 147 args.Remove(1, &removed_event_args); 148 ignore_result(removed_event_args.release()); 149 } 150 151 // static 152 void EventRouter::DispatchEvent(IPC::Sender* ipc_sender, 153 void* profile_id, 154 const std::string& extension_id, 155 const std::string& event_name, 156 scoped_ptr<ListValue> event_args, 157 UserGestureState user_gesture, 158 const EventFilteringInfo& info) { 159 DispatchExtensionMessage(ipc_sender, profile_id, extension_id, event_name, 160 event_args.get(), user_gesture, info); 161 162 BrowserThread::PostTask( 163 BrowserThread::UI, 164 FROM_HERE, 165 base::Bind(&EventRouter::IncrementInFlightEventsOnUI, 166 profile_id, 167 extension_id)); 168 } 169 170 EventRouter::EventRouter(Profile* profile, ExtensionPrefs* extension_prefs) 171 : profile_(profile), 172 listeners_(this), 173 dispatch_chrome_updated_event_(false) { 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, chrome::NOTIFICATION_EXTENSIONS_READY, 179 content::Source<Profile>(profile_)); 180 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, 181 content::Source<Profile>(profile_)); 182 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, 183 content::Source<Profile>(profile_)); 184 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 185 content::Source<Profile>(profile_)); 186 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 187 content::Source<Profile>(profile_)); 188 189 // NULL in unit_tests. 190 if (extension_prefs) { 191 // Check if registered events are up-to-date. We can only do this once 192 // per profile, since it updates internal state when called. 193 dispatch_chrome_updated_event_ = !CheckRegisteredEventsUpToDate(); 194 } 195 } 196 197 EventRouter::~EventRouter() {} 198 199 void EventRouter::AddEventListener(const std::string& event_name, 200 content::RenderProcessHost* process, 201 const std::string& extension_id) { 202 listeners_.AddListener(scoped_ptr<EventListener>(new EventListener( 203 event_name, extension_id, process, scoped_ptr<DictionaryValue>()))); 204 } 205 206 void EventRouter::RemoveEventListener(const std::string& event_name, 207 content::RenderProcessHost* process, 208 const std::string& extension_id) { 209 EventListener listener(event_name, extension_id, process, 210 scoped_ptr<DictionaryValue>()); 211 listeners_.RemoveListener(&listener); 212 } 213 214 void EventRouter::RegisterObserver(Observer* observer, 215 const std::string& event_name) { 216 observers_[event_name] = observer; 217 } 218 219 void EventRouter::UnregisterObserver(Observer* observer) { 220 std::vector<ObserverMap::iterator> iters_to_remove; 221 for (ObserverMap::iterator iter = observers_.begin(); 222 iter != observers_.end(); ++iter) { 223 if (iter->second == observer) 224 iters_to_remove.push_back(iter); 225 } 226 for (size_t i = 0; i < iters_to_remove.size(); ++i) 227 observers_.erase(iters_to_remove[i]); 228 } 229 230 void EventRouter::OnListenerAdded(const EventListener* listener) { 231 const std::string& event_name = listener->event_name; 232 const EventListenerInfo details(event_name, listener->extension_id); 233 ObserverMap::iterator observer = observers_.find(event_name); 234 if (observer != observers_.end()) 235 observer->second->OnListenerAdded(details); 236 237 #if 0 238 // TODO(felt): Experimentally determine if these are needed, or if they 239 // can be permanently removed. Temporarily removing for now to reduce log 240 // size while under investigation. 241 const Extension* extension = ExtensionSystem::Get(profile_)-> 242 extension_service()->GetExtensionById(listener->extension_id, 243 ExtensionService::INCLUDE_ENABLED); 244 if (extension) { 245 scoped_ptr<ListValue> args(new ListValue()); 246 if (listener->filter) 247 args->Append(listener->filter->DeepCopy()); 248 ActivityLog::GetInstance(profile)->LogAPIAction( 249 extension, event_name + ".addListener", args.get(), std::string()); 250 } 251 #endif 252 } 253 254 void EventRouter::OnListenerRemoved(const EventListener* listener) { 255 const std::string& event_name = listener->event_name; 256 const EventListenerInfo details(event_name, listener->extension_id); 257 ObserverMap::iterator observer = observers_.find(event_name); 258 if (observer != observers_.end()) 259 observer->second->OnListenerRemoved(details); 260 261 void* profile = 262 listener->process 263 ? Profile::FromBrowserContext(listener->process->GetBrowserContext()) 264 : NULL; 265 BrowserThread::PostTask( 266 BrowserThread::IO, FROM_HERE, 267 base::Bind(&NotifyEventListenerRemovedOnIOThread, 268 profile, listener->extension_id, event_name)); 269 #if 0 270 // TODO(felt): Experimentally determine if these are needed, or if they 271 // can be permanently removed. Temporarily removing for now to reduce log 272 // size while under investigation. 273 const Extension* extension = ExtensionSystem::Get(profile_)-> 274 extension_service()->GetExtensionById(listener->extension_id, 275 ExtensionService::INCLUDE_ENABLED); 276 if (extension) { 277 scoped_ptr<ListValue> args(new ListValue()); 278 ActivityLog::GetInstance(profile)->LogAPIAction( 279 extension, event_name + ".removeListener", args.get(), std::string()); 280 } 281 #endif 282 } 283 284 void EventRouter::AddLazyEventListener(const std::string& event_name, 285 const std::string& extension_id) { 286 scoped_ptr<EventListener> listener(new EventListener( 287 event_name, extension_id, NULL, scoped_ptr<DictionaryValue>())); 288 bool is_new = listeners_.AddListener(listener.Pass()); 289 290 if (is_new) { 291 std::set<std::string> events = GetRegisteredEvents(extension_id); 292 bool prefs_is_new = events.insert(event_name).second; 293 if (prefs_is_new) 294 SetRegisteredEvents(extension_id, events); 295 } 296 } 297 298 void EventRouter::RemoveLazyEventListener(const std::string& event_name, 299 const std::string& extension_id) { 300 EventListener listener(event_name, extension_id, NULL, 301 scoped_ptr<DictionaryValue>()); 302 bool did_exist = listeners_.RemoveListener(&listener); 303 304 if (did_exist) { 305 std::set<std::string> events = GetRegisteredEvents(extension_id); 306 bool prefs_did_exist = events.erase(event_name) > 0; 307 DCHECK(prefs_did_exist); 308 SetRegisteredEvents(extension_id, events); 309 } 310 } 311 312 void EventRouter::AddFilteredEventListener(const std::string& event_name, 313 content::RenderProcessHost* process, 314 const std::string& extension_id, 315 const base::DictionaryValue& filter, 316 bool add_lazy_listener) { 317 listeners_.AddListener(scoped_ptr<EventListener>(new EventListener( 318 event_name, extension_id, process, 319 scoped_ptr<DictionaryValue>(filter.DeepCopy())))); 320 321 if (add_lazy_listener) { 322 bool added = listeners_.AddListener(scoped_ptr<EventListener>( 323 new EventListener(event_name, extension_id, NULL, 324 scoped_ptr<DictionaryValue>(filter.DeepCopy())))); 325 326 if (added) 327 AddFilterToEvent(event_name, extension_id, &filter); 328 } 329 } 330 331 void EventRouter::RemoveFilteredEventListener( 332 const std::string& event_name, 333 content::RenderProcessHost* process, 334 const std::string& extension_id, 335 const base::DictionaryValue& filter, 336 bool remove_lazy_listener) { 337 EventListener listener(event_name, extension_id, process, 338 scoped_ptr<DictionaryValue>(filter.DeepCopy())); 339 340 listeners_.RemoveListener(&listener); 341 342 if (remove_lazy_listener) { 343 listener.process = NULL; 344 bool removed = listeners_.RemoveListener(&listener); 345 346 if (removed) 347 RemoveFilterFromEvent(event_name, extension_id, &filter); 348 } 349 } 350 351 bool EventRouter::HasEventListener(const std::string& event_name) { 352 return listeners_.HasListenerForEvent(event_name); 353 } 354 355 bool EventRouter::ExtensionHasEventListener(const std::string& extension_id, 356 const std::string& event_name) { 357 return listeners_.HasListenerForExtension(extension_id, event_name); 358 } 359 360 bool EventRouter::HasEventListenerImpl(const ListenerMap& listener_map, 361 const std::string& extension_id, 362 const std::string& event_name) { 363 ListenerMap::const_iterator it = listener_map.find(event_name); 364 if (it == listener_map.end()) 365 return false; 366 367 const std::set<ListenerProcess>& listeners = it->second; 368 if (extension_id.empty()) 369 return !listeners.empty(); 370 371 for (std::set<ListenerProcess>::const_iterator listener = listeners.begin(); 372 listener != listeners.end(); ++listener) { 373 if (listener->extension_id == extension_id) 374 return true; 375 } 376 return false; 377 } 378 379 std::set<std::string> EventRouter::GetRegisteredEvents( 380 const std::string& extension_id) { 381 std::set<std::string> events; 382 const ListValue* events_value = NULL; 383 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); 384 385 if (!prefs || 386 !prefs->ReadPrefAsList(extension_id, kRegisteredEvents, &events_value)) { 387 return events; 388 } 389 390 for (size_t i = 0; i < events_value->GetSize(); ++i) { 391 std::string event; 392 if (events_value->GetString(i, &event)) 393 events.insert(event); 394 } 395 return events; 396 } 397 398 void EventRouter::SetRegisteredEvents(const std::string& extension_id, 399 const std::set<std::string>& events) { 400 ListValue* events_value = new ListValue; 401 for (std::set<std::string>::const_iterator iter = events.begin(); 402 iter != events.end(); ++iter) { 403 events_value->Append(new StringValue(*iter)); 404 } 405 ExtensionPrefs::Get(profile_)->UpdateExtensionPref( 406 extension_id, 407 kRegisteredEvents, 408 events_value); 409 } 410 411 bool EventRouter::CheckRegisteredEventsUpToDate() { 412 // If we're running inside a test, then assume prefs are all up-to-date. 413 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) 414 return true; 415 416 base::Version version; 417 PrefService* pref_service = profile_->GetPrefs(); 418 if (pref_service->HasPrefPath(ExtensionPrefs::kExtensionsLastChromeVersion)) { 419 std::string version_str = 420 pref_service->GetString(ExtensionPrefs::kExtensionsLastChromeVersion); 421 version = Version(version_str); 422 } 423 424 chrome::VersionInfo current_version_info; 425 std::string current_version = current_version_info.Version(); 426 pref_service->SetString(ExtensionPrefs::kExtensionsLastChromeVersion, 427 current_version); 428 429 // If there was no version string in prefs, assume we're out of date. 430 if (!version.IsValid() || version.IsOlderThan(current_version)) 431 return false; 432 433 return true; 434 } 435 436 void EventRouter::AddFilterToEvent(const std::string& event_name, 437 const std::string& extension_id, 438 const DictionaryValue* filter) { 439 ExtensionPrefs::ScopedDictionaryUpdate update( 440 ExtensionPrefs::Get(profile_), 441 extension_id, 442 kFilteredEvents); 443 DictionaryValue* filtered_events = update.Get(); 444 if (!filtered_events) 445 filtered_events = update.Create(); 446 447 ListValue* filter_list = NULL; 448 if (!filtered_events->GetList(event_name, &filter_list)) { 449 filter_list = new ListValue; 450 filtered_events->SetWithoutPathExpansion(event_name, filter_list); 451 } 452 453 filter_list->Append(filter->DeepCopy()); 454 } 455 456 void EventRouter::RemoveFilterFromEvent(const std::string& event_name, 457 const std::string& extension_id, 458 const DictionaryValue* filter) { 459 ExtensionPrefs::ScopedDictionaryUpdate update( 460 ExtensionPrefs::Get(profile_), 461 extension_id, 462 kFilteredEvents); 463 DictionaryValue* filtered_events = update.Get(); 464 ListValue* filter_list = NULL; 465 if (!filtered_events || 466 !filtered_events->GetListWithoutPathExpansion(event_name, &filter_list)) { 467 return; 468 } 469 470 for (size_t i = 0; i < filter_list->GetSize(); i++) { 471 DictionaryValue* filter = NULL; 472 CHECK(filter_list->GetDictionary(i, &filter)); 473 if (filter->Equals(filter)) { 474 filter_list->Remove(i, NULL); 475 break; 476 } 477 } 478 } 479 480 const DictionaryValue* EventRouter::GetFilteredEvents( 481 const std::string& extension_id) { 482 const DictionaryValue* events = NULL; 483 ExtensionPrefs::Get(profile_)->ReadPrefAsDictionary( 484 extension_id, kFilteredEvents, &events); 485 return events; 486 } 487 488 void EventRouter::BroadcastEvent(scoped_ptr<Event> event) { 489 DispatchEventImpl(std::string(), linked_ptr<Event>(event.release())); 490 } 491 492 void EventRouter::DispatchEventToExtension(const std::string& extension_id, 493 scoped_ptr<Event> event) { 494 DCHECK(!extension_id.empty()); 495 DispatchEventImpl(extension_id, linked_ptr<Event>(event.release())); 496 } 497 498 void EventRouter::DispatchEventWithLazyListener(const std::string& extension_id, 499 scoped_ptr<Event> event) { 500 DCHECK(!extension_id.empty()); 501 std::string event_name = event->event_name; 502 bool has_listener = ExtensionHasEventListener(extension_id, event_name); 503 if (!has_listener) 504 AddLazyEventListener(event_name, extension_id); 505 DispatchEventToExtension(extension_id, event.Pass()); 506 if (!has_listener) 507 RemoveLazyEventListener(event_name, extension_id); 508 } 509 510 void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id, 511 const linked_ptr<Event>& event) { 512 // We don't expect to get events from a completely different profile. 513 DCHECK(!event->restrict_to_profile || 514 profile_->IsSameProfile(event->restrict_to_profile)); 515 516 std::set<const EventListener*> listeners( 517 listeners_.GetEventListeners(*event)); 518 519 std::set<EventDispatchIdentifier> already_dispatched; 520 521 // We dispatch events for lazy background pages first because attempting to do 522 // so will cause those that are being suspended to cancel that suspension. 523 // As canceling a suspension entails sending an event to the affected 524 // background page, and as that event needs to be delivered before we dispatch 525 // the event we are dispatching here, we dispatch to the lazy listeners here 526 // first. 527 for (std::set<const EventListener*>::iterator it = listeners.begin(); 528 it != listeners.end(); it++) { 529 const EventListener* listener = *it; 530 if (restrict_to_extension_id.empty() || 531 restrict_to_extension_id == listener->extension_id) { 532 if (!listener->process) { 533 DispatchLazyEvent(listener->extension_id, event, &already_dispatched); 534 } 535 } 536 } 537 538 for (std::set<const EventListener*>::iterator it = listeners.begin(); 539 it != listeners.end(); it++) { 540 const EventListener* listener = *it; 541 if (restrict_to_extension_id.empty() || 542 restrict_to_extension_id == listener->extension_id) { 543 if (listener->process) { 544 EventDispatchIdentifier dispatch_id( 545 listener->process->GetBrowserContext(), listener->extension_id); 546 if (!ContainsKey(already_dispatched, dispatch_id)) { 547 DispatchEventToProcess(listener->extension_id, listener->process, 548 event); 549 } 550 } 551 } 552 } 553 } 554 555 void EventRouter::DispatchLazyEvent( 556 const std::string& extension_id, 557 const linked_ptr<Event>& event, 558 std::set<EventDispatchIdentifier>* already_dispatched) { 559 ExtensionService* service = 560 ExtensionSystem::Get(profile_)->extension_service(); 561 // Check both the original and the incognito profile to see if we 562 // should load a lazy bg page to handle the event. The latter case 563 // occurs in the case of split-mode extensions. 564 const Extension* extension = service->extensions()->GetByID(extension_id); 565 if (extension) { 566 if (MaybeLoadLazyBackgroundPageToDispatchEvent( 567 profile_, extension, event)) { 568 already_dispatched->insert(std::make_pair(profile_, extension_id)); 569 } 570 571 if (profile_->HasOffTheRecordProfile() && 572 IncognitoInfo::IsSplitMode(extension)) { 573 if (MaybeLoadLazyBackgroundPageToDispatchEvent( 574 profile_->GetOffTheRecordProfile(), extension, event)) { 575 already_dispatched->insert( 576 std::make_pair(profile_->GetOffTheRecordProfile(), extension_id)); 577 } 578 } 579 } 580 } 581 582 void EventRouter::DispatchEventToProcess(const std::string& extension_id, 583 content::RenderProcessHost* process, 584 const linked_ptr<Event>& event) { 585 ExtensionService* service = 586 ExtensionSystem::Get(profile_)->extension_service(); 587 const Extension* extension = service->extensions()->GetByID(extension_id); 588 589 // The extension could have been removed, but we do not unregister it until 590 // the extension process is unloaded. 591 if (!extension) 592 return; 593 594 Profile* listener_profile = Profile::FromBrowserContext( 595 process->GetBrowserContext()); 596 ProcessMap* process_map = ExtensionSystem::Get(listener_profile)-> 597 extension_service()->process_map(); 598 // If the event is privileged, only send to extension processes. Otherwise, 599 // it's OK to send to normal renderers (e.g., for content scripts). 600 if (ExtensionAPI::GetSharedInstance()->IsPrivileged(event->event_name) && 601 !process_map->Contains(extension->id(), process->GetID())) { 602 return; 603 } 604 605 // If the event is restricted to a URL, only dispatch if the extension has 606 // permission for it (or if the event originated from itself). 607 if (!event->event_url.is_empty() && 608 event->event_url.host() != extension->id() && 609 !extension->GetActivePermissions()->HasEffectiveAccessToURL( 610 event->event_url)) { 611 return; 612 } 613 614 if (!CanDispatchEventToProfile(listener_profile, extension, event)) 615 return; 616 617 if (!event->will_dispatch_callback.is_null()) { 618 event->will_dispatch_callback.Run(listener_profile, extension, 619 event->event_args.get()); 620 } 621 622 DispatchExtensionMessage(process, listener_profile, extension->id(), 623 event->event_name, event->event_args.get(), 624 event->user_gesture, event->filter_info); 625 IncrementInFlightEvents(listener_profile, extension); 626 } 627 628 bool EventRouter::CanDispatchEventToProfile(Profile* profile, 629 const Extension* extension, 630 const linked_ptr<Event>& event) { 631 // Is this event from a different profile than the renderer (ie, an 632 // incognito tab event sent to a normal process, or vice versa). 633 bool cross_incognito = 634 event->restrict_to_profile && profile != event->restrict_to_profile; 635 if (cross_incognito && 636 !ExtensionSystem::Get(profile)->extension_service()-> 637 CanCrossIncognito(extension)) { 638 return false; 639 } 640 641 return true; 642 } 643 644 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent( 645 Profile* profile, 646 const Extension* extension, 647 const linked_ptr<Event>& event) { 648 if (!CanDispatchEventToProfile(profile, extension, event)) 649 return false; 650 651 LazyBackgroundTaskQueue* queue = 652 ExtensionSystem::Get(profile)->lazy_background_task_queue(); 653 if (queue->ShouldEnqueueTask(profile, extension)) { 654 linked_ptr<Event> dispatched_event(event); 655 656 // If there's a dispatch callback, call it now (rather than dispatch time) 657 // to avoid lifetime issues. Use a separate copy of the event args, so they 658 // last until the event is dispatched. 659 if (!event->will_dispatch_callback.is_null()) { 660 dispatched_event.reset(event->DeepCopy()); 661 dispatched_event->will_dispatch_callback.Run( 662 profile, extension, dispatched_event->event_args.get()); 663 // Ensure we don't call it again at dispatch time. 664 dispatched_event->will_dispatch_callback.Reset(); 665 } 666 667 queue->AddPendingTask(profile, extension->id(), 668 base::Bind(&EventRouter::DispatchPendingEvent, 669 base::Unretained(this), dispatched_event)); 670 return true; 671 } 672 673 return false; 674 } 675 676 // static 677 void EventRouter::IncrementInFlightEventsOnUI( 678 void* profile_id, 679 const std::string& extension_id) { 680 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 681 Profile* profile = reinterpret_cast<Profile*>(profile_id); 682 if (!g_browser_process->profile_manager()->IsValidProfile(profile)) 683 return; 684 extensions::EventRouter* event_router = 685 extensions::ExtensionSystem::Get(profile)->event_router(); 686 if (!event_router) 687 return; 688 ExtensionService* extension_service = 689 extensions::ExtensionSystem::Get(profile)->extension_service(); 690 const Extension* extension = 691 extension_service->extensions()->GetByID(extension_id); 692 if (!extension) 693 return; 694 event_router->IncrementInFlightEvents(profile, extension); 695 } 696 697 void EventRouter::IncrementInFlightEvents(Profile* profile, 698 const Extension* extension) { 699 // Only increment in-flight events if the lazy background page is active, 700 // because that's the only time we'll get an ACK. 701 if (BackgroundInfo::HasLazyBackgroundPage(extension)) { 702 ExtensionProcessManager* pm = 703 ExtensionSystem::Get(profile)->process_manager(); 704 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension->id()); 705 if (host) 706 pm->IncrementLazyKeepaliveCount(extension); 707 } 708 } 709 710 void EventRouter::OnEventAck(Profile* profile, 711 const std::string& extension_id) { 712 ExtensionProcessManager* pm = 713 ExtensionSystem::Get(profile)->process_manager(); 714 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id); 715 // The event ACK is routed to the background host, so this should never be 716 // NULL. 717 CHECK(host); 718 // TODO(mpcomplete): We should never get this message unless 719 // HasLazyBackgroundPage is true. Find out why we're getting it anyway. 720 if (host->extension() && 721 BackgroundInfo::HasLazyBackgroundPage(host->extension())) 722 pm->DecrementLazyKeepaliveCount(host->extension()); 723 } 724 725 void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event, 726 ExtensionHost* host) { 727 if (!host) 728 return; 729 730 if (listeners_.HasProcessListener(host->render_process_host(), 731 host->extension()->id())) { 732 DispatchEventToProcess(host->extension()->id(), 733 host->render_process_host(), event); 734 } 735 } 736 737 void EventRouter::Observe(int type, 738 const content::NotificationSource& source, 739 const content::NotificationDetails& details) { 740 switch (type) { 741 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: 742 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 743 content::RenderProcessHost* renderer = 744 content::Source<content::RenderProcessHost>(source).ptr(); 745 // Remove all event listeners associated with this renderer. 746 listeners_.RemoveListenersForProcess(renderer); 747 break; 748 } 749 case chrome::NOTIFICATION_EXTENSIONS_READY: { 750 // We're done restarting Chrome after an update. 751 dispatch_chrome_updated_event_ = false; 752 break; 753 } 754 case chrome::NOTIFICATION_EXTENSION_ENABLED: { 755 // If the extension has a lazy background page, make sure it gets loaded 756 // to register the events the extension is interested in. 757 const Extension* extension = 758 content::Details<const Extension>(details).ptr(); 759 if (BackgroundInfo::HasLazyBackgroundPage(extension)) { 760 LazyBackgroundTaskQueue* queue = 761 ExtensionSystem::Get(profile_)->lazy_background_task_queue(); 762 queue->AddPendingTask(profile_, extension->id(), 763 base::Bind(&DoNothing)); 764 } 765 break; 766 } 767 case chrome::NOTIFICATION_EXTENSION_LOADED: { 768 // Add all registered lazy listeners to our cache. 769 const Extension* extension = 770 content::Details<const Extension>(details).ptr(); 771 std::set<std::string> registered_events = 772 GetRegisteredEvents(extension->id()); 773 listeners_.LoadUnfilteredLazyListeners(extension->id(), 774 registered_events); 775 const DictionaryValue* filtered_events = 776 GetFilteredEvents(extension->id()); 777 if (filtered_events) 778 listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events); 779 780 if (dispatch_chrome_updated_event_) { 781 base::MessageLoop::current()->PostTask(FROM_HERE, 782 base::Bind(&DispatchOnInstalledEvent, profile_, extension->id(), 783 Version(), true)); 784 } 785 break; 786 } 787 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { 788 // Remove all registered lazy listeners from our cache. 789 UnloadedExtensionInfo* unloaded = 790 content::Details<UnloadedExtensionInfo>(details).ptr(); 791 listeners_.RemoveLazyListenersForExtension(unloaded->extension->id()); 792 break; 793 } 794 case chrome::NOTIFICATION_EXTENSION_INSTALLED: { 795 // Dispatch the onInstalled event. 796 const Extension* extension = 797 content::Details<const InstalledExtensionInfo>(details)->extension; 798 799 // Get the previous version, if this is an upgrade. 800 ExtensionService* service = 801 ExtensionSystem::Get(profile_)->extension_service(); 802 const Extension* old = service->GetExtensionById(extension->id(), true); 803 Version old_version; 804 if (old) 805 old_version = *old->version(); 806 807 base::MessageLoop::current()->PostTask(FROM_HERE, 808 base::Bind(&DispatchOnInstalledEvent, profile_, extension->id(), 809 old_version, false)); 810 break; 811 } 812 default: 813 NOTREACHED(); 814 return; 815 } 816 } 817 818 Event::Event(const std::string& event_name, 819 scoped_ptr<base::ListValue> event_args) 820 : event_name(event_name), 821 event_args(event_args.Pass()), 822 restrict_to_profile(NULL), 823 user_gesture(EventRouter::USER_GESTURE_UNKNOWN) { 824 DCHECK(this->event_args.get()); 825 } 826 827 Event::Event(const std::string& event_name, 828 scoped_ptr<base::ListValue> event_args, 829 Profile* restrict_to_profile) 830 : event_name(event_name), 831 event_args(event_args.Pass()), 832 restrict_to_profile(restrict_to_profile), 833 user_gesture(EventRouter::USER_GESTURE_UNKNOWN) { 834 DCHECK(this->event_args.get()); 835 } 836 837 Event::Event(const std::string& event_name, 838 scoped_ptr<ListValue> event_args, 839 Profile* restrict_to_profile, 840 const GURL& event_url, 841 EventRouter::UserGestureState user_gesture, 842 const EventFilteringInfo& filter_info) 843 : event_name(event_name), 844 event_args(event_args.Pass()), 845 restrict_to_profile(restrict_to_profile), 846 event_url(event_url), 847 user_gesture(user_gesture), 848 filter_info(filter_info) { 849 DCHECK(this->event_args.get()); 850 } 851 852 Event::~Event() {} 853 854 Event* Event::DeepCopy() { 855 Event* copy = new Event(event_name, 856 scoped_ptr<base::ListValue>(event_args->DeepCopy()), 857 restrict_to_profile, 858 event_url, 859 user_gesture, 860 filter_info); 861 copy->will_dispatch_callback = will_dispatch_callback; 862 return copy; 863 } 864 865 EventListenerInfo::EventListenerInfo(const std::string& event_name, 866 const std::string& extension_id) 867 : event_name(event_name), 868 extension_id(extension_id) {} 869 870 } // namespace extensions 871