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 3 // found in the LICENSE file. 4 5 #include "content/browser/frame_host/render_frame_host_manager.h" 6 7 #include <utility> 8 9 #include "base/command_line.h" 10 #include "base/debug/trace_event.h" 11 #include "base/logging.h" 12 #include "base/stl_util.h" 13 #include "content/browser/child_process_security_policy_impl.h" 14 #include "content/browser/devtools/render_view_devtools_agent_host.h" 15 #include "content/browser/frame_host/cross_site_transferring_request.h" 16 #include "content/browser/frame_host/debug_urls.h" 17 #include "content/browser/frame_host/interstitial_page_impl.h" 18 #include "content/browser/frame_host/navigation_before_commit_info.h" 19 #include "content/browser/frame_host/navigation_controller_impl.h" 20 #include "content/browser/frame_host/navigation_entry_impl.h" 21 #include "content/browser/frame_host/navigation_request.h" 22 #include "content/browser/frame_host/navigation_request_info.h" 23 #include "content/browser/frame_host/navigator.h" 24 #include "content/browser/frame_host/render_frame_host_factory.h" 25 #include "content/browser/frame_host/render_frame_host_impl.h" 26 #include "content/browser/frame_host/render_frame_proxy_host.h" 27 #include "content/browser/renderer_host/render_process_host_impl.h" 28 #include "content/browser/renderer_host/render_view_host_factory.h" 29 #include "content/browser/renderer_host/render_view_host_impl.h" 30 #include "content/browser/site_instance_impl.h" 31 #include "content/browser/webui/web_ui_controller_factory_registry.h" 32 #include "content/browser/webui/web_ui_impl.h" 33 #include "content/common/view_messages.h" 34 #include "content/public/browser/content_browser_client.h" 35 #include "content/public/browser/notification_service.h" 36 #include "content/public/browser/notification_types.h" 37 #include "content/public/browser/render_widget_host_iterator.h" 38 #include "content/public/browser/render_widget_host_view.h" 39 #include "content/public/browser/user_metrics.h" 40 #include "content/public/browser/web_ui_controller.h" 41 #include "content/public/common/content_switches.h" 42 #include "content/public/common/referrer.h" 43 #include "content/public/common/url_constants.h" 44 #include "net/base/load_flags.h" 45 46 namespace content { 47 48 namespace { 49 50 // PlzNavigate 51 // Simulates a renderer response to a navigation request when there is no live 52 // renderer. 53 FrameHostMsg_BeginNavigation_Params BeginNavigationFromNavigate( 54 const FrameMsg_Navigate_Params& navigate_params) { 55 FrameHostMsg_BeginNavigation_Params begin_navigation_params; 56 begin_navigation_params.method = navigate_params.is_post ? "POST" : "GET"; 57 begin_navigation_params.url = navigate_params.url; 58 begin_navigation_params.referrer = 59 Referrer(navigate_params.referrer.url, navigate_params.referrer.policy); 60 61 // TODO(clamy): This should be modified to take into account caching policy 62 // requirements (eg for POST reloads). 63 begin_navigation_params.load_flags = net::LOAD_NORMAL; 64 65 // TODO(clamy): Post data from the browser should be put in the request body. 66 67 begin_navigation_params.has_user_gesture = false; 68 begin_navigation_params.transition_type = navigate_params.transition; 69 begin_navigation_params.should_replace_current_entry = 70 navigate_params.should_replace_current_entry; 71 begin_navigation_params.allow_download = 72 navigate_params.allow_download; 73 return begin_navigation_params; 74 } 75 76 } // namespace 77 78 bool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) { 79 node->render_manager()->pending_delete_hosts_.clear(); 80 return true; 81 } 82 83 RenderFrameHostManager::RenderFrameHostManager( 84 FrameTreeNode* frame_tree_node, 85 RenderFrameHostDelegate* render_frame_delegate, 86 RenderViewHostDelegate* render_view_delegate, 87 RenderWidgetHostDelegate* render_widget_delegate, 88 Delegate* delegate) 89 : frame_tree_node_(frame_tree_node), 90 delegate_(delegate), 91 cross_navigation_pending_(false), 92 render_frame_delegate_(render_frame_delegate), 93 render_view_delegate_(render_view_delegate), 94 render_widget_delegate_(render_widget_delegate), 95 interstitial_page_(NULL), 96 weak_factory_(this) { 97 DCHECK(frame_tree_node_); 98 } 99 100 RenderFrameHostManager::~RenderFrameHostManager() { 101 if (pending_render_frame_host_) 102 CancelPending(); 103 104 // We should always have a current RenderFrameHost except in some tests. 105 SetRenderFrameHost(scoped_ptr<RenderFrameHostImpl>()); 106 107 // Delete any swapped out RenderFrameHosts. 108 STLDeleteValues(&proxy_hosts_); 109 110 // PlzNavigate 111 // There is an active navigation request for this RFHM so it needs to be 112 // canceled. 113 if (CommandLine::ForCurrentProcess()->HasSwitch( 114 switches::kEnableBrowserSideNavigation)) { 115 if (navigation_request_.get()) 116 navigation_request_->CancelNavigation(); 117 } 118 119 } 120 121 void RenderFrameHostManager::Init(BrowserContext* browser_context, 122 SiteInstance* site_instance, 123 int view_routing_id, 124 int frame_routing_id) { 125 // Create a RenderViewHost and RenderFrameHost, once we have an instance. It 126 // is important to immediately give this SiteInstance to a RenderViewHost so 127 // that the SiteInstance is ref counted. 128 if (!site_instance) 129 site_instance = SiteInstance::Create(browser_context); 130 131 SetRenderFrameHost(CreateRenderFrameHost(site_instance, 132 view_routing_id, 133 frame_routing_id, 134 false, 135 delegate_->IsHidden())); 136 137 // Keep track of renderer processes as they start to shut down or are 138 // crashed/killed. 139 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED, 140 NotificationService::AllSources()); 141 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSING, 142 NotificationService::AllSources()); 143 } 144 145 RenderViewHostImpl* RenderFrameHostManager::current_host() const { 146 if (!render_frame_host_) 147 return NULL; 148 return render_frame_host_->render_view_host(); 149 } 150 151 RenderViewHostImpl* RenderFrameHostManager::pending_render_view_host() const { 152 if (!pending_render_frame_host_) 153 return NULL; 154 return pending_render_frame_host_->render_view_host(); 155 } 156 157 RenderWidgetHostView* RenderFrameHostManager::GetRenderWidgetHostView() const { 158 if (interstitial_page_) 159 return interstitial_page_->GetView(); 160 if (!render_frame_host_) 161 return NULL; 162 return render_frame_host_->render_view_host()->GetView(); 163 } 164 165 RenderFrameProxyHost* RenderFrameHostManager::GetProxyToParent() { 166 if (frame_tree_node_->IsMainFrame()) 167 return NULL; 168 169 RenderFrameProxyHostMap::iterator iter = 170 proxy_hosts_.find(frame_tree_node_->parent() 171 ->render_manager() 172 ->current_frame_host() 173 ->GetSiteInstance() 174 ->GetId()); 175 if (iter == proxy_hosts_.end()) 176 return NULL; 177 178 return iter->second; 179 } 180 181 void RenderFrameHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) { 182 pending_web_ui_.reset( 183 delegate_->CreateWebUIForRenderManager(entry.GetURL())); 184 pending_and_current_web_ui_.reset(); 185 186 // If we have assigned (zero or more) bindings to this NavigationEntry in the 187 // past, make sure we're not granting it different bindings than it had 188 // before. If so, note it and don't give it any bindings, to avoid a 189 // potential privilege escalation. 190 if (pending_web_ui_.get() && 191 entry.bindings() != NavigationEntryImpl::kInvalidBindings && 192 pending_web_ui_->GetBindings() != entry.bindings()) { 193 RecordAction( 194 base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM")); 195 pending_web_ui_.reset(); 196 } 197 } 198 199 RenderFrameHostImpl* RenderFrameHostManager::Navigate( 200 const NavigationEntryImpl& entry) { 201 TRACE_EVENT1("navigation", "RenderFrameHostManager:Navigate", 202 "FrameTreeNode id", frame_tree_node_->frame_tree_node_id()); 203 // Create a pending RenderFrameHost to use for the navigation. 204 RenderFrameHostImpl* dest_render_frame_host = UpdateStateForNavigate(entry); 205 if (!dest_render_frame_host) 206 return NULL; // We weren't able to create a pending render frame host. 207 208 // If the current render_frame_host_ isn't live, we should create it so 209 // that we don't show a sad tab while the dest_render_frame_host fetches 210 // its first page. (Bug 1145340) 211 if (dest_render_frame_host != render_frame_host_ && 212 !render_frame_host_->IsRenderFrameLive()) { 213 // Note: we don't call InitRenderView here because we are navigating away 214 // soon anyway, and we don't have the NavigationEntry for this host. 215 delegate_->CreateRenderViewForRenderManager( 216 render_frame_host_->render_view_host(), MSG_ROUTING_NONE, 217 MSG_ROUTING_NONE, frame_tree_node_->IsMainFrame()); 218 } 219 220 // If the renderer crashed, then try to create a new one to satisfy this 221 // navigation request. 222 if (!dest_render_frame_host->IsRenderFrameLive()) { 223 // Recreate the opener chain. 224 int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager( 225 dest_render_frame_host->GetSiteInstance()); 226 if (!InitRenderView(dest_render_frame_host->render_view_host(), 227 opener_route_id, 228 MSG_ROUTING_NONE, 229 frame_tree_node_->IsMainFrame())) 230 return NULL; 231 232 // Now that we've created a new renderer, be sure to hide it if it isn't 233 // our primary one. Otherwise, we might crash if we try to call Show() 234 // on it later. 235 if (dest_render_frame_host != render_frame_host_ && 236 dest_render_frame_host->render_view_host()->GetView()) { 237 dest_render_frame_host->render_view_host()->GetView()->Hide(); 238 } else { 239 // Notify here as we won't be calling CommitPending (which does the 240 // notify). 241 delegate_->NotifySwappedFromRenderManager( 242 NULL, render_frame_host_.get(), frame_tree_node_->IsMainFrame()); 243 } 244 } 245 246 // If entry includes the request ID of a request that is being transferred, 247 // the destination render frame will take ownership, so release ownership of 248 // the request. 249 if (cross_site_transferring_request_.get() && 250 cross_site_transferring_request_->request_id() == 251 entry.transferred_global_request_id()) { 252 cross_site_transferring_request_->ReleaseRequest(); 253 } 254 255 return dest_render_frame_host; 256 } 257 258 void RenderFrameHostManager::Stop() { 259 render_frame_host_->Stop(); 260 261 // If we are cross-navigating, we should stop the pending renderers. This 262 // will lead to a DidFailProvisionalLoad, which will properly destroy them. 263 if (cross_navigation_pending_) { 264 pending_render_frame_host_->Send(new FrameMsg_Stop( 265 pending_render_frame_host_->GetRoutingID())); 266 } 267 } 268 269 void RenderFrameHostManager::SetIsLoading(bool is_loading) { 270 render_frame_host_->render_view_host()->SetIsLoading(is_loading); 271 if (pending_render_frame_host_) 272 pending_render_frame_host_->render_view_host()->SetIsLoading(is_loading); 273 } 274 275 bool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() { 276 if (!cross_navigation_pending_) 277 return true; 278 279 // We should always have a pending RFH when there's a cross-process navigation 280 // in progress. Sanity check this for http://crbug.com/276333. 281 CHECK(pending_render_frame_host_); 282 283 // If the tab becomes unresponsive during {before}unload while doing a 284 // cross-site navigation, proceed with the navigation. (This assumes that 285 // the pending RenderFrameHost is still responsive.) 286 if (render_frame_host_->render_view_host()->IsWaitingForUnloadACK()) { 287 // The request has been started and paused while we're waiting for the 288 // unload handler to finish. We'll pretend that it did. The pending 289 // renderer will then be swapped in as part of the usual DidNavigate logic. 290 // (If the unload handler later finishes, this call will be ignored because 291 // the pending_nav_params_ state will already be cleaned up.) 292 current_host()->OnSwappedOut(true); 293 } else if (render_frame_host_->render_view_host()-> 294 is_waiting_for_beforeunload_ack()) { 295 // Haven't gotten around to starting the request, because we're still 296 // waiting for the beforeunload handler to finish. We'll pretend that it 297 // did finish, to let the navigation proceed. Note that there's a danger 298 // that the beforeunload handler will later finish and possibly return 299 // false (meaning the navigation should not proceed), but we'll ignore it 300 // in this case because it took too long. 301 if (pending_render_frame_host_->are_navigations_suspended()) { 302 pending_render_frame_host_->SetNavigationsSuspended( 303 false, base::TimeTicks::Now()); 304 } 305 } 306 return false; 307 } 308 309 void RenderFrameHostManager::OnBeforeUnloadACK( 310 bool for_cross_site_transition, 311 bool proceed, 312 const base::TimeTicks& proceed_time) { 313 if (for_cross_site_transition) { 314 // Ignore if we're not in a cross-site navigation. 315 if (!cross_navigation_pending_) 316 return; 317 318 if (proceed) { 319 // Ok to unload the current page, so proceed with the cross-site 320 // navigation. Note that if navigations are not currently suspended, it 321 // might be because the renderer was deemed unresponsive and this call was 322 // already made by ShouldCloseTabOnUnresponsiveRenderer. In that case, it 323 // is ok to do nothing here. 324 if (pending_render_frame_host_ && 325 pending_render_frame_host_->are_navigations_suspended()) { 326 pending_render_frame_host_->SetNavigationsSuspended(false, 327 proceed_time); 328 } 329 } else { 330 // Current page says to cancel. 331 CancelPending(); 332 cross_navigation_pending_ = false; 333 } 334 } else { 335 // Non-cross site transition means closing the entire tab. 336 bool proceed_to_fire_unload; 337 delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time, 338 &proceed_to_fire_unload); 339 340 if (proceed_to_fire_unload) { 341 // If we're about to close the tab and there's a pending RFH, cancel it. 342 // Otherwise, if the navigation in the pending RFH completes before the 343 // close in the current RFH, we'll lose the tab close. 344 if (pending_render_frame_host_) { 345 CancelPending(); 346 cross_navigation_pending_ = false; 347 } 348 349 // This is not a cross-site navigation, the tab is being closed. 350 render_frame_host_->render_view_host()->ClosePage(); 351 } 352 } 353 } 354 355 void RenderFrameHostManager::OnCrossSiteResponse( 356 RenderFrameHostImpl* pending_render_frame_host, 357 const GlobalRequestID& global_request_id, 358 scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request, 359 const std::vector<GURL>& transfer_url_chain, 360 const Referrer& referrer, 361 ui::PageTransition page_transition, 362 bool should_replace_current_entry) { 363 // We should only get here for transfer navigations. Most cross-process 364 // navigations can just continue and wait to run the unload handler (by 365 // swapping out) when the new navigation commits. 366 CHECK(cross_site_transferring_request.get()); 367 368 // A transfer should only have come from our pending or current RFH. 369 // TODO(creis): We need to handle the case that the pending RFH has changed 370 // in the mean time, while this was being posted from the IO thread. We 371 // should probably cancel the request in that case. 372 DCHECK(pending_render_frame_host == pending_render_frame_host_ || 373 pending_render_frame_host == render_frame_host_); 374 375 // Store the transferring request so that we can release it if the transfer 376 // navigation matches. 377 cross_site_transferring_request_ = cross_site_transferring_request.Pass(); 378 379 // Sanity check that the params are for the correct frame and process. 380 // These should match the RenderFrameHost that made the request. 381 // If it started as a cross-process navigation via OpenURL, this is the 382 // pending one. If it wasn't cross-process until the transfer, this is the 383 // current one. 384 int render_frame_id = pending_render_frame_host_ ? 385 pending_render_frame_host_->GetRoutingID() : 386 render_frame_host_->GetRoutingID(); 387 DCHECK_EQ(render_frame_id, pending_render_frame_host->GetRoutingID()); 388 int process_id = pending_render_frame_host_ ? 389 pending_render_frame_host_->GetProcess()->GetID() : 390 render_frame_host_->GetProcess()->GetID(); 391 DCHECK_EQ(process_id, global_request_id.child_id); 392 393 // Treat the last URL in the chain as the destination and the remainder as 394 // the redirect chain. 395 CHECK(transfer_url_chain.size()); 396 GURL transfer_url = transfer_url_chain.back(); 397 std::vector<GURL> rest_of_chain = transfer_url_chain; 398 rest_of_chain.pop_back(); 399 400 // We don't know whether the original request had |user_action| set to true. 401 // However, since we force the navigation to be in the current tab, it 402 // doesn't matter. 403 pending_render_frame_host->frame_tree_node()->navigator()->RequestTransferURL( 404 pending_render_frame_host, 405 transfer_url, 406 rest_of_chain, 407 referrer, 408 page_transition, 409 CURRENT_TAB, 410 global_request_id, 411 should_replace_current_entry, 412 true); 413 414 // The transferring request was only needed during the RequestTransferURL 415 // call, so it is safe to clear at this point. 416 cross_site_transferring_request_.reset(); 417 } 418 419 void RenderFrameHostManager::OnDeferredAfterResponseStarted( 420 const GlobalRequestID& global_request_id, 421 RenderFrameHostImpl* pending_render_frame_host) { 422 DCHECK(!response_started_id_.get()); 423 424 response_started_id_.reset(new GlobalRequestID(global_request_id)); 425 } 426 427 void RenderFrameHostManager::ResumeResponseDeferredAtStart() { 428 DCHECK(response_started_id_.get()); 429 430 RenderProcessHostImpl* process = 431 static_cast<RenderProcessHostImpl*>(render_frame_host_->GetProcess()); 432 process->ResumeResponseDeferredAtStart(*response_started_id_); 433 434 render_frame_host_->ClearPendingTransitionRequestData(); 435 436 response_started_id_.reset(); 437 } 438 439 void RenderFrameHostManager::DidNavigateFrame( 440 RenderFrameHostImpl* render_frame_host) { 441 // PlzNavigate 442 // The navigation request has been committed so the browser process doesn't 443 // need to care about it anymore. 444 if (CommandLine::ForCurrentProcess()->HasSwitch( 445 switches::kEnableBrowserSideNavigation)) { 446 navigation_request_.reset(); 447 } 448 449 if (!cross_navigation_pending_) { 450 DCHECK(!pending_render_frame_host_); 451 452 // We should only hear this from our current renderer. 453 DCHECK_EQ(render_frame_host_, render_frame_host); 454 455 // Even when there is no pending RVH, there may be a pending Web UI. 456 if (pending_web_ui()) 457 CommitPending(); 458 return; 459 } 460 461 if (render_frame_host == pending_render_frame_host_) { 462 // The pending cross-site navigation completed, so show the renderer. 463 CommitPending(); 464 cross_navigation_pending_ = false; 465 } else if (render_frame_host == render_frame_host_) { 466 // A navigation in the original page has taken place. Cancel the pending 467 // one. 468 CancelPending(); 469 cross_navigation_pending_ = false; 470 } else { 471 // No one else should be sending us DidNavigate in this state. 472 DCHECK(false); 473 } 474 } 475 476 void RenderFrameHostManager::DidDisownOpener( 477 RenderFrameHost* render_frame_host) { 478 // Notify all RenderFrameHosts but the one that notified us. This is necessary 479 // in case a process swap has occurred while the message was in flight. 480 for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin(); 481 iter != proxy_hosts_.end(); 482 ++iter) { 483 DCHECK_NE(iter->second->GetSiteInstance(), 484 current_frame_host()->GetSiteInstance()); 485 iter->second->DisownOpener(); 486 } 487 488 if (render_frame_host_.get() != render_frame_host) 489 render_frame_host_->DisownOpener(); 490 491 if (pending_render_frame_host_ && 492 pending_render_frame_host_.get() != render_frame_host) { 493 pending_render_frame_host_->DisownOpener(); 494 } 495 } 496 497 void RenderFrameHostManager::RendererProcessClosing( 498 RenderProcessHost* render_process_host) { 499 // Remove any swapped out RVHs from this process, so that we don't try to 500 // swap them back in while the process is exiting. Start by finding them, 501 // since there could be more than one. 502 std::list<int> ids_to_remove; 503 for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin(); 504 iter != proxy_hosts_.end(); 505 ++iter) { 506 if (iter->second->GetProcess() == render_process_host) 507 ids_to_remove.push_back(iter->first); 508 } 509 510 // Now delete them. 511 while (!ids_to_remove.empty()) { 512 delete proxy_hosts_[ids_to_remove.back()]; 513 proxy_hosts_.erase(ids_to_remove.back()); 514 ids_to_remove.pop_back(); 515 } 516 } 517 518 void RenderFrameHostManager::SwapOutOldPage( 519 RenderFrameHostImpl* old_render_frame_host) { 520 TRACE_EVENT1("navigation", "RenderFrameHostManager::SwapOutOldPage", 521 "FrameTreeNode id", frame_tree_node_->frame_tree_node_id()); 522 // Should only see this while we have a pending renderer. 523 CHECK(cross_navigation_pending_); 524 525 // Tell the renderer to suppress any further modal dialogs so that we can swap 526 // it out. This must be done before canceling any current dialog, in case 527 // there is a loop creating additional dialogs. 528 // TODO(creis): Handle modal dialogs in subframe processes. 529 old_render_frame_host->render_view_host()->SuppressDialogsUntilSwapOut(); 530 531 // Now close any modal dialogs that would prevent us from swapping out. This 532 // must be done separately from SwapOut, so that the PageGroupLoadDeferrer is 533 // no longer on the stack when we send the SwapOut message. 534 delegate_->CancelModalDialogsForRenderManager(); 535 536 // Create the RenderFrameProxyHost that will replace the 537 // RenderFrameHost which is swapping out. If one exists, ensure it is deleted 538 // from the map and not leaked. 539 DeleteRenderFrameProxyHost(old_render_frame_host->GetSiteInstance()); 540 541 RenderFrameProxyHost* proxy = new RenderFrameProxyHost( 542 old_render_frame_host->GetSiteInstance(), frame_tree_node_); 543 std::pair<RenderFrameProxyHostMap::iterator, bool> result = 544 proxy_hosts_.insert(std::make_pair( 545 old_render_frame_host->GetSiteInstance()->GetId(), proxy)); 546 CHECK(result.second) << "Inserting a duplicate item."; 547 548 // Tell the old frame it is being swapped out. This will fire the unload 549 // handler in the background (without firing the beforeunload handler a second 550 // time). This is done right after we commit the new RenderFrameHost. 551 old_render_frame_host->SwapOut(proxy); 552 } 553 554 void RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance( 555 int32 site_instance_id, 556 RenderFrameHostImpl* rfh) { 557 RFHPendingDeleteMap::iterator iter = 558 pending_delete_hosts_.find(site_instance_id); 559 if (iter != pending_delete_hosts_.end() && iter->second.get() == rfh) 560 pending_delete_hosts_.erase(site_instance_id); 561 } 562 563 void RenderFrameHostManager::ResetProxyHosts() { 564 STLDeleteValues(&proxy_hosts_); 565 } 566 567 // PlzNavigate 568 bool RenderFrameHostManager::RequestNavigation( 569 const NavigationEntryImpl& entry, 570 const FrameMsg_Navigate_Params& navigate_params) { 571 CHECK(CommandLine::ForCurrentProcess()->HasSwitch( 572 switches::kEnableBrowserSideNavigation)); 573 if (render_frame_host_->IsRenderFrameLive()) { 574 // TODO(clamy): send a RequestNavigation IPC. 575 return true; 576 } 577 578 // The navigation request is sent directly to the IO thread. 579 OnBeginNavigation(BeginNavigationFromNavigate(navigate_params)); 580 return true; 581 } 582 583 // PlzNavigate 584 void RenderFrameHostManager::OnBeginNavigation( 585 const FrameHostMsg_BeginNavigation_Params& params) { 586 CHECK(CommandLine::ForCurrentProcess()->HasSwitch( 587 switches::kEnableBrowserSideNavigation)); 588 // TODO(clamy): Check if navigations are blocked and if so, return 589 // immediately. 590 NavigationRequestInfo info(params); 591 592 info.first_party_for_cookies = frame_tree_node_->IsMainFrame() ? 593 params.url : frame_tree_node_->frame_tree()->root()->current_url(); 594 info.is_main_frame = frame_tree_node_->IsMainFrame(); 595 info.parent_is_main_frame = !frame_tree_node_->parent() ? 596 false : frame_tree_node_->parent()->IsMainFrame(); 597 598 // TODO(clamy): Check if the current RFH should be initialized (in case it has 599 // crashed) not to display a sad tab while navigating. 600 // TODO(clamy): Spawn a speculative renderer process if we do not have one to 601 // use for the navigation. 602 603 // If there is an ongoing request it must be canceled. 604 if (navigation_request_.get()) 605 navigation_request_->CancelNavigation(); 606 607 navigation_request_.reset(new NavigationRequest( 608 info, frame_tree_node_->frame_tree_node_id())); 609 navigation_request_->BeginNavigation(params.request_body); 610 } 611 612 // PlzNavigate 613 void RenderFrameHostManager::CommitNavigation( 614 const NavigationBeforeCommitInfo& info) { 615 CHECK(CommandLine::ForCurrentProcess()->HasSwitch( 616 switches::kEnableBrowserSideNavigation)); 617 DCHECK(navigation_request_.get()); 618 // Ignores navigation commits if the request ID doesn't match the current 619 // active request. 620 if (navigation_request_->navigation_request_id() != 621 info.navigation_request_id) { 622 return; 623 } 624 625 // Pick the right RenderFrameHost to commit the navigation. 626 SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); 627 // TODO(clamy): Replace the default values by the right ones. This may require 628 // some storing in RequestNavigation. 629 scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation( 630 info.navigation_url, 631 NULL, 632 navigation_request_->info().navigation_params.transition_type, 633 false, 634 false); 635 DCHECK(!pending_render_frame_host_.get()); 636 637 // TODO(clamy): Update how pending WebUI objects are handled. 638 if (current_instance != new_instance.get()) { 639 CreateRenderFrameHostForNewSiteInstance( 640 current_instance, new_instance.get(), frame_tree_node_->IsMainFrame()); 641 DCHECK(pending_render_frame_host_.get()); 642 // TODO(clamy): Wait until the navigation has committed before swapping 643 // renderers. 644 scoped_ptr<RenderFrameHostImpl> old_render_frame_host = 645 SetRenderFrameHost(pending_render_frame_host_.Pass()); 646 if (frame_tree_node_->IsMainFrame()) 647 render_frame_host_->render_view_host()->AttachToFrameTree(); 648 } 649 650 // If the renderer that needs to navigate is not live (it was just created or 651 // it crashed), initialize it. 652 if (!render_frame_host_->render_view_host()->IsRenderViewLive()) { 653 // Recreate the opener chain. 654 int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager( 655 render_frame_host_->GetSiteInstance()); 656 if (!InitRenderView(render_frame_host_->render_view_host(), 657 opener_route_id, 658 MSG_ROUTING_NONE, 659 frame_tree_node_->IsMainFrame())) { 660 return; 661 } 662 } 663 664 frame_tree_node_->navigator()->CommitNavigation( 665 render_frame_host_.get(), info); 666 } 667 668 void RenderFrameHostManager::Observe( 669 int type, 670 const NotificationSource& source, 671 const NotificationDetails& details) { 672 switch (type) { 673 case NOTIFICATION_RENDERER_PROCESS_CLOSED: 674 case NOTIFICATION_RENDERER_PROCESS_CLOSING: 675 RendererProcessClosing( 676 Source<RenderProcessHost>(source).ptr()); 677 break; 678 679 default: 680 NOTREACHED(); 681 } 682 } 683 684 bool RenderFrameHostManager::ClearProxiesInSiteInstance( 685 int32 site_instance_id, 686 FrameTreeNode* node) { 687 RenderFrameProxyHostMap::iterator iter = 688 node->render_manager()->proxy_hosts_.find(site_instance_id); 689 if (iter != node->render_manager()->proxy_hosts_.end()) { 690 RenderFrameProxyHost* proxy = iter->second; 691 // If the RVH is pending swap out, it needs to switch state to 692 // pending shutdown. Otherwise it is deleted. 693 if (proxy->GetRenderViewHost()->rvh_state() == 694 RenderViewHostImpl::STATE_PENDING_SWAP_OUT) { 695 scoped_ptr<RenderFrameHostImpl> swapped_out_rfh = 696 proxy->PassFrameHostOwnership(); 697 698 swapped_out_rfh->SetPendingShutdown(base::Bind( 699 &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance, 700 node->render_manager()->weak_factory_.GetWeakPtr(), 701 site_instance_id, 702 swapped_out_rfh.get())); 703 RFHPendingDeleteMap::iterator pending_delete_iter = 704 node->render_manager()->pending_delete_hosts_.find(site_instance_id); 705 if (pending_delete_iter == 706 node->render_manager()->pending_delete_hosts_.end() || 707 pending_delete_iter->second.get() != swapped_out_rfh) { 708 node->render_manager()->pending_delete_hosts_[site_instance_id] = 709 linked_ptr<RenderFrameHostImpl>(swapped_out_rfh.release()); 710 } 711 } 712 delete proxy; 713 node->render_manager()->proxy_hosts_.erase(site_instance_id); 714 } 715 716 return true; 717 } 718 719 bool RenderFrameHostManager::ShouldTransitionCrossSite() { 720 // False in the single-process mode, as it makes RVHs to accumulate 721 // in swapped_out_hosts_. 722 // True if we are using process-per-site-instance (default) or 723 // process-per-site (kProcessPerSite). 724 return 725 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) && 726 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab); 727 } 728 729 bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation( 730 const GURL& current_effective_url, 731 bool current_is_view_source_mode, 732 SiteInstance* new_site_instance, 733 const GURL& new_effective_url, 734 bool new_is_view_source_mode) const { 735 // If new_entry already has a SiteInstance, assume it is correct. We only 736 // need to force a swap if it is in a different BrowsingInstance. 737 if (new_site_instance) { 738 return !new_site_instance->IsRelatedSiteInstance( 739 render_frame_host_->GetSiteInstance()); 740 } 741 742 // Check for reasons to swap processes even if we are in a process model that 743 // doesn't usually swap (e.g., process-per-tab). Any time we return true, 744 // the new_entry will be rendered in a new SiteInstance AND BrowsingInstance. 745 BrowserContext* browser_context = 746 delegate_->GetControllerForRenderManager().GetBrowserContext(); 747 748 // Don't force a new BrowsingInstance for debug URLs that are handled in the 749 // renderer process, like javascript: or chrome://crash. 750 if (IsRendererDebugURL(new_effective_url)) 751 return false; 752 753 // For security, we should transition between processes when one is a Web UI 754 // page and one isn't. 755 if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL( 756 browser_context, current_effective_url)) { 757 // If so, force a swap if destination is not an acceptable URL for Web UI. 758 // Here, data URLs are never allowed. 759 if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI( 760 browser_context, new_effective_url)) { 761 return true; 762 } 763 } else { 764 // Force a swap if it's a Web UI URL. 765 if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL( 766 browser_context, new_effective_url)) { 767 return true; 768 } 769 } 770 771 // Check with the content client as well. Important to pass 772 // current_effective_url here, which uses the SiteInstance's site if there is 773 // no current_entry. 774 if (GetContentClient()->browser()->ShouldSwapBrowsingInstancesForNavigation( 775 render_frame_host_->GetSiteInstance(), 776 current_effective_url, new_effective_url)) { 777 return true; 778 } 779 780 // We can't switch a RenderView between view source and non-view source mode 781 // without screwing up the session history sometimes (when navigating between 782 // "view-source:http://foo.com/" and "http://foo.com/", Blink doesn't treat 783 // it as a new navigation). So require a BrowsingInstance switch. 784 if (current_is_view_source_mode != new_is_view_source_mode) 785 return true; 786 787 return false; 788 } 789 790 bool RenderFrameHostManager::ShouldReuseWebUI( 791 const NavigationEntry* current_entry, 792 const NavigationEntryImpl* new_entry) const { 793 NavigationControllerImpl& controller = 794 delegate_->GetControllerForRenderManager(); 795 return current_entry && web_ui_.get() && 796 (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType( 797 controller.GetBrowserContext(), current_entry->GetURL()) == 798 WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType( 799 controller.GetBrowserContext(), new_entry->GetURL())); 800 } 801 802 SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation( 803 const GURL& dest_url, 804 SiteInstance* dest_instance, 805 ui::PageTransition dest_transition, 806 bool dest_is_restore, 807 bool dest_is_view_source_mode) { 808 SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); 809 SiteInstance* new_instance = current_instance; 810 811 // We do not currently swap processes for navigations in webview tag guests. 812 bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme); 813 814 // Determine if we need a new BrowsingInstance for this entry. If true, this 815 // implies that it will get a new SiteInstance (and likely process), and that 816 // other tabs in the current BrowsingInstance will be unable to script it. 817 // This is used for cases that require a process swap even in the 818 // process-per-tab model, such as WebUI pages. 819 // TODO(clamy): Remove the dependency on the current entry. 820 const NavigationEntry* current_entry = 821 delegate_->GetLastCommittedNavigationEntryForRenderManager(); 822 BrowserContext* browser_context = 823 delegate_->GetControllerForRenderManager().GetBrowserContext(); 824 const GURL& current_effective_url = current_entry ? 825 SiteInstanceImpl::GetEffectiveURL(browser_context, 826 current_entry->GetURL()) : 827 render_frame_host_->GetSiteInstance()->GetSiteURL(); 828 bool current_is_view_source_mode = current_entry ? 829 current_entry->IsViewSourceMode() : dest_is_view_source_mode; 830 bool force_swap = !is_guest_scheme && 831 ShouldSwapBrowsingInstancesForNavigation( 832 current_effective_url, 833 current_is_view_source_mode, 834 dest_instance, 835 SiteInstanceImpl::GetEffectiveURL(browser_context, dest_url), 836 dest_is_view_source_mode); 837 if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap)) { 838 new_instance = GetSiteInstanceForURL( 839 dest_url, 840 dest_instance, 841 dest_transition, 842 dest_is_restore, 843 dest_is_view_source_mode, 844 current_instance, 845 force_swap); 846 } 847 848 // If force_swap is true, we must use a different SiteInstance. If we didn't, 849 // we would have two RenderFrameHosts in the same SiteInstance and the same 850 // frame, resulting in page_id conflicts for their NavigationEntries. 851 if (force_swap) 852 CHECK_NE(new_instance, current_instance); 853 return new_instance; 854 } 855 856 SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL( 857 const GURL& dest_url, 858 SiteInstance* dest_instance, 859 ui::PageTransition dest_transition, 860 bool dest_is_restore, 861 bool dest_is_view_source_mode, 862 SiteInstance* current_instance, 863 bool force_browsing_instance_swap) { 864 NavigationControllerImpl& controller = 865 delegate_->GetControllerForRenderManager(); 866 BrowserContext* browser_context = controller.GetBrowserContext(); 867 868 // If the entry has an instance already we should use it. 869 if (dest_instance) { 870 // If we are forcing a swap, this should be in a different BrowsingInstance. 871 if (force_browsing_instance_swap) { 872 CHECK(!dest_instance->IsRelatedSiteInstance( 873 render_frame_host_->GetSiteInstance())); 874 } 875 return dest_instance; 876 } 877 878 // If a swap is required, we need to force the SiteInstance AND 879 // BrowsingInstance to be different ones, using CreateForURL. 880 if (force_browsing_instance_swap) 881 return SiteInstance::CreateForURL(browser_context, dest_url); 882 883 // (UGLY) HEURISTIC, process-per-site only: 884 // 885 // If this navigation is generated, then it probably corresponds to a search 886 // query. Given that search results typically lead to users navigating to 887 // other sites, we don't really want to use the search engine hostname to 888 // determine the site instance for this navigation. 889 // 890 // NOTE: This can be removed once we have a way to transition between 891 // RenderViews in response to a link click. 892 // 893 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) && 894 ui::PageTransitionCoreTypeIs( 895 dest_transition, ui::PAGE_TRANSITION_GENERATED)) { 896 return current_instance; 897 } 898 899 SiteInstanceImpl* current_site_instance = 900 static_cast<SiteInstanceImpl*>(current_instance); 901 902 // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it 903 // for this entry. We won't commit the SiteInstance to this site until the 904 // navigation commits (in DidNavigate), unless the navigation entry was 905 // restored or it's a Web UI as described below. 906 if (!current_site_instance->HasSite()) { 907 // If we've already created a SiteInstance for our destination, we don't 908 // want to use this unused SiteInstance; use the existing one. (We don't 909 // do this check if the current_instance has a site, because for now, we 910 // want to compare against the current URL and not the SiteInstance's site. 911 // In this case, there is no current URL, so comparing against the site is 912 // ok. See additional comments below.) 913 // 914 // Also, if the URL should use process-per-site mode and there is an 915 // existing process for the site, we should use it. We can call 916 // GetRelatedSiteInstance() for this, which will eagerly set the site and 917 // thus use the correct process. 918 bool use_process_per_site = 919 RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) && 920 RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url); 921 if (current_site_instance->HasRelatedSiteInstance(dest_url) || 922 use_process_per_site) { 923 return current_site_instance->GetRelatedSiteInstance(dest_url); 924 } 925 926 // For extensions, Web UI URLs (such as the new tab page), and apps we do 927 // not want to use the current_instance if it has no site, since it will 928 // have a RenderProcessHost of PRIV_NORMAL. Create a new SiteInstance for 929 // this URL instead (with the correct process type). 930 if (current_site_instance->HasWrongProcessForURL(dest_url)) 931 return current_site_instance->GetRelatedSiteInstance(dest_url); 932 933 // View-source URLs must use a new SiteInstance and BrowsingInstance. 934 // TODO(nasko): This is the same condition as later in the function. This 935 // should be taken into account when refactoring this method as part of 936 // http://crbug.com/123007. 937 if (dest_is_view_source_mode) 938 return SiteInstance::CreateForURL(browser_context, dest_url); 939 940 // If we are navigating from a blank SiteInstance to a WebUI, make sure we 941 // create a new SiteInstance. 942 if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL( 943 browser_context, dest_url)) { 944 return SiteInstance::CreateForURL(browser_context, dest_url); 945 } 946 947 // Normally the "site" on the SiteInstance is set lazily when the load 948 // actually commits. This is to support better process sharing in case 949 // the site redirects to some other site: we want to use the destination 950 // site in the site instance. 951 // 952 // In the case of session restore, as it loads all the pages immediately 953 // we need to set the site first, otherwise after a restore none of the 954 // pages would share renderers in process-per-site. 955 // 956 // The embedder can request some urls never to be assigned to SiteInstance 957 // through the ShouldAssignSiteForURL() content client method, so that 958 // renderers created for particular chrome urls (e.g. the chrome-native:// 959 // scheme) can be reused for subsequent navigations in the same WebContents. 960 // See http://crbug.com/386542. 961 if (dest_is_restore && 962 GetContentClient()->browser()->ShouldAssignSiteForURL(dest_url)) { 963 current_site_instance->SetSite(dest_url); 964 } 965 966 return current_site_instance; 967 } 968 969 // Otherwise, only create a new SiteInstance for a cross-site navigation. 970 971 // TODO(creis): Once we intercept links and script-based navigations, we 972 // will be able to enforce that all entries in a SiteInstance actually have 973 // the same site, and it will be safe to compare the URL against the 974 // SiteInstance's site, as follows: 975 // const GURL& current_url = current_instance->site(); 976 // For now, though, we're in a hybrid model where you only switch 977 // SiteInstances if you type in a cross-site URL. This means we have to 978 // compare the entry's URL to the last committed entry's URL. 979 NavigationEntry* current_entry = controller.GetLastCommittedEntry(); 980 if (interstitial_page_) { 981 // The interstitial is currently the last committed entry, but we want to 982 // compare against the last non-interstitial entry. 983 current_entry = controller.GetEntryAtOffset(-1); 984 } 985 // If there is no last non-interstitial entry (and current_instance already 986 // has a site), then we must have been opened from another tab. We want 987 // to compare against the URL of the page that opened us, but we can't 988 // get to it directly. The best we can do is check against the site of 989 // the SiteInstance. This will be correct when we intercept links and 990 // script-based navigations, but for now, it could place some pages in a 991 // new process unnecessarily. We should only hit this case if a page tries 992 // to open a new tab to an interstitial-inducing URL, and then navigates 993 // the page to a different same-site URL. (This seems very unlikely in 994 // practice.) 995 const GURL& current_url = (current_entry) ? current_entry->GetURL() : 996 current_instance->GetSiteURL(); 997 998 // View-source URLs must use a new SiteInstance and BrowsingInstance. 999 // We don't need a swap when going from view-source to a debug URL like 1000 // chrome://crash, however. 1001 // TODO(creis): Refactor this method so this duplicated code isn't needed. 1002 // See http://crbug.com/123007. 1003 if (current_entry && 1004 current_entry->IsViewSourceMode() != dest_is_view_source_mode && 1005 !IsRendererDebugURL(dest_url)) { 1006 return SiteInstance::CreateForURL(browser_context, dest_url); 1007 } 1008 1009 // Use the current SiteInstance for same site navigations, as long as the 1010 // process type is correct. (The URL may have been installed as an app since 1011 // the last time we visited it.) 1012 if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) && 1013 !current_site_instance->HasWrongProcessForURL(dest_url)) { 1014 return current_instance; 1015 } 1016 1017 // Start the new renderer in a new SiteInstance, but in the current 1018 // BrowsingInstance. It is important to immediately give this new 1019 // SiteInstance to a RenderViewHost (if it is different than our current 1020 // SiteInstance), so that it is ref counted. This will happen in 1021 // CreateRenderView. 1022 return current_instance->GetRelatedSiteInstance(dest_url); 1023 } 1024 1025 void RenderFrameHostManager::CreateRenderFrameHostForNewSiteInstance( 1026 SiteInstance* old_instance, 1027 SiteInstance* new_instance, 1028 bool is_main_frame) { 1029 // Ensure that we have created RFHs for the new RFH's opener chain if 1030 // we are staying in the same BrowsingInstance. This allows the new RFH 1031 // to send cross-process script calls to its opener(s). 1032 int opener_route_id = MSG_ROUTING_NONE; 1033 if (new_instance->IsRelatedSiteInstance(old_instance)) { 1034 opener_route_id = 1035 delegate_->CreateOpenerRenderViewsForRenderManager(new_instance); 1036 if (CommandLine::ForCurrentProcess()->HasSwitch( 1037 switches::kSitePerProcess)) { 1038 // Ensure that the frame tree has RenderFrameProxyHosts for the new 1039 // SiteInstance in all nodes except the current one. 1040 frame_tree_node_->frame_tree()->CreateProxiesForSiteInstance( 1041 frame_tree_node_, new_instance); 1042 } 1043 } 1044 1045 // Create a non-swapped-out RFH with the given opener. 1046 int route_id = CreateRenderFrame( 1047 new_instance, opener_route_id, false, is_main_frame, 1048 delegate_->IsHidden()); 1049 if (route_id == MSG_ROUTING_NONE) { 1050 pending_render_frame_host_.reset(); 1051 return; 1052 } 1053 } 1054 1055 scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost( 1056 SiteInstance* site_instance, 1057 int view_routing_id, 1058 int frame_routing_id, 1059 bool swapped_out, 1060 bool hidden) { 1061 if (frame_routing_id == MSG_ROUTING_NONE) 1062 frame_routing_id = site_instance->GetProcess()->GetNextRoutingID(); 1063 1064 // Create a RVH for main frames, or find the existing one for subframes. 1065 FrameTree* frame_tree = frame_tree_node_->frame_tree(); 1066 RenderViewHostImpl* render_view_host = NULL; 1067 if (frame_tree_node_->IsMainFrame()) { 1068 render_view_host = frame_tree->CreateRenderViewHost( 1069 site_instance, view_routing_id, frame_routing_id, swapped_out, hidden); 1070 } else { 1071 render_view_host = frame_tree->GetRenderViewHost(site_instance); 1072 1073 CHECK(render_view_host); 1074 } 1075 1076 // TODO(creis): Pass hidden to RFH. 1077 scoped_ptr<RenderFrameHostImpl> render_frame_host = 1078 make_scoped_ptr(RenderFrameHostFactory::Create(render_view_host, 1079 render_frame_delegate_, 1080 frame_tree, 1081 frame_tree_node_, 1082 frame_routing_id, 1083 swapped_out).release()); 1084 return render_frame_host.Pass(); 1085 } 1086 1087 int RenderFrameHostManager::CreateRenderFrame(SiteInstance* instance, 1088 int opener_route_id, 1089 bool swapped_out, 1090 bool for_main_frame_navigation, 1091 bool hidden) { 1092 CHECK(instance); 1093 DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden. 1094 1095 // TODO(nasko): Remove the following CHECK once cross-site navigation no 1096 // longer relies on swapped out RFH for the top-level frame. 1097 if (!frame_tree_node_->IsMainFrame()) { 1098 CHECK(!swapped_out); 1099 } 1100 1101 scoped_ptr<RenderFrameHostImpl> new_render_frame_host; 1102 RenderFrameHostImpl* frame_to_announce = NULL; 1103 int routing_id = MSG_ROUTING_NONE; 1104 1105 // We are creating a pending or swapped out RFH here. We should never create 1106 // it in the same SiteInstance as our current RFH. 1107 CHECK_NE(render_frame_host_->GetSiteInstance(), instance); 1108 1109 // Check if we've already created an RFH for this SiteInstance. If so, try 1110 // to re-use the existing one, which has already been initialized. We'll 1111 // remove it from the list of proxy hosts below if it will be active. 1112 RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance); 1113 1114 if (proxy && proxy->render_frame_host()) { 1115 routing_id = proxy->GetRenderViewHost()->GetRoutingID(); 1116 // Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost. 1117 // Prevent the process from exiting while we're trying to use it. 1118 if (!swapped_out) { 1119 new_render_frame_host = proxy->PassFrameHostOwnership(); 1120 new_render_frame_host->GetProcess()->AddPendingView(); 1121 1122 proxy_hosts_.erase(instance->GetId()); 1123 delete proxy; 1124 1125 // When a new render view is created by the renderer, the new WebContents 1126 // gets a RenderViewHost in the SiteInstance of its opener WebContents. 1127 // If not used in the first navigation, this RVH is swapped out and is not 1128 // granted bindings, so we may need to grant them when swapping it in. 1129 if (pending_web_ui() && 1130 !new_render_frame_host->GetProcess()->IsIsolatedGuest()) { 1131 int required_bindings = pending_web_ui()->GetBindings(); 1132 RenderViewHost* rvh = new_render_frame_host->render_view_host(); 1133 if ((rvh->GetEnabledBindings() & required_bindings) != 1134 required_bindings) { 1135 rvh->AllowBindings(required_bindings); 1136 } 1137 } 1138 } 1139 } else { 1140 // Create a new RenderFrameHost if we don't find an existing one. 1141 new_render_frame_host = CreateRenderFrameHost( 1142 instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, swapped_out, hidden); 1143 RenderViewHostImpl* render_view_host = 1144 new_render_frame_host->render_view_host(); 1145 int proxy_routing_id = MSG_ROUTING_NONE; 1146 1147 // Prevent the process from exiting while we're trying to navigate in it. 1148 // Otherwise, if the new RFH is swapped out already, store it. 1149 if (!swapped_out) { 1150 new_render_frame_host->GetProcess()->AddPendingView(); 1151 } else { 1152 proxy = new RenderFrameProxyHost( 1153 new_render_frame_host->GetSiteInstance(), frame_tree_node_); 1154 proxy_hosts_[instance->GetId()] = proxy; 1155 proxy_routing_id = proxy->GetRoutingID(); 1156 if (frame_tree_node_->IsMainFrame()) 1157 proxy->TakeFrameHostOwnership(new_render_frame_host.Pass()); 1158 } 1159 1160 bool success = InitRenderView(render_view_host, 1161 opener_route_id, 1162 proxy_routing_id, 1163 for_main_frame_navigation); 1164 if (success) { 1165 if (frame_tree_node_->IsMainFrame()) { 1166 // Don't show the main frame's view until we get a DidNavigate from it. 1167 render_view_host->GetView()->Hide(); 1168 } else if (!swapped_out) { 1169 // Init the RFH, so a RenderFrame is created in the renderer. 1170 DCHECK(new_render_frame_host.get()); 1171 success = InitRenderFrame(new_render_frame_host.get()); 1172 } 1173 if (swapped_out) { 1174 proxy_hosts_[instance->GetId()]->InitRenderFrameProxy(); 1175 } 1176 } else if (!swapped_out && pending_render_frame_host_) { 1177 CancelPending(); 1178 } 1179 routing_id = render_view_host->GetRoutingID(); 1180 frame_to_announce = new_render_frame_host.get(); 1181 } 1182 1183 // Use this as our new pending RFH if it isn't swapped out. 1184 if (!swapped_out) 1185 pending_render_frame_host_ = new_render_frame_host.Pass(); 1186 1187 // If a brand new RFH was created, announce it to observers. 1188 if (frame_to_announce) 1189 render_frame_delegate_->RenderFrameCreated(frame_to_announce); 1190 1191 return routing_id; 1192 } 1193 1194 int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance) { 1195 // A RenderFrameProxyHost should never be created in the same SiteInstance as 1196 // the current RFH. 1197 CHECK(instance); 1198 CHECK_NE(instance, render_frame_host_->GetSiteInstance()); 1199 1200 RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance); 1201 if (proxy) 1202 return proxy->GetRoutingID(); 1203 1204 proxy = new RenderFrameProxyHost(instance, frame_tree_node_); 1205 proxy_hosts_[instance->GetId()] = proxy; 1206 proxy->InitRenderFrameProxy(); 1207 return proxy->GetRoutingID(); 1208 } 1209 1210 bool RenderFrameHostManager::InitRenderView( 1211 RenderViewHostImpl* render_view_host, 1212 int opener_route_id, 1213 int proxy_routing_id, 1214 bool for_main_frame_navigation) { 1215 // We may have initialized this RenderViewHost for another RenderFrameHost. 1216 if (render_view_host->IsRenderViewLive()) 1217 return true; 1218 1219 // If the pending navigation is to a WebUI and the RenderView is not in a 1220 // guest process, tell the RenderViewHost about any bindings it will need 1221 // enabled. 1222 if (pending_web_ui() && !render_view_host->GetProcess()->IsIsolatedGuest()) { 1223 render_view_host->AllowBindings(pending_web_ui()->GetBindings()); 1224 } else { 1225 // Ensure that we don't create an unprivileged RenderView in a WebUI-enabled 1226 // process unless it's swapped out. 1227 if (!render_view_host->IsSwappedOut()) { 1228 CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 1229 render_view_host->GetProcess()->GetID())); 1230 } 1231 } 1232 1233 return delegate_->CreateRenderViewForRenderManager(render_view_host, 1234 opener_route_id, 1235 proxy_routing_id, 1236 for_main_frame_navigation); 1237 } 1238 1239 bool RenderFrameHostManager::InitRenderFrame( 1240 RenderFrameHostImpl* render_frame_host) { 1241 if (render_frame_host->IsRenderFrameLive()) 1242 return true; 1243 1244 int parent_routing_id = MSG_ROUTING_NONE; 1245 if (frame_tree_node_->parent()) { 1246 parent_routing_id = frame_tree_node_->parent()->render_manager()-> 1247 GetRoutingIdForSiteInstance(render_frame_host->GetSiteInstance()); 1248 CHECK_NE(parent_routing_id, MSG_ROUTING_NONE); 1249 } 1250 return delegate_->CreateRenderFrameForRenderManager(render_frame_host, 1251 parent_routing_id); 1252 } 1253 1254 int RenderFrameHostManager::GetRoutingIdForSiteInstance( 1255 SiteInstance* site_instance) { 1256 if (render_frame_host_->GetSiteInstance() == site_instance) 1257 return render_frame_host_->GetRoutingID(); 1258 1259 RenderFrameProxyHostMap::iterator iter = 1260 proxy_hosts_.find(site_instance->GetId()); 1261 if (iter != proxy_hosts_.end()) 1262 return iter->second->GetRoutingID(); 1263 1264 return MSG_ROUTING_NONE; 1265 } 1266 1267 void RenderFrameHostManager::CommitPending() { 1268 TRACE_EVENT1("navigation", "RenderFrameHostManager::CommitPending", 1269 "FrameTreeNode id", frame_tree_node_->frame_tree_node_id()); 1270 // First check whether we're going to want to focus the location bar after 1271 // this commit. We do this now because the navigation hasn't formally 1272 // committed yet, so if we've already cleared |pending_web_ui_| the call chain 1273 // this triggers won't be able to figure out what's going on. 1274 bool will_focus_location_bar = delegate_->FocusLocationBarByDefault(); 1275 1276 // Next commit the Web UI, if any. Either replace |web_ui_| with 1277 // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or 1278 // leave |web_ui_| as is if reusing it. 1279 DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get())); 1280 if (pending_web_ui_) { 1281 web_ui_.reset(pending_web_ui_.release()); 1282 } else if (!pending_and_current_web_ui_.get()) { 1283 web_ui_.reset(); 1284 } else { 1285 DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get()); 1286 pending_and_current_web_ui_.reset(); 1287 } 1288 1289 // It's possible for the pending_render_frame_host_ to be NULL when we aren't 1290 // crossing process boundaries. If so, we just needed to handle the Web UI 1291 // committing above and we're done. 1292 if (!pending_render_frame_host_) { 1293 if (will_focus_location_bar) 1294 delegate_->SetFocusToLocationBar(false); 1295 return; 1296 } 1297 1298 // Remember if the page was focused so we can focus the new renderer in 1299 // that case. 1300 bool focus_render_view = !will_focus_location_bar && 1301 render_frame_host_->render_view_host()->GetView() && 1302 render_frame_host_->render_view_host()->GetView()->HasFocus(); 1303 1304 // TODO(creis): As long as show/hide are on RVH, we don't want to do them for 1305 // subframe navigations or they'll interfere with the top-level page. 1306 bool is_main_frame = frame_tree_node_->IsMainFrame(); 1307 1308 // Swap in the pending frame and make it active. Also ensure the FrameTree 1309 // stays in sync. 1310 scoped_ptr<RenderFrameHostImpl> old_render_frame_host = 1311 SetRenderFrameHost(pending_render_frame_host_.Pass()); 1312 if (is_main_frame) 1313 render_frame_host_->render_view_host()->AttachToFrameTree(); 1314 1315 // The process will no longer try to exit, so we can decrement the count. 1316 render_frame_host_->GetProcess()->RemovePendingView(); 1317 1318 // If the view is gone, then this RenderViewHost died while it was hidden. 1319 // We ignored the RenderProcessGone call at the time, so we should send it now 1320 // to make sure the sad tab shows up, etc. 1321 if (!render_frame_host_->render_view_host()->GetView()) { 1322 delegate_->RenderProcessGoneFromRenderManager( 1323 render_frame_host_->render_view_host()); 1324 } else if (!delegate_->IsHidden()) { 1325 render_frame_host_->render_view_host()->GetView()->Show(); 1326 } 1327 1328 // If the old frame is live, swap it out now that the new frame is visible. 1329 int32 old_site_instance_id = 1330 old_render_frame_host->GetSiteInstance()->GetId(); 1331 if (old_render_frame_host->IsRenderFrameLive()) { 1332 SwapOutOldPage(old_render_frame_host.get()); 1333 1334 // Schedule the old frame to shut down after it swaps out, if there are no 1335 // other active views in its SiteInstance. 1336 if (!static_cast<SiteInstanceImpl*>( 1337 old_render_frame_host->GetSiteInstance())->active_view_count()) { 1338 old_render_frame_host->render_view_host()->SetPendingShutdown(base::Bind( 1339 &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance, 1340 weak_factory_.GetWeakPtr(), 1341 old_site_instance_id, 1342 old_render_frame_host.get())); 1343 } 1344 } 1345 1346 // For top-level frames, also hide the old RenderViewHost's view. 1347 if (is_main_frame && old_render_frame_host->render_view_host()->GetView()) 1348 old_render_frame_host->render_view_host()->GetView()->Hide(); 1349 1350 // Make sure the size is up to date. (Fix for bug 1079768.) 1351 delegate_->UpdateRenderViewSizeForRenderManager(); 1352 1353 if (will_focus_location_bar) { 1354 delegate_->SetFocusToLocationBar(false); 1355 } else if (focus_render_view && 1356 render_frame_host_->render_view_host()->GetView()) { 1357 render_frame_host_->render_view_host()->GetView()->Focus(); 1358 } 1359 1360 // Notify that we've swapped RenderFrameHosts. We do this before shutting down 1361 // the RFH so that we can clean up RendererResources related to the RFH first. 1362 delegate_->NotifySwappedFromRenderManager( 1363 old_render_frame_host.get(), render_frame_host_.get(), is_main_frame); 1364 1365 // If the old RFH is not live, just return as there is no further work to do. 1366 if (!old_render_frame_host->IsRenderFrameLive()) 1367 return; 1368 1369 // If the old RFH is live, we are swapping it out and should keep track of 1370 // it in case we navigate back to it, or it is waiting for the unload event 1371 // to execute in the background. 1372 // TODO(creis): Swap out the subframe in --site-per-process. 1373 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) { 1374 DCHECK(old_render_frame_host->is_swapped_out() || 1375 !RenderViewHostImpl::IsRVHStateActive( 1376 old_render_frame_host->render_view_host()->rvh_state())); 1377 } 1378 1379 // If the RenderViewHost backing the RenderFrameHost is pending shutdown, 1380 // the RenderFrameHost should be put in the map of RenderFrameHosts pending 1381 // shutdown. Otherwise, it is stored in the map of proxy hosts. 1382 if (old_render_frame_host->render_view_host()->rvh_state() == 1383 RenderViewHostImpl::STATE_PENDING_SHUTDOWN) { 1384 // The proxy for this RenderFrameHost is created when sending the 1385 // SwapOut message, so check if it already exists and delete it. 1386 RenderFrameProxyHostMap::iterator iter = 1387 proxy_hosts_.find(old_site_instance_id); 1388 if (iter != proxy_hosts_.end()) { 1389 delete iter->second; 1390 proxy_hosts_.erase(iter); 1391 } 1392 RFHPendingDeleteMap::iterator pending_delete_iter = 1393 pending_delete_hosts_.find(old_site_instance_id); 1394 if (pending_delete_iter == pending_delete_hosts_.end() || 1395 pending_delete_iter->second.get() != old_render_frame_host) { 1396 pending_delete_hosts_[old_site_instance_id] = 1397 linked_ptr<RenderFrameHostImpl>(old_render_frame_host.release()); 1398 } 1399 } else { 1400 CHECK(proxy_hosts_.find(render_frame_host_->GetSiteInstance()->GetId()) == 1401 proxy_hosts_.end()); 1402 1403 // Capture the active view count on the old RFH SiteInstance, since the 1404 // ownership might be passed into the proxy and the pointer will be 1405 // invalid. 1406 int active_view_count = 1407 static_cast<SiteInstanceImpl*>(old_render_frame_host->GetSiteInstance()) 1408 ->active_view_count(); 1409 1410 if (is_main_frame) { 1411 RenderFrameProxyHostMap::iterator iter = 1412 proxy_hosts_.find(old_site_instance_id); 1413 CHECK(iter != proxy_hosts_.end()); 1414 iter->second->TakeFrameHostOwnership(old_render_frame_host.Pass()); 1415 } 1416 1417 // If there are no active views in this SiteInstance, it means that 1418 // this RFH was the last active one in the SiteInstance. Now that we 1419 // know that all RFHs are swapped out, we can delete all the RFPHs and 1420 // RVHs in this SiteInstance. 1421 if (!active_view_count) { 1422 ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id); 1423 } else { 1424 // If this is a subframe, it should have a CrossProcessFrameConnector 1425 // created already and we just need to link it to the proper view in the 1426 // new process. 1427 if (!is_main_frame) { 1428 RenderFrameProxyHost* proxy = GetProxyToParent(); 1429 if (proxy) { 1430 proxy->SetChildRWHView( 1431 render_frame_host_->render_view_host()->GetView()); 1432 } 1433 } 1434 } 1435 } 1436 } 1437 1438 void RenderFrameHostManager::ShutdownRenderFrameProxyHostsInSiteInstance( 1439 int32 site_instance_id) { 1440 // First remove any swapped out RFH for this SiteInstance from our own list. 1441 ClearProxiesInSiteInstance(site_instance_id, frame_tree_node_); 1442 1443 // Use the safe RenderWidgetHost iterator for now to find all RenderViewHosts 1444 // in the SiteInstance, then tell their respective FrameTrees to remove all 1445 // RenderFrameProxyHosts corresponding to them. 1446 // TODO(creis): Replace this with a RenderFrameHostIterator that protects 1447 // against use-after-frees if a later element is deleted before getting to it. 1448 scoped_ptr<RenderWidgetHostIterator> widgets( 1449 RenderWidgetHostImpl::GetAllRenderWidgetHosts()); 1450 while (RenderWidgetHost* widget = widgets->GetNextHost()) { 1451 if (!widget->IsRenderView()) 1452 continue; 1453 RenderViewHostImpl* rvh = 1454 static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget)); 1455 if (site_instance_id == rvh->GetSiteInstance()->GetId()) { 1456 // This deletes all RenderFrameHosts using the |rvh|, which then causes 1457 // |rvh| to Shutdown. 1458 FrameTree* tree = rvh->GetDelegate()->GetFrameTree(); 1459 tree->ForEach(base::Bind( 1460 &RenderFrameHostManager::ClearProxiesInSiteInstance, 1461 site_instance_id)); 1462 } 1463 } 1464 } 1465 1466 RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate( 1467 const NavigationEntryImpl& entry) { 1468 // If we are currently navigating cross-process, we want to get back to normal 1469 // and then navigate as usual. 1470 if (cross_navigation_pending_) { 1471 if (pending_render_frame_host_) 1472 CancelPending(); 1473 cross_navigation_pending_ = false; 1474 } 1475 1476 SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); 1477 scoped_refptr<SiteInstance> new_instance = 1478 GetSiteInstanceForNavigation( 1479 entry.GetURL(), 1480 entry.site_instance(), 1481 entry.GetTransitionType(), 1482 entry.restore_type() != NavigationEntryImpl::RESTORE_NONE, 1483 entry.IsViewSourceMode()); 1484 1485 const NavigationEntry* current_entry = 1486 delegate_->GetLastCommittedNavigationEntryForRenderManager(); 1487 1488 if (new_instance.get() != current_instance) { 1489 TRACE_EVENT_INSTANT2( 1490 "navigation", 1491 "RenderFrameHostManager::UpdateStateForNavigate:New SiteInstance", 1492 TRACE_EVENT_SCOPE_THREAD, 1493 "current_instance id", current_instance->GetId(), 1494 "new_instance id", new_instance->GetId()); 1495 1496 // New SiteInstance: create a pending RFH to navigate. 1497 DCHECK(!cross_navigation_pending_); 1498 1499 // This will possibly create (set to NULL) a Web UI object for the pending 1500 // page. We'll use this later to give the page special access. This must 1501 // happen before the new renderer is created below so it will get bindings. 1502 // It must also happen after the above conditional call to CancelPending(), 1503 // otherwise CancelPending may clear the pending_web_ui_ and the page will 1504 // not have its bindings set appropriately. 1505 SetPendingWebUI(entry); 1506 CreateRenderFrameHostForNewSiteInstance( 1507 current_instance, new_instance.get(), frame_tree_node_->IsMainFrame()); 1508 if (!pending_render_frame_host_.get()) { 1509 return NULL; 1510 } 1511 1512 // Check if our current RFH is live before we set up a transition. 1513 if (!render_frame_host_->IsRenderFrameLive()) { 1514 if (!cross_navigation_pending_) { 1515 // The current RFH is not live. There's no reason to sit around with a 1516 // sad tab or a newly created RFH while we wait for the pending RFH to 1517 // navigate. Just switch to the pending RFH now and go back to non 1518 // cross-navigating (Note that we don't care about on{before}unload 1519 // handlers if the current RFH isn't live.) 1520 CommitPending(); 1521 return render_frame_host_.get(); 1522 } else { 1523 NOTREACHED(); 1524 return render_frame_host_.get(); 1525 } 1526 } 1527 // Otherwise, it's safe to treat this as a pending cross-site transition. 1528 1529 // We need to wait until the beforeunload handler has run, unless we are 1530 // transferring an existing request (in which case it has already run). 1531 // Suspend the new render view (i.e., don't let it send the cross-site 1532 // Navigate message) until we hear back from the old renderer's 1533 // beforeunload handler. If the handler returns false, we'll have to 1534 // cancel the request. 1535 DCHECK(!pending_render_frame_host_->are_navigations_suspended()); 1536 bool is_transfer = 1537 entry.transferred_global_request_id() != GlobalRequestID(); 1538 if (is_transfer) { 1539 // We don't need to stop the old renderer or run beforeunload/unload 1540 // handlers, because those have already been done. 1541 DCHECK(cross_site_transferring_request_->request_id() == 1542 entry.transferred_global_request_id()); 1543 } else { 1544 // Also make sure the old render view stops, in case a load is in 1545 // progress. (We don't want to do this for transfers, since it will 1546 // interrupt the transfer with an unexpected DidStopLoading.) 1547 render_frame_host_->Send(new FrameMsg_Stop( 1548 render_frame_host_->GetRoutingID())); 1549 pending_render_frame_host_->SetNavigationsSuspended(true, 1550 base::TimeTicks()); 1551 } 1552 1553 // We now have a pending RFH. 1554 DCHECK(!cross_navigation_pending_); 1555 cross_navigation_pending_ = true; 1556 1557 // Unless we are transferring an existing request, we should now 1558 // tell the old render view to run its beforeunload handler, since it 1559 // doesn't otherwise know that the cross-site request is happening. This 1560 // will trigger a call to OnBeforeUnloadACK with the reply. 1561 if (!is_transfer) 1562 render_frame_host_->DispatchBeforeUnload(true); 1563 1564 return pending_render_frame_host_.get(); 1565 } 1566 1567 // Otherwise the same SiteInstance can be used. Navigate render_frame_host_. 1568 DCHECK(!cross_navigation_pending_); 1569 1570 // It's possible to swap out the current RFH and then decide to navigate in it 1571 // anyway (e.g., a cross-process navigation that redirects back to the 1572 // original site). In that case, we have a proxy for the current RFH but 1573 // haven't deleted it yet. The new navigation will swap it back in, so we can 1574 // delete the proxy. 1575 DeleteRenderFrameProxyHost(new_instance.get()); 1576 1577 if (ShouldReuseWebUI(current_entry, &entry)) { 1578 pending_web_ui_.reset(); 1579 pending_and_current_web_ui_ = web_ui_->AsWeakPtr(); 1580 } else { 1581 SetPendingWebUI(entry); 1582 1583 // Make sure the new RenderViewHost has the right bindings. 1584 if (pending_web_ui() && 1585 !render_frame_host_->GetProcess()->IsIsolatedGuest()) { 1586 render_frame_host_->render_view_host()->AllowBindings( 1587 pending_web_ui()->GetBindings()); 1588 } 1589 } 1590 1591 if (pending_web_ui() && render_frame_host_->IsRenderFrameLive()) { 1592 pending_web_ui()->GetController()->RenderViewReused( 1593 render_frame_host_->render_view_host()); 1594 } 1595 1596 // The renderer can exit view source mode when any error or cancellation 1597 // happen. We must overwrite to recover the mode. 1598 if (entry.IsViewSourceMode()) { 1599 render_frame_host_->render_view_host()->Send( 1600 new ViewMsg_EnableViewSourceMode( 1601 render_frame_host_->render_view_host()->GetRoutingID())); 1602 } 1603 1604 return render_frame_host_.get(); 1605 } 1606 1607 void RenderFrameHostManager::CancelPending() { 1608 TRACE_EVENT1("navigation", "RenderFrameHostManager::CancelPending", 1609 "FrameTreeNode id", frame_tree_node_->frame_tree_node_id()); 1610 scoped_ptr<RenderFrameHostImpl> pending_render_frame_host = 1611 pending_render_frame_host_.Pass(); 1612 1613 RenderViewDevToolsAgentHost::OnCancelPendingNavigation( 1614 pending_render_frame_host->render_view_host(), 1615 render_frame_host_->render_view_host()); 1616 1617 // We no longer need to prevent the process from exiting. 1618 pending_render_frame_host->GetProcess()->RemovePendingView(); 1619 1620 // If the SiteInstance for the pending RFH is being used by others, don't 1621 // delete the RFH, just swap it out and it can be reused at a later point. 1622 SiteInstanceImpl* site_instance = static_cast<SiteInstanceImpl*>( 1623 pending_render_frame_host->GetSiteInstance()); 1624 if (site_instance->active_view_count() > 1) { 1625 // Any currently suspended navigations are no longer needed. 1626 pending_render_frame_host->CancelSuspendedNavigations(); 1627 1628 RenderFrameProxyHost* proxy = 1629 new RenderFrameProxyHost(site_instance, frame_tree_node_); 1630 proxy_hosts_[site_instance->GetId()] = proxy; 1631 pending_render_frame_host->SwapOut(proxy); 1632 if (frame_tree_node_->IsMainFrame()) 1633 proxy->TakeFrameHostOwnership(pending_render_frame_host.Pass()); 1634 } else { 1635 // We won't be coming back, so delete this one. 1636 pending_render_frame_host.reset(); 1637 } 1638 1639 pending_web_ui_.reset(); 1640 pending_and_current_web_ui_.reset(); 1641 } 1642 1643 scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::SetRenderFrameHost( 1644 scoped_ptr<RenderFrameHostImpl> render_frame_host) { 1645 // Swap the two. 1646 scoped_ptr<RenderFrameHostImpl> old_render_frame_host = 1647 render_frame_host_.Pass(); 1648 render_frame_host_ = render_frame_host.Pass(); 1649 1650 if (frame_tree_node_->IsMainFrame()) { 1651 // Update the count of top-level frames using this SiteInstance. All 1652 // subframes are in the same BrowsingInstance as the main frame, so we only 1653 // count top-level ones. This makes the value easier for consumers to 1654 // interpret. 1655 if (render_frame_host_) { 1656 static_cast<SiteInstanceImpl*>(render_frame_host_->GetSiteInstance())-> 1657 IncrementRelatedActiveContentsCount(); 1658 } 1659 if (old_render_frame_host) { 1660 static_cast<SiteInstanceImpl*>(old_render_frame_host->GetSiteInstance())-> 1661 DecrementRelatedActiveContentsCount(); 1662 } 1663 } 1664 1665 return old_render_frame_host.Pass(); 1666 } 1667 1668 bool RenderFrameHostManager::IsRVHOnSwappedOutList( 1669 RenderViewHostImpl* rvh) const { 1670 RenderFrameProxyHost* proxy = GetRenderFrameProxyHost( 1671 rvh->GetSiteInstance()); 1672 if (!proxy) 1673 return false; 1674 // If there is a proxy without RFH, it is for a subframe in the SiteInstance 1675 // of |rvh|. Subframes should be ignored in this case. 1676 if (!proxy->render_frame_host()) 1677 return false; 1678 return IsOnSwappedOutList(proxy->render_frame_host()); 1679 } 1680 1681 bool RenderFrameHostManager::IsOnSwappedOutList( 1682 RenderFrameHostImpl* rfh) const { 1683 if (!rfh->GetSiteInstance()) 1684 return false; 1685 1686 RenderFrameProxyHostMap::const_iterator iter = proxy_hosts_.find( 1687 rfh->GetSiteInstance()->GetId()); 1688 if (iter == proxy_hosts_.end()) 1689 return false; 1690 1691 return iter->second->render_frame_host() == rfh; 1692 } 1693 1694 RenderViewHostImpl* RenderFrameHostManager::GetSwappedOutRenderViewHost( 1695 SiteInstance* instance) const { 1696 RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance); 1697 if (proxy) 1698 return proxy->GetRenderViewHost(); 1699 return NULL; 1700 } 1701 1702 RenderFrameProxyHost* RenderFrameHostManager::GetRenderFrameProxyHost( 1703 SiteInstance* instance) const { 1704 RenderFrameProxyHostMap::const_iterator iter = 1705 proxy_hosts_.find(instance->GetId()); 1706 if (iter != proxy_hosts_.end()) 1707 return iter->second; 1708 1709 return NULL; 1710 } 1711 1712 void RenderFrameHostManager::DeleteRenderFrameProxyHost( 1713 SiteInstance* instance) { 1714 RenderFrameProxyHostMap::iterator iter = proxy_hosts_.find(instance->GetId()); 1715 if (iter != proxy_hosts_.end()) { 1716 delete iter->second; 1717 proxy_hosts_.erase(iter); 1718 } 1719 } 1720 1721 } // namespace content 1722