diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 13:56:25 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 13:56:25 +0000 |
commit | 7c6877dea4bdbc7bd434ea9c96795529e466903c (patch) | |
tree | d7ac3fa32188710955166e416c6bd632759fcf10 | |
parent | 5b3986e89eca4e3045dde25635e270f6ea5d2961 (diff) | |
download | chromium_src-7c6877dea4bdbc7bd434ea9c96795529e466903c.zip chromium_src-7c6877dea4bdbc7bd434ea9c96795529e466903c.tar.gz chromium_src-7c6877dea4bdbc7bd434ea9c96795529e466903c.tar.bz2 |
Display an infobar alert when extension process crashes.
Also correctly handle crashes in task manager. The infobar allows user to restart the extension process.
TEST=Install buildbot extension, see its content in the shelf. Open task manager, kill extension process. Click "restart" in the infobar that should appear. The extension content in the shelf should re-appear after the crash.
http://crbug.com/14111
Review URL: http://codereview.chromium.org/126289
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18809 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/generated_resources.grd | 8 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_host.cc | 73 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_host.h | 8 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_process_manager.cc | 14 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_process_manager.h | 6 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_view.cc | 76 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_view.h | 11 | ||||
-rw-r--r-- | chrome/browser/task_manager_resource_providers.cc | 18 | ||||
-rw-r--r-- | chrome/common/notification_type.h | 8 |
9 files changed, 190 insertions, 32 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 369f427..56eaa67 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -1882,6 +1882,14 @@ each locale. --> Web Worker: <ph name="WORKER_NAME">$1<ex>http://www.domain.com</ex></ph> </message> + <!-- Extension Crashed Info Bar--> + <message name="IDS_EXTENSION_CRASHED_INFOBAR_RESTART_BUTTON" desc="Title of the restart button in the extension crashed infobar. After the button is clicked, the extension process will be restarted."> + Restart + </message> + <message name="IDS_EXTENSION_CRASHED_INFOBAR_MESSAGE" desc="Message displayed on the extension crashed infobar."> + The following extension has crashed : <ph name="EXTENSION_NAME">$1<ex>Buildbot Monitor</ex></ph> + </message> + <!-- Session Crashed Info Bar--> <message name="IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON" desc="Title of the restore button in the session crashed view."> Restore diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index aebf7cf..b993f73 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -4,7 +4,9 @@ #include "chrome/browser/extensions/extension_host.h" +#include "app/l10n_util.h" #include "app/resource_bundle.h" +#include "base/string_util.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" @@ -16,6 +18,7 @@ #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_widget_host.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" +#include "chrome/browser/tab_contents/infobar_delegate.h" #include "chrome/browser/tab_contents/site_instance.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" @@ -25,9 +28,55 @@ #include "grit/browser_resources.h" #include "grit/generated_resources.h" +#include "grit/theme_resources.h" #include "webkit/glue/context_menu.h" +namespace { + +class CrashedExtensionInfobarDelegate : public ConfirmInfoBarDelegate { + public: + CrashedExtensionInfobarDelegate(TabContents* tab_contents, + ExtensionHost* extension_host) + : ConfirmInfoBarDelegate(tab_contents), + extension_host_(extension_host) { + } + + virtual std::wstring GetMessageText() const { + return l10n_util::GetStringF(IDS_EXTENSION_CRASHED_INFOBAR_MESSAGE, + UTF8ToWide(extension_host_->extension()->name())); + } + + virtual SkBitmap* GetIcon() const { + // TODO(erikkay): Create extension-specific icon. http://crbug.com/14591 + return ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_INFOBAR_PLUGIN_CRASHED); + } + + virtual int GetButtons() const { + return BUTTON_OK; + } + + virtual std::wstring GetButtonLabel( + ConfirmInfoBarDelegate::InfoBarButton button) const { + if (button == BUTTON_OK) + return l10n_util::GetString(IDS_EXTENSION_CRASHED_INFOBAR_RESTART_BUTTON); + return ConfirmInfoBarDelegate::GetButtonLabel(button); + } + + virtual bool Accept() { + extension_host_->RecoverCrashedExtension(); + return true; + } + + private: + ExtensionHost* extension_host_; + + DISALLOW_COPY_AND_ASSIGN(CrashedExtensionInfobarDelegate); +}; + +} // namespace + ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance, const GURL& url, ExtensionProcessManager* manager) : extension_(extension), @@ -65,12 +114,25 @@ SiteInstance* ExtensionHost::site_instance() const { return render_view_host_->site_instance(); } +bool ExtensionHost::IsRenderViewLive() const { + return render_view_host_->IsRenderViewLive(); +} + void ExtensionHost::CreateRenderView(RenderWidgetHostView* host_view) { render_view_host_->set_view(host_view); render_view_host_->CreateRenderView(); render_view_host_->NavigateToURL(url_); } +void ExtensionHost::RecoverCrashedExtension() { + DCHECK(!IsRenderViewLive()); +#if defined(TOOLKIT_VIEWS) + view_->RecoverCrashedExtension(); +#endif + if (IsRenderViewLive()) + manager_->OnExtensionProcessRestored(this); +} + void ExtensionHost::UpdatePreferredWidth(int pref_width) { #if defined(OS_WIN) if (view_.get()) @@ -78,6 +140,17 @@ void ExtensionHost::UpdatePreferredWidth(int pref_width) { #endif } +void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host) { + DCHECK_EQ(render_view_host_, render_view_host); + TabContents* current_tab = GetBrowser()->GetSelectedTabContents(); + DCHECK(current_tab); + if (current_tab) { + current_tab->AddInfoBar( + new CrashedExtensionInfobarDelegate(current_tab, this)); + } + manager_->OnExtensionProcessCrashed(this); +} + WebPreferences ExtensionHost::GetWebkitPrefs() { PrefService* prefs = render_view_host()->process()->profile()->GetPrefs(); const bool kIsDomUI = true; diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index 4634723..f54f4fc 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -49,13 +49,21 @@ class ExtensionHost : public RenderViewHostDelegate, SiteInstance* site_instance() const; bool did_stop_loading() const { return did_stop_loading_; } + // 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); + // Restarts extension's renderer process. Can be called only if the renderer + // process crashed. + void RecoverCrashedExtension(); + // RenderViewHostDelegate virtual const GURL& GetURL() const { return url_; } + virtual void RenderViewGone(RenderViewHost* render_view_host); virtual WebPreferences GetWebkitPrefs(); virtual void RunJavaScriptMessage( const std::wstring& message, diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc index a4f2df7..774d3a9e 100644 --- a/chrome/browser/extensions/extension_process_manager.cc +++ b/chrome/browser/extensions/extension_process_manager.cc @@ -120,6 +120,20 @@ void ExtensionProcessManager::OnExtensionHostDestroyed(ExtensionHost* host) { Details<ExtensionHost>(host)); } +void ExtensionProcessManager::OnExtensionProcessCrashed(ExtensionHost* host) { + NotificationService::current()->Notify( + NotificationType::EXTENSION_PROCESS_CRASHED, + Source<ExtensionProcessManager>(this), + Details<ExtensionHost>(host)); +} + +void ExtensionProcessManager::OnExtensionProcessRestored(ExtensionHost* host) { + NotificationService::current()->Notify( + NotificationType::EXTENSION_PROCESS_RESTORED, + Source<ExtensionProcessManager>(this), + Details<ExtensionHost>(host)); +} + void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host, bool is_background) { all_hosts_.insert(host); diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h index 9cd861c..a5c6296 100644 --- a/chrome/browser/extensions/extension_process_manager.h +++ b/chrome/browser/extensions/extension_process_manager.h @@ -57,6 +57,12 @@ class ExtensionProcessManager : public NotificationObserver { // from our lists. void OnExtensionHostDestroyed(ExtensionHost* host); + // Called after an extension render process crashes. + void OnExtensionProcessCrashed(ExtensionHost* host); + + // Called after an extension process successfully restarts after crash. + void OnExtensionProcessRestored(ExtensionHost* host); + private: // Called just after |host| is created so it can be registered in our lists. void OnExtensionHostCreated(ExtensionHost* host, bool is_background); diff --git a/chrome/browser/extensions/extension_view.cc b/chrome/browser/extensions/extension_view.cc index a375c04..7a8be62 100644 --- a/chrome/browser/extensions/extension_view.cc +++ b/chrome/browser/extensions/extension_view.cc @@ -19,8 +19,7 @@ ExtensionView::ExtensionView(ExtensionHost* host, Browser* browser) } ExtensionView::~ExtensionView() { - if (native_view()) - Detach(); + CleanUp(); } Extension* ExtensionView::extension() const { @@ -56,6 +55,37 @@ void ExtensionView::DidChangeBounds(const gfx::Rect& previous, render_view_host()->view()->SetSize(gfx::Size(width(), height())); } +void ExtensionView::CreateWidgetHostView() { + DCHECK(!initialized_); + initialized_ = true; + RenderWidgetHostView* view = + RenderWidgetHostView::CreateViewForWidget(render_view_host()); + + // TODO(mpcomplete): RWHV needs a cross-platform Init function. +#if defined(OS_WIN) + // Create the HWND. Note: + // RenderWidgetHostHWND supports windowed plugins, but if we ever also + // wanted to support constrained windows with this, we would need an + // additional HWND to parent off of because windowed plugin HWNDs cannot + // exist in the same z-order as constrained windows. + RenderWidgetHostViewWin* view_win = + static_cast<RenderWidgetHostViewWin*>(view); + HWND hwnd = view_win->Create(GetWidget()->GetNativeView()); + view_win->ShowWindow(SW_SHOW); + Attach(hwnd); +#else + NOTIMPLEMENTED(); +#endif + + host_->CreateRenderView(view); + SetVisible(false); + + if (!pending_background_.empty()) { + render_view_host()->view()->SetBackground(pending_background_); + pending_background_.reset(); + } +} + void ExtensionView::ShowIfCompletelyLoaded() { // We wait to show the ExtensionView until it has loaded and our parent has // given us a background. These can happen in different orders. @@ -66,6 +96,14 @@ void ExtensionView::ShowIfCompletelyLoaded() { } } +void ExtensionView::CleanUp() { + if (!initialized_) + return; + if (native_view()) + Detach(); + initialized_ = false; +} + void ExtensionView::SetBackground(const SkBitmap& background) { if (initialized_ && render_view_host()->view()) { render_view_host()->view()->SetBackground(background); @@ -89,35 +127,13 @@ void ExtensionView::ViewHierarchyChanged(bool is_add, views::View *parent, views::View *child) { NativeViewHost::ViewHierarchyChanged(is_add, parent, child); - if (is_add && GetWidget() && !initialized_) { - initialized_ = true; - RenderWidgetHostView* view = - RenderWidgetHostView::CreateViewForWidget(render_view_host()); - - // TODO(mpcomplete): RWHV needs a cross-platform Init function. -#if defined(OS_WIN) - // Create the HWND. Note: - // RenderWidgetHostHWND supports windowed plugins, but if we ever also - // wanted to support constrained windows with this, we would need an - // additional HWND to parent off of because windowed plugin HWNDs cannot - // exist in the same z-order as constrained windows. - RenderWidgetHostViewWin* view_win = - static_cast<RenderWidgetHostViewWin*>(view); - HWND hwnd = view_win->Create(GetWidget()->GetNativeView()); - view_win->ShowWindow(SW_SHOW); - Attach(hwnd); -#else - NOTIMPLEMENTED(); -#endif - - host_->CreateRenderView(view); - SetVisible(false); + if (is_add && GetWidget() && !initialized_) + CreateWidgetHostView(); +} - if (!pending_background_.empty()) { - render_view_host()->view()->SetBackground(pending_background_); - pending_background_.reset(); - } - } +void ExtensionView::RecoverCrashedExtension() { + CleanUp(); + CreateWidgetHostView(); } void ExtensionView::HandleMouseEvent() { diff --git a/chrome/browser/extensions/extension_view.h b/chrome/browser/extensions/extension_view.h index cf2fc40..1904db2 100644 --- a/chrome/browser/extensions/extension_view.h +++ b/chrome/browser/extensions/extension_view.h @@ -56,12 +56,23 @@ class ExtensionView : public views::NativeViewHost { virtual void ViewHierarchyChanged(bool is_add, views::View *parent, views::View *child); + // Call after extension process crash to re-initialize view, so that + // extension content can be rendered again. + void RecoverCrashedExtension(); + private: friend class ExtensionHost; + // Initializes the RenderWidgetHostView for this object. + void CreateWidgetHostView(); + // We wait to show the ExtensionView until several things have loaded. void ShowIfCompletelyLoaded(); + // Restore object to initial state. Called on shutdown or after a renderer + // crash. + void CleanUp(); + // The running extension instance that we're displaying. // Note that host_ owns view ExtensionHost* host_; diff --git a/chrome/browser/task_manager_resource_providers.cc b/chrome/browser/task_manager_resource_providers.cc index 7279aab..f76d8ad 100644 --- a/chrome/browser/task_manager_resource_providers.cc +++ b/chrome/browser/task_manager_resource_providers.cc @@ -540,22 +540,30 @@ void TaskManagerExtensionProcessResourceProvider::StartUpdating() { AddToTaskManager(*jt); } - // Register for notifications to get new extension processes. + // Register for notifications about extension process changes. registrar_.Add(this, NotificationType::EXTENSION_HOST_CREATED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED, NotificationService::AllSources()); + registrar_.Add(this, NotificationType::EXTENSION_PROCESS_CRASHED, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::EXTENSION_PROCESS_RESTORED, + NotificationService::AllSources()); } void TaskManagerExtensionProcessResourceProvider::StopUpdating() { DCHECK(updating_); updating_ = false; - // Unregister for notifications to get new extension processes. + // Unregister for notifications about extension process changes. registrar_.Remove(this, NotificationType::EXTENSION_HOST_CREATED, NotificationService::AllSources()); registrar_.Remove(this, NotificationType::EXTENSION_HOST_DESTROYED, NotificationService::AllSources()); + registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_CRASHED, + NotificationService::AllSources()); + registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_RESTORED, + NotificationService::AllSources()); // Delete all the resources. STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end()); @@ -570,9 +578,11 @@ void TaskManagerExtensionProcessResourceProvider::Observe( const NotificationDetails& details) { switch (type.value) { case NotificationType::EXTENSION_HOST_CREATED: + case NotificationType::EXTENSION_PROCESS_RESTORED: AddToTaskManager(Details<ExtensionHost>(details).ptr()); break; case NotificationType::EXTENSION_HOST_DESTROYED: + case NotificationType::EXTENSION_PROCESS_CRASHED: RemoveFromTaskManager(Details<ExtensionHost>(details).ptr()); break; default: @@ -583,6 +593,10 @@ void TaskManagerExtensionProcessResourceProvider::Observe( void TaskManagerExtensionProcessResourceProvider::AddToTaskManager( ExtensionHost* extension_host) { + // Don't add dead extension processes. + if (!extension_host->IsRenderViewLive()) + return; + TaskManagerExtensionProcessResource* resource = new TaskManagerExtensionProcessResource(extension_host); DCHECK(resources_.find(extension_host) == resources_.end()); diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index e6efd5d..d4ced73 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -592,6 +592,14 @@ class NotificationType { // an ExtensionHost*. EXTENSION_HOST_DESTROYED, + // Sent when extension render process crashes. The details are + // an ExtensionHost*. + EXTENSION_PROCESS_CRASHED, + + // Sent after an extension render process is restarted after a crash + // and is fully functional. The details are an ExtensionHost*. + EXTENSION_PROCESS_RESTORED, + // Debugging --------------------------------------------------------------- // Sent from ~RenderViewHost. The source is the RenderViewHost. |