Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: content/browser/site_per_process_browsertest.cc

Issue 1886413002: Always swap with a replacement proxy in OnSwapOut. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix compile Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/site_per_process_browsertest.h" 5 #include "content/browser/site_per_process_browsertest.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
(...skipping 13 matching lines...) Expand all
24 #include "content/browser/frame_host/frame_tree.h" 24 #include "content/browser/frame_host/frame_tree.h"
25 #include "content/browser/frame_host/navigator.h" 25 #include "content/browser/frame_host/navigator.h"
26 #include "content/browser/frame_host/render_frame_proxy_host.h" 26 #include "content/browser/frame_host/render_frame_proxy_host.h"
27 #include "content/browser/frame_host/render_widget_host_view_child_frame.h" 27 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
28 #include "content/browser/gpu/compositor_util.h" 28 #include "content/browser/gpu/compositor_util.h"
29 #include "content/browser/loader/resource_dispatcher_host_impl.h" 29 #include "content/browser/loader/resource_dispatcher_host_impl.h"
30 #include "content/browser/renderer_host/input/synthetic_tap_gesture.h" 30 #include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
31 #include "content/browser/renderer_host/render_view_host_impl.h" 31 #include "content/browser/renderer_host/render_view_host_impl.h"
32 #include "content/browser/renderer_host/render_widget_host_input_event_router.h" 32 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
33 #include "content/browser/renderer_host/render_widget_host_view_aura.h" 33 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
34 #include "content/common/child_process_messages.h"
34 #include "content/common/frame_messages.h" 35 #include "content/common/frame_messages.h"
35 #include "content/common/input/synthetic_tap_gesture_params.h" 36 #include "content/common/input/synthetic_tap_gesture_params.h"
37 #include "content/common/input_messages.h"
36 #include "content/common/view_messages.h" 38 #include "content/common/view_messages.h"
37 #include "content/public/browser/cert_store.h" 39 #include "content/public/browser/cert_store.h"
38 #include "content/public/browser/notification_observer.h" 40 #include "content/public/browser/notification_observer.h"
39 #include "content/public/browser/notification_service.h" 41 #include "content/public/browser/notification_service.h"
40 #include "content/public/browser/notification_types.h" 42 #include "content/public/browser/notification_types.h"
41 #include "content/public/browser/resource_dispatcher_host.h" 43 #include "content/public/browser/resource_dispatcher_host.h"
42 #include "content/public/common/browser_side_navigation_policy.h" 44 #include "content/public/common/browser_side_navigation_policy.h"
43 #include "content/public/common/content_switches.h" 45 #include "content/public/common/content_switches.h"
44 #include "content/public/common/url_constants.h" 46 #include "content/public/common/url_constants.h"
45 #include "content/public/test/browser_test_utils.h" 47 #include "content/public/test/browser_test_utils.h"
(...skipping 4068 matching lines...) Expand 10 before | Expand all | Expand 10 after
4114 EXPECT_TRUE(ExecuteScriptAndExtractBool( 4116 EXPECT_TRUE(ExecuteScriptAndExtractBool(
4115 popup_root->child_at(0)->current_frame_host(), 4117 popup_root->child_at(0)->current_frame_host(),
4116 "window.domAutomationController.send(" 4118 "window.domAutomationController.send("
4117 " postToOpenerOfSibling('subframe2', 'msg', '*'));", 4119 " postToOpenerOfSibling('subframe2', 'msg', '*'));",
4118 &success)); 4120 &success));
4119 EXPECT_TRUE(success); 4121 EXPECT_TRUE(success);
4120 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 4122 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
4121 } 4123 }
4122 4124
4123 // Test for https://crbug.com/515302. Perform two navigations, A->B->A, and 4125 // Test for https://crbug.com/515302. Perform two navigations, A->B->A, and
4124 // delay the SwapOut ACK from the A->B navigation, so that the second B->A 4126 // drop the SwapOut ACK from the A->B navigation, so that the second B->A
4125 // navigation is initiated before the first page receives the SwapOut ACK. 4127 // navigation is initiated before the first page receives the SwapOut ACK.
4126 // Ensure that the RVH(A) that's pending deletion is not reused in that case. 4128 // Ensure that this doesn't crash and that the RVH(A) is not reused in that
4129 // case.
4127 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, 4130 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
4128 RenderViewHostPendingDeletionIsNotReused) { 4131 RenderViewHostIsNotReusedAfterDelayedSwapOutACK) {
4129 GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html")); 4132 GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
4130 NavigateToURL(shell(), a_url); 4133 NavigateToURL(shell(), a_url);
4131 4134
4132 FrameTreeNode* root = web_contents()->GetFrameTree()->root(); 4135 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
4133 RenderFrameHostImpl* rfh = root->current_frame_host(); 4136 RenderFrameHostImpl* rfh = root->current_frame_host();
4134 RenderViewHostImpl* rvh = rfh->render_view_host(); 4137 RenderViewHostImpl* rvh = rfh->render_view_host();
4135 int rvh_routing_id = rvh->GetRoutingID(); 4138 int rvh_routing_id = rvh->GetRoutingID();
4136 SiteInstanceImpl* site_instance = rfh->GetSiteInstance(); 4139 SiteInstanceImpl* site_instance = rfh->GetSiteInstance();
4137 RenderFrameDeletedObserver deleted_observer(rfh); 4140 RenderFrameDeletedObserver deleted_observer(rfh);
4138 4141
4139 // Install a BrowserMessageFilter to drop SwapOut ACK messages in A's 4142 // Install a BrowserMessageFilter to drop SwapOut ACK messages in A's
4140 // process. 4143 // process.
4141 scoped_refptr<SwapoutACKMessageFilter> filter = new SwapoutACKMessageFilter(); 4144 scoped_refptr<SwapoutACKMessageFilter> filter = new SwapoutACKMessageFilter();
4142 rfh->GetProcess()->AddFilter(filter.get()); 4145 rfh->GetProcess()->AddFilter(filter.get());
4143 rfh->DisableSwapOutTimerForTesting(); 4146 rfh->DisableSwapOutTimerForTesting();
4144 4147
4145 // Navigate to B. This must wait for DidCommitProvisionalLoad, as opposed to 4148 // Navigate to B. This must wait for DidCommitProvisionalLoad and not
4146 // DidStopLoading, since otherwise the SwapOut timer might call OnSwappedOut 4149 // DidStopLoading, so that the SwapOut timer doesn't call OnSwappedOut and
4147 // and destroy |rvh| before its pending deletion status is checked. 4150 // destroy |rfh| and |rvh| before they are checked in the test.
4148 GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html")); 4151 GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
4149 TestFrameNavigationObserver commit_observer(root); 4152 TestFrameNavigationObserver commit_observer(root);
4150 shell()->LoadURL(b_url); 4153 shell()->LoadURL(b_url);
4151 commit_observer.WaitForCommit(); 4154 commit_observer.WaitForCommit();
4152 EXPECT_FALSE(deleted_observer.deleted()); 4155 EXPECT_FALSE(deleted_observer.deleted());
4153 4156
4154 // Since the SwapOut ACK for A->B is dropped, the first page's 4157 // Since the SwapOut ACK for A->B is dropped, the first page's
4155 // RenderFrameHost and RenderViewHost should be pending deletion after the 4158 // RenderFrameHost should be pending deletion after the last navigation.
4156 // last navigation.
4157 EXPECT_FALSE(rfh->is_active()); 4159 EXPECT_FALSE(rfh->is_active());
4158 EXPECT_TRUE(root->render_manager()->IsViewPendingDeletion(rvh));
4159 4160
4160 // Wait for process A to exit so we can reinitialize it cleanly for the next 4161 // Wait for process A to exit so we can reinitialize it cleanly for the next
4161 // navigation. This can be removed once https://crbug.com/535246 is fixed. 4162 // navigation. Since process A doesn't have any active views, it will
4163 // initiate shutdown via ChildProcessHostMsg_ShutdownRequest. After process
4164 // A shuts down, the |rfh| and |rvh| should get destroyed via
4165 // OnRenderProcessGone.
4166 //
4167 // Not waiting for process shutdown here could lead to the |rvh| being
4168 // reused, now that there is no notion of pending deletion RenderViewHosts.
4169 // This would also be fine; however, the race in https://crbug.com/535246
4170 // still needs to be addressed and tested in that case.
4162 RenderProcessHostWatcher process_exit_observer( 4171 RenderProcessHostWatcher process_exit_observer(
4163 rvh->GetProcess(), 4172 rvh->GetProcess(),
4164 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 4173 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
4165 process_exit_observer.Wait(); 4174 process_exit_observer.Wait();
4166 4175
4176 // Verify that the RVH and RFH for A were cleaned up.
4177 EXPECT_FALSE(root->frame_tree()->GetRenderViewHost(site_instance));
4178 EXPECT_TRUE(deleted_observer.deleted());
4179
4167 // Start a navigation back to A and check that the RenderViewHost wasn't 4180 // Start a navigation back to A and check that the RenderViewHost wasn't
4168 // reused. 4181 // reused.
4169 TestNavigationObserver navigation_observer(shell()->web_contents()); 4182 TestNavigationObserver navigation_observer(shell()->web_contents());
4170 shell()->LoadURL(a_url); 4183 shell()->LoadURL(a_url);
4171 RenderViewHostImpl* pending_rvh = 4184 RenderViewHostImpl* pending_rvh =
4172 IsBrowserSideNavigationEnabled() 4185 IsBrowserSideNavigationEnabled()
4173 ? root->render_manager()->speculative_frame_host()->render_view_host() 4186 ? root->render_manager()->speculative_frame_host()->render_view_host()
4174 : root->render_manager()->pending_render_view_host(); 4187 : root->render_manager()->pending_render_view_host();
4175 EXPECT_EQ(site_instance, pending_rvh->GetSiteInstance()); 4188 EXPECT_EQ(site_instance, pending_rvh->GetSiteInstance());
4176 EXPECT_NE(rvh_routing_id, pending_rvh->GetRoutingID()); 4189 EXPECT_NE(rvh_routing_id, pending_rvh->GetRoutingID());
4177 4190
4178 // TODO(alexmos, creis): Once https://crbug.com/535246 is fixed and the
4179 // process_exit_observer is not needed above, we'll need to simulate that the
4180 // dropped SwapOut ACK message arrives now on the original RenderFrameHost,
4181 // causing it to be deleted.
4182 EXPECT_TRUE(deleted_observer.deleted());
alexmos 2016/04/22 05:09:34 I'm leaving dealing with issue 535246 (race trying
Charlie Reis 2016/04/22 19:11:34 Acknowledged.
4183
4184 // Make sure the last navigation finishes without crashing. 4191 // Make sure the last navigation finishes without crashing.
4185 navigation_observer.Wait(); 4192 navigation_observer.Wait();
4186 } 4193 }
4187 4194
4188 // Test for https://crbug.com/591478, where navigating to a cross-site page with 4195 // Test for https://crbug.com/591478, where navigating to a cross-site page with
4189 // a subframe on the old site could cause the old RenderViewHost (now pending 4196 // a subframe on the old site caused a crash while trying to reuse the old
4190 // deletion) to be reused. 4197 // RenderViewHost.
4191 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, 4198 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
4192 DontReusePendingDeleteRenderViewHostForSubframe) { 4199 DontReusePendingDeleteRenderViewHostForSubframe) {
4193 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html")); 4200 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
4194 EXPECT_TRUE(NavigateToURL(shell(), main_url)); 4201 EXPECT_TRUE(NavigateToURL(shell(), main_url));
4195 4202
4196 std::string script = 4203 std::string script =
4197 "window.onunload = function() { " 4204 "window.onunload = function() { "
4198 " var start = Date.now();" 4205 " var start = Date.now();"
4199 " while (Date.now() - start < 1000);" 4206 " while (Date.now() - start < 1000);"
4200 "}"; 4207 "}";
4201 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script)); 4208 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
4202 4209
4203 // Navigating cross-site with an iframe to the original site shouldn't crash. 4210 // Navigating cross-site with an iframe to the original site shouldn't crash.
4204 GURL second_url(embedded_test_server()->GetURL( 4211 GURL second_url(embedded_test_server()->GetURL(
4205 "b.com", "/cross_site_iframe_factory.html?b(a)")); 4212 "b.com", "/cross_site_iframe_factory.html?b(a)"));
4206 EXPECT_TRUE(NavigateToURL(shell(), second_url)); 4213 EXPECT_TRUE(NavigateToURL(shell(), second_url));
4207 4214
4208 // If the subframe is created while the main frame is pending deletion, then 4215 // If the subframe is created while the main frame is pending deletion, then
4209 // the RVH will be different. 4216 // the RVH will be reused. The main frame should've been swapped with a
4210 // TODO(creis, alexmos): Find a way to assert this that isn't flaky. For now, 4217 // proxy despite being the last active frame in the progress (see
4218 // https://crbug.com/568836), and this proxy should also be reused by the new
4219 // page.
4220 //
4221 // TODO(creis, alexmos): Find a way to assert this that isn't flaky. For now,
4211 // the test is just likely (not certain) to catch regressions by crashing. 4222 // the test is just likely (not certain) to catch regressions by crashing.
4212 } 4223 }
4213 4224
4214 // Check that when a cross-process frame acquires focus, the old focused frame 4225 // Check that when a cross-process frame acquires focus, the old focused frame
4215 // loses focus and fires blur events. Starting on a page with a cross-site 4226 // loses focus and fires blur events. Starting on a page with a cross-site
4216 // subframe, simulate mouse clicks to switch focus from root frame to subframe 4227 // subframe, simulate mouse clicks to switch focus from root frame to subframe
4217 // and then back to root frame. 4228 // and then back to root frame.
4218 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, 4229 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
4219 CrossProcessFocusChangeFiresBlurEvents) { 4230 CrossProcessFocusChangeFiresBlurEvents) {
4220 GURL main_url( 4231 GURL main_url(
(...skipping 1865 matching lines...) Expand 10 before | Expand all | Expand 10 after
6086 frame_observer.Wait(); 6097 frame_observer.Wait();
6087 EXPECT_EQ(b_url, root->current_url()); 6098 EXPECT_EQ(b_url, root->current_url());
6088 6099
6089 // Verify that the same RenderViewHost is preserved and that it is no longer 6100 // Verify that the same RenderViewHost is preserved and that it is no longer
6090 // in swapped out state. 6101 // in swapped out state.
6091 EXPECT_EQ(rvh, contents->GetFrameTree()->GetRenderViewHost( 6102 EXPECT_EQ(rvh, contents->GetFrameTree()->GetRenderViewHost(
6092 root->current_frame_host()->GetSiteInstance())); 6103 root->current_frame_host()->GetSiteInstance()));
6093 EXPECT_FALSE(rvh->is_swapped_out_); 6104 EXPECT_FALSE(rvh->is_swapped_out_);
6094 } 6105 }
6095 6106
6107 // Helper class to wait for a ChildProcessHostMsg_ShutdownRequest message to
6108 // arrive.
6109 class ShutdownRequestMessageFilter : public BrowserMessageFilter {
6110 public:
6111 ShutdownRequestMessageFilter()
6112 : BrowserMessageFilter(ChildProcessMsgStart),
6113 message_loop_runner_(new MessageLoopRunner) {}
6114
6115 bool OnMessageReceived(const IPC::Message& message) override {
6116 if (message.type() == ChildProcessHostMsg_ShutdownRequest::ID) {
6117 content::BrowserThread::PostTask(
6118 content::BrowserThread::UI, FROM_HERE,
6119 base::Bind(&ShutdownRequestMessageFilter::OnShutdownRequest, this));
6120 }
6121 return false;
6122 }
6123
6124 void OnShutdownRequest() { message_loop_runner_->Quit(); }
6125
6126 void Wait() { message_loop_runner_->Run(); }
6127
6128 private:
6129 ~ShutdownRequestMessageFilter() override {}
6130
6131 scoped_refptr<MessageLoopRunner> message_loop_runner_;
6132
6133 DISALLOW_COPY_AND_ASSIGN(ShutdownRequestMessageFilter);
6134 };
6135
6136 // Test for https://crbug.com/568836. From an A-embed-B page, navigate the
6137 // subframe from B to A. This cleans up the process for B, but the test delays
6138 // the browser side from killing the B process right away. This allows the
6139 // B process to process two ViewMsg_Close messages sent to the subframe's
6140 // RenderWidget and to the RenderView, in that order. In the bug, the latter
6141 // crashed while detaching the subframe's LocalFrame (triggered as part of
6142 // closing the RenderView), because this tried to access the subframe's
6143 // WebFrameWidget (from RenderFrameImpl::didChangeSelection), which had already
6144 // been cleared by the former.
6145 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
6146 CloseSubframeWidgetAndViewOnProcessExit) {
6147 GURL main_url(embedded_test_server()->GetURL(
6148 "a.com", "/cross_site_iframe_factory.html?a(b)"));
6149 EXPECT_TRUE(NavigateToURL(shell(), main_url));
6150
6151 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
6152 ->GetFrameTree()
6153 ->root();
6154
6155 // "Select all" in the subframe. The bug only happens if there's a selection
6156 // change, which triggers the path through didChangeSelection.
6157 root->child_at(0)->current_frame_host()->Send(new InputMsg_SelectAll(
6158 root->child_at(0)->current_frame_host()->GetRoutingID()));
6159
6160 // Prevent b.com process from terminating right away once the subframe
6161 // navigates away from b.com below. This is necessary so that the renderer
6162 // process has time to process the closings of RenderWidget and RenderView,
6163 // which is where the original bug was triggered. Incrementing worker
6164 // RefCount will cause RenderProcessHostImpl::Cleanup to forego process
6165 // termination.
6166 RenderProcessHost* subframe_process =
6167 root->child_at(0)->current_frame_host()->GetProcess();
6168 subframe_process->IncrementWorkerRefCount();
6169
6170 // Navigate the subframe away from b.com. Since this is the last active
6171 // frame in the b.com process, this causes the RenderWidget and RenderView to
6172 // be closed. If this succeeds without crashing, the renderer will release
6173 // the process and send a ChildProcessHostMsg_ShutdownRequest to the browser
6174 // process to ask whether it's ok to terminate. Thus, wait for this message
6175 // to ensure that the RenderView and widget were closed without crashing.
6176 scoped_refptr<ShutdownRequestMessageFilter> filter =
6177 new ShutdownRequestMessageFilter();
6178 subframe_process->AddFilter(filter.get());
6179 NavigateFrameToURL(root->child_at(0),
6180 embedded_test_server()->GetURL("a.com", "/title1.html"));
6181 filter->Wait();
6182
6183 // TODO(alexmos): Navigating the subframe back to b.com at this point would
6184 // trigger the race in https://crbug.com/535246, where the browser process
6185 // tries to reuse the b.com process thinking it's still initialized, whereas
6186 // the process has actually been destroyed by the renderer (but the browser
6187 // process hasn't heard the OnChannelError yet). This race will need to be
6188 // fixed.
6189
6190 subframe_process->DecrementWorkerRefCount();
6191 }
6192
6096 } // namespace content 6193 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698