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 <algorithm> | 7 #include <algorithm> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "content/browser/frame_host/render_widget_host_view_child_frame.h" | 22 #include "content/browser/frame_host/render_widget_host_view_child_frame.h" |
23 #include "content/browser/gpu/compositor_util.h" | 23 #include "content/browser/gpu/compositor_util.h" |
24 #include "content/browser/renderer_host/render_view_host_impl.h" | 24 #include "content/browser/renderer_host/render_view_host_impl.h" |
25 #include "content/browser/renderer_host/render_widget_host_input_event_router.h" | 25 #include "content/browser/renderer_host/render_widget_host_input_event_router.h" |
26 #include "content/browser/web_contents/web_contents_impl.h" | 26 #include "content/browser/web_contents/web_contents_impl.h" |
27 #include "content/common/frame_messages.h" | 27 #include "content/common/frame_messages.h" |
28 #include "content/common/view_messages.h" | 28 #include "content/common/view_messages.h" |
29 #include "content/public/browser/notification_observer.h" | 29 #include "content/public/browser/notification_observer.h" |
30 #include "content/public/browser/notification_service.h" | 30 #include "content/public/browser/notification_service.h" |
31 #include "content/public/browser/notification_types.h" | 31 #include "content/public/browser/notification_types.h" |
| 32 #include "content/public/browser/resource_dispatcher_host.h" |
32 #include "content/public/common/content_switches.h" | 33 #include "content/public/common/content_switches.h" |
33 #include "content/public/test/browser_test_utils.h" | 34 #include "content/public/test/browser_test_utils.h" |
34 #include "content/public/test/content_browser_test_utils.h" | 35 #include "content/public/test/content_browser_test_utils.h" |
35 #include "content/public/test/test_navigation_observer.h" | 36 #include "content/public/test/test_navigation_observer.h" |
36 #include "content/public/test/test_utils.h" | 37 #include "content/public/test/test_utils.h" |
37 #include "content/shell/browser/shell.h" | 38 #include "content/shell/browser/shell.h" |
38 #include "content/test/content_browser_test_utils_internal.h" | 39 #include "content/test/content_browser_test_utils_internal.h" |
39 #include "content/test/test_frame_navigation_observer.h" | 40 #include "content/test/test_frame_navigation_observer.h" |
40 #include "ipc/ipc_security_test_util.h" | 41 #include "ipc/ipc_security_test_util.h" |
41 #include "net/dns/mock_host_resolver.h" | 42 #include "net/dns/mock_host_resolver.h" |
(...skipping 4318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4360 | 4361 |
4361 // Make sure the a.com renderer does not crash. | 4362 // Make sure the a.com renderer does not crash. |
4362 int child_count = 0; | 4363 int child_count = 0; |
4363 EXPECT_TRUE(ExecuteScriptAndExtractInt( | 4364 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
4364 root->current_frame_host(), | 4365 root->current_frame_host(), |
4365 "domAutomationController.send(frames.length)", | 4366 "domAutomationController.send(frames.length)", |
4366 &child_count)); | 4367 &child_count)); |
4367 EXPECT_EQ(1, child_count); | 4368 EXPECT_EQ(1, child_count); |
4368 } | 4369 } |
4369 | 4370 |
| 4371 // This test ensures that the RenderFrame isn't leaked in the renderer process |
| 4372 // if a pending cross-process navigation is cancelled. The test works by trying |
| 4373 // to create a new RenderFrame with the same routing id. If there is an |
| 4374 // entry with the same routing ID, a CHECK is hit and the process crashes. |
| 4375 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 4376 SubframePendingAndBackToSameSiteInstance) { |
| 4377 GURL main_url(embedded_test_server()->GetURL( |
| 4378 "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 4379 NavigateToURL(shell(), main_url); |
| 4380 |
| 4381 // Capture the FrameTreeNode this test will be navigating. |
| 4382 FrameTreeNode* node = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| 4383 ->GetFrameTree() |
| 4384 ->root() |
| 4385 ->child_at(0); |
| 4386 EXPECT_TRUE(node); |
| 4387 EXPECT_NE(node->current_frame_host()->GetSiteInstance(), |
| 4388 node->parent()->current_frame_host()->GetSiteInstance()); |
| 4389 |
| 4390 // Navigate to the site of the parent, but to a page that will not commit. |
| 4391 GURL same_site_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 4392 NavigationStallDelegate stall_delegate(same_site_url); |
| 4393 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate); |
| 4394 { |
| 4395 NavigationController::LoadURLParams params(same_site_url); |
| 4396 params.transition_type = ui::PAGE_TRANSITION_LINK; |
| 4397 params.frame_tree_node_id = node->frame_tree_node_id(); |
| 4398 node->navigator()->GetController()->LoadURLWithParams(params); |
| 4399 } |
| 4400 |
| 4401 // Grab the routing id of the pending RenderFrameHost and set up a process |
| 4402 // observer to ensure there is no crash when a new RenderFrame creation is |
| 4403 // attempted. |
| 4404 RenderProcessHost* process = |
| 4405 node->render_manager()->pending_frame_host()->GetProcess(); |
| 4406 RenderProcessHostWatcher watcher( |
| 4407 process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 4408 int frame_routing_id = |
| 4409 node->render_manager()->pending_frame_host()->GetRoutingID(); |
| 4410 int proxy_routing_id = |
| 4411 node->render_manager()->GetProxyToParent()->GetRoutingID(); |
| 4412 |
| 4413 // Now go to c.com so the navigation to a.com is cancelled and send an IPC |
| 4414 // to create a new RenderFrame with the routing id of the previously pending |
| 4415 // one. |
| 4416 NavigateFrameToURL(node, |
| 4417 embedded_test_server()->GetURL("c.com", "/title2.html")); |
| 4418 { |
| 4419 FrameMsg_NewFrame_Params params; |
| 4420 params.routing_id = frame_routing_id; |
| 4421 params.proxy_routing_id = proxy_routing_id; |
| 4422 params.opener_routing_id = MSG_ROUTING_NONE; |
| 4423 params.parent_routing_id = |
| 4424 shell()->web_contents()->GetMainFrame()->GetRoutingID(); |
| 4425 params.previous_sibling_routing_id = MSG_ROUTING_NONE; |
| 4426 params.widget_params.routing_id = MSG_ROUTING_NONE; |
| 4427 params.widget_params.hidden = true; |
| 4428 |
| 4429 process->Send(new FrameMsg_NewFrame(params)); |
| 4430 } |
| 4431 |
| 4432 // The test must wait for the process to exit, but if there is no leak, the |
| 4433 // RenderFrame will be properly created and there will be no crash. |
| 4434 // Therefore, navigate the main frame to completely different site, which |
| 4435 // will cause the original process to exit cleanly. |
| 4436 EXPECT_TRUE(NavigateToURL( |
| 4437 shell(), embedded_test_server()->GetURL("d.com", "/title3.html"))); |
| 4438 watcher.Wait(); |
| 4439 EXPECT_TRUE(watcher.did_exit_normally()); |
| 4440 |
| 4441 ResourceDispatcherHost::Get()->SetDelegate(nullptr); |
| 4442 } |
| 4443 |
| 4444 // This test ensures that the RenderFrame isn't leaked in the renderer process |
| 4445 // when a remote parent detaches a child frame. The test works by trying |
| 4446 // to create a new RenderFrame with the same routing id. If there is an |
| 4447 // entry with the same routing ID, a CHECK is hit and the process crashes. |
| 4448 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ParentDetachRemoteChild) { |
| 4449 GURL main_url(embedded_test_server()->GetURL( |
| 4450 "a.com", "/cross_site_iframe_factory.html?a(b,b)")); |
| 4451 NavigateToURL(shell(), main_url); |
| 4452 |
| 4453 WebContentsImpl* web_contents = |
| 4454 static_cast<WebContentsImpl*>(shell()->web_contents()); |
| 4455 EXPECT_EQ(2U, web_contents->GetFrameTree()->root()->child_count()); |
| 4456 |
| 4457 // Capture the FrameTreeNode this test will be navigating. |
| 4458 FrameTreeNode* node = web_contents->GetFrameTree()->root()->child_at(0); |
| 4459 EXPECT_TRUE(node); |
| 4460 EXPECT_NE(node->current_frame_host()->GetSiteInstance(), |
| 4461 node->parent()->current_frame_host()->GetSiteInstance()); |
| 4462 |
| 4463 // Grab the routing id of the first child RenderFrameHost and set up a process |
| 4464 // observer to ensure there is no crash when a new RenderFrame creation is |
| 4465 // attempted. |
| 4466 RenderProcessHost* process = node->current_frame_host()->GetProcess(); |
| 4467 RenderProcessHostWatcher watcher( |
| 4468 process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 4469 int frame_routing_id = node->current_frame_host()->GetRoutingID(); |
| 4470 int widget_routing_id = |
| 4471 node->current_frame_host()->GetRenderWidgetHost()->GetRoutingID(); |
| 4472 int parent_routing_id = |
| 4473 node->parent()->render_manager()->GetRoutingIdForSiteInstance( |
| 4474 node->current_frame_host()->GetSiteInstance()); |
| 4475 |
| 4476 // Have the parent frame remove the child frame from its DOM. This should |
| 4477 // result in the child RenderFrame being deleted in the remote process. |
| 4478 EXPECT_TRUE(ExecuteScript(web_contents, |
| 4479 "document.body.removeChild(" |
| 4480 "document.querySelectorAll('iframe')[0])")); |
| 4481 EXPECT_EQ(1U, web_contents->GetFrameTree()->root()->child_count()); |
| 4482 |
| 4483 { |
| 4484 FrameMsg_NewFrame_Params params; |
| 4485 params.routing_id = frame_routing_id; |
| 4486 params.proxy_routing_id = MSG_ROUTING_NONE; |
| 4487 params.opener_routing_id = MSG_ROUTING_NONE; |
| 4488 params.parent_routing_id = parent_routing_id; |
| 4489 params.previous_sibling_routing_id = MSG_ROUTING_NONE; |
| 4490 params.widget_params.routing_id = widget_routing_id; |
| 4491 params.widget_params.hidden = true; |
| 4492 |
| 4493 process->Send(new FrameMsg_NewFrame(params)); |
| 4494 } |
| 4495 |
| 4496 // The test must wait for the process to exit, but if there is no leak, the |
| 4497 // RenderFrame will be properly created and there will be no crash. |
| 4498 // Therefore, navigate the remaining subframe to completely different site, |
| 4499 // which will cause the original process to exit cleanly. |
| 4500 NavigateFrameToURL( |
| 4501 web_contents->GetFrameTree()->root()->child_at(0), |
| 4502 embedded_test_server()->GetURL("d.com", "/title3.html")); |
| 4503 watcher.Wait(); |
| 4504 EXPECT_TRUE(watcher.did_exit_normally()); |
| 4505 } |
| 4506 |
4370 } // namespace content | 4507 } // namespace content |
OLD | NEW |