diff options
author | nasko <nasko@chromium.org> | 2014-10-20 14:05:02 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-10-20 21:05:53 +0000 |
commit | d2c7272b80fe61a11cd2f04f17fb6caf52631010 (patch) | |
tree | b1ff489847b6c061fc1ff0b0897915e5b4848938 | |
parent | b7893322082382329bf46d20d91c4695c234026c (diff) | |
download | chromium_src-d2c7272b80fe61a11cd2f04f17fb6caf52631010.zip chromium_src-d2c7272b80fe61a11cd2f04f17fb6caf52631010.tar.gz chromium_src-d2c7272b80fe61a11cd2f04f17fb6caf52631010.tar.bz2 |
Revert of Drop CreateChildFrame messages when swapping out. (patchset #1 id:1 of https://codereview.chromium.org/649683007/)
Reason for revert:
It broke compile since this CL relies on https://crrev.com/cce56cd951f6685a0120db63418aa7e6d3df28f2 and it isn't in this branch.
Original issue's description:
> Drop CreateChildFrame messages when swapping out.
>
> There is a race condition in the current state of the code where in cross-process navigation we swap the existing RenderFrameHost with a new RenderFrameHost. If the existing host sends an IPC message to create a new child frame, it arrives on the IO thread, allocates a routing id based of the existing process (p1) and does a PostTask to the UI thread. If there is a CommitPending event either executing on the UI thread or in the task queue before the task posted from the IO thread, it will end up putting the existing RenderFrameHost in swapped out state (or waiting for swapped out). When the task to create a child frame is executed after that, it creates a new RenderFrameHost, but it uses the "current" process (p2), which is different than the process that sent the message (p1). This manifests sometimes as adding duplicate routing ids to RenderProcessHost and is in general really bad bug.
>
> BUG=415059, 423691, 381990
>
> Review URL: https://codereview.chromium.org/642813007
>
> Cr-Commit-Position: refs/heads/master@{#299939}
> (cherry picked from commit dcdb02fab210ec5f7b8b560075ce96d0f48f344c)
>
> Conflicts:
> content/browser/frame_host/navigator_impl_unittest.cc
>
> R=creis@chromium.org
>
> Committed: https://chromium.googlesource.com/chromium/src/+/a6a21983b1a29ad11d30782c66d95facca65ab55
TBR=creis@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=415059, 423691, 381990
Review URL: https://codereview.chromium.org/663183003
Cr-Commit-Position: refs/heads/master@{#300332}
-rw-r--r-- | content/browser/frame_host/frame_tree.cc | 10 | ||||
-rw-r--r-- | content/browser/frame_host/frame_tree.h | 1 | ||||
-rw-r--r-- | content/browser/frame_host/frame_tree_node.cc | 4 | ||||
-rw-r--r-- | content/browser/frame_host/frame_tree_node.h | 4 | ||||
-rw-r--r-- | content/browser/frame_host/frame_tree_unittest.cc | 50 | ||||
-rw-r--r-- | content/browser/frame_host/render_frame_host_impl.cc | 11 | ||||
-rw-r--r-- | content/browser/frame_host/render_frame_host_manager_unittest.cc | 65 |
7 files changed, 20 insertions, 125 deletions
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc index 90c1f8d..caa1ab3 100644 --- a/content/browser/frame_host/frame_tree.cc +++ b/content/browser/frame_host/frame_tree.cc @@ -147,16 +147,8 @@ void FrameTree::ForEach( } RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent, - int process_id, int new_routing_id, const std::string& frame_name) { - // A child frame always starts with an initial empty document, which means - // it is in the same SiteInstance as the parent frame. Ensure that the process - // which requested a child frame to be added is the same as the process of the - // parent node. - if (parent->current_frame_host()->GetProcess()->GetID() != process_id) - return nullptr; - scoped_ptr<FrameTreeNode> node(new FrameTreeNode( this, parent->navigator(), render_frame_delegate_, render_view_delegate_, render_widget_delegate_, manager_delegate_, frame_name)); @@ -166,7 +158,7 @@ RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent, CHECK(result.second); FrameTreeNode* node_ptr = node.get(); // AddChild is what creates the RenderFrameHost. - parent->AddChild(node.Pass(), process_id, new_routing_id); + parent->AddChild(node.Pass(), new_routing_id); return node_ptr->current_frame_host(); } diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h index b312265..26d5760 100644 --- a/content/browser/frame_host/frame_tree.h +++ b/content/browser/frame_host/frame_tree.h @@ -71,7 +71,6 @@ class CONTENT_EXPORT FrameTree { // Frame tree manipulation routines. RenderFrameHostImpl* AddFrame(FrameTreeNode* parent, - int process_id, int new_routing_id, const std::string& frame_name); void RemoveFrame(FrameTreeNode* child); diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc index 41be622..bc044bc 100644 --- a/content/browser/frame_host/frame_tree_node.cc +++ b/content/browser/frame_host/frame_tree_node.cc @@ -48,11 +48,7 @@ bool FrameTreeNode::IsMainFrame() const { } void FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child, - int process_id, int frame_routing_id) { - // Child frame must always be created in the same process as the parent. - CHECK_EQ(process_id, render_manager_.current_host()->GetProcess()->GetID()); - // Initialize the RenderFrameHost for the new node. We always create child // frames in the same SiteInstance as the current frame, and they can swap to // a different one if they navigate away. diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h index 5974fd2..3b5e6ac 100644 --- a/content/browser/frame_host/frame_tree_node.h +++ b/content/browser/frame_host/frame_tree_node.h @@ -41,9 +41,7 @@ class CONTENT_EXPORT FrameTreeNode { bool IsMainFrame() const; - void AddChild(scoped_ptr<FrameTreeNode> child, - int process_id, - int frame_routing_id); + void AddChild(scoped_ptr<FrameTreeNode> child, int frame_routing_id); void RemoveChild(FrameTreeNode* child); // Clears process specific-state in this node to prepare for a new process. diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc index b4d41b2..a477d57 100644 --- a/content/browser/frame_host/frame_tree_unittest.cc +++ b/content/browser/frame_host/frame_tree_unittest.cc @@ -22,7 +22,6 @@ #include "testing/gtest/include/gtest/gtest.h" namespace content { - namespace { // Appends a description of the structure of the frame tree to |result|. @@ -103,8 +102,6 @@ class TreeWalkingWebContentsLogger : public WebContentsObserver { DISALLOW_COPY_AND_ASSIGN(TreeWalkingWebContentsLogger); }; -} // namespace - class FrameTreeTest : public RenderViewHostImplTestHarness { protected: // Prints a FrameTree, for easy assertions of the tree hierarchy. @@ -126,18 +123,17 @@ TEST_F(FrameTreeTest, Shape) { std::string no_children_node("no children node"); std::string deep_subtree("node with deep subtree"); - int process_id = root->current_frame_host()->GetProcess()->GetID(); ASSERT_EQ("1: []", GetTreeState(frame_tree)); // Simulate attaching a series of frames to build the frame tree. - frame_tree->AddFrame(root, process_id, 14, std::string()); - frame_tree->AddFrame(root, process_id, 15, std::string()); - frame_tree->AddFrame(root, process_id, 16, std::string()); + frame_tree->AddFrame(root, 14, std::string()); + frame_tree->AddFrame(root, 15, std::string()); + frame_tree->AddFrame(root, 16, std::string()); - frame_tree->AddFrame(root->child_at(0), process_id, 244, std::string()); - frame_tree->AddFrame(root->child_at(1), process_id, 255, no_children_node); - frame_tree->AddFrame(root->child_at(0), process_id, 245, std::string()); + frame_tree->AddFrame(root->child_at(0), 244, std::string()); + frame_tree->AddFrame(root->child_at(1), 255, no_children_node); + frame_tree->AddFrame(root->child_at(0), 245, std::string()); ASSERT_EQ("1: [14: [244: [], 245: []], " "15: [255 'no children node': []], " @@ -145,19 +141,18 @@ TEST_F(FrameTreeTest, Shape) { GetTreeState(frame_tree)); FrameTreeNode* child_16 = root->child_at(2); - frame_tree->AddFrame(child_16, process_id, 264, std::string()); - frame_tree->AddFrame(child_16, process_id, 265, std::string()); - frame_tree->AddFrame(child_16, process_id, 266, std::string()); - frame_tree->AddFrame(child_16, process_id, 267, deep_subtree); - frame_tree->AddFrame(child_16, process_id, 268, std::string()); + frame_tree->AddFrame(child_16, 264, std::string()); + frame_tree->AddFrame(child_16, 265, std::string()); + frame_tree->AddFrame(child_16, 266, std::string()); + frame_tree->AddFrame(child_16, 267, deep_subtree); + frame_tree->AddFrame(child_16, 268, std::string()); FrameTreeNode* child_267 = child_16->child_at(3); - frame_tree->AddFrame(child_267, process_id, 365, std::string()); - frame_tree->AddFrame(child_267->child_at(0), process_id, 455, std::string()); - frame_tree->AddFrame(child_267->child_at(0)->child_at(0), process_id, 555, + frame_tree->AddFrame(child_267, 365, std::string()); + frame_tree->AddFrame(child_267->child_at(0), 455, std::string()); + frame_tree->AddFrame(child_267->child_at(0)->child_at(0), 555, std::string()); + frame_tree->AddFrame(child_267->child_at(0)->child_at(0)->child_at(0), 655, std::string()); - frame_tree->AddFrame(child_267->child_at(0)->child_at(0)->child_at(0), - process_id, 655, std::string()); // Now that's it's fully built, verify the tree structure is as expected. ASSERT_EQ("1: [14: [244: [], 245: []], " @@ -232,18 +227,5 @@ TEST_F(FrameTreeTest, ObserverWalksTreeAfterCrash) { activity.GetLog()); } -// Ensure that frames are not added to the tree, if the process passed in -// is different than the process of the parent node. -TEST_F(FrameTreeTest, FailAddFrameWithWrongProcessId) { - FrameTree* frame_tree = contents()->GetFrameTree(); - FrameTreeNode* root = frame_tree->root(); - int process_id = root->current_frame_host()->GetProcess()->GetID(); - - ASSERT_EQ("1: []", GetTreeState(frame_tree)); - - // Simulate attaching a frame from mismatched process id. - ASSERT_FALSE(frame_tree->AddFrame(root, process_id + 1, 1, std::string())); - ASSERT_EQ("1: []", GetTreeState(frame_tree)); -} - +} // namespace } // namespace content diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index e4f174e..aae6568 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc @@ -610,17 +610,8 @@ void RenderFrameHostImpl::OnAddMessageToConsole( void RenderFrameHostImpl::OnCreateChildFrame(int new_routing_id, const std::string& frame_name) { - // It is possible that while a new RenderFrameHost was committed, the - // RenderFrame corresponding to this host sent an IPC message to create a - // frame and it is delivered after this host is swapped out. - // Ignore such messages, as we know this RenderFrameHost is going away. - if (rfh_state_ != RenderFrameHostImpl::STATE_DEFAULT) - return; - RenderFrameHostImpl* new_frame = frame_tree_->AddFrame( - frame_tree_node_, GetProcess()->GetID(), new_routing_id, frame_name); - if (!new_frame) - return; + frame_tree_node_, new_routing_id, frame_name); // We know that the RenderFrame has been created in this case, immediately // after the CreateChildFrame IPC was sent. diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc index c718043..b03471e 100644 --- a/content/browser/frame_host/render_frame_host_manager_unittest.cc +++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc @@ -148,29 +148,6 @@ class RenderViewHostDeletedObserver : public WebContentsObserver { DISALLOW_COPY_AND_ASSIGN(RenderViewHostDeletedObserver); }; -// This observer keeps track of the last created RenderFrameHost to allow tests -// to ensure that no RenderFrameHost objects are created when not expected. -class RenderFrameHostCreatedObserver : public WebContentsObserver { - public: - RenderFrameHostCreatedObserver(WebContents* web_contents) - : WebContentsObserver(web_contents), - created_(false) { - } - - virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) override { - created_ = true; - } - - bool created() { - return created_; - } - - private: - bool created_; - - DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver); -}; - // This observer keeps track of the last deleted RenderFrameHost to avoid // accessing it and causing use-after-free condition. class RenderFrameHostDeletedObserver : public WebContentsObserver { @@ -201,6 +178,7 @@ class RenderFrameHostDeletedObserver : public WebContentsObserver { DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver); }; + // This observer is used to check whether IPC messages are being filtered for // swapped out RenderFrameHost objects. It observes the plugin crash and favicon // update events, which the FilterMessagesWhileSwappedOut test simulates being @@ -589,47 +567,6 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) { EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID)); } -// Ensure that frames aren't added to the frame tree, if the message is coming -// from a process different than the parent frame's current RenderFrameHost -// process. Otherwise it is possible to have collisions of routing ids, as they -// are scoped per process. See https://crbug.com/415059. -TEST_F(RenderFrameHostManagerTest, DropCreateChildFrameWhileSwappedOut) { - const GURL kUrl1("http://foo.com"); - const GURL kUrl2("http://www.google.com/"); - - // Navigate to the first site. - NavigateActiveAndCommit(kUrl1); - TestRenderFrameHost* initial_rfh = contents()->GetMainFrame(); - { - RenderFrameHostCreatedObserver observer(contents()); - initial_rfh->OnCreateChildFrame( - initial_rfh->GetProcess()->GetNextRoutingID(), std::string()); - EXPECT_TRUE(observer.created()); - } - - // Create one more frame in the same SiteInstance where initial_rfh - // exists so that initial_rfh doesn't get deleted on navigation to another - // site. - initial_rfh->GetSiteInstance()->increment_active_frame_count(); - - // Navigate to a cross-site URL. - NavigateActiveAndCommit(kUrl2); - EXPECT_TRUE(initial_rfh->is_swapped_out()); - - TestRenderFrameHost* dest_rfh = contents()->GetMainFrame(); - ASSERT_TRUE(dest_rfh); - EXPECT_NE(initial_rfh, dest_rfh); - - { - // Since the old RFH is now swapped out, it shouldn't process any messages - // to create child frames. - RenderFrameHostCreatedObserver observer(contents()); - initial_rfh->OnCreateChildFrame( - initial_rfh->GetProcess()->GetNextRoutingID(), std::string()); - EXPECT_FALSE(observer.created()); - } -} - TEST_F(RenderFrameHostManagerTest, WhiteListSwapCompositorFrame) { TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost(); TestRenderWidgetHostView* swapped_out_rwhv = |