OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/process_manager.h" | 5 #include "extensions/browser/process_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 15 matching lines...) Expand all Loading... |
26 #include "content/public/browser/web_contents.h" | 26 #include "content/public/browser/web_contents.h" |
27 #include "content/public/browser/web_contents_delegate.h" | 27 #include "content/public/browser/web_contents_delegate.h" |
28 #include "content/public/browser/web_contents_observer.h" | 28 #include "content/public/browser/web_contents_observer.h" |
29 #include "content/public/browser/web_contents_user_data.h" | 29 #include "content/public/browser/web_contents_user_data.h" |
30 #include "content/public/common/renderer_preferences.h" | 30 #include "content/public/common/renderer_preferences.h" |
31 #include "content/public/common/url_constants.h" | 31 #include "content/public/common/url_constants.h" |
32 #include "extensions/browser/extension_host.h" | 32 #include "extensions/browser/extension_host.h" |
33 #include "extensions/browser/extension_registry.h" | 33 #include "extensions/browser/extension_registry.h" |
34 #include "extensions/browser/extension_system.h" | 34 #include "extensions/browser/extension_system.h" |
35 #include "extensions/browser/extensions_browser_client.h" | 35 #include "extensions/browser/extensions_browser_client.h" |
| 36 #include "extensions/browser/process_manager_delegate.h" |
36 #include "extensions/browser/process_manager_observer.h" | 37 #include "extensions/browser/process_manager_observer.h" |
37 #include "extensions/browser/view_type_utils.h" | 38 #include "extensions/browser/view_type_utils.h" |
38 #include "extensions/common/constants.h" | 39 #include "extensions/common/constants.h" |
39 #include "extensions/common/extension.h" | 40 #include "extensions/common/extension.h" |
40 #include "extensions/common/extension_messages.h" | 41 #include "extensions/common/extension_messages.h" |
41 #include "extensions/common/manifest_handlers/background_info.h" | 42 #include "extensions/common/manifest_handlers/background_info.h" |
42 #include "extensions/common/manifest_handlers/incognito_info.h" | 43 #include "extensions/common/manifest_handlers/incognito_info.h" |
43 #include "extensions/common/one_shot_event.h" | 44 #include "extensions/common/one_shot_event.h" |
44 #include "extensions/common/switches.h" | 45 #include "extensions/common/switches.h" |
45 | 46 |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, | 239 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, |
239 content::Source<BrowserContext>(original_context)); | 240 content::Source<BrowserContext>(original_context)); |
240 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, | 241 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, |
241 content::Source<BrowserContext>(context)); | 242 content::Source<BrowserContext>(context)); |
242 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, | 243 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
243 content::Source<BrowserContext>(context)); | 244 content::Source<BrowserContext>(context)); |
244 registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, | 245 registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, |
245 content::NotificationService::AllSources()); | 246 content::NotificationService::AllSources()); |
246 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED, | 247 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED, |
247 content::NotificationService::AllSources()); | 248 content::NotificationService::AllSources()); |
248 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, | |
249 content::Source<BrowserContext>(original_context)); | |
250 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 249 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
251 content::Source<BrowserContext>(context)); | 250 content::Source<BrowserContext>(context)); |
252 if (context->IsOffTheRecord()) { | 251 if (context->IsOffTheRecord()) { |
253 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 252 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
254 content::Source<BrowserContext>(original_context)); | 253 content::Source<BrowserContext>(original_context)); |
255 } | 254 } |
256 | 255 |
257 // Note: event_page_idle_time_ must be sufficiently larger (e.g. 2x) than | 256 // Note: event_page_idle_time_ must be sufficiently larger (e.g. 2x) than |
258 // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals. | 257 // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals. |
259 event_page_idle_time_ = base::TimeDelta::FromSeconds(10); | 258 event_page_idle_time_ = base::TimeDelta::FromSeconds(10); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 } | 299 } |
301 | 300 |
302 void ProcessManager::RemoveObserver(ProcessManagerObserver* observer) { | 301 void ProcessManager::RemoveObserver(ProcessManagerObserver* observer) { |
303 observer_list_.RemoveObserver(observer); | 302 observer_list_.RemoveObserver(observer); |
304 } | 303 } |
305 | 304 |
306 bool ProcessManager::CreateBackgroundHost(const Extension* extension, | 305 bool ProcessManager::CreateBackgroundHost(const Extension* extension, |
307 const GURL& url) { | 306 const GURL& url) { |
308 // Hosted apps are taken care of from BackgroundContentsService. Ignore them | 307 // Hosted apps are taken care of from BackgroundContentsService. Ignore them |
309 // here. | 308 // here. |
310 if (extension->is_hosted_app() || | 309 if (extension->is_hosted_app()) |
311 !ExtensionsBrowserClient::Get()-> | |
312 IsBackgroundPageAllowed(GetBrowserContext())) { | |
313 return false; | 310 return false; |
314 } | 311 |
| 312 // Don't create hosts if the embedder doesn't allow it. |
| 313 ProcessManagerDelegate* delegate = |
| 314 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate(); |
| 315 if (delegate && !delegate->IsBackgroundPageAllowed(GetBrowserContext())) |
| 316 return false; |
315 | 317 |
316 // Don't create multiple background hosts for an extension. | 318 // Don't create multiple background hosts for an extension. |
317 if (GetBackgroundHostForExtension(extension->id())) | 319 if (GetBackgroundHostForExtension(extension->id())) |
318 return true; // TODO(kalman): return false here? It might break things... | 320 return true; // TODO(kalman): return false here? It might break things... |
319 | 321 |
320 ExtensionHost* host = | 322 ExtensionHost* host = |
321 new ExtensionHost(extension, GetSiteInstanceForURL(url), url, | 323 new ExtensionHost(extension, GetSiteInstanceForURL(url), url, |
322 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); | 324 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); |
323 host->CreateRenderViewSoon(); | 325 host->CreateRenderViewSoon(); |
324 OnBackgroundHostCreated(host); | 326 OnBackgroundHostCreated(host); |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
613 new ExtensionMsg_CancelSuspend(extension->id())); | 615 new ExtensionMsg_CancelSuspend(extension->id())); |
614 // This increment / decrement is to simulate an instantaneous event. This | 616 // This increment / decrement is to simulate an instantaneous event. This |
615 // has the effect of invalidating close_sequence_id, preventing any in | 617 // has the effect of invalidating close_sequence_id, preventing any in |
616 // progress closes from completing and starting a new close process if | 618 // progress closes from completing and starting a new close process if |
617 // necessary. | 619 // necessary. |
618 IncrementLazyKeepaliveCount(extension); | 620 IncrementLazyKeepaliveCount(extension); |
619 DecrementLazyKeepaliveCount(extension); | 621 DecrementLazyKeepaliveCount(extension); |
620 } | 622 } |
621 } | 623 } |
622 | 624 |
623 void ProcessManager::OnBrowserWindowReady() { | |
624 // If the extension system isn't ready yet the background hosts will be | |
625 // created via NOTIFICATION_EXTENSIONS_READY below. | |
626 ExtensionSystem* system = ExtensionSystem::Get(GetBrowserContext()); | |
627 if (!system->ready().is_signaled()) | |
628 return; | |
629 | |
630 CreateBackgroundHostsForProfileStartup(); | |
631 } | |
632 | |
633 content::BrowserContext* ProcessManager::GetBrowserContext() const { | 625 content::BrowserContext* ProcessManager::GetBrowserContext() const { |
634 return site_instance_->GetBrowserContext(); | 626 return site_instance_->GetBrowserContext(); |
635 } | 627 } |
636 | 628 |
637 void ProcessManager::SetKeepaliveImpulseCallbackForTesting( | 629 void ProcessManager::SetKeepaliveImpulseCallbackForTesting( |
638 const ImpulseCallbackForTesting& callback) { | 630 const ImpulseCallbackForTesting& callback) { |
639 keepalive_impulse_callback_for_testing_ = callback; | 631 keepalive_impulse_callback_for_testing_ = callback; |
640 } | 632 } |
641 | 633 |
642 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting( | 634 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting( |
643 const ImpulseCallbackForTesting& callback) { | 635 const ImpulseCallbackForTesting& callback) { |
644 keepalive_impulse_decrement_callback_for_testing_ = callback; | 636 keepalive_impulse_decrement_callback_for_testing_ = callback; |
645 } | 637 } |
646 | 638 |
647 void ProcessManager::Observe(int type, | 639 void ProcessManager::Observe(int type, |
648 const content::NotificationSource& source, | 640 const content::NotificationSource& source, |
649 const content::NotificationDetails& details) { | 641 const content::NotificationDetails& details) { |
650 switch (type) { | 642 switch (type) { |
651 case chrome::NOTIFICATION_EXTENSIONS_READY: | 643 case chrome::NOTIFICATION_EXTENSIONS_READY: { |
652 case chrome::NOTIFICATION_PROFILE_CREATED: { | 644 // TODO(jamescook): Convert this to use ExtensionSystem::ready() instead |
653 // Don't load background hosts now if the loading should be deferred. | 645 // of a notification. |
654 // Instead they will be loaded when a browser window for this profile | 646 MaybeCreateStartupBackgroundHosts(); |
655 // (or an incognito profile from this profile) is ready. | |
656 if (DeferLoadingBackgroundHosts()) | |
657 break; | |
658 | |
659 CreateBackgroundHostsForProfileStartup(); | |
660 break; | 647 break; |
661 } | 648 } |
662 | 649 |
663 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: { | 650 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: { |
664 BrowserContext* context = content::Source<BrowserContext>(source).ptr(); | 651 BrowserContext* context = content::Source<BrowserContext>(source).ptr(); |
665 ExtensionSystem* system = ExtensionSystem::Get(context); | 652 ExtensionSystem* system = ExtensionSystem::Get(context); |
666 if (system->ready().is_signaled()) { | 653 if (system->ready().is_signaled()) { |
667 // The extension system is ready, so create the background host. | 654 // The extension system is ready, so create the background host. |
668 const Extension* extension = | 655 const Extension* extension = |
669 content::Details<const Extension>(details).ptr(); | 656 content::Details<const Extension>(details).ptr(); |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 return; | 764 return; |
778 if (attached) { | 765 if (attached) { |
779 // Keep the lazy background page alive while it's being inspected. | 766 // Keep the lazy background page alive while it's being inspected. |
780 CancelSuspend(extension); | 767 CancelSuspend(extension); |
781 IncrementLazyKeepaliveCount(extension); | 768 IncrementLazyKeepaliveCount(extension); |
782 } else { | 769 } else { |
783 DecrementLazyKeepaliveCount(extension); | 770 DecrementLazyKeepaliveCount(extension); |
784 } | 771 } |
785 } | 772 } |
786 | 773 |
787 void ProcessManager::CreateBackgroundHostsForProfileStartup() { | 774 void ProcessManager::MaybeCreateStartupBackgroundHosts() { |
788 if (startup_background_hosts_created_ || | 775 if (startup_background_hosts_created_) |
789 !ExtensionsBrowserClient::Get()-> | |
790 IsBackgroundPageAllowed(GetBrowserContext())) { | |
791 return; | 776 return; |
792 } | |
793 | 777 |
794 const ExtensionSet& enabled_extensions = | 778 // The embedder might disallow background pages entirely. |
795 ExtensionRegistry::Get(GetBrowserContext())->enabled_extensions(); | 779 ProcessManagerDelegate* delegate = |
796 for (ExtensionSet::const_iterator extension = enabled_extensions.begin(); | 780 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate(); |
797 extension != enabled_extensions.end(); | 781 if (delegate && !delegate->IsBackgroundPageAllowed(GetBrowserContext())) |
798 ++extension) { | 782 return; |
799 CreateBackgroundHostForExtensionLoad(this, extension->get()); | |
800 | 783 |
801 FOR_EACH_OBSERVER(ProcessManagerObserver, | 784 // The embedder might want to defer background page loading. For example, |
802 observer_list_, | 785 // Chrome defers background page loading when it is launched to show the app |
803 OnBackgroundHostStartup(*extension)); | 786 // list, then triggers a load later when a browser window opens. |
804 } | 787 if (delegate && |
| 788 delegate->DeferCreatingStartupBackgroundHosts(GetBrowserContext())) |
| 789 return; |
| 790 |
| 791 CreateStartupBackgroundHosts(); |
805 startup_background_hosts_created_ = true; | 792 startup_background_hosts_created_ = true; |
806 | 793 |
807 // Background pages should only be loaded once. To prevent any further loads | 794 // Background pages should only be loaded once. To prevent any further loads |
808 // occurring, we remove the notification listeners. | 795 // occurring, we remove the notification listeners. |
809 BrowserContext* original_context = | 796 BrowserContext* original_context = |
810 ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext()); | 797 ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext()); |
811 if (registrar_.IsRegistered( | 798 if (registrar_.IsRegistered( |
812 this, | 799 this, |
813 chrome::NOTIFICATION_PROFILE_CREATED, | |
814 content::Source<BrowserContext>(original_context))) { | |
815 registrar_.Remove(this, | |
816 chrome::NOTIFICATION_PROFILE_CREATED, | |
817 content::Source<BrowserContext>(original_context)); | |
818 } | |
819 if (registrar_.IsRegistered( | |
820 this, | |
821 chrome::NOTIFICATION_EXTENSIONS_READY, | 800 chrome::NOTIFICATION_EXTENSIONS_READY, |
822 content::Source<BrowserContext>(original_context))) { | 801 content::Source<BrowserContext>(original_context))) { |
823 registrar_.Remove(this, | 802 registrar_.Remove(this, |
824 chrome::NOTIFICATION_EXTENSIONS_READY, | 803 chrome::NOTIFICATION_EXTENSIONS_READY, |
825 content::Source<BrowserContext>(original_context)); | 804 content::Source<BrowserContext>(original_context)); |
826 } | 805 } |
827 } | 806 } |
828 | 807 |
| 808 void ProcessManager::CreateStartupBackgroundHosts() { |
| 809 DCHECK(!startup_background_hosts_created_); |
| 810 const ExtensionSet& enabled_extensions = |
| 811 ExtensionRegistry::Get(GetBrowserContext())->enabled_extensions(); |
| 812 for (ExtensionSet::const_iterator extension = enabled_extensions.begin(); |
| 813 extension != enabled_extensions.end(); |
| 814 ++extension) { |
| 815 CreateBackgroundHostForExtensionLoad(this, extension->get()); |
| 816 |
| 817 FOR_EACH_OBSERVER(ProcessManagerObserver, |
| 818 observer_list_, |
| 819 OnBackgroundHostStartup(*extension)); |
| 820 } |
| 821 } |
| 822 |
829 void ProcessManager::OnBackgroundHostCreated(ExtensionHost* host) { | 823 void ProcessManager::OnBackgroundHostCreated(ExtensionHost* host) { |
830 DCHECK_EQ(GetBrowserContext(), host->browser_context()); | 824 DCHECK_EQ(GetBrowserContext(), host->browser_context()); |
831 background_hosts_.insert(host); | 825 background_hosts_.insert(host); |
832 | 826 |
833 if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) { | 827 if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) { |
834 linked_ptr<base::ElapsedTimer> since_suspended( | 828 linked_ptr<base::ElapsedTimer> since_suspended( |
835 background_page_data_[host->extension()->id()]. | 829 background_page_data_[host->extension()->id()]. |
836 since_suspended.release()); | 830 since_suspended.release()); |
837 if (since_suspended.get()) { | 831 if (since_suspended.get()) { |
838 UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime", | 832 UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime", |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
883 // Re-register all RenderViews for this extension. We do this to restore | 877 // Re-register all RenderViews for this extension. We do this to restore |
884 // the lazy_keepalive_count (if any) to properly reflect the number of open | 878 // the lazy_keepalive_count (if any) to properly reflect the number of open |
885 // views. | 879 // views. |
886 for (ExtensionRenderViews::const_iterator it = all_extension_views_.begin(); | 880 for (ExtensionRenderViews::const_iterator it = all_extension_views_.begin(); |
887 it != all_extension_views_.end(); ++it) { | 881 it != all_extension_views_.end(); ++it) { |
888 if (GetExtensionID(it->first) == extension_id) | 882 if (GetExtensionID(it->first) == extension_id) |
889 IncrementLazyKeepaliveCountForView(it->first); | 883 IncrementLazyKeepaliveCountForView(it->first); |
890 } | 884 } |
891 } | 885 } |
892 | 886 |
893 bool ProcessManager::DeferLoadingBackgroundHosts() const { | |
894 // The extensions embedder may have special rules about background hosts. | |
895 return ExtensionsBrowserClient::Get()->DeferLoadingBackgroundHosts( | |
896 GetBrowserContext()); | |
897 } | |
898 | |
899 // | 887 // |
900 // IncognitoProcessManager | 888 // IncognitoProcessManager |
901 // | 889 // |
902 | 890 |
903 IncognitoProcessManager::IncognitoProcessManager( | 891 IncognitoProcessManager::IncognitoProcessManager( |
904 BrowserContext* incognito_context, | 892 BrowserContext* incognito_context, |
905 BrowserContext* original_context, | 893 BrowserContext* original_context, |
906 ProcessManager* original_manager) | 894 ProcessManager* original_manager) |
907 : ProcessManager(incognito_context, original_context), | 895 : ProcessManager(incognito_context, original_context), |
908 original_manager_(original_manager) { | 896 original_manager_(original_manager) { |
909 DCHECK(incognito_context->IsOffTheRecord()); | 897 DCHECK(incognito_context->IsOffTheRecord()); |
910 | 898 |
911 // The original profile will have its own ProcessManager to | 899 // The original profile will have its own ProcessManager to |
912 // load the background pages of the spanning extensions. This process | 900 // load the background pages of the spanning extensions. This process |
913 // manager need only worry about the split mode extensions, which is handled | 901 // manager need only worry about the split mode extensions, which is handled |
914 // in the NOTIFICATION_BROWSER_WINDOW_READY notification handler. | 902 // in the NOTIFICATION_BROWSER_WINDOW_READY notification handler. |
915 registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY, | 903 registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY, |
916 content::Source<BrowserContext>(original_context)); | 904 content::Source<BrowserContext>(original_context)); |
917 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_CREATED, | |
918 content::Source<BrowserContext>(original_context)); | |
919 } | 905 } |
920 | 906 |
921 bool IncognitoProcessManager::CreateBackgroundHost(const Extension* extension, | 907 bool IncognitoProcessManager::CreateBackgroundHost(const Extension* extension, |
922 const GURL& url) { | 908 const GURL& url) { |
923 if (IncognitoInfo::IsSplitMode(extension)) { | 909 if (IncognitoInfo::IsSplitMode(extension)) { |
924 if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled( | 910 if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled( |
925 extension->id(), GetBrowserContext())) | 911 extension->id(), GetBrowserContext())) |
926 return ProcessManager::CreateBackgroundHost(extension, url); | 912 return ProcessManager::CreateBackgroundHost(extension, url); |
927 } else { | 913 } else { |
928 // Do nothing. If an extension is spanning, then its original-profile | 914 // Do nothing. If an extension is spanning, then its original-profile |
929 // background page is shared with incognito, so we don't create another. | 915 // background page is shared with incognito, so we don't create another. |
930 } | 916 } |
931 return false; | 917 return false; |
932 } | 918 } |
933 | 919 |
934 SiteInstance* IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) { | 920 SiteInstance* IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) { |
935 ExtensionRegistry* registry = ExtensionRegistry::Get(GetBrowserContext()); | 921 ExtensionRegistry* registry = ExtensionRegistry::Get(GetBrowserContext()); |
936 if (registry) { | 922 if (registry) { |
937 const Extension* extension = | 923 const Extension* extension = |
938 registry->enabled_extensions().GetExtensionOrAppByURL(url); | 924 registry->enabled_extensions().GetExtensionOrAppByURL(url); |
939 if (extension && !IncognitoInfo::IsSplitMode(extension)) { | 925 if (extension && !IncognitoInfo::IsSplitMode(extension)) { |
940 return original_manager_->GetSiteInstanceForURL(url); | 926 return original_manager_->GetSiteInstanceForURL(url); |
941 } | 927 } |
942 } | 928 } |
943 return ProcessManager::GetSiteInstanceForURL(url); | 929 return ProcessManager::GetSiteInstanceForURL(url); |
944 } | 930 } |
945 | 931 |
946 } // namespace extensions | 932 } // namespace extensions |
OLD | NEW |