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 <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/atomic_sequence_num.h" | 9 #include "base/atomic_sequence_num.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
| 13 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
| 14 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
| 15 #include "base/values.h" | 15 #include "base/values.h" |
| 16 #include "content/public/browser/notification_service.h" | 16 #include "content/public/browser/notification_service.h" |
| 17 #include "content/public/browser/render_process_host.h" | 17 #include "content/public/browser/render_process_host.h" |
| 18 #include "extensions/browser/api_activity_monitor.h" | 18 #include "extensions/browser/api_activity_monitor.h" |
| 19 #include "extensions/browser/event_router_factory.h" | 19 #include "extensions/browser/event_router_factory.h" |
| 20 #include "extensions/browser/extension_host.h" | 20 #include "extensions/browser/extension_host.h" |
| 21 #include "extensions/browser/extension_prefs.h" | 21 #include "extensions/browser/extension_prefs.h" |
| 22 #include "extensions/browser/extension_registry.h" | 22 #include "extensions/browser/extension_registry.h" |
| 23 #include "extensions/browser/extension_system.h" | 23 #include "extensions/browser/extension_system.h" |
| 24 #include "extensions/browser/extensions_browser_client.h" | 24 #include "extensions/browser/extensions_browser_client.h" |
| 25 #include "extensions/browser/lazy_background_task_queue.h" | 25 #include "extensions/browser/lazy_background_task_queue.h" |
| 26 #include "extensions/browser/notification_types.h" | 26 #include "extensions/browser/notification_types.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/extension.h" | 30 #include "extensions/common/extension.h" |
| 30 #include "extensions/common/extension_api.h" | 31 #include "extensions/common/extension_api.h" |
| 31 #include "extensions/common/extension_messages.h" | 32 #include "extensions/common/extension_messages.h" |
| 32 #include "extensions/common/extension_urls.h" | 33 #include "extensions/common/extension_urls.h" |
| 33 #include "extensions/common/features/feature.h" | 34 #include "extensions/common/features/feature.h" |
| 34 #include "extensions/common/features/feature_provider.h" | 35 #include "extensions/common/features/feature_provider.h" |
| 35 #include "extensions/common/manifest_handlers/background_info.h" | 36 #include "extensions/common/manifest_handlers/background_info.h" |
| 36 #include "extensions/common/manifest_handlers/incognito_info.h" | 37 #include "extensions/common/manifest_handlers/incognito_info.h" |
| 37 #include "extensions/common/permissions/permissions_data.h" | 38 #include "extensions/common/permissions/permissions_data.h" |
| 38 | 39 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 return EventRouterFactory::GetForBrowserContext(browser_context); | 141 return EventRouterFactory::GetForBrowserContext(browser_context); |
| 141 } | 142 } |
| 142 | 143 |
| 143 // static | 144 // static |
| 144 std::string EventRouter::GetBaseEventName(const std::string& full_event_name) { | 145 std::string EventRouter::GetBaseEventName(const std::string& full_event_name) { |
| 145 size_t slash_sep = full_event_name.find('/'); | 146 size_t slash_sep = full_event_name.find('/'); |
| 146 return full_event_name.substr(0, slash_sep); | 147 return full_event_name.substr(0, slash_sep); |
| 147 } | 148 } |
| 148 | 149 |
| 149 // static | 150 // static |
| 150 void EventRouter::DispatchEvent(IPC::Sender* ipc_sender, | 151 void EventRouter::DispatchEventToSender(IPC::Sender* ipc_sender, |
| 151 void* browser_context_id, | 152 void* browser_context_id, |
| 152 const std::string& extension_id, | 153 const GURL& url, |
| 153 const std::string& event_name, | 154 const std::string& extension_id, |
| 154 scoped_ptr<ListValue> event_args, | 155 events::HistogramValue histogram_value, |
| 155 UserGestureState user_gesture, | 156 const std::string& event_name, |
| 156 const EventFilteringInfo& info) { | 157 scoped_ptr<ListValue> event_args, |
| 158 UserGestureState user_gesture, | |
| 159 const EventFilteringInfo& info) { | |
| 157 int event_id = g_extension_event_id.GetNext(); | 160 int event_id = g_extension_event_id.GetNext(); |
| 158 | 161 |
| 159 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 162 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 163 DoDispatchEventToSenderBookkeepingOnUI(browser_context_id, extension_id, | |
| 164 url, event_id, histogram_value, | |
| 165 event_name); | |
| 166 } else { | |
| 160 // This is called from WebRequest API. | 167 // This is called from WebRequest API. |
| 161 // TODO(lazyboy): Skip this entirely: http://crbug.com/488747. | 168 // TODO(lazyboy): Skip this entirely: http://crbug.com/488747. |
| 162 BrowserThread::PostTask( | 169 BrowserThread::PostTask( |
| 163 BrowserThread::UI, FROM_HERE, | 170 BrowserThread::UI, FROM_HERE, |
| 164 base::Bind(&EventRouter::IncrementInFlightEventsOnUI, | 171 base::Bind(&EventRouter::DoDispatchEventToSenderBookkeepingOnUI, |
| 165 browser_context_id, extension_id, event_id, event_name)); | 172 browser_context_id, extension_id, url, event_id, |
| 166 } else { | 173 histogram_value, event_name)); |
| 167 IncrementInFlightEventsOnUI(browser_context_id, extension_id, event_id, | |
| 168 event_name); | |
| 169 } | 174 } |
| 170 | 175 |
| 171 DispatchExtensionMessage(ipc_sender, browser_context_id, extension_id, | 176 DispatchExtensionMessage(ipc_sender, browser_context_id, extension_id, |
| 172 event_id, event_name, event_args.get(), user_gesture, | 177 event_id, event_name, event_args.get(), user_gesture, |
| 173 info); | 178 info); |
| 174 } | 179 } |
| 175 | 180 |
| 176 EventRouter::EventRouter(BrowserContext* browser_context, | 181 EventRouter::EventRouter(BrowserContext* browser_context, |
| 177 ExtensionPrefs* extension_prefs) | 182 ExtensionPrefs* extension_prefs) |
| 178 : browser_context_(browser_context), | 183 : browser_context_(browser_context), |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 493 listeners_.GetEventListeners(*event)); | 498 listeners_.GetEventListeners(*event)); |
| 494 | 499 |
| 495 std::set<EventDispatchIdentifier> already_dispatched; | 500 std::set<EventDispatchIdentifier> already_dispatched; |
| 496 | 501 |
| 497 // We dispatch events for lazy background pages first because attempting to do | 502 // We dispatch events for lazy background pages first because attempting to do |
| 498 // so will cause those that are being suspended to cancel that suspension. | 503 // so will cause those that are being suspended to cancel that suspension. |
| 499 // As canceling a suspension entails sending an event to the affected | 504 // As canceling a suspension entails sending an event to the affected |
| 500 // background page, and as that event needs to be delivered before we dispatch | 505 // background page, and as that event needs to be delivered before we dispatch |
| 501 // the event we are dispatching here, we dispatch to the lazy listeners here | 506 // the event we are dispatching here, we dispatch to the lazy listeners here |
| 502 // first. | 507 // first. |
| 503 for (std::set<const EventListener*>::iterator it = listeners.begin(); | 508 for (const EventListener* listener : listeners) { |
| 504 it != listeners.end(); it++) { | |
| 505 const EventListener* listener = *it; | |
| 506 if (restrict_to_extension_id.empty() || | 509 if (restrict_to_extension_id.empty() || |
| 507 restrict_to_extension_id == listener->extension_id()) { | 510 restrict_to_extension_id == listener->extension_id()) { |
| 508 if (listener->IsLazy()) { | 511 if (listener->IsLazy()) { |
| 509 DispatchLazyEvent(listener->extension_id(), event, &already_dispatched, | 512 DispatchLazyEvent(listener->extension_id(), event, &already_dispatched, |
| 510 listener->filter()); | 513 listener->filter()); |
| 511 } | 514 } |
| 512 } | 515 } |
| 513 } | 516 } |
| 514 | 517 |
| 515 for (std::set<const EventListener*>::iterator it = listeners.begin(); | 518 for (const EventListener* listener : listeners) { |
| 516 it != listeners.end(); it++) { | |
| 517 const EventListener* listener = *it; | |
| 518 if (restrict_to_extension_id.empty() || | 519 if (restrict_to_extension_id.empty() || |
| 519 restrict_to_extension_id == listener->extension_id()) { | 520 restrict_to_extension_id == listener->extension_id()) { |
| 520 if (listener->process()) { | 521 if (listener->process()) { |
| 521 EventDispatchIdentifier dispatch_id(listener->GetBrowserContext(), | 522 EventDispatchIdentifier dispatch_id(listener->GetBrowserContext(), |
| 522 listener->extension_id()); | 523 listener->extension_id()); |
| 523 if (!ContainsKey(already_dispatched, dispatch_id)) { | 524 if (!ContainsKey(already_dispatched, dispatch_id)) { |
| 524 DispatchEventToProcess(listener->extension_id(), | 525 DispatchEventToProcess(listener->extension_id(), |
| 525 listener->listener_url(), listener->process(), | 526 listener->listener_url(), listener->process(), |
| 526 event, listener->filter()); | 527 event, listener->filter(), |
| 528 false /* did_enqueue */); | |
| 527 } | 529 } |
| 528 } | 530 } |
| 529 } | 531 } |
| 530 } | 532 } |
| 531 } | 533 } |
| 532 | 534 |
| 533 void EventRouter::DispatchLazyEvent( | 535 void EventRouter::DispatchLazyEvent( |
| 534 const std::string& extension_id, | 536 const std::string& extension_id, |
| 535 const linked_ptr<Event>& event, | 537 const linked_ptr<Event>& event, |
| 536 std::set<EventDispatchIdentifier>* already_dispatched, | 538 std::set<EventDispatchIdentifier>* already_dispatched, |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 560 std::make_pair(incognito_context, extension_id)); | 562 std::make_pair(incognito_context, extension_id)); |
| 561 } | 563 } |
| 562 } | 564 } |
| 563 } | 565 } |
| 564 | 566 |
| 565 void EventRouter::DispatchEventToProcess( | 567 void EventRouter::DispatchEventToProcess( |
| 566 const std::string& extension_id, | 568 const std::string& extension_id, |
| 567 const GURL& listener_url, | 569 const GURL& listener_url, |
| 568 content::RenderProcessHost* process, | 570 content::RenderProcessHost* process, |
| 569 const linked_ptr<Event>& event, | 571 const linked_ptr<Event>& event, |
| 570 const base::DictionaryValue* listener_filter) { | 572 const base::DictionaryValue* listener_filter, |
| 573 bool did_enqueue) { | |
| 571 BrowserContext* listener_context = process->GetBrowserContext(); | 574 BrowserContext* listener_context = process->GetBrowserContext(); |
| 572 ProcessMap* process_map = ProcessMap::Get(listener_context); | 575 ProcessMap* process_map = ProcessMap::Get(listener_context); |
| 573 | 576 |
| 574 // NOTE: |extension| being NULL does not necessarily imply that this event | 577 // NOTE: |extension| being NULL does not necessarily imply that this event |
| 575 // shouldn't be dispatched. Events can be dispatched to WebUI and webviews as | 578 // shouldn't be dispatched. Events can be dispatched to WebUI and webviews as |
| 576 // well. It all depends on what GetMostLikelyContextType returns. | 579 // well. It all depends on what GetMostLikelyContextType returns. |
| 577 const Extension* extension = | 580 const Extension* extension = |
| 578 ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID( | 581 ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID( |
| 579 extension_id); | 582 extension_id); |
| 580 | 583 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 630 listener_filter)) { | 633 listener_filter)) { |
| 631 return; | 634 return; |
| 632 } | 635 } |
| 633 | 636 |
| 634 int event_id = g_extension_event_id.GetNext(); | 637 int event_id = g_extension_event_id.GetNext(); |
| 635 DispatchExtensionMessage(process, listener_context, extension_id, event_id, | 638 DispatchExtensionMessage(process, listener_context, extension_id, event_id, |
| 636 event->event_name, event->event_args.get(), | 639 event->event_name, event->event_args.get(), |
| 637 event->user_gesture, event->filter_info); | 640 event->user_gesture, event->filter_info); |
| 638 | 641 |
| 639 if (extension) { | 642 if (extension) { |
| 643 ReportEvent(event->histogram_value, extension, did_enqueue); | |
| 640 IncrementInFlightEvents(listener_context, extension, event_id, | 644 IncrementInFlightEvents(listener_context, extension, event_id, |
| 641 event->event_name); | 645 event->event_name); |
| 642 } | 646 } |
| 643 } | 647 } |
| 644 | 648 |
| 645 bool EventRouter::CanDispatchEventToBrowserContext( | 649 bool EventRouter::CanDispatchEventToBrowserContext( |
| 646 BrowserContext* context, | 650 BrowserContext* context, |
| 647 const Extension* extension, | 651 const Extension* extension, |
| 648 const linked_ptr<Event>& event) { | 652 const linked_ptr<Event>& event) { |
| 649 // Is this event from a different browser context than the renderer (ie, an | 653 // Is this event from a different browser context than the renderer (ie, an |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 686 queue->AddPendingTask(context, extension->id(), | 690 queue->AddPendingTask(context, extension->id(), |
| 687 base::Bind(&EventRouter::DispatchPendingEvent, | 691 base::Bind(&EventRouter::DispatchPendingEvent, |
| 688 base::Unretained(this), dispatched_event)); | 692 base::Unretained(this), dispatched_event)); |
| 689 return true; | 693 return true; |
| 690 } | 694 } |
| 691 | 695 |
| 692 return false; | 696 return false; |
| 693 } | 697 } |
| 694 | 698 |
| 695 // static | 699 // static |
| 696 void EventRouter::IncrementInFlightEventsOnUI(void* browser_context_id, | 700 void EventRouter::DoDispatchEventToSenderBookkeepingOnUI( |
| 697 const std::string& extension_id, | 701 void* browser_context_id, |
| 698 int event_id, | 702 const std::string& extension_id, |
| 699 const std::string& event_name) { | 703 const GURL& url, |
| 704 int event_id, | |
| 705 events::HistogramValue histogram_value, | |
| 706 const std::string& event_name) { | |
| 700 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 707 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 701 BrowserContext* browser_context = | 708 BrowserContext* browser_context = |
| 702 reinterpret_cast<BrowserContext*>(browser_context_id); | 709 reinterpret_cast<BrowserContext*>(browser_context_id); |
| 703 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context)) | 710 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context)) |
| 704 return; | 711 return; |
| 705 EventRouter* event_router = EventRouter::Get(browser_context); | |
| 706 if (!event_router) | |
| 707 return; | |
| 708 const Extension* extension = | 712 const Extension* extension = |
| 709 ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID( | 713 ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID( |
| 710 extension_id); | 714 extension_id); |
| 711 if (!extension) | 715 if (!extension) |
| 712 return; | 716 return; |
| 717 EventRouter* event_router = EventRouter::Get(browser_context); | |
| 713 event_router->IncrementInFlightEvents(browser_context, extension, event_id, | 718 event_router->IncrementInFlightEvents(browser_context, extension, event_id, |
| 714 event_name); | 719 event_name); |
| 720 event_router->ReportEvent(histogram_value, extension, | |
| 721 false /* did_enqueue */); | |
| 715 } | 722 } |
| 716 | 723 |
| 717 void EventRouter::IncrementInFlightEvents(BrowserContext* context, | 724 void EventRouter::IncrementInFlightEvents(BrowserContext* context, |
| 718 const Extension* extension, | 725 const Extension* extension, |
| 719 int event_id, | 726 int event_id, |
| 720 const std::string& event_name) { | 727 const std::string& event_name) { |
| 721 // TODO(chirantan): Turn this on once crbug.com/464513 is fixed. | 728 // TODO(chirantan): Turn this on once crbug.com/464513 is fixed. |
| 722 // DCHECK_CURRENTLY_ON(BrowserThread::UI); | 729 // DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 723 | 730 |
| 724 // Only increment in-flight events if the lazy background page is active, | 731 // Only increment in-flight events if the lazy background page is active, |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 740 // The event ACK is routed to the background host, so this should never be | 747 // The event ACK is routed to the background host, so this should never be |
| 741 // NULL. | 748 // NULL. |
| 742 CHECK(host); | 749 CHECK(host); |
| 743 // TODO(mpcomplete): We should never get this message unless | 750 // TODO(mpcomplete): We should never get this message unless |
| 744 // HasLazyBackgroundPage is true. Find out why we're getting it anyway. | 751 // HasLazyBackgroundPage is true. Find out why we're getting it anyway. |
| 745 if (host->extension() && | 752 if (host->extension() && |
| 746 BackgroundInfo::HasLazyBackgroundPage(host->extension())) | 753 BackgroundInfo::HasLazyBackgroundPage(host->extension())) |
| 747 pm->DecrementLazyKeepaliveCount(host->extension()); | 754 pm->DecrementLazyKeepaliveCount(host->extension()); |
| 748 } | 755 } |
| 749 | 756 |
| 757 void EventRouter::ReportEvent(events::HistogramValue histogram_value, | |
| 758 const Extension* extension, | |
| 759 bool did_enqueue) { | |
| 760 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 761 | |
| 762 // TODO(kalman): UMA for dispatched event. | |
| 763 // TODO(kalman): UMA specifically for component extensions. | |
| 764 | |
| 765 // Note: for these, all we know is that the extension *has* a persistent or | |
| 766 // event page, not that the event is being dispatched *to* such a page. | |
|
not at google - send to devlin
2015/08/07 20:55:03
This is new as well, I had forgotten that for even
| |
| 767 // | |
| 768 // However, this is an academic distinction, since extensions with any | |
| 769 // background page have that background page running (or in the case of | |
| 770 // dormant event pages, must be started) regardless of where the event is | |
| 771 // being dispatched. Events are dispatched to a *process* not a *frame*. | |
| 772 if (BackgroundInfo::HasPersistentBackgroundPage(extension)) { | |
| 773 // TODO(kalman): UMA for dispatched event to an extension with a persistent | |
| 774 // background page. | |
| 775 } else if (BackgroundInfo::HasLazyBackgroundPage(extension)) { | |
| 776 if (did_enqueue) { | |
| 777 // TODO(kalman): UMA for dispatched event to an extension with an event | |
| 778 // page, and the event page was woken up to do so. | |
| 779 } else { | |
| 780 // TODO(kalman): UMA for dispatched event to an extension with an event | |
| 781 // page that was already running. | |
| 782 } | |
| 783 } | |
| 784 } | |
| 785 | |
| 750 void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event, | 786 void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event, |
| 751 ExtensionHost* host) { | 787 ExtensionHost* host) { |
| 752 if (!host) | 788 if (!host) |
| 753 return; | 789 return; |
| 754 | 790 |
| 755 if (listeners_.HasProcessListener(host->render_process_host(), | 791 if (listeners_.HasProcessListener(host->render_process_host(), |
| 756 host->extension()->id())) { | 792 host->extension()->id())) { |
| 757 // URL events cannot be lazy therefore can't be pending, hence the GURL(). | 793 DispatchEventToProcess(host->extension()->id(), host->GetURL(), |
| 758 DispatchEventToProcess(host->extension()->id(), GURL(), | 794 host->render_process_host(), event, nullptr, |
| 759 host->render_process_host(), event, nullptr); | 795 true /* did_enqueue */); |
| 760 } | 796 } |
| 761 } | 797 } |
| 762 | 798 |
| 763 void EventRouter::Observe(int type, | 799 void EventRouter::Observe(int type, |
| 764 const content::NotificationSource& source, | 800 const content::NotificationSource& source, |
| 765 const content::NotificationDetails& details) { | 801 const content::NotificationDetails& details) { |
| 766 switch (type) { | 802 switch (type) { |
| 767 case extensions::NOTIFICATION_EXTENSION_ENABLED: { | 803 case extensions::NOTIFICATION_EXTENSION_ENABLED: { |
| 768 // If the extension has a lazy background page, make sure it gets loaded | 804 // If the extension has a lazy background page, make sure it gets loaded |
| 769 // to register the events the extension is interested in. | 805 // to register the events the extension is interested in. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 855 const std::string& extension_id, | 891 const std::string& extension_id, |
| 856 const GURL& listener_url, | 892 const GURL& listener_url, |
| 857 content::BrowserContext* browser_context) | 893 content::BrowserContext* browser_context) |
| 858 : event_name(event_name), | 894 : event_name(event_name), |
| 859 extension_id(extension_id), | 895 extension_id(extension_id), |
| 860 listener_url(listener_url), | 896 listener_url(listener_url), |
| 861 browser_context(browser_context) { | 897 browser_context(browser_context) { |
| 862 } | 898 } |
| 863 | 899 |
| 864 } // namespace extensions | 900 } // namespace extensions |
| OLD | NEW |