summaryrefslogtreecommitdiffstats
path: root/content/browser/renderer_host
diff options
context:
space:
mode:
authormichaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-06 10:46:44 +0000
committermichaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-06 10:46:44 +0000
commit6de7fc488e8b179cd4b4031510a42ab9d3c82b86 (patch)
tree6e86e6116209607ff917b2c23a61664889de5565 /content/browser/renderer_host
parent80bc8a08d44568118d4614b61cf942c6e1bc3263 (diff)
downloadchromium_src-6de7fc488e8b179cd4b4031510a42ab9d3c82b86.zip
chromium_src-6de7fc488e8b179cd4b4031510a42ab9d3c82b86.tar.gz
chromium_src-6de7fc488e8b179cd4b4031510a42ab9d3c82b86.tar.bz2
When deleting a WebContents, keep SessionStorageNamespaces used in the tab alive until we receive an acknowledgment from the renderer that the renderer side constructs have been cleaned up. Otherwise we can receive messages from still executing content referring to sessions that were prematurely deleted.
BUG=371304 Review URL: https://codereview.chromium.org/305103003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275383 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/renderer_host')
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc50
-rw-r--r--content/browser/renderer_host/render_process_host_impl.h10
-rw-r--r--content/browser/renderer_host/render_view_host_browsertest.cc32
-rw-r--r--content/browser/renderer_host/render_view_host_delegate.cc5
-rw-r--r--content/browser/renderer_host/render_view_host_delegate.h5
-rw-r--r--content/browser/renderer_host/render_view_host_impl.cc9
6 files changed, 111 insertions, 0 deletions
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 11f3944..11a629d 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -354,6 +354,27 @@ void AddIntegerValue(CFMutableDictionaryRef dictionary,
}
#endif
+const char kSessionStorageHolderKey[] = "kSessionStorageHolderKey";
+
+class SessionStorageHolder : public base::SupportsUserData::Data {
+ public:
+ SessionStorageHolder() {}
+ virtual ~SessionStorageHolder() {}
+
+ void Hold(const SessionStorageNamespaceMap& sessions, int view_route_id) {
+ session_storage_namespaces_awaiting_close_[view_route_id] = sessions;
+ }
+
+ void Release(int old_route_id) {
+ session_storage_namespaces_awaiting_close_.erase(old_route_id);
+ }
+
+ private:
+ std::map<int, SessionStorageNamespaceMap >
+ session_storage_namespaces_awaiting_close_;
+ DISALLOW_COPY_AND_ASSIGN(SessionStorageHolder);
+};
+
} // namespace
RendererMainThreadFactoryFunction g_renderer_main_thread_factory = NULL;
@@ -1353,6 +1374,7 @@ bool RenderProcessHostImpl::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER_DELAY_REPLY(
ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
OnAllocateGpuMemoryBuffer)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Close_ACK, OnCloseACK)
// Adding single handlers for your service here is fine, but once your
// service needs more than one handler, please extract them into a new
// message filter and add that filter to CreateMessageFilters().
@@ -1484,6 +1506,7 @@ void RenderProcessHostImpl::Cleanup() {
gpu_message_filter_ = NULL;
message_port_message_filter_ = NULL;
screen_orientation_dispatcher_host_ = NULL;
+ RemoveUserData(kSessionStorageHolderKey);
// Remove ourself from the list of renderer processes so that we can't be
// reused in between now and when the Delete task runs.
@@ -1897,6 +1920,7 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead) {
gpu_message_filter_ = NULL;
message_port_message_filter_ = NULL;
screen_orientation_dispatcher_host_ = NULL;
+ RemoveUserData(kSessionStorageHolderKey);
IDMap<IPC::Listener>::iterator iter(&listeners_);
while (!iter.IsAtEnd()) {
@@ -1965,6 +1989,24 @@ RenderProcessHostImpl::screen_orientation_dispatcher_host() const {
return make_scoped_refptr(screen_orientation_dispatcher_host_);
}
+void RenderProcessHostImpl::ReleaseOnCloseACK(
+ RenderProcessHost* host,
+ const SessionStorageNamespaceMap& sessions,
+ int view_route_id) {
+ DCHECK(host);
+ if (sessions.empty())
+ return;
+ SessionStorageHolder* holder = static_cast<SessionStorageHolder*>
+ (host->GetUserData(kSessionStorageHolderKey));
+ if (!holder) {
+ holder = new SessionStorageHolder();
+ host->SetUserData(
+ kSessionStorageHolderKey,
+ holder);
+ }
+ holder->Hold(sessions, view_route_id);
+}
+
void RenderProcessHostImpl::OnShutdownRequest() {
// Don't shut down if there are active RenderViews, or if there are pending
// RenderViews being swapped back in.
@@ -2082,6 +2124,14 @@ void RenderProcessHostImpl::OnUserMetricsRecordAction(
RecordComputedAction(action);
}
+void RenderProcessHostImpl::OnCloseACK(int old_route_id) {
+ SessionStorageHolder* holder = static_cast<SessionStorageHolder*>
+ (GetUserData(kSessionStorageHolderKey));
+ if (!holder)
+ return;
+ holder->Release(old_route_id);
+}
+
void RenderProcessHostImpl::OnSavedPageAsMHTML(int job_id, int64 data_size) {
MHTMLGenerationManager::GetInstance()->MHTMLGenerated(job_id, data_size);
}
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index e2c7b24..cd7ec89 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -14,6 +14,7 @@
#include "base/process/process.h"
#include "base/timer/timer.h"
#include "content/browser/child_process_launcher.h"
+#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/browser/power_monitor_message_broadcaster.h"
#include "content/common/content_export.h"
#include "content/public/browser/gpu_data_manager_observer.h"
@@ -183,6 +184,14 @@ class CONTENT_EXPORT RenderProcessHostImpl
scoped_refptr<ScreenOrientationDispatcherHost>
screen_orientation_dispatcher_host() const;
+ // Used to extend the lifetime of the sessions until the render view
+ // in the renderer is fully closed. This is static because its also called
+ // with mock hosts as input in test cases.
+ static void ReleaseOnCloseACK(
+ RenderProcessHost* host,
+ const SessionStorageNamespaceMap& sessions,
+ int view_route_id);
+
// Register/unregister the host identified by the host id in the global host
// list.
static void RegisterHost(int host_id, RenderProcessHost* host);
@@ -293,6 +302,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
void SuddenTerminationChanged(bool enabled);
void OnUserMetricsRecordAction(const std::string& action);
void OnSavedPageAsMHTML(int job_id, int64 mhtml_file_size);
+ void OnCloseACK(int old_route_id);
// CompositorSurfaceBuffersSwapped handler when there's no RWH.
void OnCompositorSurfaceBuffersSwappedNoHost(
diff --git a/content/browser/renderer_host/render_view_host_browsertest.cc b/content/browser/renderer_host/render_view_host_browsertest.cc
index 31ecee9..6015c04 100644
--- a/content/browser/renderer_host/render_view_host_browsertest.cc
+++ b/content/browser/renderer_host/render_view_host_browsertest.cc
@@ -129,4 +129,36 @@ IN_PROC_BROWSER_TEST_F(RenderViewHostTest, IsFocusedElementEditable) {
EXPECT_TRUE(rvh->IsFocusedElementEditable());
}
+IN_PROC_BROWSER_TEST_F(RenderViewHostTest, ReleaseSessionOnCloseACK) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ GURL test_url = embedded_test_server()->GetURL(
+ "/access-session-storage.html");
+ NavigateToURL(shell(), test_url);
+
+ // Make a new Shell, a seperate tab with it's own session namespace and
+ // have it start loading a url but still be in progress.
+ ShellAddedObserver new_shell_observer;
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(), "window.open();"));
+ Shell* new_shell = new_shell_observer.GetShell();
+ new_shell->LoadURL(test_url);
+ RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
+ SiteInstance* site_instance = rvh->GetSiteInstance();
+ scoped_refptr<SessionStorageNamespace> session_namespace =
+ rvh->GetDelegate()->GetSessionStorageNamespace(site_instance);
+ EXPECT_FALSE(session_namespace->HasOneRef());
+
+ // Close it, or rather start the close operation. The session namespace
+ // should remain until RPH gets an ACK from the renderer about having
+ // closed the view.
+ new_shell->Close();
+ EXPECT_FALSE(session_namespace->HasOneRef());
+
+ // Do something that causes ipc queues to flush and tasks in
+ // flight to complete such that we should have received the ACK.
+ NavigateToURL(shell(), test_url);
+
+ // Verify we have the only remaining reference to the namespace.
+ EXPECT_TRUE(session_namespace->HasOneRef());
+}
+
} // namespace content
diff --git a/content/browser/renderer_host/render_view_host_delegate.cc b/content/browser/renderer_host/render_view_host_delegate.cc
index 84bbba8..88e590b 100644
--- a/content/browser/renderer_host/render_view_host_delegate.cc
+++ b/content/browser/renderer_host/render_view_host_delegate.cc
@@ -35,6 +35,11 @@ SessionStorageNamespace* RenderViewHostDelegate::GetSessionStorageNamespace(
return NULL;
}
+SessionStorageNamespaceMap
+RenderViewHostDelegate::GetSessionStorageNamespaceMap() {
+ return SessionStorageNamespaceMap();
+}
+
FrameTree* RenderViewHostDelegate::GetFrameTree() {
return NULL;
}
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h
index 51fc3dc..fd8aeae 100644
--- a/content/browser/renderer_host/render_view_host_delegate.h
+++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/process/kill.h"
#include "base/strings/string16.h"
+#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/common/content_export.h"
#include "content/public/common/media_stream_request.h"
#include "content/public/common/page_transition_types.h"
@@ -277,6 +278,10 @@ class CONTENT_EXPORT RenderViewHostDelegate {
virtual SessionStorageNamespace* GetSessionStorageNamespace(
SiteInstance* instance);
+ // Returns a copy of the map of all session storage namespaces related
+ // to this view.
+ virtual SessionStorageNamespaceMap GetSessionStorageNamespaceMap();
+
// Returns true if the RenderViewHost will never be visible.
virtual bool IsNeverVisible();
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 8198f2d..fd8f86f 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -1039,6 +1039,15 @@ void RenderViewHostImpl::Shutdown() {
run_modal_opener_id_ = MSG_ROUTING_NONE;
}
+ // We can't release the SessionStorageNamespace until our peer
+ // in the renderer has wound down.
+ if (GetProcess()->HasConnection()) {
+ RenderProcessHostImpl::ReleaseOnCloseACK(
+ GetProcess(),
+ delegate_->GetSessionStorageNamespaceMap(),
+ GetRoutingID());
+ }
+
RenderWidgetHostImpl::Shutdown();
}