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

Side by Side Diff: content/browser/frame_host/render_frame_host_manager.cc

Issue 1309043003: Handle frame openers in the same FrameTree when navigating subframes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@opener-cycle-detection
Patch Set: Add comment for the DCHECK Created 5 years, 3 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/frame_host/render_frame_host_manager.h" 5 #include "content/browser/frame_host/render_frame_host_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 // Instruct the destination render frame host to set up a Mojo connection 411 // Instruct the destination render frame host to set up a Mojo connection
412 // with the new render frame if necessary. Note that this call needs to 412 // with the new render frame if necessary. Note that this call needs to
413 // occur before initializing the RenderView; the flow of creating the 413 // occur before initializing the RenderView; the flow of creating the
414 // RenderView can cause browser-side code to execute that expects the this 414 // RenderView can cause browser-side code to execute that expects the this
415 // RFH's ServiceRegistry to be initialized (e.g., if the site is a WebUI 415 // RFH's ServiceRegistry to be initialized (e.g., if the site is a WebUI
416 // site that is handled via Mojo, then Mojo WebUI code in //chrome will 416 // site that is handled via Mojo, then Mojo WebUI code in //chrome will
417 // add a service to this RFH's ServiceRegistry). 417 // add a service to this RFH's ServiceRegistry).
418 dest_render_frame_host->SetUpMojoIfNeeded(); 418 dest_render_frame_host->SetUpMojoIfNeeded();
419 419
420 // Recreate the opener chain. 420 // Recreate the opener chain.
421 CreateOpenerProxiesIfNeeded(dest_render_frame_host->GetSiteInstance()); 421 CreateOpenerProxies(dest_render_frame_host->GetSiteInstance(),
422 frame_tree_node_);
422 if (!InitRenderView(dest_render_frame_host->render_view_host(), 423 if (!InitRenderView(dest_render_frame_host->render_view_host(),
423 MSG_ROUTING_NONE, 424 MSG_ROUTING_NONE,
424 frame_tree_node_->IsMainFrame())) 425 frame_tree_node_->IsMainFrame()))
425 return nullptr; 426 return nullptr;
426 427
427 // Now that we've created a new renderer, be sure to hide it if it isn't 428 // Now that we've created a new renderer, be sure to hide it if it isn't
428 // our primary one. Otherwise, we might crash if we try to call Show() 429 // our primary one. Otherwise, we might crash if we try to call Show()
429 // on it later. 430 // on it later.
430 if (dest_render_frame_host != render_frame_host_) { 431 if (dest_render_frame_host != render_frame_host_) {
431 if (dest_render_frame_host->GetView()) 432 if (dest_render_frame_host->GetView())
(...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after
1036 } 1037 }
1037 } 1038 }
1038 DCHECK(navigation_rfh && 1039 DCHECK(navigation_rfh &&
1039 (navigation_rfh == render_frame_host_.get() || 1040 (navigation_rfh == render_frame_host_.get() ||
1040 navigation_rfh == speculative_render_frame_host_.get())); 1041 navigation_rfh == speculative_render_frame_host_.get()));
1041 1042
1042 // If the RenderFrame that needs to navigate is not live (its process was just 1043 // If the RenderFrame that needs to navigate is not live (its process was just
1043 // created or has crashed), initialize it. 1044 // created or has crashed), initialize it.
1044 if (!navigation_rfh->IsRenderFrameLive()) { 1045 if (!navigation_rfh->IsRenderFrameLive()) {
1045 // Recreate the opener chain. 1046 // Recreate the opener chain.
1046 CreateOpenerProxiesIfNeeded(navigation_rfh->GetSiteInstance()); 1047 CreateOpenerProxies(navigation_rfh->GetSiteInstance(), frame_tree_node_);
1047 if (!InitRenderView(navigation_rfh->render_view_host(), MSG_ROUTING_NONE, 1048 if (!InitRenderView(navigation_rfh->render_view_host(), MSG_ROUTING_NONE,
1048 frame_tree_node_->IsMainFrame())) { 1049 frame_tree_node_->IsMainFrame())) {
1049 return nullptr; 1050 return nullptr;
1050 } 1051 }
1051 1052
1052 if (navigation_rfh == render_frame_host_) { 1053 if (navigation_rfh == render_frame_host_) {
1053 // TODO(nasko): This is a very ugly hack. The Chrome extensions process 1054 // TODO(nasko): This is a very ugly hack. The Chrome extensions process
1054 // manager still uses NotificationService and expects to see a 1055 // manager still uses NotificationService and expects to see a
1055 // RenderViewHost changed notification after WebContents and 1056 // RenderViewHost changed notification after WebContents and
1056 // RenderFrameHostManager are completely initialized. This should be 1057 // RenderFrameHostManager are completely initialized. This should be
(...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after
1571 1572
1572 // Create a non-swapped-out RFH with the given opener. 1573 // Create a non-swapped-out RFH with the given opener.
1573 pending_render_frame_host_ = CreateRenderFrame( 1574 pending_render_frame_host_ = CreateRenderFrame(
1574 new_instance, pending_web_ui(), create_render_frame_flags, nullptr); 1575 new_instance, pending_web_ui(), create_render_frame_flags, nullptr);
1575 } 1576 }
1576 1577
1577 void RenderFrameHostManager::CreateProxiesForNewRenderFrameHost( 1578 void RenderFrameHostManager::CreateProxiesForNewRenderFrameHost(
1578 SiteInstance* old_instance, 1579 SiteInstance* old_instance,
1579 SiteInstance* new_instance) { 1580 SiteInstance* new_instance) {
1580 // Only create opener proxies if they are in the same BrowsingInstance. 1581 // Only create opener proxies if they are in the same BrowsingInstance.
1581 if (new_instance->IsRelatedSiteInstance(old_instance)) 1582 if (new_instance->IsRelatedSiteInstance(old_instance)) {
1582 CreateOpenerProxiesIfNeeded(new_instance); 1583 CreateOpenerProxies(new_instance, frame_tree_node_);
1583 if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) { 1584 } else if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
1584 // Ensure that the frame tree has RenderFrameProxyHosts for the new 1585 // Ensure that the frame tree has RenderFrameProxyHosts for the
1585 // SiteInstance in all nodes except the current one. We do this for all 1586 // new SiteInstance in all nodes except the current one. We do this for
1586 // frames in the tree, whether they are in the same BrowsingInstance or not. 1587 // all frames in the tree, whether they are in the same BrowsingInstance or
1587 // We will still check whether two frames are in the same BrowsingInstance 1588 // not. If |new_instance| is in the same BrowsingInstance as
1588 // before we allow them to interact (e.g., postMessage). 1589 // |old_instance|, this will be done as part of CreateOpenerProxies above;
1590 // otherwise, we do this here. We will still check whether two frames are
1591 // in the same BrowsingInstance before we allow them to interact (e.g.,
1592 // postMessage).
1589 frame_tree_node_->frame_tree()->CreateProxiesForSiteInstance( 1593 frame_tree_node_->frame_tree()->CreateProxiesForSiteInstance(
1590 frame_tree_node_, new_instance); 1594 frame_tree_node_, new_instance);
1591 } 1595 }
1592 } 1596 }
1593 1597
1594 void RenderFrameHostManager::CreateProxiesForNewNamedFrame() { 1598 void RenderFrameHostManager::CreateProxiesForNewNamedFrame() {
1595 if (!SiteIsolationPolicy::AreCrossProcessFramesPossible()) 1599 if (!SiteIsolationPolicy::AreCrossProcessFramesPossible())
1596 return; 1600 return;
1597 1601
1598 DCHECK(!frame_tree_node_->frame_name().empty()); 1602 DCHECK(!frame_tree_node_->frame_name().empty());
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
1876 } 1880 }
1877 1881
1878 void RenderFrameHostManager::EnsureRenderViewInitialized( 1882 void RenderFrameHostManager::EnsureRenderViewInitialized(
1879 RenderViewHostImpl* render_view_host, 1883 RenderViewHostImpl* render_view_host,
1880 SiteInstance* instance) { 1884 SiteInstance* instance) {
1881 DCHECK(frame_tree_node_->IsMainFrame()); 1885 DCHECK(frame_tree_node_->IsMainFrame());
1882 1886
1883 if (render_view_host->IsRenderViewLive()) 1887 if (render_view_host->IsRenderViewLive())
1884 return; 1888 return;
1885 1889
1886 // Recreate the opener chain.
1887 CreateOpenerProxiesIfNeeded(instance);
1888
1889 // If the proxy in |instance| doesn't exist, this RenderView is not swapped 1890 // If the proxy in |instance| doesn't exist, this RenderView is not swapped
1890 // out and shouldn't be reinitialized here. 1891 // out and shouldn't be reinitialized here.
1891 RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance); 1892 RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
1892 if (!proxy) 1893 if (!proxy)
1893 return; 1894 return;
1894 1895
1895 InitRenderView(render_view_host, proxy->GetRoutingID(), false); 1896 InitRenderView(render_view_host, proxy->GetRoutingID(), false);
1896 proxy->set_render_frame_proxy_created(true); 1897 proxy->set_render_frame_proxy_created(true);
1897 } 1898 }
1898 1899
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after
2453 return proxy_hosts_->Get(instance->GetId()); 2454 return proxy_hosts_->Get(instance->GetId());
2454 } 2455 }
2455 2456
2456 std::map<int, RenderFrameProxyHost*> 2457 std::map<int, RenderFrameProxyHost*>
2457 RenderFrameHostManager::GetAllProxyHostsForTesting() { 2458 RenderFrameHostManager::GetAllProxyHostsForTesting() {
2458 std::map<int, RenderFrameProxyHost*> result; 2459 std::map<int, RenderFrameProxyHost*> result;
2459 result.insert(proxy_hosts_->begin(), proxy_hosts_->end()); 2460 result.insert(proxy_hosts_->begin(), proxy_hosts_->end());
2460 return result; 2461 return result;
2461 } 2462 }
2462 2463
2463 void RenderFrameHostManager::CreateOpenerProxiesIfNeeded(
2464 SiteInstance* instance) {
2465 FrameTreeNode* opener = frame_tree_node_->opener();
2466 if (!opener)
2467 return;
2468
2469 // TODO(alexmos): This should process all openers in the current frame tree,
2470 // not just current node's opener.
2471
2472 // Create proxies for the opener chain.
2473 opener->render_manager()->CreateOpenerProxies(instance);
2474 }
2475
2476 void RenderFrameHostManager::CollectOpenerFrameTrees( 2464 void RenderFrameHostManager::CollectOpenerFrameTrees(
2477 std::vector<FrameTree*>* opener_frame_trees, 2465 std::vector<FrameTree*>* opener_frame_trees,
2478 base::hash_set<FrameTreeNode*>* nodes_with_back_links) { 2466 base::hash_set<FrameTreeNode*>* nodes_with_back_links) {
2479 CHECK(opener_frame_trees); 2467 CHECK(opener_frame_trees);
2480 opener_frame_trees->push_back(frame_tree_node_->frame_tree()); 2468 opener_frame_trees->push_back(frame_tree_node_->frame_tree());
2481 2469
2482 size_t visited_index = 0; 2470 size_t visited_index = 0;
2483 while (visited_index < opener_frame_trees->size()) { 2471 while (visited_index < opener_frame_trees->size()) {
2484 FrameTree* frame_tree = (*opener_frame_trees)[visited_index]; 2472 FrameTree* frame_tree = (*opener_frame_trees)[visited_index];
2485 visited_index++; 2473 visited_index++;
2486 frame_tree->ForEach(base::Bind(&OpenerForFrameTreeNode, visited_index, 2474 frame_tree->ForEach(base::Bind(&OpenerForFrameTreeNode, visited_index,
2487 opener_frame_trees, nodes_with_back_links)); 2475 opener_frame_trees, nodes_with_back_links));
2488 } 2476 }
2489 } 2477 }
2490 2478
2491 void RenderFrameHostManager::CreateOpenerProxies(SiteInstance* instance) { 2479 void RenderFrameHostManager::CreateOpenerProxies(
2480 SiteInstance* instance,
2481 FrameTreeNode* skip_this_node) {
2492 std::vector<FrameTree*> opener_frame_trees; 2482 std::vector<FrameTree*> opener_frame_trees;
2493 base::hash_set<FrameTreeNode*> nodes_with_back_links; 2483 base::hash_set<FrameTreeNode*> nodes_with_back_links;
2494 2484
2495 CollectOpenerFrameTrees(&opener_frame_trees, &nodes_with_back_links); 2485 CollectOpenerFrameTrees(&opener_frame_trees, &nodes_with_back_links);
2496 2486
2497 // Create opener proxies for frame trees, processing furthest openers from 2487 // Create opener proxies for frame trees, processing furthest openers from
2498 // this node first and this node last. In the common case without cycles, 2488 // this node first and this node last. In the common case without cycles,
2499 // this will ensure that each tree's openers are created before the tree's 2489 // this will ensure that each tree's openers are created before the tree's
2500 // nodes need to reference them. 2490 // nodes need to reference them.
2501 for (int i = opener_frame_trees.size() - 1; i >= 0; i--) { 2491 for (int i = opener_frame_trees.size() - 1; i >= 0; i--) {
2502 opener_frame_trees[i] 2492 opener_frame_trees[i]
2503 ->root() 2493 ->root()
2504 ->render_manager() 2494 ->render_manager()
2505 ->CreateOpenerProxiesForFrameTree(instance); 2495 ->CreateOpenerProxiesForFrameTree(instance, skip_this_node);
2506 } 2496 }
2507 2497
2508 // Set openers for nodes in |nodes_with_back_links| in a second pass. 2498 // Set openers for nodes in |nodes_with_back_links| in a second pass.
2509 // The proxies created at these FrameTreeNodes in 2499 // The proxies created at these FrameTreeNodes in
2510 // CreateOpenerProxiesForFrameTree won't have their opener routing ID 2500 // CreateOpenerProxiesForFrameTree won't have their opener routing ID
2511 // available when created due to cycles or back links in the opener chain. 2501 // available when created due to cycles or back links in the opener chain.
2512 // They must have their openers updated as a separate step after proxy 2502 // They must have their openers updated as a separate step after proxy
2513 // creation. 2503 // creation.
2514 for (const auto& node : nodes_with_back_links) { 2504 for (const auto& node : nodes_with_back_links) {
2515 RenderFrameProxyHost* proxy = 2505 RenderFrameProxyHost* proxy =
2516 node->render_manager()->GetRenderFrameProxyHost(instance); 2506 node->render_manager()->GetRenderFrameProxyHost(instance);
2517 // If there is no proxy, the cycle may involve nodes in the same process, 2507 // If there is no proxy, the cycle may involve nodes in the same process,
2518 // or, if this is a subframe, --site-per-process may be off. Either way, 2508 // or, if this is a subframe, --site-per-process may be off. Either way,
2519 // there's nothing more to do. 2509 // there's nothing more to do.
2520 if (!proxy) 2510 if (!proxy)
2521 continue; 2511 continue;
2522 2512
2523 int opener_routing_id = 2513 int opener_routing_id =
2524 node->render_manager()->GetOpenerRoutingID(instance); 2514 node->render_manager()->GetOpenerRoutingID(instance);
2525 DCHECK_NE(opener_routing_id, MSG_ROUTING_NONE); 2515 DCHECK_NE(opener_routing_id, MSG_ROUTING_NONE);
2526 proxy->Send(new FrameMsg_UpdateOpener(proxy->GetRoutingID(), 2516 proxy->Send(new FrameMsg_UpdateOpener(proxy->GetRoutingID(),
2527 opener_routing_id)); 2517 opener_routing_id));
2528 } 2518 }
2529 } 2519 }
2530 2520
2531 void RenderFrameHostManager::CreateOpenerProxiesForFrameTree( 2521 void RenderFrameHostManager::CreateOpenerProxiesForFrameTree(
2532 SiteInstance* instance) { 2522 SiteInstance* instance,
2533 // If any of the RenderViewHosts (current, pending, or swapped out) for this 2523 FrameTreeNode* skip_this_node) {
2534 // FrameTree has the same SiteInstance, then we can return early, since 2524 // Currently, this function is only called on main frames. It should
2535 // proxies for other nodes in the tree should also exist (when in 2525 // actually work correctly for subframes as well, so if that need ever
2536 // site-per-process mode). An exception is if we are in 2526 // arises, it should be sufficient to remove this DCHECK.
2537 // IsSwappedOutStateForbidden mode and find a pending RenderViewHost: in this 2527 DCHECK(frame_tree_node_->IsMainFrame());
2538 // case, we should still create a proxy, which will allow communicating with 2528
2539 // the opener until the pending RenderView commits, or if the pending 2529 if (frame_tree_node_ == skip_this_node)
2540 // navigation is canceled.
2541 FrameTree* frame_tree = frame_tree_node_->frame_tree();
2542 RenderViewHostImpl* rvh = frame_tree->GetRenderViewHost(instance);
2543 bool need_proxy_for_pending_rvh =
2544 SiteIsolationPolicy::IsSwappedOutStateForbidden() &&
2545 (rvh == pending_render_view_host());
2546 if (rvh && rvh->IsRenderViewLive() && !need_proxy_for_pending_rvh)
2547 return; 2530 return;
2548 2531
2549 if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) { 2532 FrameTree* frame_tree = frame_tree_node_->frame_tree();
2550 // Ensure that all the nodes in the opener's frame tree have 2533 if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
2551 // RenderFrameProxyHosts for the new SiteInstance. 2534 // Ensure that all the nodes in the opener's FrameTree have
2552 frame_tree->CreateProxiesForSiteInstance(nullptr, instance); 2535 // RenderFrameProxyHosts for the new SiteInstance. Only pass the node to
2553 } else if (rvh && !rvh->IsRenderViewLive()) { 2536 // be skipped if it's in the same FrameTree.
2554 EnsureRenderViewInitialized(rvh, instance); 2537 if (skip_this_node && skip_this_node->frame_tree() != frame_tree)
2538 skip_this_node = nullptr;
2539 frame_tree->CreateProxiesForSiteInstance(skip_this_node, instance);
2555 } else { 2540 } else {
2556 // Create a swapped out RenderView in the given SiteInstance if none exists, 2541 // If any of the RenderViewHosts (current, pending, or swapped out) for this
2557 // setting its opener to the given route_id. Since the opener can point to 2542 // FrameTree has the same SiteInstance, then we can return early and reuse
2558 // a subframe, do this on the root frame of the opener's frame tree. 2543 // them. An exception is if we are in IsSwappedOutStateForbidden mode and
2559 // Return the new view's route_id. 2544 // find a pending RenderViewHost: in this case, we should still create a
2560 frame_tree->root()->render_manager()-> 2545 // proxy, which will allow communicating with the opener until the pending
2561 CreateRenderFrame(instance, nullptr, 2546 // RenderView commits, or if the pending navigation is canceled.
2562 CREATE_RF_FOR_MAIN_FRAME_NAVIGATION | 2547 RenderViewHostImpl* rvh = frame_tree->GetRenderViewHost(instance);
2563 CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, 2548 bool need_proxy_for_pending_rvh =
2564 nullptr); 2549 SiteIsolationPolicy::IsSwappedOutStateForbidden() &&
2550 (rvh == pending_render_view_host());
2551 if (rvh && rvh->IsRenderViewLive() && !need_proxy_for_pending_rvh)
2552 return;
2553
2554 if (rvh && !rvh->IsRenderViewLive()) {
2555 EnsureRenderViewInitialized(rvh, instance);
2556 } else {
2557 // Create a swapped out RenderView in the given SiteInstance if none
2558 // exists. Since an opener can point to a subframe, do this on the root
2559 // frame of the current opener's frame tree.
2560 frame_tree->root()->render_manager()->
2561 CreateRenderFrame(instance, nullptr,
2562 CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
2563 CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN,
2564 nullptr);
2565 }
2565 } 2566 }
2566 } 2567 }
2567 2568
2568 int RenderFrameHostManager::GetOpenerRoutingID(SiteInstance* instance) { 2569 int RenderFrameHostManager::GetOpenerRoutingID(SiteInstance* instance) {
2569 if (!frame_tree_node_->opener()) 2570 if (!frame_tree_node_->opener())
2570 return MSG_ROUTING_NONE; 2571 return MSG_ROUTING_NONE;
2571 2572
2572 return frame_tree_node_->opener() 2573 return frame_tree_node_->opener()
2573 ->render_manager() 2574 ->render_manager()
2574 ->GetRoutingIdForSiteInstance(instance); 2575 ->GetRoutingIdForSiteInstance(instance);
2575 } 2576 }
2576 2577
2577 } // namespace content 2578 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/frame_host/render_frame_host_manager.h ('k') | content/browser/frame_host/render_frame_proxy_host.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698