diff options
-rw-r--r-- | chrome/browser/cocoa/extension_view_mac.mm | 2 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_host.cc | 78 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_host.h | 15 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_process_manager.cc | 2 | ||||
-rw-r--r-- | chrome/browser/gtk/extension_view_gtk.cc | 2 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_view.cc | 2 |
6 files changed, 92 insertions, 9 deletions
diff --git a/chrome/browser/cocoa/extension_view_mac.mm b/chrome/browser/cocoa/extension_view_mac.mm index c3ef722c..171cc30 100644 --- a/chrome/browser/cocoa/extension_view_mac.mm +++ b/chrome/browser/cocoa/extension_view_mac.mm @@ -75,5 +75,5 @@ void ExtensionViewMac::CreateWidgetHostView() { // disappear. [render_widget_host_view_->native_view() retain]; - extension_host_->CreateRenderView(render_widget_host_view_); + extension_host_->CreateRenderViewSoon(render_widget_host_view_); } diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 9fce7cd..c037e90 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -4,9 +4,13 @@ #include "chrome/browser/extensions/extension_host.h" +#include <list> + #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/keyboard_codes.h" +#include "base/message_loop.h" +#include "base/singleton.h" #include "base/string_util.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" @@ -49,6 +53,66 @@ bool ExtensionHost::enable_dom_automation_ = false; static const char* kToolstripTextColorSubstitution = "$TEXT_COLOR$"; +// Helper class that rate-limits the creation of renderer processes for +// ExtensionHosts, to avoid blocking the UI. +class ExtensionHost::ProcessCreationQueue { + public: + static ProcessCreationQueue* get() { + return Singleton<ProcessCreationQueue>::get(); + } + + // Add a host to the queue for RenderView creation. + void CreateSoon(ExtensionHost* host) { + queue_.push_back(host); + PostTask(); + } + + // Remove a host from the queue (in case it's being deleted). + void Remove(ExtensionHost* host) { + Queue::iterator it = std::find(queue_.begin(), queue_.end(), host); + if (it != queue_.end()) + queue_.erase(it); + } + + private: + friend class Singleton<ProcessCreationQueue>; + friend struct DefaultSingletonTraits<ProcessCreationQueue>; + ProcessCreationQueue() + : pending_create_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { } + + // Queue up a delayed task to process the next ExtensionHost in the queue. + void PostTask() { + if (!pending_create_) { + MessageLoop::current()->PostTask(FROM_HERE, + method_factory_.NewRunnableMethod( + &ProcessCreationQueue::ProcessOneHost)); + pending_create_ = true; + } + } + + // Create the RenderView for the next host in the queue. + void ProcessOneHost() { + pending_create_ = false; + if (queue_.empty()) + return; // can happen on shutdown + + queue_.front()->CreateRenderViewNow(); + queue_.pop_front(); + + if (!queue_.empty()) + PostTask(); + } + + typedef std::list<ExtensionHost*> Queue; + Queue queue_; + bool pending_create_; + ScopedRunnableMethodFactory<ProcessCreationQueue> method_factory_; +}; + +//////////////// +// ExtensionHost + ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance, const GURL& url, ViewType::Type host_type) : extension_(extension), @@ -73,6 +137,7 @@ ExtensionHost::~ExtensionHost() { NotificationType::EXTENSION_HOST_DESTROYED, Source<Profile>(profile_), Details<ExtensionHost>(this)); + ProcessCreationQueue::get()->Remove(this); render_view_host_->Shutdown(); // deletes render_view_host } @@ -106,9 +171,20 @@ bool ExtensionHost::IsRenderViewLive() const { return render_view_host_->IsRenderViewLive(); } -void ExtensionHost::CreateRenderView(RenderWidgetHostView* host_view) { +void ExtensionHost::CreateRenderViewSoon(RenderWidgetHostView* host_view) { LOG(INFO) << "Creating RenderView for " + extension_->name(); render_view_host_->set_view(host_view); + if (render_view_host_->process()->HasConnection()) { + // If the process is already started, go ahead and initialize the RenderView + // synchronously. The process creation is the real meaty part that we want + // to defer. + CreateRenderViewNow(); + } else { + ProcessCreationQueue::get()->CreateSoon(this); + } +} + +void ExtensionHost::CreateRenderViewNow() { render_view_host_->CreateRenderView(profile_->GetRequestContext()); NavigateToURL(url_); DCHECK(IsRenderViewLive()); diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index 552bc8c..9407b85 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -44,6 +44,8 @@ class ExtensionHost : public ExtensionPopupHost::PopupDelegate, public NotificationObserver, public JavaScriptMessageBoxClient { public: + class ProcessCreationQueue; + // Enable DOM automation in created render view hosts. static void EnableDOMAutomation() { enable_dom_automation_ = true; } @@ -82,10 +84,10 @@ class ExtensionHost : public ExtensionPopupHost::PopupDelegate, // Returns true if the render view is initialized and didn't crash. bool IsRenderViewLive() const; - // Initializes our RenderViewHost by creating its RenderView and navigating - // to this host's url. Uses host_view for the RenderViewHost's view (can be - // NULL). - void CreateRenderView(RenderWidgetHostView* host_view); + // Prepares to initializes our RenderViewHost by creating its RenderView and + // navigating to this host's url. Uses host_view for the RenderViewHost's view + // (can be NULL). This happens delayed to avoid locking the UI. + void CreateRenderViewSoon(RenderWidgetHostView* host_view); // Sets |url_| and navigates |render_view_host_|. void NavigateToURL(const GURL& url); @@ -156,10 +158,15 @@ class ExtensionHost : public ExtensionPopupHost::PopupDelegate, virtual TabContents* AsTabContents() { return NULL; } private: + friend class ProcessCreationQueue; + // Whether to allow DOM automation for created RenderViewHosts. This is used // for testing. static bool enable_dom_automation_; + // Actually create the RenderView for this host. See CreateRenderViewSoon. + void CreateRenderViewNow(); + // ExtensionFunctionDispatcher::Delegate // If this ExtensionHost has a view, this returns the Browser that view is a // part of. If this is a global background page, we use the active Browser diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc index 25a1fc2..02587a4 100644 --- a/chrome/browser/extensions/extension_process_manager.cc +++ b/chrome/browser/extensions/extension_process_manager.cc @@ -106,7 +106,7 @@ ExtensionHost* ExtensionProcessManager::CreateBackgroundHost( ExtensionHost* host = new ExtensionHost(extension, GetSiteInstanceForURL(url), url, ViewType::EXTENSION_BACKGROUND_PAGE); - host->CreateRenderView(NULL); // create a RenderViewHost with no view + host->CreateRenderViewSoon(NULL); // create a RenderViewHost with no view OnExtensionHostCreated(host, true); return host; } diff --git a/chrome/browser/gtk/extension_view_gtk.cc b/chrome/browser/gtk/extension_view_gtk.cc index 3bbac61..691ce54 100644 --- a/chrome/browser/gtk/extension_view_gtk.cc +++ b/chrome/browser/gtk/extension_view_gtk.cc @@ -49,7 +49,7 @@ void ExtensionViewGtk::CreateWidgetHostView() { render_widget_host_view_ = new RenderWidgetHostViewGtk(render_view_host()); render_widget_host_view_->InitAsChild(); - extension_host_->CreateRenderView(render_widget_host_view_); + extension_host_->CreateRenderViewSoon(render_widget_host_view_); } void ExtensionViewGtk::RenderViewCreated() { diff --git a/chrome/browser/views/extensions/extension_view.cc b/chrome/browser/views/extensions/extension_view.cc index b8bb0a6..7945307 100644 --- a/chrome/browser/views/extensions/extension_view.cc +++ b/chrome/browser/views/extensions/extension_view.cc @@ -108,7 +108,7 @@ void ExtensionView::CreateWidgetHostView() { NOTIMPLEMENTED(); #endif - host_->CreateRenderView(view); + host_->CreateRenderViewSoon(view); SetVisible(false); } |