Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / prerender / prerender_manager.cc
index 7c7e27d..dbd401d 100644 (file)
@@ -23,7 +23,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/common/cancelable_request.h"
-#include "chrome/browser/favicon/favicon_tab_helper.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/net/chrome_cookie_notification_details.h"
 #include "chrome/browser/predictors/predictor_database.h"
@@ -49,6 +48,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/prerender_messages.h"
+#include "chrome/common/prerender_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/navigation_controller.h"
@@ -61,7 +61,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_view.h"
-#include "content/public/common/favicon_url.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
 #include "net/url_request/url_request_context.h"
@@ -96,6 +95,9 @@ const int kHistoryLength = 100;
 // Timeout, in ms, for a session storage namespace merge.
 const int kSessionStorageNamespaceMergeTimeoutMs = 500;
 
+// If true, all session storage merges hang indefinitely.
+bool g_hang_session_storage_merges_for_testing = false;
+
 // Indicates whether a Prerender has been cancelled such that we need
 // a dummy replacement for the purpose of recording the correct PPLT for
 // the Match Complete case.
@@ -230,16 +232,6 @@ struct PrerenderManager::NavigationRecord {
   base::TimeTicks time;
 };
 
-PrerenderManager::PrerenderedWebContentsData::
-PrerenderedWebContentsData(Origin origin) : origin(origin) {
-}
-
-PrerenderManager::WouldBePrerenderedWebContentsData::
-WouldBePrerenderedWebContentsData(Origin origin)
-    : origin(origin),
-      state(WAITING_FOR_PROVISIONAL_LOAD) {
-}
-
 PrerenderManager::PrerenderManager(Profile* profile,
                                    PrerenderTracker* prerender_tracker)
     : enabled_(profile && profile->GetPrefs() &&
@@ -250,7 +242,9 @@ PrerenderManager::PrerenderManager(Profile* profile,
       last_prerender_start_time_(GetCurrentTimeTicks() -
           base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)),
       prerender_history_(new PrerenderHistory(kHistoryLength)),
-      histograms_(new PrerenderHistograms()) {
+      histograms_(new PrerenderHistograms()),
+      profile_network_bytes_(0),
+      last_recorded_profile_network_bytes_(0) {
   // There are some assumptions that the PrerenderManager is on the UI thread.
   // Any other checks simply make sure that the PrerenderManager is accessed on
   // the same thread that it was created on.
@@ -323,9 +317,12 @@ PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender(
     int process_id,
     int route_id,
     const GURL& url,
+    const uint32 rel_types,
     const content::Referrer& referrer,
     const gfx::Size& size) {
-  Origin origin = ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN;
+  Origin origin = rel_types & PrerenderRelTypePrerender ?
+                      ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN :
+                      ORIGIN_LINK_REL_NEXT;
   SessionStorageNamespace* session_storage_namespace = NULL;
   // Unit tests pass in a process_id == -1.
   if (process_id != -1) {
@@ -337,45 +334,16 @@ PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender(
         WebContents::FromRenderViewHost(source_render_view_host);
     if (!source_web_contents)
       return NULL;
-    if (source_web_contents->GetURL().host() == url.host())
+    if (origin == ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN &&
+        source_web_contents->GetURL().host() == url.host()) {
       origin = ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN;
+    }
     // TODO(ajwong): This does not correctly handle storage for isolated apps.
     session_storage_namespace =
         source_web_contents->GetController()
             .GetDefaultSessionStorageNamespace();
   }
 
-  // If the prerender request comes from a recently cancelled prerender that
-  // |this| still owns, then abort the prerender.
-  for (ScopedVector<PrerenderData>::iterator it = to_delete_prerenders_.begin();
-       it != to_delete_prerenders_.end(); ++it) {
-    PrerenderContents* prerender_contents = (*it)->contents();
-    int contents_child_id;
-    int contents_route_id;
-    if (prerender_contents->GetChildId(&contents_child_id) &&
-        prerender_contents->GetRouteId(&contents_route_id)) {
-      if (contents_child_id == process_id && contents_route_id == route_id)
-        return NULL;
-    }
-  }
-
-  if (PrerenderData* parent_prerender_data =
-          FindPrerenderDataForChildAndRoute(process_id, route_id)) {
-    // Instead of prerendering from inside of a running prerender, we will defer
-    // this request until its launcher is made visible.
-    if (PrerenderContents* contents = parent_prerender_data->contents()) {
-      PrerenderHandle* prerender_handle =
-          new PrerenderHandle(static_cast<PrerenderData*>(NULL));
-      scoped_ptr<PrerenderContents::PendingPrerenderInfo>
-          pending_prerender_info(new PrerenderContents::PendingPrerenderInfo(
-              prerender_handle->weak_ptr_factory_.GetWeakPtr(),
-              origin, url, referrer, size));
-
-      contents->AddPendingPrerender(pending_prerender_info.Pass());
-      return prerender_handle;
-    }
-  }
-
   return AddPrerender(origin, process_id, url, referrer, size,
                       session_storage_namespace);
 }
@@ -461,12 +429,18 @@ bool PrerenderManager::MaybeUsePrerenderedPage(const GURL& url,
   RecordEvent(prerender_data->contents(), PRERENDER_EVENT_SWAPIN_CANDIDATE);
   DCHECK(prerender_data->contents());
 
-  // If there is currently a merge pending for this prerender data,
-  // or this webcontents, do not swap in, but give the merge a chance to
-  // finish and swap into the intended target webcontents.
+  // If there is currently a merge pending for this prerender data, don't swap.
   if (prerender_data->pending_swap())
     return false;
 
+  // Abort any existing pending swap on the target contents.
+  PrerenderData* pending_swap =
+      FindPrerenderDataForTargetContents(web_contents);
+  if (pending_swap) {
+    pending_swap->ClearPendingSwap();
+    DCHECK(FindPrerenderDataForTargetContents(web_contents) == NULL);
+  }
+
   RecordEvent(prerender_data->contents(),
               PRERENDER_EVENT_SWAPIN_NO_MERGE_PENDING);
   SessionStorageNamespace* target_namespace =
@@ -522,6 +496,13 @@ WebContents* PrerenderManager::SwapInternal(
     return NULL;
   }
 
+  PrerenderTabHelper* target_tab_helper =
+      PrerenderTabHelper::FromWebContents(web_contents);
+  if (!target_tab_helper) {
+    NOTREACHED();
+    return NULL;
+  }
+
   if (IsNoSwapInExperiment(prerender_data->contents()->experiment_id()))
     return NULL;
 
@@ -558,8 +539,8 @@ WebContents* PrerenderManager::SwapInternal(
   // that prerendering hasn't even started yet), record that |web_contents| now
   // would be showing a prerendered contents, but otherwise, don't do anything.
   if (!prerender_data->contents()->prerendering_has_started()) {
-    MarkWebContentsAsWouldBePrerendered(web_contents,
-                                        prerender_data->contents()->origin());
+    target_tab_helper->WouldHavePrerenderedNextLoad(
+        prerender_data->contents()->origin());
     prerender_data->contents()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED);
     return NULL;
   }
@@ -584,16 +565,12 @@ WebContents* PrerenderManager::SwapInternal(
   // For bookkeeping purposes, we need to mark this WebContents to
   // reflect that it would have been prerendered.
   if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) {
-    MarkWebContentsAsWouldBePrerendered(web_contents,
-                                        prerender_data->contents()->origin());
+    target_tab_helper->WouldHavePrerenderedNextLoad(
+        prerender_data->contents()->origin());
     prerender_data->contents()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED);
     return NULL;
   }
 
-  int child_id, route_id;
-  CHECK(prerender_data->contents()->GetChildId(&child_id));
-  CHECK(prerender_data->contents()->GetRouteId(&route_id));
-
   // At this point, we've determined that we will use the prerender.
   if (prerender_data->pending_swap())
     prerender_data->pending_swap()->set_swap_successful(true);
@@ -614,10 +591,8 @@ WebContents* PrerenderManager::SwapInternal(
   histograms_->RecordPerSessionCount(prerender_contents->origin(),
                                      ++prerenders_per_session_count_);
   histograms_->RecordUsedPrerender(prerender_contents->origin());
-  prerender_contents->SetFinalStatus(FINAL_STATUS_USED);
 
-  // Start pending prerender requests from the PrerenderContents, if there are
-  // any.
+  // Mark prerender as used.
   prerender_contents->PrepareForUse();
 
   WebContents* new_web_contents =
@@ -626,34 +601,17 @@ WebContents* PrerenderManager::SwapInternal(
   DCHECK(new_web_contents);
   DCHECK(old_web_contents);
 
-  MarkWebContentsAsPrerendered(new_web_contents, prerender_contents->origin());
-
   // Merge the browsing history.
   new_web_contents->GetController().CopyStateFromAndPrune(
       &old_web_contents->GetController(),
       should_replace_current_entry);
   CoreTabHelper::FromWebContents(old_web_contents)->delegate()->
-      SwapTabContents(old_web_contents, new_web_contents);
+      SwapTabContents(old_web_contents,
+                      new_web_contents,
+                      true,
+                      prerender_contents->has_finished_loading());
   prerender_contents->CommitHistory(new_web_contents);
 
-  GURL icon_url = prerender_contents->icon_url();
-
-  if (!icon_url.is_empty()) {
-#if defined(OS_ANDROID)
-    // Do the delayed icon fetch since we didn't download
-    // the favicon during prerendering on mobile devices.
-    FaviconTabHelper * favicon_tap_helper =
-        FaviconTabHelper::FromWebContents(new_web_contents);
-    favicon_tap_helper->set_should_fetch_icons(true);
-    favicon_tap_helper->FetchFavicon(icon_url);
-#endif  // defined(OS_ANDROID)
-
-    std::vector<content::FaviconURL> urls;
-    urls.push_back(content::FaviconURL(icon_url, content::FaviconURL::FAVICON));
-    FaviconTabHelper::FromWebContents(new_web_contents)->
-        DidUpdateFaviconURL(prerender_contents->page_id(), urls);
-  }
-
   // Update PPLT metrics:
   // If the tab has finished loading, record a PPLT of 0.
   // If the tab is still loading, reset its start time to the current time.
@@ -708,6 +666,7 @@ void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry,
     (*it)->MakeIntoMatchCompleteReplacement();
   } else {
     to_delete_prerenders_.push_back(*it);
+    (*it)->ClearPendingSwap();
     active_prerenders_.weak_erase(it);
   }
 
@@ -715,45 +674,33 @@ void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry,
   PostCleanupTask();
 }
 
-// static
+void PrerenderManager::RecordPageLoadTimeNotSwappedIn(
+    Origin origin,
+    base::TimeDelta page_load_time,
+    const GURL& url) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  histograms_->RecordPageLoadTimeNotSwappedIn(origin, page_load_time, url);
+}
+
 void PrerenderManager::RecordPerceivedPageLoadTime(
+    Origin origin,
+    NavigationType navigation_type,
     base::TimeDelta perceived_page_load_time,
     double fraction_plt_elapsed_at_swap_in,
-    WebContents* web_contents,
     const GURL& url) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  PrerenderManager* prerender_manager =
-      PrerenderManagerFactory::GetForProfile(
-          Profile::FromBrowserContext(web_contents->GetBrowserContext()));
-  if (!prerender_manager)
-    return;
-  if (!prerender_manager->IsEnabled())
+  if (!IsEnabled())
     return;
 
-  Origin prerender_origin = ORIGIN_NONE;
-  if (prerender_manager->IsWebContentsPrerendering(web_contents,
-                                                   &prerender_origin)) {
-    prerender_manager->histograms_->RecordPageLoadTimeNotSwappedIn(
-        prerender_origin, perceived_page_load_time, url);
-    return;
-  }
+  histograms_->RecordPerceivedPageLoadTime(
+      origin, perceived_page_load_time, navigation_type, url);
 
-  bool was_prerender = prerender_manager->IsWebContentsPrerendered(
-      web_contents, &prerender_origin);
-  bool was_complete_prerender = was_prerender ||
-      prerender_manager->WouldWebContentsBePrerendered(web_contents,
-                                                       &prerender_origin);
-  prerender_manager->histograms_->RecordPerceivedPageLoadTime(
-      prerender_origin, perceived_page_load_time, was_prerender,
-      was_complete_prerender, url);
-
-  if (was_prerender) {
-    prerender_manager->histograms_->RecordPercentLoadDoneAtSwapin(
-        prerender_origin, fraction_plt_elapsed_at_swap_in);
+  if (navigation_type == NAVIGATION_TYPE_PRERENDERED) {
+    histograms_->RecordPercentLoadDoneAtSwapin(
+        origin, fraction_plt_elapsed_at_swap_in);
   }
-  if (prerender_manager->local_predictor_.get()) {
-    prerender_manager->local_predictor_->
-        OnPLTEventForURL(url, perceived_page_load_time);
+  if (local_predictor_) {
+    local_predictor_->OnPLTEventForURL(url, perceived_page_load_time);
   }
 }
 
@@ -874,6 +821,16 @@ PrerenderContents* PrerenderManager::GetPrerenderContents(
   return NULL;
 }
 
+PrerenderContents* PrerenderManager::GetPrerenderContentsForRoute(
+    int child_id,
+    int route_id) const {
+  content::WebContents* web_contents =
+      tab_util::GetWebContentsByID(child_id, route_id);
+  if (web_contents == NULL)
+    return NULL;
+  return GetPrerenderContents(web_contents);
+}
+
 const std::vector<WebContents*>
 PrerenderManager::GetAllPrerenderingContents() const {
   DCHECK(CalledOnValidThread());
@@ -889,69 +846,6 @@ PrerenderManager::GetAllPrerenderingContents() const {
   return result;
 }
 
-void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents,
-                                                    Origin origin) {
-  DCHECK(CalledOnValidThread());
-  prerendered_web_contents_data_.insert(
-      base::hash_map<content::WebContents*,
-                     PrerenderedWebContentsData>::value_type(
-                         web_contents, PrerenderedWebContentsData(origin)));
-}
-
-void PrerenderManager::MarkWebContentsAsWouldBePrerendered(
-    WebContents* web_contents,
-    Origin origin) {
-  DCHECK(CalledOnValidThread());
-  would_be_prerendered_map_.insert(
-      base::hash_map<content::WebContents*,
-                     WouldBePrerenderedWebContentsData>::value_type(
-                         web_contents,
-                         WouldBePrerenderedWebContentsData(origin)));
-}
-
-void PrerenderManager::MarkWebContentsAsNotPrerendered(
-    WebContents* web_contents) {
-  DCHECK(CalledOnValidThread());
-  prerendered_web_contents_data_.erase(web_contents);
-  base::hash_map<content::WebContents*, WouldBePrerenderedWebContentsData>::
-      iterator it = would_be_prerendered_map_.find(web_contents);
-  if (it != would_be_prerendered_map_.end()) {
-    if (it->second.state ==
-            WouldBePrerenderedWebContentsData::WAITING_FOR_PROVISIONAL_LOAD) {
-      it->second.state =
-          WouldBePrerenderedWebContentsData::SEEN_PROVISIONAL_LOAD;
-    } else {
-      would_be_prerendered_map_.erase(it);
-    }
-  }
-}
-
-bool PrerenderManager::IsWebContentsPrerendered(
-    content::WebContents* web_contents,
-    Origin* origin) const {
-  DCHECK(CalledOnValidThread());
-  base::hash_map<content::WebContents*, PrerenderedWebContentsData>::
-      const_iterator it = prerendered_web_contents_data_.find(web_contents);
-  if (it == prerendered_web_contents_data_.end())
-    return false;
-  if (origin)
-    *origin = it->second.origin;
-  return true;
-}
-
-bool PrerenderManager::WouldWebContentsBePrerendered(
-    WebContents* web_contents,
-    Origin* origin) const {
-  DCHECK(CalledOnValidThread());
-  base::hash_map<content::WebContents*, WouldBePrerenderedWebContentsData>::
-      const_iterator it = would_be_prerendered_map_.find(web_contents);
-  if (it == would_be_prerendered_map_.end())
-    return false;
-  if (origin)
-    *origin = it->second.origin;
-  return true;
-}
-
 bool PrerenderManager::HasRecentlyBeenNavigatedTo(Origin origin,
                                                   const GURL& url) {
   DCHECK(CalledOnValidThread());
@@ -1121,7 +1015,6 @@ PrerenderManager::PendingSwap::PendingSwap(
     bool should_replace_current_entry)
     : content::WebContentsObserver(target_contents),
       manager_(manager),
-      target_contents_(target_contents),
       prerender_data_(prerender_data),
       url_(url),
       should_replace_current_entry_(should_replace_current_entry),
@@ -1136,9 +1029,16 @@ PrerenderManager::PendingSwap::~PendingSwap() {
       target_route_id_, swap_successful_);
 }
 
+WebContents* PrerenderManager::PendingSwap::target_contents() const {
+  return web_contents();
+}
+
 void PrerenderManager::PendingSwap::BeginSwap() {
+  if (g_hang_session_storage_merges_for_testing)
+    return;
+
   SessionStorageNamespace* target_namespace =
-      target_contents_->GetController().GetDefaultSessionStorageNamespace();
+      target_contents()->GetController().GetDefaultSessionStorageNamespace();
   SessionStorageNamespace* prerender_namespace =
       prerender_data_->contents()->GetSessionStorageNamespace();
 
@@ -1258,23 +1158,25 @@ void PrerenderManager::PendingSwap::OnMergeCompleted(
 
   RecordEvent(PRERENDER_EVENT_MERGE_RESULT_SWAPPING_IN);
 
-  WebContents* new_web_contents = NULL;
-  // Ensure that the prerendering hasn't been destroyed in the meantime.
-  if (prerender_data_->contents()->final_status() == FINAL_STATUS_MAX) {
-    // Note that SwapInternal, on success, will delete |prerender_data_| and
-    // |this|. Pass in a new GURL object rather than a reference to |url_|.
-    //
-    // TODO(davidben): See about deleting PrerenderData asynchronously so this
-    // behavior is more reasonable.
-
-    new_web_contents =  manager_->SwapInternal(
-        GURL(url_), target_contents_, prerender_data_,
+  // Note that SwapInternal will, on success, delete |prerender_data_| and
+  // |this|. It will also delete |this| in some failure cases. Pass in a new
+  // GURL object rather than a reference to |url_|. Also hold on to |manager_|
+  // and |prerender_data_|.
+  //
+  // TODO(davidben): Can we make this less fragile?
+  PrerenderManager* manager = manager_;
+  PrerenderData* prerender_data = prerender_data_;
+  WebContents* new_web_contents = manager_->SwapInternal(
+        GURL(url_), target_contents(), prerender_data_,
         should_replace_current_entry_);
-  }
-
   if (!new_web_contents) {
-    RecordEvent(PRERENDER_EVENT_MERGE_RESULT_SWAPIN_FAILED);
-    prerender_data_->ClearPendingSwap();
+    manager->RecordEvent(prerender_data->contents(),
+                         PRERENDER_EVENT_MERGE_RESULT_SWAPIN_FAILED);
+    // Depending on whether SwapInternal called Destroy() or simply failed to
+    // swap, |this| may or may not be deleted. Either way, if the swap failed,
+    // |prerender_data| is deleted asynchronously, so this call is a no-op if
+    // |this| is already gone.
+    prerender_data->ClearPendingSwap();
   }
 }
 
@@ -1289,38 +1191,6 @@ void PrerenderManager::SetPrerenderContentsFactory(
   prerender_contents_factory_.reset(prerender_contents_factory);
 }
 
-
-void PrerenderManager::StartPendingPrerenders(
-    const int process_id,
-    ScopedVector<PrerenderContents::PendingPrerenderInfo>* pending_prerenders,
-    content::SessionStorageNamespace* session_storage_namespace) {
-  for (ScopedVector<PrerenderContents::PendingPrerenderInfo>::iterator
-           it = pending_prerenders->begin();
-       it != pending_prerenders->end(); ++it) {
-    PrerenderContents::PendingPrerenderInfo* info = *it;
-    PrerenderHandle* existing_prerender_handle =
-        info->weak_prerender_handle.get();
-    if (!existing_prerender_handle)
-      continue;
-
-    DCHECK(!existing_prerender_handle->IsPrerendering());
-    DCHECK(process_id == -1 || session_storage_namespace);
-
-    scoped_ptr<PrerenderHandle> new_prerender_handle(AddPrerender(
-        info->origin, process_id,
-        info->url, info->referrer, info->size,
-        session_storage_namespace));
-    if (new_prerender_handle) {
-      // AddPrerender has returned a new prerender handle to us. We want to make
-      // |existing_prerender_handle| active, so move the underlying
-      // PrerenderData to our new handle.
-      existing_prerender_handle->AdoptPrerenderDataFrom(
-          new_prerender_handle.get());
-      continue;
-    }
-  }
-}
-
 void PrerenderManager::SourceNavigatedAway(PrerenderData* prerender_data) {
   // The expiry time of our prerender data will likely change because of
   // this navigation. This requires a resort of active_prerenders_.
@@ -1573,20 +1443,12 @@ PrerenderManager::PrerenderData* PrerenderManager::FindPrerenderData(
 }
 
 PrerenderManager::PrerenderData*
-PrerenderManager::FindPrerenderDataForChildAndRoute(
-    const int child_id, const int route_id) {
+PrerenderManager::FindPrerenderDataForTargetContents(
+    WebContents* target_contents) {
   for (ScopedVector<PrerenderData>::iterator it = active_prerenders_.begin();
        it != active_prerenders_.end(); ++it) {
-    PrerenderContents* prerender_contents = (*it)->contents();
-
-    int contents_child_id;
-    if (!prerender_contents->GetChildId(&contents_child_id))
-      continue;
-    int contents_route_id;
-    if (!prerender_contents->GetRouteId(&contents_route_id))
-      continue;
-
-    if (contents_child_id == child_id && contents_route_id == route_id)
+    if ((*it)->pending_swap() &&
+        (*it)->pending_swap()->target_contents() == target_contents)
       return *it;
   }
   return NULL;
@@ -1716,23 +1578,6 @@ bool PrerenderManager::IsEnabled() const {
   return true;
 }
 
-PrerenderManager* FindPrerenderManagerUsingRenderProcessId(
-    int render_process_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  content::RenderProcessHost* render_process_host =
-      content::RenderProcessHost::FromID(render_process_id);
-  // Each render process is guaranteed to only hold RenderViews owned by the
-  // same BrowserContext. This is enforced by
-  // RenderProcessHost::GetExistingProcessHost.
-  if (!render_process_host || !render_process_host->GetBrowserContext())
-    return NULL;
-  Profile* profile = Profile::FromBrowserContext(
-      render_process_host->GetBrowserContext());
-  if (!profile)
-    return NULL;
-  return PrerenderManagerFactory::GetInstance()->GetForProfile(profile);
-}
-
 void PrerenderManager::Observe(int type,
                                const content::NotificationSource& source,
                                const content::NotificationDetails& details) {
@@ -1925,4 +1770,25 @@ void PrerenderManager::OnHistoryServiceDidQueryURL(
   histograms_->RecordPrerenderPageVisitedStatus(origin, experiment_id, success);
 }
 
+// static
+void PrerenderManager::HangSessionStorageMergesForTesting() {
+  g_hang_session_storage_merges_for_testing = true;
+}
+
+void PrerenderManager::RecordNetworkBytes(bool used, int64 prerender_bytes) {
+  if (!ActuallyPrerendering())
+    return;
+  int64 recent_profile_bytes =
+      profile_network_bytes_ - last_recorded_profile_network_bytes_;
+  last_recorded_profile_network_bytes_ = profile_network_bytes_;
+  DCHECK_GE(recent_profile_bytes, 0);
+  histograms_->RecordNetworkBytes(used, prerender_bytes, recent_profile_bytes);
+}
+
+void PrerenderManager::AddProfileNetworkBytesIfEnabled(int64 bytes) {
+  DCHECK_GE(bytes, 0);
+  if (IsEnabled() && ActuallyPrerendering())
+    profile_network_bytes_ += bytes;
+}
+
 }  // namespace prerender