Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "extensions/browser/event_router.h" | 5 #include "extensions/browser/event_router.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/atomic_sequence_num.h" | 11 #include "base/atomic_sequence_num.h" |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
| 15 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" |
| 16 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
| 17 #include "base/values.h" | 17 #include "base/values.h" |
| 18 #include "content/public/browser/render_process_host.h" | 18 #include "content/public/browser/render_process_host.h" |
| 19 #include "extensions/browser/api_activity_monitor.h" | 19 #include "extensions/browser/api_activity_monitor.h" |
| 20 #include "extensions/browser/event_router_factory.h" | 20 #include "extensions/browser/event_router_factory.h" |
| 21 #include "extensions/browser/events/lazy_event_dispatcher.h" | |
| 21 #include "extensions/browser/extension_host.h" | 22 #include "extensions/browser/extension_host.h" |
| 22 #include "extensions/browser/extension_prefs.h" | 23 #include "extensions/browser/extension_prefs.h" |
| 23 #include "extensions/browser/extension_registry.h" | 24 #include "extensions/browser/extension_registry.h" |
| 24 #include "extensions/browser/extension_system.h" | 25 #include "extensions/browser/extension_system.h" |
| 25 #include "extensions/browser/extensions_browser_client.h" | 26 #include "extensions/browser/extensions_browser_client.h" |
| 26 #include "extensions/browser/lazy_background_task_queue.h" | |
| 27 #include "extensions/browser/process_manager.h" | 27 #include "extensions/browser/process_manager.h" |
| 28 #include "extensions/browser/process_map.h" | 28 #include "extensions/browser/process_map.h" |
| 29 #include "extensions/common/constants.h" | 29 #include "extensions/common/constants.h" |
| 30 #include "extensions/common/extension.h" | 30 #include "extensions/common/extension.h" |
| 31 #include "extensions/common/extension_api.h" | 31 #include "extensions/common/extension_api.h" |
| 32 #include "extensions/common/extension_messages.h" | 32 #include "extensions/common/extension_messages.h" |
| 33 #include "extensions/common/extension_urls.h" | 33 #include "extensions/common/extension_urls.h" |
| 34 #include "extensions/common/features/feature.h" | 34 #include "extensions/common/features/feature.h" |
| 35 #include "extensions/common/features/feature_provider.h" | 35 #include "extensions/common/features/feature_provider.h" |
| 36 #include "extensions/common/manifest_handlers/background_info.h" | 36 #include "extensions/common/manifest_handlers/background_info.h" |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 } | 133 } |
| 134 | 134 |
| 135 DispatchExtensionMessage(ipc_sender, | 135 DispatchExtensionMessage(ipc_sender, |
| 136 // TODO(lazyboy): |kNonWorkerThreadId| means these | 136 // TODO(lazyboy): |kNonWorkerThreadId| means these |
| 137 // will not work for extension SW. | 137 // will not work for extension SW. |
| 138 kNonWorkerThreadId, browser_context_id, extension_id, | 138 kNonWorkerThreadId, browser_context_id, extension_id, |
| 139 event_id, event_name, event_args.get(), user_gesture, | 139 event_id, event_name, event_args.get(), user_gesture, |
| 140 info); | 140 info); |
| 141 } | 141 } |
| 142 | 142 |
| 143 // static. | |
| 144 bool EventRouter::CanDispatchEventToBrowserContext(BrowserContext* context, | |
| 145 const Extension* extension, | |
| 146 const Event& event) { | |
| 147 // Is this event from a different browser context than the renderer (ie, an | |
| 148 // incognito tab event sent to a normal process, or vice versa). | |
| 149 bool cross_incognito = event.restrict_to_browser_context && | |
|
Devlin
2017/06/15 01:37:26
nit: since we're here, maybe s/cross/crosses
lazyboy
2017/06/15 04:39:22
Done.
| |
| 150 context != event.restrict_to_browser_context; | |
| 151 if (!cross_incognito) | |
| 152 return true; | |
| 153 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(extension, | |
| 154 context); | |
| 155 } | |
| 156 | |
| 143 EventRouter::EventRouter(BrowserContext* browser_context, | 157 EventRouter::EventRouter(BrowserContext* browser_context, |
| 144 ExtensionPrefs* extension_prefs) | 158 ExtensionPrefs* extension_prefs) |
| 145 : browser_context_(browser_context), | 159 : browser_context_(browser_context), |
| 146 extension_prefs_(extension_prefs), | 160 extension_prefs_(extension_prefs), |
| 147 extension_registry_observer_(this), | 161 extension_registry_observer_(this), |
| 148 listeners_(this), | 162 listeners_(this), |
| 149 lazy_event_dispatch_util_(browser_context_) { | 163 lazy_event_dispatch_util_(browser_context_) { |
| 150 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); | 164 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); |
| 151 } | 165 } |
| 152 | 166 |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 424 | 438 |
| 425 void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id, | 439 void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id, |
| 426 const linked_ptr<Event>& event) { | 440 const linked_ptr<Event>& event) { |
| 427 // We don't expect to get events from a completely different browser context. | 441 // We don't expect to get events from a completely different browser context. |
| 428 DCHECK(!event->restrict_to_browser_context || | 442 DCHECK(!event->restrict_to_browser_context || |
| 429 ExtensionsBrowserClient::Get()->IsSameContext( | 443 ExtensionsBrowserClient::Get()->IsSameContext( |
| 430 browser_context_, event->restrict_to_browser_context)); | 444 browser_context_, event->restrict_to_browser_context)); |
| 431 std::set<const EventListener*> listeners( | 445 std::set<const EventListener*> listeners( |
| 432 listeners_.GetEventListeners(*event)); | 446 listeners_.GetEventListeners(*event)); |
| 433 | 447 |
| 434 std::set<EventDispatchIdentifier> already_dispatched; | 448 LazyEventDispatcher lazy_event_dispatcher( |
| 449 browser_context_, event, | |
| 450 base::Bind(&EventRouter::DispatchPendingEvent, base::Unretained(this))); | |
|
Devlin
2017/06/15 01:37:26
This Unretained was just copied, but isn't inheren
lazyboy
2017/06/15 04:39:22
Good point, fixed.
| |
| 435 | 451 |
| 436 // We dispatch events for lazy background pages first because attempting to do | 452 // We dispatch events for lazy background pages first because attempting to do |
| 437 // so will cause those that are being suspended to cancel that suspension. | 453 // so will cause those that are being suspended to cancel that suspension. |
| 438 // As canceling a suspension entails sending an event to the affected | 454 // As canceling a suspension entails sending an event to the affected |
| 439 // background page, and as that event needs to be delivered before we dispatch | 455 // background page, and as that event needs to be delivered before we dispatch |
| 440 // the event we are dispatching here, we dispatch to the lazy listeners here | 456 // the event we are dispatching here, we dispatch to the lazy listeners here |
| 441 // first. | 457 // first. |
| 442 for (const EventListener* listener : listeners) { | 458 for (const EventListener* listener : listeners) { |
| 443 if (restrict_to_extension_id.empty() || | 459 if (!restrict_to_extension_id.empty() && |
| 444 restrict_to_extension_id == listener->extension_id()) { | 460 restrict_to_extension_id != listener->extension_id()) { |
| 445 // TODO(lazyboy): Support lazy listeners for extension SW events. | 461 continue; |
| 446 if (listener->IsLazy() && !listener->IsForServiceWorker()) { | 462 } |
| 447 DispatchLazyEvent(listener->extension_id(), event, &already_dispatched, | 463 // TODO(lazyboy): Support lazy listeners for extension SW events. |
| 448 listener->filter()); | 464 if (listener->IsLazy() && !listener->IsForServiceWorker()) { |
| 449 } | 465 lazy_event_dispatcher.DispatchToEventPage(listener->extension_id(), |
| 466 listener->filter()); | |
| 450 } | 467 } |
| 451 } | 468 } |
| 452 | 469 |
| 453 for (const EventListener* listener : listeners) { | 470 for (const EventListener* listener : listeners) { |
| 454 if (restrict_to_extension_id.empty() || | 471 if (!restrict_to_extension_id.empty() && |
| 455 restrict_to_extension_id == listener->extension_id()) { | 472 restrict_to_extension_id != listener->extension_id()) { |
| 456 if (listener->process()) { | 473 continue; |
| 457 EventDispatchIdentifier dispatch_id(listener->GetBrowserContext(), | |
| 458 listener->extension_id(), | |
| 459 listener->worker_thread_id()); | |
| 460 if (!base::ContainsKey(already_dispatched, dispatch_id)) { | |
| 461 DispatchEventToProcess(listener->extension_id(), | |
| 462 listener->listener_url(), listener->process(), | |
| 463 listener->worker_thread_id(), event, | |
| 464 listener->filter(), false /* did_enqueue */); | |
| 465 } | |
| 466 } | |
| 467 } | 474 } |
| 475 if (!listener->process()) | |
| 476 continue; | |
| 477 if (lazy_event_dispatcher.HasAlreadyDispatched( | |
| 478 listener->process()->GetBrowserContext(), listener)) { | |
| 479 continue; | |
| 480 } | |
| 481 DispatchEventToProcess(listener->extension_id(), listener->listener_url(), | |
| 482 listener->process(), listener->worker_thread_id(), | |
| 483 event, listener->filter(), false /* did_enqueue */); | |
| 468 } | 484 } |
| 469 } | 485 } |
| 470 | 486 |
| 471 void EventRouter::DispatchLazyEvent( | |
| 472 const std::string& extension_id, | |
| 473 const linked_ptr<Event>& event, | |
| 474 std::set<EventDispatchIdentifier>* already_dispatched, | |
| 475 const base::DictionaryValue* listener_filter) { | |
| 476 // Check both the original and the incognito browser context to see if we | |
| 477 // should load a lazy bg page to handle the event. The latter case | |
| 478 // occurs in the case of split-mode extensions. | |
| 479 const Extension* extension = | |
| 480 ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID( | |
| 481 extension_id); | |
| 482 if (!extension) | |
| 483 return; | |
| 484 | |
| 485 if (MaybeLoadLazyBackgroundPageToDispatchEvent(browser_context_, extension, | |
| 486 event, listener_filter)) { | |
| 487 already_dispatched->insert( | |
| 488 std::make_tuple(browser_context_, extension_id, kNonWorkerThreadId)); | |
| 489 } | |
| 490 | |
| 491 ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get(); | |
| 492 if (browser_client->HasOffTheRecordContext(browser_context_) && | |
| 493 IncognitoInfo::IsSplitMode(extension)) { | |
| 494 BrowserContext* incognito_context = | |
| 495 browser_client->GetOffTheRecordContext(browser_context_); | |
| 496 if (MaybeLoadLazyBackgroundPageToDispatchEvent(incognito_context, extension, | |
| 497 event, listener_filter)) { | |
| 498 already_dispatched->insert( | |
| 499 std::make_tuple(incognito_context, extension_id, kNonWorkerThreadId)); | |
| 500 } | |
| 501 } | |
| 502 } | |
| 503 | |
| 504 void EventRouter::DispatchEventToProcess( | 487 void EventRouter::DispatchEventToProcess( |
| 505 const std::string& extension_id, | 488 const std::string& extension_id, |
| 506 const GURL& listener_url, | 489 const GURL& listener_url, |
| 507 content::RenderProcessHost* process, | 490 content::RenderProcessHost* process, |
| 508 int worker_thread_id, | 491 int worker_thread_id, |
| 509 const linked_ptr<Event>& event, | 492 const linked_ptr<Event>& event, |
| 510 const base::DictionaryValue* listener_filter, | 493 const base::DictionaryValue* listener_filter, |
| 511 bool did_enqueue) { | 494 bool did_enqueue) { |
| 512 BrowserContext* listener_context = process->GetBrowserContext(); | 495 BrowserContext* listener_context = process->GetBrowserContext(); |
| 513 ProcessMap* process_map = ProcessMap::Get(listener_context); | 496 ProcessMap* process_map = ProcessMap::Get(listener_context); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 532 // to access that URL. | 515 // to access that URL. |
| 533 if (!event->event_url.is_empty() && | 516 if (!event->event_url.is_empty() && |
| 534 event->event_url.host() != extension->id() && // event for self is ok | 517 event->event_url.host() != extension->id() && // event for self is ok |
| 535 !extension->permissions_data() | 518 !extension->permissions_data() |
| 536 ->active_permissions() | 519 ->active_permissions() |
| 537 .HasEffectiveAccessToURL(event->event_url)) { | 520 .HasEffectiveAccessToURL(event->event_url)) { |
| 538 return; | 521 return; |
| 539 } | 522 } |
| 540 // Secondly, if the event is for incognito mode, the Extension must be | 523 // Secondly, if the event is for incognito mode, the Extension must be |
| 541 // enabled in incognito mode. | 524 // enabled in incognito mode. |
| 542 if (!CanDispatchEventToBrowserContext(listener_context, extension, event)) { | 525 if (!CanDispatchEventToBrowserContext(listener_context, extension, |
| 526 *event)) { | |
| 543 return; | 527 return; |
| 544 } | 528 } |
| 545 } | 529 } |
| 546 | 530 |
| 547 Feature::Context target_context = | 531 Feature::Context target_context = |
| 548 process_map->GetMostLikelyContextType(extension, process->GetID()); | 532 process_map->GetMostLikelyContextType(extension, process->GetID()); |
| 549 | 533 |
| 550 // We shouldn't be dispatching an event to a webpage, since all such events | 534 // We shouldn't be dispatching an event to a webpage, since all such events |
| 551 // (e.g. messaging) don't go through EventRouter. | 535 // (e.g. messaging) don't go through EventRouter. |
| 552 DCHECK_NE(Feature::WEB_PAGE_CONTEXT, target_context) | 536 DCHECK_NE(Feature::WEB_PAGE_CONTEXT, target_context) |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 578 event->event_args.get(), event->user_gesture, | 562 event->event_args.get(), event->user_gesture, |
| 579 event->filter_info); | 563 event->filter_info); |
| 580 | 564 |
| 581 if (extension) { | 565 if (extension) { |
| 582 ReportEvent(event->histogram_value, extension, did_enqueue); | 566 ReportEvent(event->histogram_value, extension, did_enqueue); |
| 583 IncrementInFlightEvents(listener_context, extension, event_id, | 567 IncrementInFlightEvents(listener_context, extension, event_id, |
| 584 event->event_name); | 568 event->event_name); |
| 585 } | 569 } |
| 586 } | 570 } |
| 587 | 571 |
| 588 bool EventRouter::CanDispatchEventToBrowserContext( | |
| 589 BrowserContext* context, | |
| 590 const Extension* extension, | |
| 591 const linked_ptr<Event>& event) { | |
| 592 // Is this event from a different browser context than the renderer (ie, an | |
| 593 // incognito tab event sent to a normal process, or vice versa). | |
| 594 bool cross_incognito = event->restrict_to_browser_context && | |
| 595 context != event->restrict_to_browser_context; | |
| 596 if (!cross_incognito) | |
| 597 return true; | |
| 598 return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito( | |
| 599 extension, context); | |
| 600 } | |
| 601 | |
| 602 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent( | |
| 603 BrowserContext* context, | |
| 604 const Extension* extension, | |
| 605 const linked_ptr<Event>& event, | |
| 606 const base::DictionaryValue* listener_filter) { | |
| 607 if (!CanDispatchEventToBrowserContext(context, extension, event)) | |
| 608 return false; | |
| 609 | |
| 610 LazyBackgroundTaskQueue* queue = LazyBackgroundTaskQueue::Get(context); | |
| 611 if (!queue->ShouldEnqueueTask(context, extension)) | |
| 612 return false; | |
| 613 | |
| 614 linked_ptr<Event> dispatched_event(event); | |
| 615 | |
| 616 // If there's a dispatch callback, call it now (rather than dispatch time) | |
| 617 // to avoid lifetime issues. Use a separate copy of the event args, so they | |
| 618 // last until the event is dispatched. | |
| 619 if (!event->will_dispatch_callback.is_null()) { | |
| 620 dispatched_event.reset(event->DeepCopy()); | |
| 621 if (!dispatched_event->will_dispatch_callback.Run( | |
| 622 context, extension, dispatched_event.get(), listener_filter)) { | |
| 623 // The event has been canceled. | |
| 624 return true; | |
| 625 } | |
| 626 // Ensure we don't call it again at dispatch time. | |
| 627 dispatched_event->will_dispatch_callback.Reset(); | |
| 628 } | |
| 629 | |
| 630 queue->AddPendingTask(context, extension->id(), | |
| 631 base::Bind(&EventRouter::DispatchPendingEvent, | |
| 632 base::Unretained(this), dispatched_event)); | |
| 633 return true; | |
| 634 } | |
| 635 | |
| 636 // static | 572 // static |
| 637 void EventRouter::DoDispatchEventToSenderBookkeepingOnUI( | 573 void EventRouter::DoDispatchEventToSenderBookkeepingOnUI( |
| 638 void* browser_context_id, | 574 void* browser_context_id, |
| 639 const std::string& extension_id, | 575 const std::string& extension_id, |
| 640 int event_id, | 576 int event_id, |
| 641 events::HistogramValue histogram_value, | 577 events::HistogramValue histogram_value, |
| 642 const std::string& event_name) { | 578 const std::string& event_name) { |
| 643 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 579 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 644 BrowserContext* browser_context = | 580 BrowserContext* browser_context = |
| 645 reinterpret_cast<BrowserContext*>(browser_context_id); | 581 reinterpret_cast<BrowserContext*>(browser_context_id); |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 907 const std::string& extension_id, | 843 const std::string& extension_id, |
| 908 const GURL& listener_url, | 844 const GURL& listener_url, |
| 909 content::BrowserContext* browser_context) | 845 content::BrowserContext* browser_context) |
| 910 : event_name(event_name), | 846 : event_name(event_name), |
| 911 extension_id(extension_id), | 847 extension_id(extension_id), |
| 912 listener_url(listener_url), | 848 listener_url(listener_url), |
| 913 browser_context(browser_context) { | 849 browser_context(browser_context) { |
| 914 } | 850 } |
| 915 | 851 |
| 916 } // namespace extensions | 852 } // namespace extensions |
| OLD | NEW |