Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(117)

Side by Side Diff: extensions/browser/event_router.cc

Issue 2940883007: Move lazy event dispatching code out of EventRouter. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698