Reland "Handle race of SwapIn() and browser destroying the speculative MainFrame"
This is a reland of e7d59816288ef3246defc4b86cb4e03e28d75956
TestExpectations added for the portals test that is hitting crbug.com/838348
[email protected], [email protected]
Original change's description:
> Handle race of SwapIn() and browser destroying the speculative MainFrame
>
> When WebContentsImpl destroys, it deletes the speculative main frame,
> but the renderer may have taken ownership of it already, and the notice
> of such action is in flight to the browser still. This leads to DCHECKs
> failing in the renderer. So inform the FrameMsg_Delete IPC what the
> intention of the browser is, there are 3 modes:
>
> - Deleting a non-main frame. This is the common case. These frames are
> all owned by the browser so it's all good, no races.
> - Deleting a speculative main frame at shutdown. This is the race we
> address here.
> - Deleting a speculative main frame because it's no longer needed. This
> race is not handled by this CL but we CHECK() it explicitly now instead
> of letting the renderer continue with a missing RenderFrame that it
> expects to be present until it crashes somewhere random later.
>
> [email protected], [email protected]
>
> Bug: 957858, 838348
> Change-Id: I2110bdaf8b116df48037f69db6cb992fa3796e29
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1594834
> Commit-Queue: danakj <[email protected]>
> Reviewed-by: Daniel Cheng <[email protected]>
> Reviewed-by: Avi Drissman <[email protected]>
> Cr-Commit-Position: refs/heads/master@{#660025}
Bug: 957858, 838348
Change-Id: Iba424cc7be7db053c7ca617677b3cacf972fa067
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1614132
Commit-Queue: danakj <[email protected]>
Reviewed-by: Lucas Gadani <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Cr-Commit-Position: refs/heads/master@{#660128}
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 3cc4e533..47e5d1da8 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1758,12 +1758,12 @@
return true;
}
-void RenderFrameHostImpl::DeleteRenderFrame() {
+void RenderFrameHostImpl::DeleteRenderFrame(FrameDeleteIntention intent) {
if (!is_active())
return;
if (render_frame_created_) {
- Send(new FrameMsg_Delete(routing_id_));
+ Send(new FrameMsg_Delete(routing_id_, intent));
if (!frame_tree_node_->IsMainFrame() && IsCurrent()) {
// If this subframe has an unload handler (and isn't speculative), ensure
@@ -2036,7 +2036,8 @@
// observers are notified of its deletion.
std::unique_ptr<FrameTreeNode> node_to_delete(std::move(*iter));
children_.erase(iter);
- node_to_delete->current_frame_host()->DeleteRenderFrame();
+ node_to_delete->current_frame_host()->DeleteRenderFrame(
+ FrameDeleteIntention::kNotMainFrame);
// Speculative RenderFrameHosts are deleted by the FrameTreeNode's
// RenderFrameHostManager's destructor. RenderFrameProxyHosts send
// FrameMsg_Delete automatically in the destructor.
@@ -2059,7 +2060,8 @@
// this RenderFrameHostImpl to detach the current frame's children, rather
// than messaging each child's current frame host...
for (auto& child : children)
- child->current_frame_host()->DeleteRenderFrame();
+ child->current_frame_host()->DeleteRenderFrame(
+ FrameDeleteIntention::kNotMainFrame);
}
void RenderFrameHostImpl::SetLastCommittedUrl(const GURL& url) {
@@ -2389,7 +2391,7 @@
return;
// Start pending deletion on this frame and its children.
- DeleteRenderFrame();
+ DeleteRenderFrame(FrameDeleteIntention::kNotMainFrame);
StartPendingDeletionOnSubtree();
// Some children with no unload handler may be eligible for immediate
// deletion. Cut the dead branches now. This is a performance optimization.
@@ -4525,7 +4527,7 @@
local_ancestor = rfh;
}
- local_ancestor->DeleteRenderFrame();
+ local_ancestor->DeleteRenderFrame(FrameDeleteIntention::kNotMainFrame);
if (local_ancestor != child) {
child->unload_state_ =
child->GetSuddenTerminationDisablerState(blink::kUnloadHandler)
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index d5ad7ff..2c3a4ae 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -41,6 +41,7 @@
#include "content/common/content_export.h"
#include "content/common/content_security_policy/csp_context.h"
#include "content/common/frame.mojom.h"
+#include "content/common/frame_delete_intention.h"
#include "content/common/frame_message_enums.h"
#include "content/common/frame_replication_state.h"
#include "content/common/image_downloader/image_downloader.mojom.h"
@@ -332,7 +333,7 @@
// Deletes the RenderFrame in the renderer process.
// Postcondition: |is_active()| will return false.
- void DeleteRenderFrame();
+ void DeleteRenderFrame(FrameDeleteIntention intent);
// Tracks whether the RenderFrame for this RenderFrameHost has been created in
// the renderer process. This is currently only used for subframes.
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index de85226a..184de12 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -823,7 +823,10 @@
std::unique_ptr<RenderFrameHostImpl>
RenderFrameHostManager::UnsetSpeculativeRenderFrameHost() {
speculative_render_frame_host_->GetProcess()->RemovePendingView();
- speculative_render_frame_host_->DeleteRenderFrame();
+ speculative_render_frame_host_->DeleteRenderFrame(
+ frame_tree_node_->parent()
+ ? FrameDeleteIntention::kNotMainFrame
+ : FrameDeleteIntention::kSpeculativeMainFrameForNavigationCancelled);
return std::move(speculative_render_frame_host_);
}
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index aa8c31f..0acd4b2c 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -689,7 +689,8 @@
// Do not update state as the WebContents is being destroyed.
frame_tree_.root()->ResetNavigationRequest(true, true);
if (root->speculative_frame_host()) {
- root->speculative_frame_host()->DeleteRenderFrame();
+ root->speculative_frame_host()->DeleteRenderFrame(
+ FrameDeleteIntention::kSpeculativeMainFrameForShutdown);
root->speculative_frame_host()->SetRenderFrameCreated(false);
root->speculative_frame_host()->ResetNavigationRequests();
}