OLD | NEW |
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 Loading... |
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 Loading... |
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()); | |
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 ReusePendingDeleteRenderViewHostForSubframe) { |
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 Loading... |
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 |
OLD | NEW |