Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / frame_host / render_frame_host_manager_unittest.cc
index c0f3f6b..eac088a 100644 (file)
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
+#include "content/browser/frame_host/cross_site_transferring_request.h"
 #include "content/browser/frame_host/navigation_controller_impl.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/frame_host/navigator.h"
 #include "content/browser/frame_host/render_frame_host_manager.h"
-#include "content/browser/renderer_host/cross_site_transferring_request.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
-#include "content/common/frame_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
@@ -30,6 +31,7 @@
 #include "content/public/test/test_notification_tracker.h"
 #include "content/test/test_content_browser_client.h"
 #include "content/test/test_content_client.h"
+#include "content/test/test_render_frame_host.h"
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_web_contents.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -93,6 +95,159 @@ class BeforeUnloadFiredWebContentsDelegate : public WebContentsDelegate {
   DISALLOW_COPY_AND_ASSIGN(BeforeUnloadFiredWebContentsDelegate);
 };
 
+// This observer keeps track of the last deleted RenderViewHost to avoid
+// accessing it and causing use-after-free condition.
+class RenderViewHostDeletedObserver : public WebContentsObserver {
+ public:
+  RenderViewHostDeletedObserver(RenderViewHost* rvh)
+      : WebContentsObserver(WebContents::FromRenderViewHost(rvh)),
+        process_id_(rvh->GetProcess()->GetID()),
+        routing_id_(rvh->GetRoutingID()),
+        deleted_(false) {
+  }
+
+  virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE {
+    if (render_view_host->GetProcess()->GetID() == process_id_ &&
+        render_view_host->GetRoutingID() == routing_id_) {
+      deleted_ = true;
+    }
+  }
+
+  bool deleted() {
+    return deleted_;
+  }
+
+ private:
+  int process_id_;
+  int routing_id_;
+  bool deleted_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderViewHostDeletedObserver);
+};
+
+// This observer keeps track of the last deleted RenderFrameHost to avoid
+// accessing it and causing use-after-free condition.
+class RenderFrameHostDeletedObserver : public WebContentsObserver {
+ public:
+  RenderFrameHostDeletedObserver(RenderFrameHost* rfh)
+      : WebContentsObserver(WebContents::FromRenderFrameHost(rfh)),
+        process_id_(rfh->GetProcess()->GetID()),
+        routing_id_(rfh->GetRoutingID()),
+        deleted_(false) {
+  }
+
+  virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE {
+    if (render_frame_host->GetProcess()->GetID() == process_id_ &&
+        render_frame_host->GetRoutingID() == routing_id_) {
+      deleted_ = true;
+    }
+  }
+
+  bool deleted() {
+    return deleted_;
+  }
+
+ private:
+  int process_id_;
+  int routing_id_;
+  bool deleted_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver);
+};
+
+
+// This observer is used to check whether IPC messages are being filtered for
+// swapped out RenderFrameHost objects. It observes the plugin crash and favicon
+// update events, which the FilterMessagesWhileSwappedOut test simulates being
+// sent. The test is successful if the event is not observed.
+// See http://crbug.com/351815
+class PluginFaviconMessageObserver : public WebContentsObserver {
+ public:
+  PluginFaviconMessageObserver(WebContents* web_contents)
+      : WebContentsObserver(web_contents),
+        plugin_crashed_(false),
+        favicon_received_(false) { }
+
+  virtual void PluginCrashed(const base::FilePath& plugin_path,
+                             base::ProcessId plugin_pid) OVERRIDE {
+    plugin_crashed_ = true;
+  }
+
+  virtual void DidUpdateFaviconURL(
+      const std::vector<FaviconURL>& candidates) OVERRIDE {
+    favicon_received_ = true;
+  }
+
+  bool plugin_crashed() {
+    return plugin_crashed_;
+  }
+
+  bool favicon_received() {
+    return favicon_received_;
+  }
+
+ private:
+  bool plugin_crashed_;
+  bool favicon_received_;
+
+  DISALLOW_COPY_AND_ASSIGN(PluginFaviconMessageObserver);
+};
+
+// Ensures that RenderFrameDeleted and RenderFrameCreated are called in a
+// consistent manner.
+class FrameLifetimeConsistencyChecker : public WebContentsObserver {
+ public:
+  explicit FrameLifetimeConsistencyChecker(WebContentsImpl* web_contents)
+      : WebContentsObserver(web_contents) {
+    RenderViewCreated(web_contents->GetRenderViewHost());
+    RenderFrameCreated(web_contents->GetMainFrame());
+  }
+
+  virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE {
+    std::pair<int, int> routing_pair =
+        std::make_pair(render_frame_host->GetProcess()->GetID(),
+                       render_frame_host->GetRoutingID());
+    bool was_live_already = !live_routes_.insert(routing_pair).second;
+    bool was_used_before = deleted_routes_.count(routing_pair) != 0;
+
+    if (was_live_already) {
+      FAIL() << "RenderFrameCreated called more than once for routing pair: "
+             << Format(render_frame_host);
+    } else if (was_used_before) {
+      FAIL() << "RenderFrameCreated called for routing pair "
+             << Format(render_frame_host) << " that was previously deleted.";
+    }
+  }
+
+  virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE {
+    std::pair<int, int> routing_pair =
+        std::make_pair(render_frame_host->GetProcess()->GetID(),
+                       render_frame_host->GetRoutingID());
+    bool was_live = live_routes_.erase(routing_pair);
+    bool was_dead_already = !deleted_routes_.insert(routing_pair).second;
+
+    if (was_dead_already) {
+      FAIL() << "RenderFrameDeleted called more than once for routing pair "
+             << Format(render_frame_host);
+    } else if (!was_live) {
+      FAIL() << "RenderFrameDeleted called for routing pair "
+             << Format(render_frame_host)
+             << " for which RenderFrameCreated was never called";
+    }
+  }
+
+ private:
+  std::string Format(RenderFrameHost* render_frame_host) {
+    return base::StringPrintf(
+        "(%d, %d -> %s )",
+        render_frame_host->GetProcess()->GetID(),
+        render_frame_host->GetRoutingID(),
+        render_frame_host->GetSiteInstance()->GetSiteURL().spec().c_str());
+  }
+  std::set<std::pair<int, int> > live_routes_;
+  std::set<std::pair<int, int> > deleted_routes_;
+};
+
 }  // namespace
 
 class RenderFrameHostManagerTest
@@ -101,9 +256,11 @@ class RenderFrameHostManagerTest
   virtual void SetUp() OVERRIDE {
     RenderViewHostImplTestHarness::SetUp();
     WebUIControllerFactory::RegisterFactory(&factory_);
+    lifetime_checker_.reset(new FrameLifetimeConsistencyChecker(contents()));
   }
 
   virtual void TearDown() OVERRIDE {
+    lifetime_checker_.reset();
     RenderViewHostImplTestHarness::TearDown();
     WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
   }
@@ -112,6 +269,18 @@ class RenderFrameHostManagerTest
     factory_.set_should_create_webui(should_create_webui);
   }
 
+  void StartCrossSiteTransition(TestWebContents* contents) {
+    std::vector<GURL> url_chain;
+    contents->GetRenderManagerForTesting()->OnCrossSiteResponse(
+        contents->GetRenderManagerForTesting()->pending_frame_host(),
+        GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
+        url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
+    EXPECT_TRUE(contents->cross_navigation_pending());
+    RenderViewHostImpl* rvh = contents->GetRenderViewHost();
+    EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
+              rvh->rvh_state());
+  }
+
   void NavigateActiveAndCommit(const GURL& url) {
     // Note: we navigate the active RenderViewHost because previous navigations
     // won't have committed yet, so NavigateAndCommit does the wrong thing
@@ -119,28 +288,56 @@ class RenderFrameHostManagerTest
     controller().LoadURL(url, Referrer(), PAGE_TRANSITION_LINK, std::string());
     TestRenderViewHost* old_rvh = test_rvh();
 
-    // Simulate the ShouldClose_ACK that is received from the current renderer
+    // Simulate the BeforeUnload_ACK that is received from the current renderer
     // for a cross-site navigation.
-    if (old_rvh != active_rvh())
-      old_rvh->SendShouldCloseACK(true);
+    if (old_rvh != active_rvh()) {
+      old_rvh->SendBeforeUnloadACK(true);
+      EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, old_rvh->rvh_state());
+    }
 
     // Commit the navigation with a new page ID.
     int32 max_page_id = contents()->GetMaxPageIDForSiteInstance(
         active_rvh()->GetSiteInstance());
 
+    // Simulate the response coming from the pending renderer.
+    if (old_rvh != active_rvh())
+      StartCrossSiteTransition(contents());
+
     // Simulate the SwapOut_ACK that fires if you commit a cross-site
     // navigation.
-    if (old_rvh != active_rvh())
+    if (old_rvh != active_rvh()) {
       old_rvh->OnSwappedOut(false);
+      EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT,
+                old_rvh->rvh_state());
+    }
 
+    // Use an observer to avoid accessing a deleted renderer later on when the
+    // state is being checked.
+    RenderViewHostDeletedObserver rvh_observer(old_rvh);
     active_test_rvh()->SendNavigate(max_page_id + 1, url);
+
+    if (old_rvh != active_rvh() && !rvh_observer.deleted())
+      EXPECT_TRUE(old_rvh->IsSwappedOut());
   }
 
   bool ShouldSwapProcesses(RenderFrameHostManager* manager,
                            const NavigationEntryImpl* current_entry,
                            const NavigationEntryImpl* new_entry) const {
-    return manager->ShouldSwapBrowsingInstancesForNavigation(current_entry,
-                                                             new_entry);
+    CHECK(new_entry);
+    BrowserContext* browser_context =
+        manager->delegate_->GetControllerForRenderManager().GetBrowserContext();
+    const GURL& current_effective_url = current_entry ?
+        SiteInstanceImpl::GetEffectiveURL(browser_context,
+                                          current_entry->GetURL()) :
+        manager->render_frame_host_->GetSiteInstance()->GetSiteURL();
+    bool current_is_view_source_mode = current_entry ?
+        current_entry->IsViewSourceMode() : new_entry->IsViewSourceMode();
+    return manager->ShouldSwapBrowsingInstancesForNavigation(
+        current_effective_url,
+        current_is_view_source_mode,
+        new_entry->site_instance(),
+        SiteInstanceImpl::GetEffectiveURL(browser_context, new_entry->GetURL()),
+        new_entry->IsViewSourceMode());
   }
 
   // Creates a test RenderViewHost that's swapped out.
@@ -150,8 +347,7 @@ class RenderFrameHostManagerTest
 
     // Navigate our first tab to a chrome url and then to the destination.
     NavigateActiveAndCommit(kChromeURL);
-    TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
-        contents()->GetRenderManagerForTesting()->current_host());
+    TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
 
     // Navigate to a cross-site URL.
     contents()->GetController().LoadURL(
@@ -159,28 +355,33 @@ class RenderFrameHostManagerTest
     EXPECT_TRUE(contents()->cross_navigation_pending());
 
     // Manually increase the number of active views in the
-    // SiteInstance that ntp_rvh belongs to, to prevent it from being
+    // SiteInstance that ntp_rfh belongs to, to prevent it from being
     // destroyed when it gets swapped out.
-    static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
+    static_cast<SiteInstanceImpl*>(ntp_rfh->GetSiteInstance())->
         increment_active_view_count();
 
-    TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
-        contents()->GetRenderManagerForTesting()->pending_render_view_host());
-    CHECK(dest_rvh);
-    EXPECT_NE(ntp_rvh, dest_rvh);
+    TestRenderFrameHost* dest_rfh = contents()->GetPendingMainFrame();
+    CHECK(dest_rfh);
+    EXPECT_NE(ntp_rfh, dest_rfh);
 
     // BeforeUnload finishes.
-    ntp_rvh->SendShouldCloseACK(true);
+    ntp_rfh->GetRenderViewHost()->SendBeforeUnloadACK(true);
 
-    dest_rvh->SendNavigate(101, kDestUrl);
-    ntp_rvh->OnSwappedOut(false);
+    dest_rfh->SendNavigate(101, kDestUrl);
+    ntp_rfh->OnSwappedOut(false);
 
-    EXPECT_TRUE(ntp_rvh->IsSwappedOut());
-    return ntp_rvh;
+    EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->IsSwappedOut());
+    return ntp_rfh->GetRenderViewHost();
+  }
+
+  NavigationRequest* NavigationRequestForRenderFrameManager(
+      RenderFrameHostManager* manager) const {
+    return manager->navigation_request_for_testing();
   }
 
  private:
   RenderFrameHostManagerTestWebUIControllerFactory factory_;
+  scoped_ptr<FrameLifetimeConsistencyChecker> lifetime_checker_;
 };
 
 // Tests that when you navigate from a chrome:// url to another page, and
@@ -198,54 +399,55 @@ TEST_F(RenderFrameHostManagerTest, NewTabPageProcesses) {
   EXPECT_TRUE(active_rvh()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
   NavigateActiveAndCommit(kDestUrl);
 
+  EXPECT_FALSE(contents()->GetPendingMainFrame());
+
   // Make a second tab.
   scoped_ptr<TestWebContents> contents2(
       TestWebContents::Create(browser_context(), NULL));
 
   // Load the two URLs in the second tab. Note that the first navigation creates
-  // a RVH that's not pending (since there is no cross-site transition), so
+  // a RFH that's not pending (since there is no cross-site transition), so
   // we use the committed one.
   contents2->GetController().LoadURL(
       kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
-  TestRenderViewHost* ntp_rvh2 = static_cast<TestRenderViewHost*>(
-      contents2->GetRenderManagerForTesting()->current_host());
+  TestRenderFrameHost* ntp_rfh2 = contents2->GetMainFrame();
   EXPECT_FALSE(contents2->cross_navigation_pending());
-  ntp_rvh2->SendNavigate(100, kChromeUrl);
+  ntp_rfh2->SendNavigate(100, kChromeUrl);
 
   // The second one is the opposite, creating a cross-site transition and
   // requiring a beforeunload ack.
   contents2->GetController().LoadURL(
       kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
   EXPECT_TRUE(contents2->cross_navigation_pending());
-  TestRenderViewHost* dest_rvh2 = static_cast<TestRenderViewHost*>(
-      contents2->GetRenderManagerForTesting()->pending_render_view_host());
-  ASSERT_TRUE(dest_rvh2);
+  TestRenderFrameHost* dest_rfh2 = contents2->GetPendingMainFrame();
+  ASSERT_TRUE(dest_rfh2);
 
-  ntp_rvh2->SendShouldCloseACK(true);
-  ntp_rvh2->OnSwappedOut(false);
-  dest_rvh2->SendNavigate(101, kDestUrl);
+  ntp_rfh2->GetRenderViewHost()->SendBeforeUnloadACK(true);
+  StartCrossSiteTransition(contents2.get());
+  dest_rfh2->SendNavigate(101, kDestUrl);
 
-  // The two RVH's should be different in every way.
-  EXPECT_NE(active_rvh()->GetProcess(), dest_rvh2->GetProcess());
-  EXPECT_NE(active_rvh()->GetSiteInstance(), dest_rvh2->GetSiteInstance());
-  EXPECT_FALSE(active_rvh()->GetSiteInstance()->IsRelatedSiteInstance(
-                   dest_rvh2->GetSiteInstance()));
+  // The two RFH's should be different in every way.
+  EXPECT_NE(contents()->GetMainFrame()->GetProcess(), dest_rfh2->GetProcess());
+  EXPECT_NE(contents()->GetMainFrame()->GetSiteInstance(),
+            dest_rfh2->GetSiteInstance());
+  EXPECT_FALSE(dest_rfh2->GetSiteInstance()->IsRelatedSiteInstance(
+                   contents()->GetMainFrame()->GetSiteInstance()));
 
   // Navigate both to the new tab page, and verify that they share a
   // RenderProcessHost (not a SiteInstance).
   NavigateActiveAndCommit(kChromeUrl);
+  EXPECT_FALSE(contents()->GetPendingMainFrame());
 
   contents2->GetController().LoadURL(
       kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
-  dest_rvh2->SendShouldCloseACK(true);
-  dest_rvh2->OnSwappedOut(false);
-  static_cast<TestRenderViewHost*>(contents2->GetRenderManagerForTesting()->
-     pending_render_view_host())->SendNavigate(102, kChromeUrl);
-
-  EXPECT_NE(active_rvh()->GetSiteInstance(),
-            contents2->GetRenderViewHost()->GetSiteInstance());
-  EXPECT_EQ(active_rvh()->GetSiteInstance()->GetProcess(),
-            contents2->GetRenderViewHost()->GetSiteInstance()->GetProcess());
+  dest_rfh2->GetRenderViewHost()->SendBeforeUnloadACK(true);
+  StartCrossSiteTransition(contents2.get());
+  contents2->GetPendingMainFrame()->SendNavigate(102, kChromeUrl);
+
+  EXPECT_NE(contents()->GetMainFrame()->GetSiteInstance(),
+            contents2->GetMainFrame()->GetSiteInstance());
+  EXPECT_EQ(contents()->GetMainFrame()->GetSiteInstance()->GetProcess(),
+            contents2->GetMainFrame()->GetSiteInstance()->GetProcess());
 }
 
 // Ensure that the browser ignores most IPC messages that arrive from a
@@ -256,78 +458,92 @@ TEST_F(RenderFrameHostManagerTest, NewTabPageProcesses) {
 TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
   const GURL kChromeURL("chrome://foo");
   const GURL kDestUrl("http://www.google.com/");
+  std::vector<FaviconURL> icons;
 
   // Navigate our first tab to a chrome url and then to the destination.
   NavigateActiveAndCommit(kChromeURL);
-  TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
-      contents()->GetRenderManagerForTesting()->current_host());
+  TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
 
-  // Send an update title message and make sure it works.
+  // Send an update favicon message and make sure it works.
   const base::string16 ntp_title = base::ASCIIToUTF16("NTP Title");
-  blink::WebTextDirection direction = blink::WebTextDirectionLeftToRight;
-  EXPECT_TRUE(ntp_rvh->OnMessageReceived(
-      ViewHostMsg_UpdateTitle(rvh()->GetRoutingID(), 0, ntp_title, direction)));
-  EXPECT_EQ(ntp_title, contents()->GetTitle());
-
-  // Navigate to a cross-site URL.
-  contents()->GetController().LoadURL(
-      kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
-  EXPECT_TRUE(contents()->cross_navigation_pending());
-  TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
-      contents()->GetRenderManagerForTesting()->pending_render_view_host());
-  ASSERT_TRUE(dest_rvh);
-  EXPECT_NE(ntp_rvh, dest_rvh);
-
-  // Create one more view in the same SiteInstance where dest_rvh2
+  {
+    PluginFaviconMessageObserver observer(contents());
+    EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->OnMessageReceived(
+                    ViewHostMsg_UpdateFaviconURL(
+                        ntp_rfh->GetRenderViewHost()->GetRoutingID(), icons)));
+    EXPECT_TRUE(observer.favicon_received());
+  }
+  // Create one more view in the same SiteInstance where ntp_rfh
   // exists so that it doesn't get deleted on navigation to another
   // site.
-  static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
+  static_cast<SiteInstanceImpl*>(ntp_rfh->GetSiteInstance())->
       increment_active_view_count();
 
-  // BeforeUnload finishes.
-  ntp_rvh->SendShouldCloseACK(true);
 
-  // Assume SwapOutACK times out, so the dest_rvh proceeds and commits.
-  dest_rvh->SendNavigate(101, kDestUrl);
+  // Navigate to a cross-site URL.
+  NavigateActiveAndCommit(kDestUrl);
+  TestRenderFrameHost* dest_rfh = contents()->GetMainFrame();
+  ASSERT_TRUE(dest_rfh);
+  EXPECT_NE(ntp_rfh, dest_rfh);
 
-  // The new RVH should be able to update its title.
+  // The new RVH should be able to update its favicon.
   const base::string16 dest_title = base::ASCIIToUTF16("Google");
-  EXPECT_TRUE(dest_rvh->OnMessageReceived(
-      ViewHostMsg_UpdateTitle(rvh()->GetRoutingID(), 101, dest_title,
-                              direction)));
-  EXPECT_EQ(dest_title, contents()->GetTitle());
-
-  // The old renderer, being slow, now updates the title. It should be filtered
-  // out and not take effect.
-  EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, ntp_rvh->rvh_state());
-  EXPECT_TRUE(ntp_rvh->OnMessageReceived(
-      ViewHostMsg_UpdateTitle(rvh()->GetRoutingID(), 0, ntp_title, direction)));
-  EXPECT_EQ(dest_title, contents()->GetTitle());
+  {
+    PluginFaviconMessageObserver observer(contents());
+    EXPECT_TRUE(
+        dest_rfh->GetRenderViewHost()->OnMessageReceived(
+            ViewHostMsg_UpdateFaviconURL(
+                dest_rfh->GetRenderViewHost()->GetRoutingID(), icons)));
+    EXPECT_TRUE(observer.favicon_received());
+  }
+
+  // The old renderer, being slow, now updates the favicon. It should be
+  // filtered out and not take effect.
+  EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->IsSwappedOut());
+  {
+    PluginFaviconMessageObserver observer(contents());
+    EXPECT_TRUE(
+        ntp_rfh->GetRenderViewHost()->OnMessageReceived(
+            ViewHostMsg_UpdateFaviconURL(
+                dest_rfh->GetRenderViewHost()->GetRoutingID(), icons)));
+    EXPECT_FALSE(observer.favicon_received());
+  }
+
+  // The same logic should apply to RenderFrameHosts as well and routing through
+  // swapped out RFH shouldn't be allowed. Use a PluginCrashObserver to check
+  // if the IPC message is allowed through or not.
+  {
+    PluginFaviconMessageObserver observer(contents());
+    EXPECT_TRUE(ntp_rfh->OnMessageReceived(
+                    FrameHostMsg_PluginCrashed(
+                        ntp_rfh->GetRoutingID(), base::FilePath(), 0)));
+    EXPECT_FALSE(observer.plugin_crashed());
+  }
 
   // We cannot filter out synchronous IPC messages, because the renderer would
   // be left waiting for a reply.  We pick RunBeforeUnloadConfirm as an example
   // that can run easily within a unit test, and that needs to receive a reply
   // without showing an actual dialog.
   MockRenderProcessHost* ntp_process_host =
-      static_cast<MockRenderProcessHost*>(ntp_rvh->GetProcess());
+      static_cast<MockRenderProcessHost*>(ntp_rfh->GetProcess());
   ntp_process_host->sink().ClearMessages();
   const base::string16 msg = base::ASCIIToUTF16("Message");
   bool result = false;
   base::string16 unused;
-  ViewHostMsg_RunBeforeUnloadConfirm before_unload_msg(
-      rvh()->GetRoutingID(), kChromeURL, msg, false, &result, &unused);
+  FrameHostMsg_RunBeforeUnloadConfirm before_unload_msg(
+      ntp_rfh->GetRoutingID(), kChromeURL, msg, false, &result, &unused);
   // Enable pumping for check in BrowserMessageFilter::CheckCanDispatchOnUI.
   before_unload_msg.EnableMessagePumping();
-  EXPECT_TRUE(ntp_rvh->OnMessageReceived(before_unload_msg));
+  EXPECT_TRUE(ntp_rfh->OnMessageReceived(before_unload_msg));
   EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
 
   // Also test RunJavaScriptMessage.
   ntp_process_host->sink().ClearMessages();
-  ViewHostMsg_RunJavaScriptMessage js_msg(
-      rvh()->GetRoutingID(), msg, msg, kChromeURL,
+  FrameHostMsg_RunJavaScriptMessage js_msg(
+      ntp_rfh->GetRoutingID(), msg, msg, kChromeURL,
       JAVASCRIPT_MESSAGE_TYPE_CONFIRM, &result, &unused);
   js_msg.EnableMessagePumping();
-  EXPECT_TRUE(ntp_rvh->OnMessageReceived(js_msg));
+  EXPECT_TRUE(ntp_rfh->OnMessageReceived(js_msg));
   EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
 }
 
@@ -342,24 +558,13 @@ TEST_F(RenderFrameHostManagerTest, WhiteListSwapCompositorFrame) {
   process_host->sink().ClearMessages();
 
   cc::CompositorFrame frame;
-  ViewHostMsg_SwapCompositorFrame msg(rvh()->GetRoutingID(), 0, frame);
+  ViewHostMsg_SwapCompositorFrame msg(
+      rvh()->GetRoutingID(), 0, frame, std::vector<IPC::Message>());
 
   EXPECT_TRUE(swapped_out_rvh->OnMessageReceived(msg));
   EXPECT_TRUE(swapped_out_rwhv->did_swap_compositor_frame());
 }
 
-TEST_F(RenderFrameHostManagerTest, WhiteListDidActivateAcceleratedCompositing) {
-  TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
-
-  MockRenderProcessHost* process_host =
-      static_cast<MockRenderProcessHost*>(swapped_out_rvh->GetProcess());
-  process_host->sink().ClearMessages();
-  ViewHostMsg_DidActivateAcceleratedCompositing msg(
-      rvh()->GetRoutingID(), true);
-  EXPECT_TRUE(swapped_out_rvh->OnMessageReceived(msg));
-  EXPECT_TRUE(swapped_out_rvh->is_accelerated_compositing_active());
-}
-
 // Test if RenderViewHost::GetRenderWidgetHosts() only returns active
 // widgets.
 TEST_F(RenderFrameHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
@@ -489,20 +694,20 @@ TEST_F(RenderFrameHostManagerTest,
 
   // Navigate our first tab to a chrome url and then to the destination.
   NavigateActiveAndCommit(kChromeURL);
-  TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
-      contents()->GetRenderManagerForTesting()->current_host());
+  TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
 
   // Create one more tab and navigate to kUrl1.  web_contents is not
   // wrapped as scoped_ptr since it intentionally deleted by destroyer
   // below as part of this test.
   TestWebContents* web_contents =
-      TestWebContents::Create(browser_context(), ntp_rvh->GetSiteInstance());
+      TestWebContents::Create(browser_context(), ntp_rfh->GetSiteInstance());
   web_contents->NavigateAndCommit(kUrl1);
-  RenderViewHostDestroyer destroyer(ntp_rvh, web_contents);
+  RenderViewHostDestroyer destroyer(ntp_rfh->GetRenderViewHost(),
+                                    web_contents);
 
   // This causes the first tab to navigate to kUrl2, which destroys
-  // the ntp_rvh in ShutdownRenderViewHostsInSiteInstance(). When
-  // ntp_rvh is destroyed, it also destroys the RVHs in web_contents
+  // the ntp_rfh in ShutdownRenderViewHostsInSiteInstance(). When
+  // ntp_rfh is destroyed, it also destroys the RVHs in web_contents
   // too. This can test whether
   // SiteInstanceImpl::ShutdownRenderViewHostsInSiteInstance() can
   // touch any object freed in this way or not while iterating through
@@ -529,15 +734,16 @@ TEST_F(RenderFrameHostManagerTest, AlwaysSendEnableViewSourceMode) {
   // Navigate.
   controller().LoadURL(
       kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
-  // Simulate response from RenderView for FirePageBeforeUnload.
+  // Simulate response from RenderFrame for DispatchBeforeUnload.
   base::TimeTicks now = base::TimeTicks::Now();
-  test_rvh()->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(
-      rvh()->GetRoutingID(), true, now, now));
-  ASSERT_TRUE(pending_rvh());  // New pending RenderViewHost will be created.
-  RenderViewHost* last_rvh = pending_rvh();
-  int32 new_id = contents()->GetMaxPageIDForSiteInstance(
-      active_rvh()->GetSiteInstance()) + 1;
-  pending_test_rvh()->SendNavigate(new_id, kUrl);
+  contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(
+      contents()->GetMainFrame()->GetRoutingID(), true, now, now));
+  ASSERT_TRUE(contents()->GetPendingMainFrame())
+      << "Expected new pending RenderFrameHost to be created.";
+  RenderFrameHost* last_rfh = contents()->GetPendingMainFrame();
+  int32 new_id =
+      contents()->GetMaxPageIDForSiteInstance(last_rfh->GetSiteInstance()) + 1;
+  contents()->GetPendingMainFrame()->SendNavigate(new_id, kUrl);
   EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
   ASSERT_TRUE(controller().GetLastCommittedEntry());
   EXPECT_TRUE(kUrl == controller().GetLastCommittedEntry()->GetURL());
@@ -552,9 +758,10 @@ TEST_F(RenderFrameHostManagerTest, AlwaysSendEnableViewSourceMode) {
   controller().LoadURL(
       kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   // The same RenderViewHost should be reused.
-  EXPECT_FALSE(pending_rvh());
-  EXPECT_TRUE(last_rvh == rvh());
-  test_rvh()->SendNavigate(new_id, kUrl);  // The same page_id returned.
+  EXPECT_FALSE(contents()->GetPendingMainFrame());
+  EXPECT_TRUE(last_rfh == contents()->GetMainFrame());
+  // Navigate using the returned page_id.
+  contents()->GetMainFrame()->SendNavigate(new_id, kUrl);
   EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
   EXPECT_FALSE(controller().GetPendingEntry());
   // New message should be sent out to make sure to enter view-source mode.
@@ -571,14 +778,8 @@ TEST_F(RenderFrameHostManagerTest, Init) {
 
   scoped_ptr<TestWebContents> web_contents(
       TestWebContents::Create(browser_context(), instance));
-  FrameTree tree(web_contents->GetFrameTree()->root()->navigator(),
-                 web_contents.get(), web_contents.get(),
-                 web_contents.get(), web_contents.get());
-  RenderFrameHostManager* manager = tree.root()->render_manager();
-
-  manager->Init(browser_context(), instance, MSG_ROUTING_NONE,
-                MSG_ROUTING_NONE);
 
+  RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
   RenderViewHostImpl* rvh = manager->current_host();
   RenderFrameHostImpl* rfh = manager->current_frame_host();
   ASSERT_TRUE(rvh);
@@ -603,15 +804,7 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
   notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
                           Source<WebContents>(web_contents.get()));
 
-  // Create.
-  FrameTree tree(web_contents->GetFrameTree()->root()->navigator(),
-                 web_contents.get(), web_contents.get(),
-                 web_contents.get(), web_contents.get());
-  RenderFrameHostManager* manager = tree.root()->render_manager();
-
-  manager->Init(browser_context(), instance, MSG_ROUTING_NONE,
-                MSG_ROUTING_NONE);
-
+  RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
   RenderFrameHostImpl* host;
 
   // 1) The first navigation. --------------------------
@@ -627,7 +820,7 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
   EXPECT_FALSE(manager->pending_frame_host());
 
   // Commit.
-  manager->DidNavigateMainFrame(host->render_view_host());
+  manager->DidNavigateFrame(host);
   // Commit to SiteInstance should be delayed until RenderView commit.
   EXPECT_TRUE(host == manager->current_frame_host());
   ASSERT_TRUE(host);
@@ -649,7 +842,7 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
   EXPECT_FALSE(manager->pending_frame_host());
 
   // Commit.
-  manager->DidNavigateMainFrame(host->render_view_host());
+  manager->DidNavigateFrame(host);
   EXPECT_TRUE(host == manager->current_frame_host());
   ASSERT_TRUE(host);
   EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
@@ -671,7 +864,7 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
   notifications.Reset();
 
   // Commit.
-  manager->DidNavigateMainFrame(manager->pending_render_view_host());
+  manager->DidNavigateFrame(manager->pending_frame_host());
   EXPECT_TRUE(host == manager->current_frame_host());
   ASSERT_TRUE(host);
   EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
@@ -698,14 +891,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyReNavigation) {
   notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
                           Source<WebContents>(web_contents.get()));
 
-  // Create.
-  FrameTree tree(web_contents->GetFrameTree()->root()->navigator(),
-                 web_contents.get(), web_contents.get(),
-                 web_contents.get(), web_contents.get());
-  RenderFrameHostManager* manager = tree.root()->render_manager();
-
-  manager->Init(browser_context(), instance, MSG_ROUTING_NONE,
-                MSG_ROUTING_NONE);
+  RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
 
   // 1) The first navigation. --------------------------
   const GURL kUrl1("http://www.google.com/");
@@ -725,7 +911,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyReNavigation) {
   notifications.Reset();
 
   // Commit.
-  manager->DidNavigateMainFrame(host->render_view_host());
+  manager->DidNavigateFrame(host);
 
   // Commit to SiteInstance should be delayed until RenderView commit.
   EXPECT_TRUE(host == manager->current_frame_host());
@@ -750,7 +936,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyReNavigation) {
 
   // Check that the navigation is still suspended because the old RVH
   // is not swapped out, yet.
-  EXPECT_TRUE(host2->render_view_host()->are_navigations_suspended());
+  EXPECT_TRUE(host2->are_navigations_suspended());
   MockRenderProcessHost* test_process_host2 =
       static_cast<MockRenderProcessHost*>(host2->GetProcess());
   test_process_host2->sink().ClearMessages();
@@ -759,23 +945,23 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyReNavigation) {
       FrameMsg_Navigate::ID));
 
   // Allow closing the current Render View (precondition for swapping out
-  // the RVH): Simulate response from RenderView for ViewMsg_ShouldClose sent by
-  // FirePageBeforeUnload.
+  // the RVH): Simulate response from RenderFrame for FrameMsg_BeforeUnload sent
+  // by DispatchBeforeUnload.
   TestRenderViewHost* test_host =
       static_cast<TestRenderViewHost*>(host->render_view_host());
   MockRenderProcessHost* test_process_host =
       static_cast<MockRenderProcessHost*>(test_host->GetProcess());
   EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
-      ViewMsg_ShouldClose::ID));
-  test_host->SendShouldCloseACK(true);
+      FrameMsg_BeforeUnload::ID));
+  test_host->SendBeforeUnloadACK(true);
 
   // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
   // call of RenderFrameHostManager::SwapOutOldPage before
-  // RenderFrameHostManager::DidNavigateMainFrame is called.
+  // RenderFrameHostManager::DidNavigateFrame is called.
   // The RVH is swapped out after receiving the unload ack.
   manager->SwapOutOldPage();
   EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
-      ViewMsg_SwapOut::ID));
+      FrameMsg_SwapOut::ID));
   test_host->OnSwappedOut(false);
 
   EXPECT_EQ(host, manager->current_frame_host());
@@ -800,27 +986,28 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyReNavigation) {
   EXPECT_NE(host3, host);
   EXPECT_NE(host3->GetProcess()->GetID(), host2_process_id);
 
-  // Navigations in the new RVH should be suspended.
-  EXPECT_TRUE(static_cast<RenderViewHostImpl*>(
-      host3->render_view_host())->are_navigations_suspended());
+  // Navigations in the new RFH should be suspended.
+  EXPECT_TRUE(host3->are_navigations_suspended());
   EXPECT_EQ(host, manager->current_frame_host());
   EXPECT_FALSE(manager->current_frame_host()->is_swapped_out());
 
   // Simulate a response to the second beforeunload request.
   EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
-      ViewMsg_ShouldClose::ID));
-  test_host->SendShouldCloseACK(true);
+      FrameMsg_BeforeUnload::ID));
+  test_host->SendBeforeUnloadACK(true);
 
   // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
   // call of RenderFrameHostManager::SwapOutOldPage before
-  // RenderFrameHostManager::DidNavigateMainFrame is called.
+  // RenderFrameHostManager::DidNavigateFrame is called. Since the previous
+  // navigation has already caused the renderer to start swapping out, there
+  // will be no more SwapOut messages being sent.
   manager->SwapOutOldPage();
-  EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
-      ViewMsg_SwapOut::ID));
+  EXPECT_FALSE(test_process_host->sink().GetUniqueMessageMatching(
+      FrameMsg_SwapOut::ID));
   test_host->OnSwappedOut(false);
 
   // Commit.
-  manager->DidNavigateMainFrame(host3->render_view_host());
+  manager->DidNavigateFrame(host3);
   EXPECT_TRUE(host3 == manager->current_frame_host());
   ASSERT_TRUE(host3);
   EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host3->GetSiteInstance())->
@@ -833,6 +1020,50 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyReNavigation) {
       notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
 }
 
+// Test that navigation is not blocked when we make new navigation before
+// previous one has been committed. This is also a regression test for
+// http://crbug.com/104600.
+TEST_F(RenderFrameHostManagerTest, NewCrossNavigationBetweenSwapOutAndCommit) {
+  const GURL kUrl1("http://www.google.com/");
+  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl3("http://www.youtube.com/");
+
+  contents()->NavigateAndCommit(kUrl1);
+  TestRenderViewHost* rvh1 = test_rvh();
+
+  // Keep active_view_count nonzero so that no swapped out views in
+  // this SiteInstance get forcefully deleted.
+  static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance())->
+      increment_active_view_count();
+
+  // Navigate but don't commit.
+  contents()->GetController().LoadURL(
+      kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  EXPECT_TRUE(rvh1->is_waiting_for_beforeunload_ack());
+  contents()->ProceedWithCrossSiteNavigation();
+  EXPECT_FALSE(rvh1->is_waiting_for_beforeunload_ack());
+  StartCrossSiteTransition(contents());
+  EXPECT_TRUE(rvh1->IsWaitingForUnloadACK());
+
+  rvh1->OnSwappedOut(false);
+  EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT, rvh1->rvh_state());
+
+  TestRenderViewHost* rvh2 = pending_test_rvh();
+  EXPECT_TRUE(rvh2);
+  static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance())->
+      increment_active_view_count();
+
+  contents()->GetController().LoadURL(
+      kUrl3, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  // Pending rvh2 is already deleted.
+  contents()->ProceedWithCrossSiteNavigation();
+
+  TestRenderFrameHost* rfh3 = contents()->GetPendingMainFrame();
+  EXPECT_TRUE(rfh3);
+  // Navigation should be already unblocked by rvh1.
+  EXPECT_FALSE(rfh3->are_navigations_suspended());
+}
+
 // Tests WebUI creation.
 TEST_F(RenderFrameHostManagerTest, WebUI) {
   set_should_create_webui(true);
@@ -840,13 +1071,8 @@ TEST_F(RenderFrameHostManagerTest, WebUI) {
 
   scoped_ptr<TestWebContents> web_contents(
       TestWebContents::Create(browser_context(), instance));
-  FrameTree tree(web_contents->GetFrameTree()->root()->navigator(),
-                 web_contents.get(), web_contents.get(),
-                 web_contents.get(), web_contents.get());
-  RenderFrameHostManager* manager = tree.root()->render_manager();
+  RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
 
-  manager->Init(browser_context(), instance, MSG_ROUTING_NONE,
-                MSG_ROUTING_NONE);
   EXPECT_FALSE(manager->current_host()->IsRenderViewLive());
 
   const GURL kUrl("chrome://foo");
@@ -872,12 +1098,12 @@ TEST_F(RenderFrameHostManagerTest, WebUI) {
   EXPECT_EQ(kUrl, host->GetSiteInstance()->GetSiteURL());
 
   // The Web UI is committed immediately because the RenderViewHost has not been
-  // used yet. UpdateRendererStateForNavigate() took the short cut path.
+  // used yet. UpdateStateForNavigate() took the short cut path.
   EXPECT_FALSE(manager->pending_web_ui());
   EXPECT_TRUE(manager->web_ui());
 
   // Commit.
-  manager->DidNavigateMainFrame(host->render_view_host());
+  manager->DidNavigateFrame(host);
   EXPECT_TRUE(
       host->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
 }
@@ -891,14 +1117,11 @@ TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
   // Create a blank tab.
   scoped_ptr<TestWebContents> web_contents1(
       TestWebContents::Create(browser_context(), blank_instance));
-  FrameTree tree1(web_contents1->GetFrameTree()->root()->navigator(),
-                 web_contents1.get(), web_contents1.get(),
-                 web_contents1.get(), web_contents1.get());
-  RenderFrameHostManager* manager1 = tree1.root()->render_manager();
-  manager1->Init(
-      browser_context(), blank_instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+  RenderFrameHostManager* manager1 =
+      web_contents1->GetRenderManagerForTesting();
   // Test the case that new RVH is considered live.
-  manager1->current_host()->CreateRenderView(base::string16(), -1, -1);
+  manager1->current_host()->CreateRenderView(
+      base::string16(), -1, MSG_ROUTING_NONE, -1, false);
 
   // Navigate to a WebUI page.
   const GURL kUrl1("chrome://foo");
@@ -916,7 +1139,7 @@ TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
       host1->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
 
   // Commit and ensure we still have bindings.
-  manager1->DidNavigateMainFrame(host1->render_view_host());
+  manager1->DidNavigateFrame(host1);
   SiteInstance* webui_instance = host1->GetSiteInstance();
   EXPECT_EQ(host1, manager1->current_frame_host());
   EXPECT_TRUE(
@@ -925,15 +1148,12 @@ TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
   // Now simulate clicking a link that opens in a new tab.
   scoped_ptr<TestWebContents> web_contents2(
       TestWebContents::Create(browser_context(), webui_instance));
-  FrameTree tree2(web_contents2->GetFrameTree()->root()->navigator(),
-                  web_contents2.get(), web_contents2.get(),
-                  web_contents2.get(), web_contents2.get());
-  RenderFrameHostManager* manager2 = tree2.root()->render_manager();
-  manager2->Init(
-      browser_context(), webui_instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE);
+  RenderFrameHostManager* manager2 =
+      web_contents2->GetRenderManagerForTesting();
   // Make sure the new RVH is considered live.  This is usually done in
   // RenderWidgetHost::Init when opening a new tab from a link.
-  manager2->current_host()->CreateRenderView(base::string16(), -1, -1);
+  manager2->current_host()->CreateRenderView(
+      base::string16(), -1, MSG_ROUTING_NONE, -1, false);
 
   const GURL kUrl2("chrome://foo/bar");
   NavigationEntryImpl entry2(NULL /* instance */, -1 /* page_id */, kUrl2,
@@ -948,7 +1168,7 @@ TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
   EXPECT_TRUE(
       host2->render_view_host()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
 
-  manager2->DidNavigateMainFrame(host2->render_view_host());
+  manager2->DidNavigateFrame(host2);
 }
 
 // Tests that we don't end up in an inconsistent state if a page does a back and
@@ -958,22 +1178,23 @@ TEST_F(RenderFrameHostManagerTest, PageDoesBackAndReload) {
   const GURL kUrl2("http://www.evil-site.com/");
 
   // Navigate to a safe site, then an evil site.
-  // This will switch RenderViewHosts.  We cannot assert that the first and
-  // second RVHs are different, though, because the first one may be promptly
+  // This will switch RenderFrameHosts.  We cannot assert that the first and
+  // second RFHs are different, though, because the first one may be promptly
   // deleted.
   contents()->NavigateAndCommit(kUrl1);
   contents()->NavigateAndCommit(kUrl2);
-  RenderViewHost* evil_rvh = contents()->GetRenderViewHost();
+  TestRenderFrameHost* evil_rfh = contents()->GetMainFrame();
 
   // Now let's simulate the evil page calling history.back().
   contents()->OnGoToEntryAtOffset(-1);
-  // We should have a new pending RVH.
-  // Note that in this case, the navigation has not committed, so evil_rvh will
+  // We should have a new pending RFH.
+  // Note that in this case, the navigation has not committed, so evil_rfh will
   // not be deleted yet.
-  EXPECT_NE(evil_rvh, contents()->GetRenderManagerForTesting()->
-      pending_render_view_host());
+  EXPECT_NE(evil_rfh, contents()->GetPendingMainFrame());
+  EXPECT_NE(evil_rfh->GetRenderViewHost(),
+            contents()->GetPendingMainFrame()->GetRenderViewHost());
 
-  // Before that RVH has committed, the evil page reloads itself.
+  // Before that RFH has committed, the evil page reloads itself.
   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   params.page_id = 1;
   params.url = kUrl2;
@@ -984,16 +1205,19 @@ TEST_F(RenderFrameHostManagerTest, PageDoesBackAndReload) {
   params.is_post = false;
   params.page_state = PageState::CreateFromURL(kUrl2);
 
-  RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(evil_rvh);
-  RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(
-      rvh->GetProcess()->GetID(), rvh->main_frame_routing_id());
-  contents()->GetFrameTree()->root()->navigator()->DidNavigate(rfh, params);
+  contents()->GetFrameTree()->root()->navigator()->DidNavigate(evil_rfh,
+                                                               params);
 
-  // That should have cancelled the pending RVH, and the evil RVH should be the
+  // That should have cancelled the pending RFH, and the evil RFH should be the
   // current one.
   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
       pending_render_view_host() == NULL);
-  EXPECT_EQ(evil_rvh, contents()->GetRenderManagerForTesting()->current_host());
+  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->pending_frame_host() ==
+              NULL);
+  EXPECT_EQ(evil_rfh,
+            contents()->GetRenderManagerForTesting()->current_frame_host());
+  EXPECT_EQ(evil_rfh->GetRenderViewHost(),
+            contents()->GetRenderManagerForTesting()->current_host());
 
   // Also we should not have a pending navigation entry.
   EXPECT_TRUE(contents()->GetController().GetPendingEntry() == NULL);
@@ -1029,7 +1253,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateAfterMissingSwapOutACK) {
   EXPECT_TRUE(rvh2->is_waiting_for_beforeunload_ack());
   contents()->ProceedWithCrossSiteNavigation();
   EXPECT_FALSE(rvh2->is_waiting_for_beforeunload_ack());
-  rvh2->SwapOut();
+  StartCrossSiteTransition(contents());
   EXPECT_TRUE(rvh2->IsWaitingForUnloadACK());
 
   // The back navigation commits.
@@ -1040,6 +1264,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateAfterMissingSwapOutACK) {
   // We should be able to navigate forward.
   contents()->GetController().GoForward();
   contents()->ProceedWithCrossSiteNavigation();
+  StartCrossSiteTransition(contents());
   const NavigationEntry* entry2 = contents()->GetController().GetPendingEntry();
   rvh2->SendNavigate(entry2->GetPageID(), entry2->GetURL());
   EXPECT_EQ(rvh2, rvh());
@@ -1134,7 +1359,8 @@ TEST_F(RenderFrameHostManagerTest, CleanUpSwappedOutRVHOnProcessCrash) {
   contents()->SetOpener(opener1.get());
 
   // Make sure the new opener RVH is considered live.
-  opener1_manager->current_host()->CreateRenderView(base::string16(), -1, -1);
+  opener1_manager->current_host()->CreateRenderView(
+      base::string16(), -1, MSG_ROUTING_NONE, -1, false);
 
   // Use a cross-process navigation in the opener to swap out the old RVH.
   EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
@@ -1217,14 +1443,7 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
   scoped_ptr<TestWebContents> web_contents(
       TestWebContents::Create(browser_context(), instance));
 
-  // Create.
-  FrameTree tree(web_contents->GetFrameTree()->root()->navigator(),
-                 web_contents.get(), web_contents.get(),
-                 web_contents.get(), web_contents.get());
-  RenderFrameHostManager* manager = tree.root()->render_manager();
-
-  manager->Init(browser_context(), instance, MSG_ROUTING_NONE,
-                MSG_ROUTING_NONE);
+  RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
 
   RenderFrameHostImpl* host;
 
@@ -1242,7 +1461,7 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
   EXPECT_EQ(manager->current_frame_host()->GetSiteInstance(), instance);
 
   // Commit.
-  manager->DidNavigateMainFrame(host->render_view_host());
+  manager->DidNavigateFrame(host);
   // Commit to SiteInstance should be delayed until RenderView commit.
   EXPECT_EQ(host, manager->current_frame_host());
   ASSERT_TRUE(host);
@@ -1264,7 +1483,7 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
   EXPECT_FALSE(manager->pending_frame_host());
 
   // Commit.
-  manager->DidNavigateMainFrame(host->render_view_host());
+  manager->DidNavigateFrame(host);
   EXPECT_EQ(host, manager->current_frame_host());
   ASSERT_TRUE(host);
   EXPECT_EQ(static_cast<SiteInstanceImpl*>(host->GetSiteInstance()),
@@ -1285,14 +1504,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
   notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
                           Source<WebContents>(web_contents.get()));
 
-  // Create.
-  FrameTree tree(web_contents->GetFrameTree()->root()->navigator(),
-                 web_contents.get(), web_contents.get(),
-                 web_contents.get(), web_contents.get());
-  RenderFrameHostManager* manager = tree.root()->render_manager();
-
-  manager->Init(browser_context(), instance, MSG_ROUTING_NONE,
-                MSG_ROUTING_NONE);
+  RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
 
   // 1) The first navigation. --------------------------
   const GURL kUrl1("http://www.google.com/");
@@ -1312,7 +1524,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
   notifications.Reset();
 
   // Commit.
-  manager->DidNavigateMainFrame(host->render_view_host());
+  manager->DidNavigateFrame(host);
 
   // Commit to SiteInstance should be delayed until RenderFrame commits.
   EXPECT_EQ(host, manager->current_frame_host());
@@ -1339,7 +1551,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
   // 3) Close the tab. -------------------------
   notifications.ListenFor(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
                           Source<RenderWidgetHost>(host2->render_view_host()));
-  manager->ShouldClosePage(false, true, base::TimeTicks());
+  manager->OnBeforeUnloadACK(false, true, base::TimeTicks());
 
   EXPECT_TRUE(
       notifications.Check1AndReset(NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED));
@@ -1347,28 +1559,6 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
   EXPECT_EQ(host, manager->current_frame_host());
 }
 
-// This checks that the given RVH has been properly deleted.
-class RenderViewHostDestructionObserver : public WebContentsObserver {
- public:
-  RenderViewHostDestructionObserver(RenderViewHost* render_view_host)
-      : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)),
-        render_view_host_(render_view_host),
-        rvh_deleted_(false) {}
-
-  bool rvh_deleted() { return rvh_deleted_; }
-
-  virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE {
-    if (render_view_host == render_view_host_)
-      rvh_deleted_ = true;
-  }
-
- private:
-  RenderViewHost* render_view_host_;
-  bool rvh_deleted_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver);
-};
-
 // Tests that the RenderViewHost is properly deleted when the SwapOutACK is
 // received before the new page commits.
 TEST_F(RenderFrameHostManagerTest,
@@ -1378,43 +1568,46 @@ TEST_F(RenderFrameHostManagerTest,
 
   // Navigate to the first page.
   contents()->NavigateAndCommit(kUrl1);
-  TestRenderViewHost* rvh1 = test_rvh();
-  RenderViewHostDestructionObserver destruction_observer(rvh1);
-  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+  TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
+  RenderViewHostDeletedObserver rvh_deleted_observer(rfh1->GetRenderViewHost());
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // Navigate to new site, simulating onbeforeunload approval.
   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   base::TimeTicks now = base::TimeTicks::Now();
-  rvh1->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
+  rfh1->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   EXPECT_TRUE(contents()->cross_navigation_pending());
-  TestRenderViewHost* rvh2 =
-      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+  TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
 
-  // Simulate rvh2's response, which leads to an unload request being sent to
-  // rvh1.
+  // Simulate rfh2's response, which leads to an unload request being sent to
+  // rfh1.
   std::vector<GURL> url_chain;
   url_chain.push_back(GURL());
   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
-      rvh2, GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
-      url_chain, Referrer(), PAGE_TRANSITION_TYPED, 1, false);
+      rfh2,
+      GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
+      url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
   EXPECT_TRUE(contents()->cross_navigation_pending());
   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
-            rvh1->rvh_state());
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // Simulate the swap out ack.
-  rvh1->OnSwappedOut(false);
-  EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT, rvh1->rvh_state());
+  rfh1->OnSwappedOut(false);
+  EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT,
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // The new page commits.
-  contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
+  contents()->TestDidNavigate(rfh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
   EXPECT_FALSE(contents()->cross_navigation_pending());
-  EXPECT_EQ(rvh2, rvh());
-  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
-  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
+  EXPECT_EQ(rfh2, contents()->GetMainFrame());
+  EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh2->GetRenderViewHost()->rvh_state());
 
-  // rvh1 should have been deleted.
-  EXPECT_TRUE(destruction_observer.rvh_deleted());
-  rvh1 = NULL;
+  // rfh1's rvh should have been deleted.
+  EXPECT_TRUE(rvh_deleted_observer.deleted());
+  rfh1 = NULL;
 }
 
 // Tests that the RenderViewHost is properly swapped out when the SwapOutACK is
@@ -1426,48 +1619,52 @@ TEST_F(RenderFrameHostManagerTest,
 
   // Navigate to the first page.
   contents()->NavigateAndCommit(kUrl1);
-  TestRenderViewHost* rvh1 = test_rvh();
-  RenderViewHostDestructionObserver destruction_observer(rvh1);
-  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+  TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
+  RenderViewHostDeletedObserver rvh_deleted_observer(rfh1->GetRenderViewHost());
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh1->GetRenderViewHost()->rvh_state());
 
-  // Increment the number of active views in SiteInstanceImpl so that rvh2 is
+  // Increment the number of active views in SiteInstanceImpl so that rfh2 is
   // not deleted on swap out.
   static_cast<SiteInstanceImpl*>(
-      rvh1->GetSiteInstance())->increment_active_view_count();
+      rfh1->GetSiteInstance())->increment_active_view_count();
 
   // Navigate to new site, simulating onbeforeunload approval.
   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   base::TimeTicks now = base::TimeTicks::Now();
-  rvh1->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
+  contents()->GetMainFrame()->OnMessageReceived(
+      FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   EXPECT_TRUE(contents()->cross_navigation_pending());
-  TestRenderViewHost* rvh2 =
-      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+  TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
 
-  // Simulate rvh2's response, which leads to an unload request being sent to
-  // rvh1.
+  // Simulate rfh2's response, which leads to an unload request being sent to
+  // rfh1.
   std::vector<GURL> url_chain;
   url_chain.push_back(GURL());
   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
-      rvh2, GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
-      url_chain, Referrer(), PAGE_TRANSITION_TYPED, 1, false);
+      rfh2,
+      GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
+      url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
   EXPECT_TRUE(contents()->cross_navigation_pending());
   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
-            rvh1->rvh_state());
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // Simulate the swap out ack.
-  rvh1->OnSwappedOut(false);
-  EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT, rvh1->rvh_state());
+  rfh1->OnSwappedOut(false);
+  EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT,
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // The new page commits.
-  contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
+  contents()->TestDidNavigate(rfh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
   EXPECT_FALSE(contents()->cross_navigation_pending());
-  EXPECT_EQ(rvh2, rvh());
-  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
-  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
+  EXPECT_EQ(rfh2, contents()->GetMainFrame());
+  EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh2->GetRenderViewHost()->rvh_state());
 
-  // rvh1 should be swapped out.
-  EXPECT_FALSE(destruction_observer.rvh_deleted());
-  EXPECT_TRUE(rvh1->IsSwappedOut());
+  // rfh1 should be swapped out.
+  EXPECT_FALSE(rvh_deleted_observer.deleted());
+  EXPECT_TRUE(rfh1->GetRenderViewHost()->IsSwappedOut());
 }
 
 // Tests that the RenderViewHost is properly deleted when the new
@@ -1479,43 +1676,47 @@ TEST_F(RenderFrameHostManagerTest,
 
   // Navigate to the first page.
   contents()->NavigateAndCommit(kUrl1);
-  TestRenderViewHost* rvh1 = test_rvh();
-  RenderViewHostDestructionObserver destruction_observer(rvh1);
-  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+  TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
+  RenderViewHostDeletedObserver rvh_deleted_observer(rfh1->GetRenderViewHost());
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // Navigate to new site, simulating onbeforeunload approval.
   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   base::TimeTicks now = base::TimeTicks::Now();
-  rvh1->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
+  contents()->GetMainFrame()->OnMessageReceived(
+      FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   EXPECT_TRUE(contents()->cross_navigation_pending());
-  TestRenderViewHost* rvh2 =
-      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+  TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
 
-  // Simulate rvh2's response, which leads to an unload request being sent to
-  // rvh1.
+  // Simulate rfh2's response, which leads to an unload request being sent to
+  // rfh1.
   std::vector<GURL> url_chain;
   url_chain.push_back(GURL());
   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
-      rvh2, GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
-      url_chain, Referrer(), PAGE_TRANSITION_TYPED, 1, false);
+      rfh2,
+      GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
+      url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
   EXPECT_TRUE(contents()->cross_navigation_pending());
   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
-            rvh1->rvh_state());
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // The new page commits.
-  contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
+  contents()->TestDidNavigate(rfh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
   EXPECT_FALSE(contents()->cross_navigation_pending());
-  EXPECT_EQ(rvh2, rvh());
-  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
-  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
-  EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SHUTDOWN, rvh1->rvh_state());
+  EXPECT_EQ(rfh2, contents()->GetMainFrame());
+  EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh2->GetRenderViewHost()->rvh_state());
+  EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SHUTDOWN,
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // Simulate the swap out ack.
-  rvh1->OnSwappedOut(false);
+  rfh1->OnSwappedOut(false);
 
-  // rvh1 should have been deleted.
-  EXPECT_TRUE(destruction_observer.rvh_deleted());
-  rvh1 = NULL;
+  // rfh1 should have been deleted.
+  EXPECT_TRUE(rvh_deleted_observer.deleted());
+  rfh1 = NULL;
 }
 
 // Tests that the RenderViewHost is properly swapped out when the new page
@@ -1527,48 +1728,188 @@ TEST_F(RenderFrameHostManagerTest,
 
   // Navigate to the first page.
   contents()->NavigateAndCommit(kUrl1);
-  TestRenderViewHost* rvh1 = test_rvh();
-  RenderViewHostDestructionObserver destruction_observer(rvh1);
-  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+  TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
+  RenderViewHostDeletedObserver rvh_deleted_observer(rfh1->GetRenderViewHost());
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh1->GetRenderViewHost()->rvh_state());
 
-  // Increment the number of active views in SiteInstanceImpl so that rvh1 is
+  // Increment the number of active views in SiteInstanceImpl so that rfh1 is
   // not deleted on swap out.
   static_cast<SiteInstanceImpl*>(
-      rvh1->GetSiteInstance())->increment_active_view_count();
+      rfh1->GetSiteInstance())->increment_active_view_count();
 
   // Navigate to new site, simulating onbeforeunload approval.
   controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
   base::TimeTicks now = base::TimeTicks::Now();
-  rvh1->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
+  contents()->GetMainFrame()->OnMessageReceived(
+      FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   EXPECT_TRUE(contents()->cross_navigation_pending());
-  TestRenderViewHost* rvh2 =
-      static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+  TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
 
-  // Simulate rvh2's response, which leads to an unload request being sent to
-  // rvh1.
+  // Simulate rfh2's response, which leads to an unload request being sent to
+  // rfh1.
   std::vector<GURL> url_chain;
   url_chain.push_back(GURL());
   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
-      rvh2, GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
-      url_chain, Referrer(), PAGE_TRANSITION_TYPED, 1, false);
+      rfh2,
+      GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
+      url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
   EXPECT_TRUE(contents()->cross_navigation_pending());
   EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
-            rvh1->rvh_state());
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // The new page commits.
-  contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
+  contents()->TestDidNavigate(rfh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
   EXPECT_FALSE(contents()->cross_navigation_pending());
-  EXPECT_EQ(rvh2, rvh());
-  EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
-  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
-  EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, rvh1->rvh_state());
+  EXPECT_EQ(rfh2, contents()->GetMainFrame());
+  EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh2->GetRenderViewHost()->rvh_state());
+  EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT,
+            rfh1->GetRenderViewHost()->rvh_state());
 
   // Simulate the swap out ack.
-  rvh1->OnSwappedOut(false);
+  rfh1->OnSwappedOut(false);
 
-  // rvh1 should be swapped out.
-  EXPECT_FALSE(destruction_observer.rvh_deleted());
-  EXPECT_TRUE(rvh1->IsSwappedOut());
+  // rfh1 should be swapped out.
+  EXPECT_FALSE(rvh_deleted_observer.deleted());
+  EXPECT_TRUE(rfh1->GetRenderViewHost()->IsSwappedOut());
+}
+
+// Test that the RenderViewHost is properly swapped out if a navigation in the
+// new renderer commits before sending the SwapOut message to the old renderer.
+// This simulates a cross-site navigation to a synchronously committing URL
+// (e.g., a data URL) and ensures it works properly.
+TEST_F(RenderFrameHostManagerTest,
+       CommitNewNavigationBeforeSendingSwapOut) {
+  const GURL kUrl1("http://www.google.com/");
+  const GURL kUrl2("http://www.chromium.org/");
+
+  // Navigate to the first page.
+  contents()->NavigateAndCommit(kUrl1);
+  TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
+  RenderViewHostDeletedObserver rvh_deleted_observer(rfh1->GetRenderViewHost());
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh1->GetRenderViewHost()->rvh_state());
+
+  // Increment the number of active views in SiteInstanceImpl so that rfh1 is
+  // not deleted on swap out.
+  static_cast<SiteInstanceImpl*>(
+      rfh1->GetSiteInstance())->increment_active_view_count();
+
+  // Navigate to new site, simulating onbeforeunload approval.
+  controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  base::TimeTicks now = base::TimeTicks::Now();
+  rfh1->OnMessageReceived(
+      FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
+  EXPECT_TRUE(contents()->cross_navigation_pending());
+  TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
+
+  // The new page commits.
+  contents()->TestDidNavigate(rfh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
+  EXPECT_FALSE(contents()->cross_navigation_pending());
+  EXPECT_EQ(rfh2, contents()->GetMainFrame());
+  EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
+            rfh2->GetRenderViewHost()->rvh_state());
+  EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT,
+            rfh1->GetRenderViewHost()->rvh_state());
+
+  // Simulate the swap out ack.
+  rfh1->OnSwappedOut(false);
+
+  // rfh1 should be swapped out.
+  EXPECT_FALSE(rvh_deleted_observer.deleted());
+  EXPECT_TRUE(rfh1->GetRenderViewHost()->IsSwappedOut());
+}
+
+// Test that a RenderFrameHost is properly deleted or swapped out when a
+// cross-site navigation is cancelled.
+TEST_F(RenderFrameHostManagerTest,
+       CancelPendingProperlyDeletesOrSwaps) {
+  const GURL kUrl1("http://www.google.com/");
+  const GURL kUrl2("http://www.chromium.org/");
+  RenderFrameHostImpl* pending_rfh = NULL;
+  base::TimeTicks now = base::TimeTicks::Now();
+
+  // Navigate to the first page.
+  contents()->NavigateAndCommit(kUrl1);
+  TestRenderViewHost* rvh1 = test_rvh();
+  EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+
+  // Navigate to a new site, starting a cross-site navigation.
+  controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  {
+    pending_rfh = contents()->GetFrameTree()->root()->render_manager()
+        ->pending_frame_host();
+    RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh);
+
+    // Cancel the navigation by simulating a declined beforeunload dialog.
+    contents()->GetMainFrame()->OnMessageReceived(
+        FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
+    EXPECT_FALSE(contents()->cross_navigation_pending());
+
+    // Since the pending RFH is the only one for the new SiteInstance, it should
+    // be deleted.
+    EXPECT_TRUE(rvh_deleted_observer.deleted());
+  }
+
+  // Start another cross-site navigation.
+  controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+  {
+    pending_rfh = contents()->GetFrameTree()->root()->render_manager()
+        ->pending_frame_host();
+    RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh);
+
+    // Increment the number of active views in the new SiteInstance, which will
+    // cause the pending RFH to be swapped out instead of deleted.
+    static_cast<SiteInstanceImpl*>(
+        pending_rfh->GetSiteInstance())->increment_active_view_count();
+
+    contents()->GetMainFrame()->OnMessageReceived(
+        FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
+    EXPECT_FALSE(contents()->cross_navigation_pending());
+    EXPECT_FALSE(rvh_deleted_observer.deleted());
+  }
+}
+
+// Browser-side navigation: Test that a proper NavigationRequest is created by
+// BeginNavigation.
+TEST_F(RenderFrameHostManagerTest, BrowserSideNavigationBeginNavigation) {
+  const GURL kUrl1("http://www.google.com/");
+  const GURL kUrl2("http://www.chromium.org/");
+  const GURL kUrl3("http://www.gmail.com/");
+
+  // Navigate to the first page.
+  contents()->NavigateAndCommit(kUrl1);
+
+  // Add a subframe.
+  TestRenderFrameHost* subframe_rfh = static_cast<TestRenderFrameHost*>(
+      contents()->GetFrameTree()->AddFrame(
+          contents()->GetFrameTree()->root(), 14, "Child"));
+
+  // Simulate a BeginNavigation IPC on the subframe.
+  subframe_rfh->SendBeginNavigationWithURL(kUrl2);
+  NavigationRequest* subframe_request =
+      NavigationRequestForRenderFrameManager(
+          subframe_rfh->frame_tree_node()->render_manager());
+  ASSERT_TRUE(subframe_request);
+  EXPECT_EQ(kUrl2, subframe_request->info_for_testing().navigation_params.url);
+  // First party for cookies url should be that of the main frame.
+  EXPECT_EQ(
+      kUrl1, subframe_request->info_for_testing().first_party_for_cookies);
+  EXPECT_FALSE(subframe_request->info_for_testing().is_main_frame);
+  EXPECT_TRUE(subframe_request->info_for_testing().parent_is_main_frame);
+
+  // Simulate a BeginNavigation IPC on the main frame.
+  contents()->GetMainFrame()->SendBeginNavigationWithURL(kUrl3);
+  NavigationRequest* main_request = NavigationRequestForRenderFrameManager(
+      contents()->GetMainFrame()->frame_tree_node()->render_manager());
+  ASSERT_TRUE(main_request);
+  EXPECT_EQ(kUrl3, main_request->info_for_testing().navigation_params.url);
+  EXPECT_EQ(kUrl3, main_request->info_for_testing().first_party_for_cookies);
+  EXPECT_TRUE(main_request->info_for_testing().is_main_frame);
+  EXPECT_FALSE(main_request->info_for_testing().parent_is_main_frame);
 }
 
 }  // namespace content