OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/frame_host/render_view_host_manager.h" | 5 #include "content/browser/frame_host/render_view_host_manager.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
(...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 return | 486 return |
487 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) && | 487 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) && |
488 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab); | 488 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab); |
489 } | 489 } |
490 | 490 |
491 bool RenderViewHostManager::ShouldSwapProcessesForNavigation( | 491 bool RenderViewHostManager::ShouldSwapProcessesForNavigation( |
492 const NavigationEntry* curr_entry, | 492 const NavigationEntry* curr_entry, |
493 const NavigationEntryImpl* new_entry) const { | 493 const NavigationEntryImpl* new_entry) const { |
494 DCHECK(new_entry); | 494 DCHECK(new_entry); |
495 | 495 |
| 496 // If new_entry already has a SiteInstance, assume it is correct and use it. |
| 497 if (new_entry->site_instance()) |
| 498 return false; |
| 499 |
496 // Check for reasons to swap processes even if we are in a process model that | 500 // Check for reasons to swap processes even if we are in a process model that |
497 // doesn't usually swap (e.g., process-per-tab). | 501 // doesn't usually swap (e.g., process-per-tab). |
498 | 502 |
499 // For security, we should transition between processes when one is a Web UI | 503 // We use the effective URL here, since that's what is used in the |
500 // page and one isn't. If there's no curr_entry, check the current RVH's | 504 // SiteInstance's site and when we later call IsSameWebSite. If there is no |
501 // site, which might already be committed to a Web UI URL (such as the NTP). | 505 // curr_entry, check the current SiteInstance's site, which might already be |
502 const GURL& current_url = (curr_entry) ? curr_entry->GetURL() : | 506 // committed to a Web UI URL (such as the NTP). |
503 render_view_host_->GetSiteInstance()->GetSiteURL(); | |
504 BrowserContext* browser_context = | 507 BrowserContext* browser_context = |
505 delegate_->GetControllerForRenderManager().GetBrowserContext(); | 508 delegate_->GetControllerForRenderManager().GetBrowserContext(); |
| 509 const GURL& current_url = (curr_entry) ? |
| 510 SiteInstanceImpl::GetEffectiveURL(browser_context, curr_entry->GetURL()) : |
| 511 render_view_host_->GetSiteInstance()->GetSiteURL(); |
| 512 const GURL& new_url = SiteInstanceImpl::GetEffectiveURL(browser_context, |
| 513 new_entry->GetURL()); |
| 514 |
| 515 // For security, we should transition between processes when one is a Web UI |
| 516 // page and one isn't. |
506 if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL( | 517 if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL( |
507 browser_context, current_url)) { | 518 browser_context, current_url)) { |
508 // Force swap if it's not an acceptable URL for Web UI. | 519 // Force swap if it's not an acceptable URL for Web UI. |
509 // Here, data URLs are never allowed. | 520 // Here, data URLs are never allowed. |
510 if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI( | 521 if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI( |
511 browser_context, new_entry->GetURL(), false)) { | 522 browser_context, new_url, false)) { |
512 return true; | 523 return true; |
513 } | 524 } |
514 } else { | 525 } else { |
515 // Force swap if it's a Web UI URL. | 526 // Force swap if it's a Web UI URL. |
516 if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL( | 527 if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL( |
517 browser_context, new_entry->GetURL())) { | 528 browser_context, new_url)) { |
518 return true; | 529 return true; |
519 } | 530 } |
520 } | 531 } |
521 | 532 |
| 533 // Check with the content client as well. Important to pass current_url here, |
| 534 // which uses the SiteInstance's site if there is no curr_entry. |
522 if (GetContentClient()->browser()->ShouldSwapProcessesForNavigation( | 535 if (GetContentClient()->browser()->ShouldSwapProcessesForNavigation( |
523 render_view_host_->GetSiteInstance(), | 536 render_view_host_->GetSiteInstance(), current_url, new_url)) { |
524 curr_entry ? curr_entry->GetURL() : GURL(), | |
525 new_entry->GetURL())) { | |
526 return true; | 537 return true; |
527 } | 538 } |
528 | 539 |
529 if (!curr_entry) | 540 if (!curr_entry) |
530 return false; | 541 return false; |
531 | 542 |
532 // We can't switch a RenderView between view source and non-view source mode | 543 // We can't switch a RenderView between view source and non-view source mode |
533 // without screwing up the session history sometimes (when navigating between | 544 // without screwing up the session history sometimes (when navigating between |
534 // "view-source:http://foo.com/" and "http://foo.com/", WebKit doesn't treat | 545 // "view-source:http://foo.com/" and "http://foo.com/", WebKit doesn't treat |
535 // it as a new navigation). So require a view switch. | 546 // it as a new navigation). So require a view switch. |
(...skipping 10 matching lines...) Expand all Loading... |
546 delegate_->GetControllerForRenderManager(); | 557 delegate_->GetControllerForRenderManager(); |
547 return curr_entry && web_ui_.get() && | 558 return curr_entry && web_ui_.get() && |
548 (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType( | 559 (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType( |
549 controller.GetBrowserContext(), curr_entry->GetURL()) == | 560 controller.GetBrowserContext(), curr_entry->GetURL()) == |
550 WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType( | 561 WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType( |
551 controller.GetBrowserContext(), new_entry->GetURL())); | 562 controller.GetBrowserContext(), new_entry->GetURL())); |
552 } | 563 } |
553 | 564 |
554 SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry( | 565 SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry( |
555 const NavigationEntryImpl& entry, | 566 const NavigationEntryImpl& entry, |
556 SiteInstance* curr_instance) { | 567 SiteInstance* curr_instance, |
557 // NOTE: This is only called when ShouldTransitionCrossSite is true. | 568 bool force_browsing_instance_swap) { |
558 | 569 // Determine which SiteInstance to use for navigating to |entry|. |
559 const GURL& dest_url = entry.GetURL(); | 570 const GURL& dest_url = entry.GetURL(); |
560 NavigationControllerImpl& controller = | 571 NavigationControllerImpl& controller = |
561 delegate_->GetControllerForRenderManager(); | 572 delegate_->GetControllerForRenderManager(); |
562 BrowserContext* browser_context = controller.GetBrowserContext(); | 573 BrowserContext* browser_context = controller.GetBrowserContext(); |
563 | 574 |
| 575 // If a swap is required, we need to force the SiteInstance AND |
| 576 // BrowsingInstance to be different ones, using CreateForURL. |
| 577 if (force_browsing_instance_swap) { |
| 578 // We shouldn't be forcing a swap if an entry already has a SiteInstance. |
| 579 CHECK(!entry.site_instance()); |
| 580 return SiteInstance::CreateForURL(browser_context, dest_url); |
| 581 } |
| 582 |
564 // If the entry has an instance already we should use it. | 583 // If the entry has an instance already we should use it. |
565 if (entry.site_instance()) | 584 if (entry.site_instance()) |
566 return entry.site_instance(); | 585 return entry.site_instance(); |
567 | 586 |
568 // (UGLY) HEURISTIC, process-per-site only: | 587 // (UGLY) HEURISTIC, process-per-site only: |
569 // | 588 // |
570 // If this navigation is generated, then it probably corresponds to a search | 589 // If this navigation is generated, then it probably corresponds to a search |
571 // query. Given that search results typically lead to users navigating to | 590 // query. Given that search results typically lead to users navigating to |
572 // other sites, we don't really want to use the search engine hostname to | 591 // other sites, we don't really want to use the search engine hostname to |
573 // determine the site instance for this navigation. | 592 // determine the site instance for this navigation. |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 return SiteInstance::CreateForURL(browser_context, dest_url); | 699 return SiteInstance::CreateForURL(browser_context, dest_url); |
681 } | 700 } |
682 | 701 |
683 // Use the current SiteInstance for same site navigations, as long as the | 702 // Use the current SiteInstance for same site navigations, as long as the |
684 // process type is correct. (The URL may have been installed as an app since | 703 // process type is correct. (The URL may have been installed as an app since |
685 // the last time we visited it.) | 704 // the last time we visited it.) |
686 if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) && | 705 if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) && |
687 !static_cast<SiteInstanceImpl*>(curr_instance)->HasWrongProcessForURL( | 706 !static_cast<SiteInstanceImpl*>(curr_instance)->HasWrongProcessForURL( |
688 dest_url)) { | 707 dest_url)) { |
689 return curr_instance; | 708 return curr_instance; |
690 } else if (ShouldSwapProcessesForNavigation(curr_entry, &entry)) { | |
691 // When we're swapping, we need to force the site instance AND browsing | |
692 // instance to be different ones. This addresses special cases where we use | |
693 // a single BrowsingInstance for all pages of a certain type (e.g., New Tab | |
694 // Pages), keeping them in the same process. When you navigate away from | |
695 // that page, we want to explicity ignore that BrowsingInstance and group | |
696 // this page into the appropriate SiteInstance for its URL. | |
697 return SiteInstance::CreateForURL(browser_context, dest_url); | |
698 } else { | |
699 // Start the new renderer in a new SiteInstance, but in the current | |
700 // BrowsingInstance. It is important to immediately give this new | |
701 // SiteInstance to a RenderViewHost (if it is different than our current | |
702 // SiteInstance), so that it is ref counted. This will happen in | |
703 // CreateRenderView. | |
704 return curr_instance->GetRelatedSiteInstance(dest_url); | |
705 } | 709 } |
| 710 |
| 711 // Start the new renderer in a new SiteInstance, but in the current |
| 712 // BrowsingInstance. It is important to immediately give this new |
| 713 // SiteInstance to a RenderViewHost (if it is different than our current |
| 714 // SiteInstance), so that it is ref counted. This will happen in |
| 715 // CreateRenderView. |
| 716 return curr_instance->GetRelatedSiteInstance(dest_url); |
706 } | 717 } |
707 | 718 |
708 int RenderViewHostManager::CreateRenderView( | 719 int RenderViewHostManager::CreateRenderView( |
709 SiteInstance* instance, | 720 SiteInstance* instance, |
710 int opener_route_id, | 721 int opener_route_id, |
711 bool swapped_out, | 722 bool swapped_out, |
712 bool hidden) { | 723 bool hidden) { |
713 CHECK(instance); | 724 CHECK(instance); |
714 DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden. | 725 DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden. |
715 | 726 |
| 727 // We are creating a pending or swapped out RVH here. We should never create |
| 728 // it in the same SiteInstance as our current RVH. |
| 729 CHECK_NE(render_view_host_->GetSiteInstance(), instance); |
| 730 |
716 // Check if we've already created an RVH for this SiteInstance. If so, try | 731 // Check if we've already created an RVH for this SiteInstance. If so, try |
717 // to re-use the existing one, which has already been initialized. We'll | 732 // to re-use the existing one, which has already been initialized. We'll |
718 // remove it from the list of swapped out hosts if it commits. | 733 // remove it from the list of swapped out hosts if it commits. |
719 RenderViewHostImpl* new_render_view_host = static_cast<RenderViewHostImpl*>( | 734 RenderViewHostImpl* new_render_view_host = static_cast<RenderViewHostImpl*>( |
720 GetSwappedOutRenderViewHost(instance)); | 735 GetSwappedOutRenderViewHost(instance)); |
721 if (new_render_view_host) { | 736 if (new_render_view_host) { |
722 // Prevent the process from exiting while we're trying to use it. | 737 // Prevent the process from exiting while we're trying to use it. |
723 if (!swapped_out) | 738 if (!swapped_out) |
724 new_render_view_host->GetProcess()->AddPendingView(); | 739 new_render_view_host->GetProcess()->AddPendingView(); |
725 } else { | 740 } else { |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
905 // don't have to worry about this SiteInstance's ref count dropping to zero. | 920 // don't have to worry about this SiteInstance's ref count dropping to zero. |
906 SiteInstance* curr_instance = render_view_host_->GetSiteInstance(); | 921 SiteInstance* curr_instance = render_view_host_->GetSiteInstance(); |
907 | 922 |
908 // Determine if we need a new SiteInstance for this entry. | 923 // Determine if we need a new SiteInstance for this entry. |
909 // Again, new_instance won't be deleted before the end of this method, so it | 924 // Again, new_instance won't be deleted before the end of this method, so it |
910 // is safe to use a normal pointer here. | 925 // is safe to use a normal pointer here. |
911 SiteInstance* new_instance = curr_instance; | 926 SiteInstance* new_instance = curr_instance; |
912 const NavigationEntry* curr_entry = | 927 const NavigationEntry* curr_entry = |
913 delegate_->GetLastCommittedNavigationEntryForRenderManager(); | 928 delegate_->GetLastCommittedNavigationEntryForRenderManager(); |
914 bool is_guest_scheme = curr_instance->GetSiteURL().SchemeIs(kGuestScheme); | 929 bool is_guest_scheme = curr_instance->GetSiteURL().SchemeIs(kGuestScheme); |
915 bool force_swap = ShouldSwapProcessesForNavigation(curr_entry, &entry); | 930 bool force_swap = !is_guest_scheme && |
| 931 ShouldSwapProcessesForNavigation(curr_entry, &entry); |
916 if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap)) | 932 if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap)) |
917 new_instance = GetSiteInstanceForEntry(entry, curr_instance); | 933 new_instance = GetSiteInstanceForEntry(entry, curr_instance, force_swap); |
918 | 934 |
919 if (!is_guest_scheme && (new_instance != curr_instance || force_swap)) { | 935 // If force_swap is true, we must use a different SiteInstance. If we didn't, |
| 936 // we would have two RenderViewHosts in the same SiteInstance and the same |
| 937 // tab, resulting in page_id conflicts for their NavigationEntries. |
| 938 if (force_swap) |
| 939 CHECK_NE(new_instance, curr_instance); |
| 940 |
| 941 if (new_instance != curr_instance) { |
920 // New SiteInstance. | 942 // New SiteInstance. |
921 DCHECK(!cross_navigation_pending_); | 943 DCHECK(!cross_navigation_pending_); |
922 | 944 |
923 // This will possibly create (set to NULL) a Web UI object for the pending | 945 // This will possibly create (set to NULL) a Web UI object for the pending |
924 // page. We'll use this later to give the page special access. This must | 946 // page. We'll use this later to give the page special access. This must |
925 // happen before the new renderer is created below so it will get bindings. | 947 // happen before the new renderer is created below so it will get bindings. |
926 // It must also happen after the above conditional call to CancelPending(), | 948 // It must also happen after the above conditional call to CancelPending(), |
927 // otherwise CancelPending may clear the pending_web_ui_ and the page will | 949 // otherwise CancelPending may clear the pending_web_ui_ and the page will |
928 // not have its bindings set appropriately. | 950 // not have its bindings set appropriately. |
929 SetPendingWebUI(entry); | 951 SetPendingWebUI(entry); |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1104 RenderViewHostImpl* RenderViewHostManager::GetSwappedOutRenderViewHost( | 1126 RenderViewHostImpl* RenderViewHostManager::GetSwappedOutRenderViewHost( |
1105 SiteInstance* instance) { | 1127 SiteInstance* instance) { |
1106 RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId()); | 1128 RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId()); |
1107 if (iter != swapped_out_hosts_.end()) | 1129 if (iter != swapped_out_hosts_.end()) |
1108 return iter->second; | 1130 return iter->second; |
1109 | 1131 |
1110 return NULL; | 1132 return NULL; |
1111 } | 1133 } |
1112 | 1134 |
1113 } // namespace content | 1135 } // namespace content |
OLD | NEW |