Index: chrome/browser/ui/extensions/shell_window.cc |
diff --git a/chrome/browser/ui/extensions/shell_window.cc b/chrome/browser/ui/extensions/shell_window.cc |
index 8be9cce5aec0a8d056b07780de034b8454e03728..bfb5fc843b029c1080c79141b4f2e5f9373880fa 100644 |
--- a/chrome/browser/ui/extensions/shell_window.cc |
+++ b/chrome/browser/ui/extensions/shell_window.cc |
@@ -249,6 +249,11 @@ ShellWindow::~ShellWindow() { |
chrome::EndKeepAlive(); |
} |
+void ShellWindow::Close() { |
+ extensions::ShellWindowRegistry::Get(profile_)->RemoveShellWindow(this); |
+ native_app_window_->Close(); |
+} |
+ |
void ShellWindow::RequestMediaAccessPermission( |
content::WebContents* web_contents, |
const content::MediaStreamRequest& request, |
@@ -348,9 +353,16 @@ void ShellWindow::RequestToLockMouse(WebContents* web_contents, |
} |
void ShellWindow::OnNativeClose() { |
+ // This method is shared between the path for the user clicking the close |
+ // button and the path where a close is triggered by code (e.g. by the |
+ // extension being unloaded). In the latter case, this RemoveShellWindow is |
+ // superfluous, since it will already have been removed, but the call is |
+ // idempotent so it's harmless the second time. |
extensions::ShellWindowRegistry::Get(profile_)->RemoveShellWindow(this); |
- content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); |
- rvh->Send(new ExtensionMsg_AppWindowClosed(rvh->GetRoutingID())); |
+ if (extension_) { |
+ content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); |
+ rvh->Send(new ExtensionMsg_AppWindowClosed(rvh->GetRoutingID())); |
+ } |
delete this; |
} |
@@ -492,7 +504,7 @@ void ShellWindow::UpdateExtensionAppIcon() { |
void ShellWindow::CloseContents(WebContents* contents) { |
DCHECK(contents == web_contents_); |
- native_app_window_->Close(); |
+ Close(); |
} |
bool ShellWindow::ShouldSuppressDialogs() { |
@@ -573,12 +585,16 @@ void ShellWindow::Observe(int type, |
const extensions::Extension* unloaded_extension = |
content::Details<extensions::UnloadedExtensionInfo>( |
details)->extension; |
- if (extension_ == unloaded_extension) |
- native_app_window_->Close(); |
+ if (extension_ == unloaded_extension) { |
+ Close(); |
+ // After this notification finishes processing, the Extension will be |
+ // deleted, so we null out our reference to avoid bad access. |
+ extension_ = NULL; |
+ } |
break; |
} |
case chrome::NOTIFICATION_APP_TERMINATING: |
- native_app_window_->Close(); |
+ Close(); |
break; |
default: |
NOTREACHED() << "Received unexpected notification"; |