Chromium Code Reviews| Index: content/browser/frame_host/render_frame_host_manager.cc |
| diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc |
| index 84823ccb8735db8b65904e3ce70fe0f894fffa94..125717ff72049cc6b07cb4f1ffa14e9eef14ff56 100644 |
| --- a/content/browser/frame_host/render_frame_host_manager.cc |
| +++ b/content/browser/frame_host/render_frame_host_manager.cc |
| @@ -336,6 +336,7 @@ void RenderFrameHostManager::OnCrossSiteResponse( |
| const Referrer& referrer, |
| PageTransition page_transition, |
| bool should_replace_current_entry) { |
| + LOG(ERROR) << "RFHM::OnCrossSiteResponse[" << this << "]"; |
| // This should be called either when the pending RFH is ready to commit or |
| // when we realize that the current RFH's request requires a transfer. |
| DCHECK(pending_render_frame_host == pending_render_frame_host_ || |
| @@ -537,7 +538,10 @@ void RenderFrameHostManager::SwapOutOldPage() { |
| RenderFrameProxyHost* proxy = new RenderFrameProxyHost( |
| render_frame_host_->GetSiteInstance(), frame_tree_node_); |
| - proxy_hosts_[render_frame_host_->GetSiteInstance()->GetId()] = proxy; |
| + std::pair<RenderFrameProxyHostMap::iterator, bool> result = |
| + proxy_hosts_.insert(std::make_pair( |
| + render_frame_host_->GetSiteInstance()->GetId(), proxy)); |
| + CHECK(result.second) << "Inserting a duplicate item."; |
| // Tell the old frame it is being swapped out. This will fire the unload |
| // handler in the background (without firing the beforeunload handler a second |
| @@ -880,24 +884,17 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost( |
| if (frame_routing_id == MSG_ROUTING_NONE) |
| frame_routing_id = site_instance->GetProcess()->GetNextRoutingID(); |
| - // Create a RVH for main frames, or find the existing one for subframes. |
| + // Create a RVH for the new frame or find an existing one. |
| FrameTree* frame_tree = frame_tree_node_->frame_tree(); |
| - RenderViewHostImpl* render_view_host = NULL; |
| - if (frame_tree_node_->IsMainFrame()) { |
| - render_view_host = frame_tree->CreateRenderViewHostForMainFrame( |
| + RenderViewHostImpl* render_view_host = |
| + frame_tree->GetRenderViewHost(site_instance); |
| + LOG(ERROR) << "RFHM::CreateRenderFrameHost[" << this << "]:" |
| + << " routing_id: " << frame_routing_id |
| + << ", rvh: " << render_view_host |
| + << ", swapped_out: " << swapped_out; |
| + if (!render_view_host) { |
| + render_view_host = frame_tree->CreateRenderViewHost( |
| site_instance, view_routing_id, frame_routing_id, swapped_out, hidden); |
| - } else { |
| - render_view_host = frame_tree->GetRenderViewHostForSubFrame(site_instance); |
| - |
| - // If we haven't found a RVH for a subframe RFH, it's because we currently |
| - // do not create top-level RFHs for pending subframe navigations. Create |
| - // the RVH here for now. |
| - // TODO(creis): Mirror the frame tree so this check isn't necessary. |
| - if (!render_view_host) { |
| - render_view_host = frame_tree->CreateRenderViewHostForMainFrame( |
| - site_instance, view_routing_id, frame_routing_id, swapped_out, |
| - hidden); |
| - } |
| } |
| // TODO(creis): Pass hidden to RFH. |
| @@ -919,6 +916,15 @@ int RenderFrameHostManager::CreateRenderFrame( |
| CHECK(instance); |
| DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden. |
| + LOG(ERROR) << "RFHM::CreateRenderFrame[" << this << "]:" |
| + << " site:" << instance->GetSiteURL() << ", swapped:" << swapped_out; |
| + |
| + // TODO(nasko): Remove this check once cross-site navigation no longer |
| + // relies on swapped out RFH for the top-level frame. |
| + if (!frame_tree_node_->IsMainFrame()) { |
| + CHECK(!swapped_out); |
| + } |
| + |
| scoped_ptr<RenderFrameHostImpl> new_render_frame_host; |
| RenderFrameHostImpl* frame_to_announce = NULL; |
| int routing_id = MSG_ROUTING_NONE; |
| @@ -933,7 +939,9 @@ int RenderFrameHostManager::CreateRenderFrame( |
| RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance); |
| if (proxy) { |
| - routing_id = proxy->GetRenderViewHost()->GetRoutingID(); |
| + routing_id = proxy->GetRoutingID(); |
| + LOG(ERROR) << "RFHM::CreateRenderFrame[" << this << "]:" |
| + << " proxy exists: " << routing_id; |
| // Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost. |
| // Prevent the process from exiting while we're trying to use it. |
| if (!swapped_out) { |
| @@ -958,6 +966,8 @@ int RenderFrameHostManager::CreateRenderFrame( |
| } |
| } |
| } else { |
| + LOG(ERROR) << "RFHM::CreateRenderFrame[" << this << "]:" |
| + << " creating new RFH"; |
| // Create a new RenderFrameHost if we don't find an existing one. |
| new_render_frame_host = CreateRenderFrameHost( |
| instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, swapped_out, hidden); |
| @@ -980,9 +990,18 @@ int RenderFrameHostManager::CreateRenderFrame( |
| bool success = InitRenderView( |
| render_view_host, opener_route_id, proxy_routing_id, |
| frame_tree_node_->IsMainFrame()); |
| - if (success && frame_tree_node_->IsMainFrame()) { |
| - // Don't show the main frame's view until we get a DidNavigate from it. |
| - render_view_host->GetView()->Hide(); |
| + if (success) { |
| + if (frame_tree_node_->IsMainFrame()) { |
| + // Don't show the main frame's view until we get a DidNavigate from it. |
| + render_view_host->GetView()->Hide(); |
| + } else if (!swapped_out) { |
| + // Init the RFH, so a RenderFrame is created in the renderer. |
| + DCHECK(new_render_frame_host.get()); |
| + success = InitRenderFrame(new_render_frame_host.get()); |
| + } |
| + if (swapped_out) { |
| + proxy_hosts_[instance->GetId()]->InitRenderFrameProxy(); |
| + } |
| } else if (!swapped_out && pending_render_frame_host_) { |
| CancelPending(); |
| } |
| @@ -998,9 +1017,37 @@ int RenderFrameHostManager::CreateRenderFrame( |
| if (frame_to_announce) |
| render_frame_delegate_->RenderFrameCreated(frame_to_announce); |
| + LOG(ERROR) << "RFHM::CreateRenderFrame[" << this << "]:" |
| + << "complete: " << routing_id; |
| + |
| return routing_id; |
| } |
| +int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance, |
| + int opener_route_id) { |
| + LOG(ERROR) << "RFHM::CreateRenderFrameProxy[" << this << "]:" |
| + << " " << instance->GetSiteURL(); |
| + |
| + // A RenderFrameProxyHost should never be created in the same SiteInstance as |
| + // the current RFH. |
| + CHECK(instance); |
| + CHECK_NE(instance, render_frame_host_->GetSiteInstance()); |
| + |
| + RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance); |
| + if (proxy) { |
| + LOG(ERROR) << "RFHM::CreateRenderFrameProxy[" << this << "]:" |
| + << " found existing proxy"; |
| + return proxy->GetRoutingID(); |
| + } |
| + |
| + LOG(ERROR) << "RFHM::CreateRenderFrameProxy[" << this << "]:" |
| + << " creating new proxy"; |
| + proxy = new RenderFrameProxyHost(instance, frame_tree_node_); |
| + proxy_hosts_[instance->GetId()] = proxy; |
|
ncarter (slow)
2014/06/25 01:07:56
Probably worthwhile to insert while checking for d
|
| + proxy->InitRenderFrameProxy(); |
| + return proxy->GetRoutingID(); |
| +} |
| + |
| bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host, |
| int opener_route_id, |
| int proxy_routing_id, |
| @@ -1029,6 +1076,36 @@ bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host, |
| render_view_host, opener_route_id, proxy_routing_id, for_main_frame); |
| } |
| +bool RenderFrameHostManager::InitRenderFrame( |
| + RenderFrameHost* render_frame_host) { |
| + RenderFrameHostImpl* rfh = |
| + static_cast<RenderFrameHostImpl*>(render_frame_host); |
| + if (rfh->IsRenderFrameLive()) |
| + return true; |
| + |
| + int parent_routing_id = MSG_ROUTING_NONE; |
| + if (frame_tree_node_->parent()) { |
| + parent_routing_id = frame_tree_node_->parent()->render_manager()-> |
| + GetRoutingIdForSiteInstance(render_frame_host->GetSiteInstance()); |
| + CHECK_NE(parent_routing_id, MSG_ROUTING_NONE); |
| + } |
| + return delegate_->CreateRenderFrameForRenderManager( |
| + render_frame_host, parent_routing_id); |
| +} |
| + |
| +int RenderFrameHostManager::GetRoutingIdForSiteInstance( |
| + SiteInstance* site_instance) { |
| + if (render_frame_host_->GetSiteInstance() == site_instance) |
| + return render_frame_host_->GetRoutingID(); |
| + |
| + RenderFrameProxyHostMap::iterator iter = |
| + proxy_hosts_.find(site_instance->GetId()); |
| + if (iter != proxy_hosts_.end()) |
| + return iter->second->GetRoutingID(); |
| + |
| + return MSG_ROUTING_NONE; |
| +} |
| + |
| void RenderFrameHostManager::CommitPending() { |
| // First check whether we're going to want to focus the location bar after |
| // this commit. We do this now because the navigation hasn't formally |
| @@ -1147,54 +1224,78 @@ void RenderFrameHostManager::CommitPending() { |
| !RenderViewHostImpl::IsRVHStateActive( |
| old_render_frame_host->render_view_host()->rvh_state())); |
| - // If the RenderViewHost backing the RenderFrameHost is pending shutdown, |
| - // the RenderFrameHost should be put in the map of RenderFrameHosts pending |
| - // shutdown. Otherwise, it is stored in the map of proxy hosts. |
| - if (old_render_frame_host->render_view_host()->rvh_state() == |
| - RenderViewHostImpl::STATE_PENDING_SHUTDOWN) { |
| - // The proxy for this RenderFrameHost is created when sending the |
| - // SwapOut message, so check if it already exists and delete it. |
| - RenderFrameProxyHostMap::iterator iter = |
| - proxy_hosts_.find(old_site_instance_id); |
| - if (iter != proxy_hosts_.end()) { |
| - delete iter->second; |
| - proxy_hosts_.erase(iter); |
| - } |
| - RFHPendingDeleteMap::iterator pending_delete_iter = |
| - pending_delete_hosts_.find(old_site_instance_id); |
| - if (pending_delete_iter == pending_delete_hosts_.end() || |
| - pending_delete_iter->second.get() != old_render_frame_host) { |
| - pending_delete_hosts_[old_site_instance_id] = |
| - linked_ptr<RenderFrameHostImpl>(old_render_frame_host.release()); |
| + // TODO(nasko): To keep it simple for now, just split the logic in top-level |
| + // vs subframe. |
| + if (is_main_frame) { |
| + // If the RenderViewHost backing the RenderFrameHost is pending shutdown, |
| + // the RenderFrameHost should be put in the map of RenderFrameHosts pending |
| + // shutdown. Otherwise, it is stored in the map of proxy hosts. |
| + if (old_render_frame_host->render_view_host()->rvh_state() == |
| + RenderViewHostImpl::STATE_PENDING_SHUTDOWN) { |
| + // The proxy for this RenderFrameHost is created when sending the |
| + // SwapOut message, so check if it already exists and delete it. |
| + RenderFrameProxyHostMap::iterator iter = |
| + proxy_hosts_.find(old_site_instance_id); |
| + if (iter != proxy_hosts_.end()) { |
| + delete iter->second; |
| + proxy_hosts_.erase(iter); |
| + } |
| + RFHPendingDeleteMap::iterator pending_delete_iter = |
| + pending_delete_hosts_.find(old_site_instance_id); |
| + if (pending_delete_iter == pending_delete_hosts_.end() || |
| + pending_delete_iter->second.get() != old_render_frame_host) { |
| + pending_delete_hosts_[old_site_instance_id] = |
| + linked_ptr<RenderFrameHostImpl>(old_render_frame_host.release()); |
| + } |
| + } else { |
| + // Capture the active view count on the old RFH SiteInstance, since the |
| + // ownership will be passed into the proxy and the pointer will be |
| + // invalid. |
| + int active_view_count = |
| + static_cast<SiteInstanceImpl*>( |
| + old_render_frame_host->GetSiteInstance())->active_view_count(); |
| + |
| + RenderFrameProxyHostMap::iterator iter = |
| + proxy_hosts_.find(old_site_instance_id); |
| + CHECK(iter != proxy_hosts_.end()); |
| + iter->second->TakeFrameHostOwnership(old_render_frame_host.Pass()); |
| + |
| + // If there are no active views in this SiteInstance, it means that |
| + // this RFH was the last active one in the SiteInstance. Now that we |
| + // know that all RFHs are swapped out, we can delete all the RFHs and RVHs |
| + // in this SiteInstance. |
| + if (!active_view_count) { |
| + ShutdownRenderFrameHostsInSiteInstance(old_site_instance_id); |
| + } else { |
| + // If this is a subframe, it should have a CrossProcessFrameConnector |
| + // created already and we just need to link it to the proper view in the |
| + // new process. |
| + if (!is_main_frame) { |
| + RenderFrameProxyHost* proxy = GetProxyToParent(); |
| + if (proxy) { |
| + proxy->SetChildRWHView( |
| + render_frame_host_->render_view_host()->GetView()); |
| + } |
| + } |
| + } |
| } |
| } else { |
| - // Capture the active view count on the old RFH SiteInstance, since the |
| - // ownership will be passed into the proxy and the pointer will be invalid. |
| - int active_view_count = |
| - static_cast<SiteInstanceImpl*>(old_render_frame_host->GetSiteInstance()) |
| - ->active_view_count(); |
| - |
| - RenderFrameProxyHostMap::iterator iter = |
| - proxy_hosts_.find(old_site_instance_id); |
| - CHECK(iter != proxy_hosts_.end()); |
| - iter->second->TakeFrameHostOwnership(old_render_frame_host.Pass()); |
| - |
| - // If there are no active views in this SiteInstance, it means that |
| - // this RFH was the last active one in the SiteInstance. Now that we |
| - // know that all RFHs are swapped out, we can delete all the RFHs and RVHs |
| - // in this SiteInstance. |
| - if (!active_view_count) { |
| - ShutdownRenderFrameHostsInSiteInstance(old_site_instance_id); |
| + CHECK(proxy_hosts_.find(render_frame_host_->GetSiteInstance()->GetId()) == |
| + proxy_hosts_.end()); |
| + |
| + // If the old frame has already completed running the unload handler, |
| + // it is safe to just delete immediately. Otherwise, add it to the list |
| + // of frames pending deletion. |
| + if (old_render_frame_host->has_received_swap_out_ack()) { |
| + old_render_frame_host.reset(NULL); |
| } else { |
| - // If this is a subframe, it should have a CrossProcessFrameConnector |
| - // created already and we just need to link it to the proper view in the |
| - // new process. |
| - if (!is_main_frame) { |
| - RenderFrameProxyHost* proxy = GetProxyToParent(); |
| - if (proxy) { |
| - proxy->SetChildRWHView( |
| - render_frame_host_->render_view_host()->GetView()); |
| - } |
| + // Put the old RFH on the list of hosts pending deletion. |
| + RFHPendingDeleteMap::iterator pending_delete_iter = |
| + pending_delete_hosts_.find(old_site_instance_id); |
| + if (pending_delete_iter == pending_delete_hosts_.end() || |
| + pending_delete_iter->second.get() != old_render_frame_host) { |
| + pending_delete_hosts_[old_site_instance_id] = |
| + linked_ptr<RenderFrameHostImpl>(old_render_frame_host.release()); |
| } |
| } |
| } |
| @@ -1238,11 +1339,12 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate( |
| cross_navigation_pending_ = false; |
| } |
| - // render_frame_host_'s SiteInstance and new_instance will not be deleted |
| - // before the end of this method, so we don't have to worry about their ref |
| - // counts dropping to zero. |
| + // render_frame_host_'s SiteInstance will not be deleted before the end of |
| + // this method, so we don't have to worry about the ref count dropping to |
| + // zero. The new_instance is possibly passed to CreateProxiesForSiteInstance, |
| + // which expects properly ref-counted object, so use a scoped_refptr for it. |
| SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); |
| - SiteInstance* new_instance = current_instance; |
| + scoped_refptr<SiteInstance> new_instance(current_instance); |
| // We do not currently swap processes for navigations in webview tag guests. |
| bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme); |
| @@ -1284,6 +1386,29 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate( |
| if (new_instance->IsRelatedSiteInstance(current_instance)) { |
| opener_route_id = |
| delegate_->CreateOpenerRenderViewsForRenderManager(new_instance); |
| + |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kSitePerProcess)) { |
| + // Create the swapped out RVH for the new SiteInstance. This will create |
| + // a top-level swapped out RFH as well, which will be wrapped by a |
| + // RenderFrameProxyHost in the subsequent call to create proxies. |
| + if (!frame_tree_node_->IsMainFrame()) { |
| + RenderViewHostImpl* render_view_host = |
| + frame_tree_node_->frame_tree()->GetRenderViewHost( |
| + new_instance); |
| + LOG(ERROR) << "RFHM::UpdateRendererStateForNavigate[" << this << "]:" |
| + << " rvh: " << render_view_host; |
| + if (!render_view_host) { |
| + frame_tree_node_->frame_tree()->root()->render_manager() |
| + ->CreateRenderFrame(new_instance, MSG_ROUTING_NONE, true, true); |
| + } |
| + } |
| + |
| + // Ensure that the frame tree has RenderFrameProxyHosts for the new |
| + // SiteInstance in all nodes except the current one. |
| + frame_tree_node_->frame_tree()->CreateProxiesForSiteInstance( |
| + frame_tree_node_, new_instance); |
| + } |
| } |
| // Create a non-swapped-out pending RFH with the given opener and navigate |
| @@ -1295,7 +1420,11 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate( |
| // Check if our current RFH is live before we set up a transition. |
| if (!render_frame_host_->render_view_host()->IsRenderViewLive()) { |
| + LOG(ERROR) << "RFHM::UpdateRendererStateForNavigate[" << this << "]:" |
| + << " rvh isn't live"; |
| if (!cross_navigation_pending_) { |
| + LOG(ERROR) << "RFHM::UpdateRendererStateForNavigate[" << this << "]:" |
| + << " !cross_nav_pending_, will CommitPending"; |
| // The current RFH is not live. There's no reason to sit around with a |
| // sad tab or a newly created RFH while we wait for the pending RFH to |
| // navigate. Just switch to the pending RFH now and go back to non |
| @@ -1321,11 +1450,15 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate( |
| bool is_transfer = |
| entry.transferred_global_request_id() != GlobalRequestID(); |
| if (is_transfer) { |
| + LOG(ERROR) << "RFHM::UpdateStateForNavigate[" << this << "]:" |
| + << " is_transfer: " << pending_nav_params_->global_request_id.child_id; |
| // We don't need to stop the old renderer or run beforeunload/unload |
| // handlers, because those have already been done. |
| DCHECK(pending_nav_params_->global_request_id == |
| entry.transferred_global_request_id()); |
| } else { |
| + LOG(ERROR) << "RFHM::UpdateStateForNavigate[" << this << "]:" |
| + << " !is_transfer: "; |
| // Also make sure the old render view stops, in case a load is in |
| // progress. (We don't want to do this for transfers, since it will |
| // interrupt the transfer with an unexpected DidStopLoading.) |
| @@ -1354,6 +1487,8 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate( |
| if (!is_transfer) |
| render_frame_host_->DispatchBeforeUnload(true); |
| + LOG(ERROR) << "RFHM::UpdateRendererStateForNavigate[" << this << "]:" |
| + << " returning " << pending_render_frame_host_.get(); |
| return pending_render_frame_host_.get(); |
| } |
| @@ -1413,7 +1548,10 @@ void RenderFrameHostManager::CancelPending() { |
| new RenderFrameProxyHost(site_instance, frame_tree_node_); |
| proxy_hosts_[site_instance->GetId()] = proxy; |
|
ncarter (slow)
2014/06/25 01:07:56
Is there some invariant that guarantees that a pro
|
| pending_render_frame_host->SwapOut(proxy); |
| - proxy->TakeFrameHostOwnership(pending_render_frame_host.Pass()); |
| + if (frame_tree_node_->IsMainFrame()) { |
| + proxy->TakeFrameHostOwnership(pending_render_frame_host.Pass()); |
| + } |
| + proxy_hosts_[site_instance->GetId()] = proxy; |
|
ncarter (slow)
2014/06/25 01:07:56
I'm fairly certain that the proxy is already in th
|
| } else { |
| // We won't be coming back, so delete this one. |
| pending_render_frame_host.reset(); |
| @@ -1454,6 +1592,10 @@ bool RenderFrameHostManager::IsRVHOnSwappedOutList( |
| rvh->GetSiteInstance()); |
| if (!proxy) |
| return false; |
| + // If there is a proxy without RFH, it is for a subframe in the SiteInstance |
| + // of |rvh|. Subframes should be ignored in this case. |
| + if (!proxy->render_frame_host()) |
| + return false; |
| return IsOnSwappedOutList(proxy->render_frame_host()); |
| } |