Index: extensions/browser/process_manager.cc |
diff --git a/extensions/browser/process_manager.cc b/extensions/browser/process_manager.cc |
index 60af62c4c83d9b9ed6bfd434573bc243867e620e..5e2e3aa0dcd1397ff692e3fc3ce3c25cdf671ad3 100644 |
--- a/extensions/browser/process_manager.cc |
+++ b/extensions/browser/process_manager.cc |
@@ -192,6 +192,40 @@ struct ProcessManager::BackgroundPageData { |
close_sequence_id(0) {} |
}; |
+// Data of a RenderViewHost associated with an extension. |
+struct ProcessManager::ExtensionRenderViewData { |
+ // The type of the view. |
+ extensions::ViewType view_type; |
+ |
+ // Whether the view is keeping the lazy background page alive or not. |
+ bool has_keepalive; |
+ |
+ ExtensionRenderViewData() |
+ : view_type(VIEW_TYPE_INVALID), has_keepalive(false) {} |
+ |
+ // Returns whether the view can keep the lazy background page alive or not. |
+ bool CanKeepalive() const { |
+ switch (view_type) { |
+ case VIEW_TYPE_APP_WINDOW: |
+ case VIEW_TYPE_BACKGROUND_CONTENTS: |
+ case VIEW_TYPE_EXTENSION_DIALOG: |
+ case VIEW_TYPE_EXTENSION_INFOBAR: |
+ case VIEW_TYPE_EXTENSION_POPUP: |
+ case VIEW_TYPE_LAUNCHER_PAGE: |
+ case VIEW_TYPE_PANEL: |
+ case VIEW_TYPE_TAB_CONTENTS: |
+ case VIEW_TYPE_VIRTUAL_KEYBOARD: |
+ return true; |
+ |
+ case VIEW_TYPE_INVALID: |
+ case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE: |
+ return false; |
+ } |
+ NOTREACHED(); |
+ return false; |
+ } |
+}; |
+ |
// |
// ProcessManager |
// |
@@ -368,6 +402,40 @@ const Extension* ProcessManager::GetExtensionForRenderViewHost( |
GetExtensionID(render_view_host)); |
} |
+void ProcessManager::AcquireLazyKeepaliveCountForView( |
+ content::RenderViewHost* render_view_host) { |
+ auto it = all_extension_views_.find(render_view_host); |
+ if (it == all_extension_views_.end()) |
+ return; |
+ |
+ ExtensionRenderViewData* data = &it->second; |
+ if (data->CanKeepalive() && !data->has_keepalive) { |
+ const Extension* extension = |
+ GetExtensionForRenderViewHost(render_view_host); |
+ if (extension) { |
+ IncrementLazyKeepaliveCount(extension); |
+ data->has_keepalive = true; |
+ } |
+ } |
+} |
+ |
+void ProcessManager::ReleaseLazyKeepaliveCountForView( |
+ content::RenderViewHost* render_view_host) { |
+ auto it = all_extension_views_.find(render_view_host); |
+ if (it == all_extension_views_.end()) |
+ return; |
+ |
+ ExtensionRenderViewData* data = &it->second; |
+ if (data->CanKeepalive() && data->has_keepalive) { |
+ const Extension* extension = |
+ GetExtensionForRenderViewHost(render_view_host); |
+ if (extension) { |
+ DecrementLazyKeepaliveCount(extension); |
+ data->has_keepalive = false; |
+ } |
+ } |
+} |
+ |
void ProcessManager::UnregisterRenderViewHost( |
RenderViewHost* render_view_host) { |
ExtensionRenderViews::iterator view = |
@@ -376,17 +444,10 @@ void ProcessManager::UnregisterRenderViewHost( |
return; |
OnRenderViewHostUnregistered(GetBrowserContext(), render_view_host); |
- ViewType view_type = view->second; |
- all_extension_views_.erase(view); |
// Keepalive count, balanced in RegisterRenderViewHost. |
- if (view_type != VIEW_TYPE_INVALID && |
- view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
- const Extension* extension = GetExtensionForRenderViewHost( |
- render_view_host); |
- if (extension) |
- DecrementLazyKeepaliveCount(extension); |
- } |
+ ReleaseLazyKeepaliveCountForView(render_view_host); |
+ all_extension_views_.erase(view); |
} |
bool ProcessManager::RegisterRenderViewHost(RenderViewHost* render_view_host) { |
@@ -396,12 +457,13 @@ bool ProcessManager::RegisterRenderViewHost(RenderViewHost* render_view_host) { |
return false; |
WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host); |
- all_extension_views_[render_view_host] = GetViewType(web_contents); |
+ ExtensionRenderViewData* data = &all_extension_views_[render_view_host]; |
+ data->view_type = GetViewType(web_contents); |
// Keep the lazy background page alive as long as any non-background-page |
// extension views are visible. Keepalive count balanced in |
// UnregisterRenderViewHost. |
- IncrementLazyKeepaliveCountForView(render_view_host); |
+ AcquireLazyKeepaliveCountForView(render_view_host); |
return true; |
} |
@@ -459,20 +521,6 @@ void ProcessManager::DecrementLazyKeepaliveCount( |
} |
} |
-void ProcessManager::IncrementLazyKeepaliveCountForView( |
- RenderViewHost* render_view_host) { |
- WebContents* web_contents = |
- WebContents::FromRenderViewHost(render_view_host); |
- ViewType view_type = GetViewType(web_contents); |
- if (view_type != VIEW_TYPE_INVALID && |
- view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
- const Extension* extension = GetExtensionForRenderViewHost( |
- render_view_host); |
- if (extension) |
- IncrementLazyKeepaliveCount(extension); |
- } |
-} |
- |
// This implementation layers on top of the keepalive count. An impulse sets |
// a per extension flag. On a regular interval that flag is checked. Changes |
// from the flag not being set to set cause an IncrementLazyKeepaliveCount. |
@@ -606,6 +654,24 @@ void ProcessManager::CloseLazyBackgroundPageNow(const std::string& extension_id, |
ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
if (host && |
sequence_id == background_page_data_[extension_id].close_sequence_id) { |
+ // Close remaining views. |
+ std::vector<RenderViewHost*> views_to_close; |
+ for (const auto& view : all_extension_views_) { |
+ if (view.second.CanKeepalive() && |
+ GetExtensionID(view.first) == extension_id) { |
+ DCHECK(!view.second.has_keepalive); |
+ views_to_close.push_back(view.first); |
+ } |
+ } |
+ for (auto view : views_to_close) { |
+ view->ClosePage(); |
+ // RenderViewHost::ClosePage() may result in calling |
+ // UnregisterRenderViewHost() asynchronously and may cause race conditions |
+ // when the background page is reloaded. |
+ // To avoid this, unregister the view now. |
+ UnregisterRenderViewHost(view); |
+ } |
+ |
ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
if (host) |
CloseBackgroundHost(host); |
@@ -908,8 +974,15 @@ void ProcessManager::ClearBackgroundPageData(const std::string& extension_id) { |
// views. |
for (ExtensionRenderViews::const_iterator it = all_extension_views_.begin(); |
it != all_extension_views_.end(); ++it) { |
- if (GetExtensionID(it->first) == extension_id) |
- IncrementLazyKeepaliveCountForView(it->first); |
+ RenderViewHost* view = it->first; |
+ const ExtensionRenderViewData& data = it->second; |
+ // Do not increment the count when |has_keepalive| is false |
+ // (i.e. ReleaseLazyKeepaliveCountForView() was called). |
+ if (GetExtensionID(view) == extension_id && data.has_keepalive) { |
+ const Extension* extension = GetExtensionForRenderViewHost(view); |
+ if (extension) |
+ IncrementLazyKeepaliveCount(extension); |
+ } |
} |
} |