| Index: chrome/browser/prerender/prerender_manager.cc
|
| diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
|
| index ec44cfdcdbde4bdd4fcf07fa5494da34c814e4e1..deba1a9e095e3d9b3c9de9abacad01f91baeeae4 100644
|
| --- a/chrome/browser/prerender/prerender_manager.cc
|
| +++ b/chrome/browser/prerender/prerender_manager.cc
|
| @@ -434,102 +434,6 @@ void PrerenderManager::CancelAllPrerenders() {
|
| }
|
| }
|
|
|
| -void PrerenderManager::ProcessMergeResult(
|
| - PrerenderData* prerender_data,
|
| - bool timed_out,
|
| - content::SessionStorageNamespace::MergeResult result) {
|
| - PendingSwap* pending_swap = prerender_data->pending_swap();
|
| - DCHECK(pending_swap);
|
| - // No pending_swap should never happen. If it does anyways (in a retail
|
| - // build), log this and bail.
|
| - if (!pending_swap) {
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_NO_PENDING_SWAPIN);
|
| - return;
|
| - }
|
| - if (timed_out) {
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_TIMEOUT_CB);
|
| - } else {
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_RESULT_CB);
|
| - UMA_HISTOGRAM_TIMES("Prerender.SessionStorageNamespaceMergeTime",
|
| - pending_swap->GetElapsedTime());
|
| - }
|
| -
|
| - // Any return here must call ClearPendingSwap on |prerender_data| before
|
| - // returning, with one exception: when the prerender was ultimately swapped
|
| - // in. In that case, SwapInternal will take care of deleting
|
| - // |prerender_data| and sending the appropriate notifications to the tracker.
|
| - if (timed_out) {
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_TIMED_OUT);
|
| - prerender_data->ClearPendingSwap();
|
| - return;
|
| - }
|
| -
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_MERGE_DONE);
|
| -
|
| - // Log the exact merge result in a histogram.
|
| - switch (result) {
|
| - case content::SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND:
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_FOUND);
|
| - break;
|
| - case content::SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_ALIAS:
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_ALIAS);
|
| - break;
|
| - case content::SessionStorageNamespace::MERGE_RESULT_NOT_LOGGING:
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_LOGGING);
|
| - break;
|
| - case content::SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS:
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_RESULT_NO_TRANSACTIONS);
|
| - break;
|
| - case content::SessionStorageNamespace::MERGE_RESULT_TOO_MANY_TRANSACTIONS:
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_RESULT_TOO_MANY_TRANSACTIONS);
|
| - break;
|
| - case content::SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE:
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_MERGEABLE);
|
| - break;
|
| - case content::SessionStorageNamespace::MERGE_RESULT_MERGEABLE:
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_RESULT_MERGEABLE);
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| -
|
| - if (result != content::SessionStorageNamespace::MERGE_RESULT_MERGEABLE &&
|
| - result !=
|
| - content::SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS) {
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_MERGE_FAILED);
|
| - prerender_data->ClearPendingSwap();
|
| - return;
|
| - }
|
| -
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_SWAPPING_IN);
|
| - // Notice that SwapInInternal, on success, will delete |prerender_data|
|
| - // and |pending_swap|. Therefore, we have to pass a new GURL object rather
|
| - // than a reference to the one in |pending_swap|.
|
| - content::WebContents* new_web_contents =
|
| - SwapInternal(GURL(pending_swap->url()),
|
| - pending_swap->target_contents(),
|
| - prerender_data);
|
| - if (!new_web_contents) {
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_RESULT_SWAPIN_FAILED);
|
| - prerender_data->ClearPendingSwap();
|
| - }
|
| -}
|
| -
|
| bool PrerenderManager::MaybeUsePrerenderedPage(const GURL& url,
|
| chrome::NavigateParams* params) {
|
| DCHECK(CalledOnValidThread());
|
| @@ -541,37 +445,12 @@ bool PrerenderManager::MaybeUsePrerenderedPage(const GURL& url,
|
| if (params->uses_post || !params->extra_headers.empty())
|
| return false;
|
|
|
| - content::WebContents* new_web_contents = SwapInternal(url, web_contents,
|
| - NULL);
|
| - if (!new_web_contents)
|
| - return false;
|
| -
|
| - // Record the new target_contents for the callers.
|
| - params->target_contents = new_web_contents;
|
| - return true;
|
| -}
|
| -
|
| -content::WebContents* PrerenderManager::SwapInternal(
|
| - const GURL& url,
|
| - content::WebContents* web_contents,
|
| - PrerenderData* swap_candidate) {
|
| - DCHECK(CalledOnValidThread());
|
| - DCHECK(!IsWebContentsPrerendering(web_contents, NULL));
|
| -
|
| DeleteOldEntries();
|
| to_delete_prerenders_.clear();
|
| - // TODO(ajwong): This doesn't handle isolated apps correctly.
|
| -
|
| - // Only if this WebContents is used in a tabstrip may be swap.
|
| - // We check this by examining whether its CoreTabHelper has a delegate.
|
| - CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
|
| - if (!core_tab_helper || !core_tab_helper->delegate()) {
|
| - RecordEvent(NULL, PRERENDER_EVENT_SWAPIN_NO_DELEGATE);
|
| - return NULL;
|
| - }
|
|
|
| // First, try to find prerender data with the correct session storage
|
| // namespace.
|
| + // TODO(ajwong): This doesn't handle isolated apps correctly.
|
| PrerenderData* prerender_data = FindPrerenderData(
|
| url,
|
| web_contents->GetController().GetDefaultSessionStorageNamespace());
|
| @@ -587,16 +466,15 @@ content::WebContents* PrerenderManager::SwapInternal(
|
| }
|
|
|
| if (!prerender_data)
|
| - return NULL;
|
| + return false;
|
| 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 (prerender_data != swap_candidate && prerender_data->pending_swap()) {
|
| - return NULL;
|
| - }
|
| + if (prerender_data->pending_swap())
|
| + return false;
|
|
|
| RecordEvent(prerender_data->contents(),
|
| PRERENDER_EVENT_SWAPIN_NO_MERGE_PENDING);
|
| @@ -611,46 +489,42 @@ content::WebContents* PrerenderManager::SwapInternal(
|
| if (!ShouldMergeSessionStorageNamespaces()) {
|
| RecordEvent(prerender_data->contents(),
|
| PRERENDER_EVENT_SWAPIN_MERGING_DISABLED);
|
| - return NULL;
|
| + return false;
|
| }
|
| RecordEvent(prerender_data->contents(),
|
| PRERENDER_EVENT_SWAPIN_ISSUING_MERGE);
|
| - // There should never be a |pending_swap| if we get to here:
|
| - // Per check above, |pending_swap| may only be != NULL when
|
| - // processing a successful merge, as indicated by |swap_candidate|
|
| - // != NULL. But in that case, there should be no need for yet another merge.
|
| - DCHECK(!prerender_data->pending_swap());
|
| - if (prerender_data->pending_swap()) {
|
| - // In retail builds, log this error and bail.
|
| - RecordEvent(prerender_data->contents(),
|
| - PRERENDER_EVENT_MERGE_FOR_SWAPIN_CANDIDATE);
|
| - return NULL;
|
| - }
|
| - PendingSwap* pending_swap = new PendingSwap(
|
| - prerender_tracker_,
|
| - web_contents,
|
| - prerender_data,
|
| - url,
|
| - base::Bind(&PrerenderManager::ProcessMergeResult,
|
| - AsWeakPtr(),
|
| - prerender_data,
|
| - true,
|
| - SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE),
|
| - base::Bind(&PrerenderManager::ProcessMergeResult,
|
| - AsWeakPtr(),
|
| - prerender_data,
|
| - false));
|
| - prerender_data->set_pending_swap(pending_swap);
|
| - prerender_namespace->Merge(
|
| - true,
|
| - prerender_data->contents()->child_id(),
|
| - target_namespace,
|
| - pending_swap->GetMergeResultCallback());
|
| - base::MessageLoop::current()->PostDelayedTask(
|
| - FROM_HERE,
|
| - pending_swap->GetTimeoutCallback(),
|
| - base::TimeDelta::FromMilliseconds(
|
| - kSessionStorageNamespaceMergeTimeoutMs));
|
| + prerender_data->set_pending_swap(new PendingSwap(
|
| + this, web_contents, prerender_data, url));
|
| + prerender_data->pending_swap()->BeginSwap();
|
| + // Although this returns false, creating a PendingSwap registers with
|
| + // PrerenderTracker to throttle MAIN_FRAME navigations while the swap is
|
| + // pending.
|
| + return false;
|
| + }
|
| +
|
| + // No need to merge; swap synchronously.
|
| + WebContents* new_web_contents = SwapInternal(url, web_contents,
|
| + prerender_data);
|
| + if (!new_web_contents)
|
| + return false;
|
| +
|
| + // Record the new target_contents for the callers.
|
| + params->target_contents = new_web_contents;
|
| + return true;
|
| +}
|
| +
|
| +WebContents* PrerenderManager::SwapInternal(
|
| + const GURL& url,
|
| + WebContents* web_contents,
|
| + PrerenderData* prerender_data) {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK(!IsWebContentsPrerendering(web_contents, NULL));
|
| +
|
| + // Only swap if the target WebContents has a CoreTabHelper delegate to swap
|
| + // out of it. For a normal WebContents, this is if it is in a TabStripModel.
|
| + CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
|
| + if (!core_tab_helper || !core_tab_helper->delegate()) {
|
| + RecordEvent(prerender_data->contents(), PRERENDER_EVENT_SWAPIN_NO_DELEGATE);
|
| return NULL;
|
| }
|
|
|
| @@ -734,7 +608,7 @@ content::WebContents* PrerenderManager::SwapInternal(
|
|
|
| // At this point, we've determined that we will use the prerender.
|
| if (prerender_data->pending_swap())
|
| - prerender_data->pending_swap()->SwapSuccessful();
|
| + prerender_data->pending_swap()->set_swap_successful(true);
|
| ScopedVector<PrerenderData>::iterator to_erase =
|
| FindIteratorForPrerenderContents(prerender_data->contents());
|
| DCHECK(active_prerenders_.end() != to_erase);
|
| @@ -851,7 +725,6 @@ void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry,
|
| (*it)->MakeIntoMatchCompleteReplacement();
|
| } else {
|
| to_delete_prerenders_.push_back(*it);
|
| - (*it)->ClearPendingSwap();
|
| active_prerenders_.weak_erase(it);
|
| }
|
|
|
| @@ -1282,45 +1155,45 @@ PrerenderContents* PrerenderManager::PrerenderData::ReleaseContents() {
|
| }
|
|
|
| PrerenderManager::PendingSwap::PendingSwap(
|
| - PrerenderTracker* prerender_tracker,
|
| + PrerenderManager* manager,
|
| content::WebContents* target_contents,
|
| PrerenderData* prerender_data,
|
| - const GURL& url,
|
| - const base::Closure& timeout_cb,
|
| - const SessionStorageNamespace::MergeResultCallback& merge_result_cb)
|
| + const GURL& url)
|
| : content::WebContentsObserver(target_contents),
|
| - prerender_tracker_(prerender_tracker),
|
| + manager_(manager),
|
| target_contents_(target_contents),
|
| prerender_data_(prerender_data),
|
| url_(url),
|
| - timeout_cb_(timeout_cb),
|
| - merge_result_cb_(merge_result_cb),
|
| - start_time_(base::TimeTicks::Now()) {
|
| + start_time_(base::TimeTicks::Now()),
|
| + swap_successful_(false),
|
| + weak_factory_(this) {
|
| RenderViewCreated(target_contents->GetRenderViewHost());
|
| }
|
|
|
| PrerenderManager::PendingSwap::~PendingSwap() {
|
| - timeout_cb_.Cancel();
|
| - merge_result_cb_.Cancel();
|
| - for (size_t i = 0; i < rvh_ids_.size(); i++) {
|
| - prerender_tracker_->RemovePrerenderPendingSwap(rvh_ids_[i], false);
|
| - }
|
| -}
|
| -
|
| -const base::Closure& PrerenderManager::PendingSwap::GetTimeoutCallback() {
|
| - return timeout_cb_.callback();
|
| -}
|
| -
|
| -void PrerenderManager::PendingSwap::SwapSuccessful() {
|
| for (size_t i = 0; i < rvh_ids_.size(); i++) {
|
| - prerender_tracker_->RemovePrerenderPendingSwap(rvh_ids_[i], true);
|
| + manager_->prerender_tracker()->RemovePrerenderPendingSwap(
|
| + rvh_ids_[i], swap_successful_);
|
| }
|
| - rvh_ids_.clear();
|
| }
|
|
|
| -const SessionStorageNamespace::MergeResultCallback&
|
| -PrerenderManager::PendingSwap::GetMergeResultCallback() {
|
| - return merge_result_cb_.callback();
|
| +void PrerenderManager::PendingSwap::BeginSwap() {
|
| + SessionStorageNamespace* target_namespace =
|
| + target_contents_->GetController().GetDefaultSessionStorageNamespace();
|
| + SessionStorageNamespace* prerender_namespace =
|
| + prerender_data_->contents()->GetSessionStorageNamespace();
|
| +
|
| + prerender_namespace->Merge(
|
| + true, prerender_data_->contents()->child_id(),
|
| + target_namespace,
|
| + base::Bind(&PrerenderManager::PendingSwap::OnMergeCompleted,
|
| + weak_factory_.GetWeakPtr()));
|
| +
|
| + merge_timeout_.Start(
|
| + FROM_HERE,
|
| + base::TimeDelta::FromMilliseconds(
|
| + kSessionStorageNamespaceMergeTimeoutMs),
|
| + this, &PrerenderManager::PendingSwap::OnMergeTimeout);
|
| }
|
|
|
| void PrerenderManager::PendingSwap::ProvisionalChangeToMainFrameUrl(
|
| @@ -1343,17 +1216,19 @@ void PrerenderManager::PendingSwap::DidCommitProvisionalLoadForFrame(
|
| content::RenderViewHost* render_view_host){
|
| if (!is_main_frame)
|
| return;
|
| - if (validated_url != url_)
|
| - prerender_data_->ClearPendingSwap();
|
| + prerender_data_->ClearPendingSwap();
|
| }
|
|
|
| void PrerenderManager::PendingSwap::RenderViewCreated(
|
| content::RenderViewHost* render_view_host) {
|
| + // Record the RVH id in the tracker to install throttles on MAIN_FRAME
|
| + // requests from that route.
|
| int child_id = render_view_host->GetProcess()->GetID();
|
| int route_id = render_view_host->GetRoutingID();
|
| PrerenderTracker::ChildRouteIdPair child_route_id_pair(child_id, route_id);
|
| rvh_ids_.push_back(child_route_id_pair);
|
| - prerender_tracker_->AddPrerenderPendingSwap(child_route_id_pair, url_);
|
| + manager_->prerender_tracker()->AddPrerenderPendingSwap(
|
| + child_route_id_pair, url_);
|
| }
|
|
|
| void PrerenderManager::PendingSwap::DidFailProvisionalLoad(
|
| @@ -1364,6 +1239,8 @@ void PrerenderManager::PendingSwap::DidFailProvisionalLoad(
|
| int error_code,
|
| const string16& error_description,
|
| content::RenderViewHost* render_view_host) {
|
| + if (!is_main_frame)
|
| + return;
|
| prerender_data_->ClearPendingSwap();
|
| }
|
|
|
| @@ -1372,8 +1249,67 @@ void PrerenderManager::PendingSwap::WebContentsDestroyed(
|
| prerender_data_->ClearPendingSwap();
|
| }
|
|
|
| -base::TimeDelta PrerenderManager::PendingSwap::GetElapsedTime() {
|
| - return base::TimeTicks::Now() - start_time_;
|
| +void PrerenderManager::PendingSwap::RecordEvent(PrerenderEvent event) const {
|
| + manager_->RecordEvent(prerender_data_->contents(), event);
|
| +}
|
| +
|
| +void PrerenderManager::PendingSwap::OnMergeCompleted(
|
| + SessionStorageNamespace::MergeResult result) {
|
| + UMA_HISTOGRAM_TIMES("Prerender.SessionStorageNamespaceMergeTime",
|
| + base::TimeTicks::Now() - start_time_);
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_MERGE_DONE);
|
| +
|
| + // Log the exact merge result in a histogram.
|
| + switch (result) {
|
| + case SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND:
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_FOUND);
|
| + break;
|
| + case SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_ALIAS:
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_ALIAS);
|
| + break;
|
| + case SessionStorageNamespace::MERGE_RESULT_NOT_LOGGING:
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_LOGGING);
|
| + break;
|
| + case SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS:
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NO_TRANSACTIONS);
|
| + break;
|
| + case SessionStorageNamespace::MERGE_RESULT_TOO_MANY_TRANSACTIONS:
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_TOO_MANY_TRANSACTIONS);
|
| + break;
|
| + case SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE:
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_MERGEABLE);
|
| + break;
|
| + case SessionStorageNamespace::MERGE_RESULT_MERGEABLE:
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_MERGEABLE);
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| +
|
| + if (result != SessionStorageNamespace::MERGE_RESULT_MERGEABLE &&
|
| + result != SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS) {
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_MERGE_FAILED);
|
| + prerender_data_->ClearPendingSwap();
|
| + return;
|
| + }
|
| +
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_SWAPPING_IN);
|
| + // 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.
|
| + WebContents* new_web_contents =
|
| + manager_->SwapInternal(GURL(url_), target_contents_, prerender_data_);
|
| + if (!new_web_contents) {
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_SWAPIN_FAILED);
|
| + prerender_data_->ClearPendingSwap();
|
| + }
|
| +}
|
| +
|
| +void PrerenderManager::PendingSwap::OnMergeTimeout() {
|
| + RecordEvent(PRERENDER_EVENT_MERGE_RESULT_TIMED_OUT);
|
| + prerender_data_->ClearPendingSwap();
|
| }
|
|
|
| void PrerenderManager::SetPrerenderContentsFactory(
|
|
|