OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/prerender/prerender_manager.h" | 5 #include "chrome/browser/prerender/prerender_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 | 427 |
428 void PrerenderManager::CancelAllPrerenders() { | 428 void PrerenderManager::CancelAllPrerenders() { |
429 DCHECK(CalledOnValidThread()); | 429 DCHECK(CalledOnValidThread()); |
430 while (!active_prerenders_.empty()) { | 430 while (!active_prerenders_.empty()) { |
431 PrerenderContents* prerender_contents = | 431 PrerenderContents* prerender_contents = |
432 active_prerenders_.front()->contents(); | 432 active_prerenders_.front()->contents(); |
433 prerender_contents->Destroy(FINAL_STATUS_CANCELLED); | 433 prerender_contents->Destroy(FINAL_STATUS_CANCELLED); |
434 } | 434 } |
435 } | 435 } |
436 | 436 |
437 void PrerenderManager::ProcessMergeResult( | |
438 PrerenderData* prerender_data, | |
439 bool timed_out, | |
440 content::SessionStorageNamespace::MergeResult result) { | |
441 PendingSwap* pending_swap = prerender_data->pending_swap(); | |
442 DCHECK(pending_swap); | |
443 // No pending_swap should never happen. If it does anyways (in a retail | |
444 // build), log this and bail. | |
445 if (!pending_swap) { | |
446 RecordEvent(prerender_data->contents(), | |
447 PRERENDER_EVENT_MERGE_RESULT_NO_PENDING_SWAPIN); | |
448 return; | |
449 } | |
450 if (timed_out) { | |
451 RecordEvent(prerender_data->contents(), | |
452 PRERENDER_EVENT_MERGE_RESULT_TIMEOUT_CB); | |
453 } else { | |
454 RecordEvent(prerender_data->contents(), | |
455 PRERENDER_EVENT_MERGE_RESULT_RESULT_CB); | |
456 UMA_HISTOGRAM_TIMES("Prerender.SessionStorageNamespaceMergeTime", | |
457 pending_swap->GetElapsedTime()); | |
458 } | |
459 | |
460 // Any return here must call ClearPendingSwap on |prerender_data| before | |
461 // returning, with one exception: when the prerender was ultimately swapped | |
462 // in. In that case, SwapInternal will take care of deleting | |
463 // |prerender_data| and sending the appropriate notifications to the tracker. | |
464 if (timed_out) { | |
465 RecordEvent(prerender_data->contents(), | |
466 PRERENDER_EVENT_MERGE_RESULT_TIMED_OUT); | |
467 prerender_data->ClearPendingSwap(); | |
468 return; | |
469 } | |
470 | |
471 RecordEvent(prerender_data->contents(), | |
472 PRERENDER_EVENT_MERGE_RESULT_MERGE_DONE); | |
473 | |
474 // Log the exact merge result in a histogram. | |
475 switch (result) { | |
476 case content::SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND: | |
477 RecordEvent(prerender_data->contents(), | |
478 PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_FOUND); | |
479 break; | |
480 case content::SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_ALIAS: | |
481 RecordEvent(prerender_data->contents(), | |
482 PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_ALIAS); | |
483 break; | |
484 case content::SessionStorageNamespace::MERGE_RESULT_NOT_LOGGING: | |
485 RecordEvent(prerender_data->contents(), | |
486 PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_LOGGING); | |
487 break; | |
488 case content::SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS: | |
489 RecordEvent(prerender_data->contents(), | |
490 PRERENDER_EVENT_MERGE_RESULT_RESULT_NO_TRANSACTIONS); | |
491 break; | |
492 case content::SessionStorageNamespace::MERGE_RESULT_TOO_MANY_TRANSACTIONS: | |
493 RecordEvent(prerender_data->contents(), | |
494 PRERENDER_EVENT_MERGE_RESULT_RESULT_TOO_MANY_TRANSACTIONS); | |
495 break; | |
496 case content::SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE: | |
497 RecordEvent(prerender_data->contents(), | |
498 PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_MERGEABLE); | |
499 break; | |
500 case content::SessionStorageNamespace::MERGE_RESULT_MERGEABLE: | |
501 RecordEvent(prerender_data->contents(), | |
502 PRERENDER_EVENT_MERGE_RESULT_RESULT_MERGEABLE); | |
503 break; | |
504 default: | |
505 NOTREACHED(); | |
506 } | |
507 | |
508 if (result != content::SessionStorageNamespace::MERGE_RESULT_MERGEABLE && | |
509 result != | |
510 content::SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS) { | |
511 RecordEvent(prerender_data->contents(), | |
512 PRERENDER_EVENT_MERGE_RESULT_MERGE_FAILED); | |
513 prerender_data->ClearPendingSwap(); | |
514 return; | |
515 } | |
516 | |
517 RecordEvent(prerender_data->contents(), | |
518 PRERENDER_EVENT_MERGE_RESULT_SWAPPING_IN); | |
519 // Notice that SwapInInternal, on success, will delete |prerender_data| | |
520 // and |pending_swap|. Therefore, we have to pass a new GURL object rather | |
521 // than a reference to the one in |pending_swap|. | |
522 content::WebContents* new_web_contents = | |
523 SwapInternal(GURL(pending_swap->url()), | |
524 pending_swap->target_contents(), | |
525 prerender_data); | |
526 if (!new_web_contents) { | |
527 RecordEvent(prerender_data->contents(), | |
528 PRERENDER_EVENT_MERGE_RESULT_SWAPIN_FAILED); | |
529 prerender_data->ClearPendingSwap(); | |
530 } | |
531 } | |
532 | |
533 bool PrerenderManager::MaybeUsePrerenderedPage(const GURL& url, | 437 bool PrerenderManager::MaybeUsePrerenderedPage(const GURL& url, |
534 chrome::NavigateParams* params) { | 438 chrome::NavigateParams* params) { |
535 DCHECK(CalledOnValidThread()); | 439 DCHECK(CalledOnValidThread()); |
536 | 440 |
537 content::WebContents* web_contents = params->target_contents; | 441 content::WebContents* web_contents = params->target_contents; |
538 DCHECK(!IsWebContentsPrerendering(web_contents, NULL)); | 442 DCHECK(!IsWebContentsPrerendering(web_contents, NULL)); |
539 | 443 |
540 // Don't prerender if the navigation involves some special parameters. | 444 // Don't prerender if the navigation involves some special parameters. |
541 if (params->uses_post || !params->extra_headers.empty()) | 445 if (params->uses_post || !params->extra_headers.empty()) |
542 return false; | 446 return false; |
543 | 447 |
544 content::WebContents* new_web_contents = SwapInternal(url, web_contents, | |
545 NULL); | |
546 if (!new_web_contents) | |
547 return false; | |
548 | |
549 // Record the new target_contents for the callers. | |
550 params->target_contents = new_web_contents; | |
551 return true; | |
552 } | |
553 | |
554 content::WebContents* PrerenderManager::SwapInternal( | |
555 const GURL& url, | |
556 content::WebContents* web_contents, | |
557 PrerenderData* swap_candidate) { | |
558 DCHECK(CalledOnValidThread()); | |
559 DCHECK(!IsWebContentsPrerendering(web_contents, NULL)); | |
560 | |
561 DeleteOldEntries(); | 448 DeleteOldEntries(); |
562 to_delete_prerenders_.clear(); | 449 to_delete_prerenders_.clear(); |
563 // TODO(ajwong): This doesn't handle isolated apps correctly. | |
564 | |
565 // Only if this WebContents is used in a tabstrip may be swap. | |
566 // We check this by examining whether its CoreTabHelper has a delegate. | |
567 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents); | |
568 if (!core_tab_helper || !core_tab_helper->delegate()) { | |
569 RecordEvent(NULL, PRERENDER_EVENT_SWAPIN_NO_DELEGATE); | |
570 return NULL; | |
571 } | |
572 | 450 |
573 // First, try to find prerender data with the correct session storage | 451 // First, try to find prerender data with the correct session storage |
574 // namespace. | 452 // namespace. |
| 453 // TODO(ajwong): This doesn't handle isolated apps correctly. |
575 PrerenderData* prerender_data = FindPrerenderData( | 454 PrerenderData* prerender_data = FindPrerenderData( |
576 url, | 455 url, |
577 web_contents->GetController().GetDefaultSessionStorageNamespace()); | 456 web_contents->GetController().GetDefaultSessionStorageNamespace()); |
578 | 457 |
579 // If this failed, we may still find a prerender for the same URL, but a | 458 // If this failed, we may still find a prerender for the same URL, but a |
580 // different session storage namespace. If we do, we might have to perform | 459 // different session storage namespace. If we do, we might have to perform |
581 // a merge. | 460 // a merge. |
582 if (!prerender_data) { | 461 if (!prerender_data) { |
583 prerender_data = FindPrerenderData(url, NULL); | 462 prerender_data = FindPrerenderData(url, NULL); |
584 } else { | 463 } else { |
585 RecordEvent(prerender_data->contents(), | 464 RecordEvent(prerender_data->contents(), |
586 PRERENDER_EVENT_SWAPIN_CANDIDATE_NAMESPACE_MATCHES); | 465 PRERENDER_EVENT_SWAPIN_CANDIDATE_NAMESPACE_MATCHES); |
587 } | 466 } |
588 | 467 |
589 if (!prerender_data) | 468 if (!prerender_data) |
590 return NULL; | 469 return false; |
591 RecordEvent(prerender_data->contents(), PRERENDER_EVENT_SWAPIN_CANDIDATE); | 470 RecordEvent(prerender_data->contents(), PRERENDER_EVENT_SWAPIN_CANDIDATE); |
592 DCHECK(prerender_data->contents()); | 471 DCHECK(prerender_data->contents()); |
593 | 472 |
594 // If there is currently a merge pending for this prerender data, | 473 // If there is currently a merge pending for this prerender data, |
595 // or this webcontents, do not swap in, but give the merge a chance to | 474 // or this webcontents, do not swap in, but give the merge a chance to |
596 // finish and swap into the intended target webcontents. | 475 // finish and swap into the intended target webcontents. |
597 if (prerender_data != swap_candidate && prerender_data->pending_swap()) { | 476 if (prerender_data->pending_swap()) |
598 return NULL; | 477 return false; |
599 } | |
600 | 478 |
601 RecordEvent(prerender_data->contents(), | 479 RecordEvent(prerender_data->contents(), |
602 PRERENDER_EVENT_SWAPIN_NO_MERGE_PENDING); | 480 PRERENDER_EVENT_SWAPIN_NO_MERGE_PENDING); |
603 SessionStorageNamespace* target_namespace = | 481 SessionStorageNamespace* target_namespace = |
604 web_contents->GetController().GetDefaultSessionStorageNamespace(); | 482 web_contents->GetController().GetDefaultSessionStorageNamespace(); |
605 SessionStorageNamespace* prerender_namespace = | 483 SessionStorageNamespace* prerender_namespace = |
606 prerender_data->contents()->GetSessionStorageNamespace(); | 484 prerender_data->contents()->GetSessionStorageNamespace(); |
607 // Only when actually prerendering is session storage namespace merging an | 485 // Only when actually prerendering is session storage namespace merging an |
608 // issue. For the control group, it will be assumed that the merge succeeded. | 486 // issue. For the control group, it will be assumed that the merge succeeded. |
609 if (prerender_namespace && prerender_namespace != target_namespace && | 487 if (prerender_namespace && prerender_namespace != target_namespace && |
610 !prerender_namespace->IsAliasOf(target_namespace)) { | 488 !prerender_namespace->IsAliasOf(target_namespace)) { |
611 if (!ShouldMergeSessionStorageNamespaces()) { | 489 if (!ShouldMergeSessionStorageNamespaces()) { |
612 RecordEvent(prerender_data->contents(), | 490 RecordEvent(prerender_data->contents(), |
613 PRERENDER_EVENT_SWAPIN_MERGING_DISABLED); | 491 PRERENDER_EVENT_SWAPIN_MERGING_DISABLED); |
614 return NULL; | 492 return false; |
615 } | 493 } |
616 RecordEvent(prerender_data->contents(), | 494 RecordEvent(prerender_data->contents(), |
617 PRERENDER_EVENT_SWAPIN_ISSUING_MERGE); | 495 PRERENDER_EVENT_SWAPIN_ISSUING_MERGE); |
618 // There should never be a |pending_swap| if we get to here: | 496 prerender_data->set_pending_swap(new PendingSwap( |
619 // Per check above, |pending_swap| may only be != NULL when | 497 this, web_contents, prerender_data, url)); |
620 // processing a successful merge, as indicated by |swap_candidate| | 498 prerender_data->pending_swap()->BeginSwap(); |
621 // != NULL. But in that case, there should be no need for yet another merge. | 499 // Although this returns false, creating a PendingSwap registers with |
622 DCHECK(!prerender_data->pending_swap()); | 500 // PrerenderTracker to throttle MAIN_FRAME navigations while the swap is |
623 if (prerender_data->pending_swap()) { | 501 // pending. |
624 // In retail builds, log this error and bail. | 502 return false; |
625 RecordEvent(prerender_data->contents(), | 503 } |
626 PRERENDER_EVENT_MERGE_FOR_SWAPIN_CANDIDATE); | 504 |
627 return NULL; | 505 // No need to merge; swap synchronously. |
628 } | 506 WebContents* new_web_contents = SwapInternal(url, web_contents, |
629 PendingSwap* pending_swap = new PendingSwap( | 507 prerender_data); |
630 prerender_tracker_, | 508 if (!new_web_contents) |
631 web_contents, | 509 return false; |
632 prerender_data, | 510 |
633 url, | 511 // Record the new target_contents for the callers. |
634 base::Bind(&PrerenderManager::ProcessMergeResult, | 512 params->target_contents = new_web_contents; |
635 AsWeakPtr(), | 513 return true; |
636 prerender_data, | 514 } |
637 true, | 515 |
638 SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE), | 516 WebContents* PrerenderManager::SwapInternal( |
639 base::Bind(&PrerenderManager::ProcessMergeResult, | 517 const GURL& url, |
640 AsWeakPtr(), | 518 WebContents* web_contents, |
641 prerender_data, | 519 PrerenderData* prerender_data) { |
642 false)); | 520 DCHECK(CalledOnValidThread()); |
643 prerender_data->set_pending_swap(pending_swap); | 521 DCHECK(!IsWebContentsPrerendering(web_contents, NULL)); |
644 prerender_namespace->Merge( | 522 |
645 true, | 523 // Only swap if the target WebContents has a CoreTabHelper delegate to swap |
646 prerender_data->contents()->child_id(), | 524 // out of it. For a normal WebContents, this is if it is in a TabStripModel. |
647 target_namespace, | 525 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents); |
648 pending_swap->GetMergeResultCallback()); | 526 if (!core_tab_helper || !core_tab_helper->delegate()) { |
649 base::MessageLoop::current()->PostDelayedTask( | 527 RecordEvent(prerender_data->contents(), PRERENDER_EVENT_SWAPIN_NO_DELEGATE); |
650 FROM_HERE, | |
651 pending_swap->GetTimeoutCallback(), | |
652 base::TimeDelta::FromMilliseconds( | |
653 kSessionStorageNamespaceMergeTimeoutMs)); | |
654 return NULL; | 528 return NULL; |
655 } | 529 } |
656 | 530 |
657 if (IsNoSwapInExperiment(prerender_data->contents()->experiment_id())) | 531 if (IsNoSwapInExperiment(prerender_data->contents()->experiment_id())) |
658 return NULL; | 532 return NULL; |
659 | 533 |
660 if (WebContents* new_web_contents = | 534 if (WebContents* new_web_contents = |
661 prerender_data->contents()->prerender_contents()) { | 535 prerender_data->contents()->prerender_contents()) { |
662 if (web_contents == new_web_contents) | 536 if (web_contents == new_web_contents) |
663 return NULL; // Do not swap in to ourself. | 537 return NULL; // Do not swap in to ourself. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 CHECK(prerender_data->contents()->GetRouteId(&route_id)); | 601 CHECK(prerender_data->contents()->GetRouteId(&route_id)); |
728 | 602 |
729 // Try to set the prerendered page as used, so any subsequent attempts to | 603 // Try to set the prerendered page as used, so any subsequent attempts to |
730 // cancel on other threads will fail. If this fails because the prerender | 604 // cancel on other threads will fail. If this fails because the prerender |
731 // was already cancelled, possibly on another thread, fail. | 605 // was already cancelled, possibly on another thread, fail. |
732 if (!prerender_tracker_->TryUse(child_id, route_id)) | 606 if (!prerender_tracker_->TryUse(child_id, route_id)) |
733 return NULL; | 607 return NULL; |
734 | 608 |
735 // At this point, we've determined that we will use the prerender. | 609 // At this point, we've determined that we will use the prerender. |
736 if (prerender_data->pending_swap()) | 610 if (prerender_data->pending_swap()) |
737 prerender_data->pending_swap()->SwapSuccessful(); | 611 prerender_data->pending_swap()->set_swap_successful(true); |
738 ScopedVector<PrerenderData>::iterator to_erase = | 612 ScopedVector<PrerenderData>::iterator to_erase = |
739 FindIteratorForPrerenderContents(prerender_data->contents()); | 613 FindIteratorForPrerenderContents(prerender_data->contents()); |
740 DCHECK(active_prerenders_.end() != to_erase); | 614 DCHECK(active_prerenders_.end() != to_erase); |
741 DCHECK_EQ(prerender_data, *to_erase); | 615 DCHECK_EQ(prerender_data, *to_erase); |
742 scoped_ptr<PrerenderContents> | 616 scoped_ptr<PrerenderContents> |
743 prerender_contents(prerender_data->ReleaseContents()); | 617 prerender_contents(prerender_data->ReleaseContents()); |
744 active_prerenders_.erase(to_erase); | 618 active_prerenders_.erase(to_erase); |
745 | 619 |
746 if (!prerender_contents->load_start_time().is_null()) { | 620 if (!prerender_contents->load_start_time().is_null()) { |
747 histograms_->RecordTimeUntilUsed( | 621 histograms_->RecordTimeUntilUsed( |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
844 NeedMatchCompleteDummyForFinalStatus(final_status) && | 718 NeedMatchCompleteDummyForFinalStatus(final_status) && |
845 ActuallyPrerendering()) { | 719 ActuallyPrerendering()) { |
846 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. | 720 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. |
847 // However, what if new conditions are added and | 721 // However, what if new conditions are added and |
848 // NeedMatchCompleteDummyForFinalStatus is not being updated. Not sure | 722 // NeedMatchCompleteDummyForFinalStatus is not being updated. Not sure |
849 // what's the best thing to do here. For now, I will just check whether | 723 // what's the best thing to do here. For now, I will just check whether |
850 // we are actually prerendering. | 724 // we are actually prerendering. |
851 (*it)->MakeIntoMatchCompleteReplacement(); | 725 (*it)->MakeIntoMatchCompleteReplacement(); |
852 } else { | 726 } else { |
853 to_delete_prerenders_.push_back(*it); | 727 to_delete_prerenders_.push_back(*it); |
854 (*it)->ClearPendingSwap(); | |
855 active_prerenders_.weak_erase(it); | 728 active_prerenders_.weak_erase(it); |
856 } | 729 } |
857 | 730 |
858 // Destroy the old WebContents relatively promptly to reduce resource usage. | 731 // Destroy the old WebContents relatively promptly to reduce resource usage. |
859 PostCleanupTask(); | 732 PostCleanupTask(); |
860 } | 733 } |
861 | 734 |
862 // static | 735 // static |
863 void PrerenderManager::RecordPerceivedPageLoadTime( | 736 void PrerenderManager::RecordPerceivedPageLoadTime( |
864 base::TimeDelta perceived_page_load_time, | 737 base::TimeDelta perceived_page_load_time, |
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1275 | 1148 |
1276 void PrerenderManager::PrerenderData::ClearPendingSwap() { | 1149 void PrerenderManager::PrerenderData::ClearPendingSwap() { |
1277 pending_swap_.reset(NULL); | 1150 pending_swap_.reset(NULL); |
1278 } | 1151 } |
1279 | 1152 |
1280 PrerenderContents* PrerenderManager::PrerenderData::ReleaseContents() { | 1153 PrerenderContents* PrerenderManager::PrerenderData::ReleaseContents() { |
1281 return contents_.release(); | 1154 return contents_.release(); |
1282 } | 1155 } |
1283 | 1156 |
1284 PrerenderManager::PendingSwap::PendingSwap( | 1157 PrerenderManager::PendingSwap::PendingSwap( |
1285 PrerenderTracker* prerender_tracker, | 1158 PrerenderManager* manager, |
1286 content::WebContents* target_contents, | 1159 content::WebContents* target_contents, |
1287 PrerenderData* prerender_data, | 1160 PrerenderData* prerender_data, |
1288 const GURL& url, | 1161 const GURL& url) |
1289 const base::Closure& timeout_cb, | |
1290 const SessionStorageNamespace::MergeResultCallback& merge_result_cb) | |
1291 : content::WebContentsObserver(target_contents), | 1162 : content::WebContentsObserver(target_contents), |
1292 prerender_tracker_(prerender_tracker), | 1163 manager_(manager), |
1293 target_contents_(target_contents), | 1164 target_contents_(target_contents), |
1294 prerender_data_(prerender_data), | 1165 prerender_data_(prerender_data), |
1295 url_(url), | 1166 url_(url), |
1296 timeout_cb_(timeout_cb), | 1167 start_time_(base::TimeTicks::Now()), |
1297 merge_result_cb_(merge_result_cb), | 1168 swap_successful_(false), |
1298 start_time_(base::TimeTicks::Now()) { | 1169 weak_factory_(this) { |
1299 RenderViewCreated(target_contents->GetRenderViewHost()); | 1170 RenderViewCreated(target_contents->GetRenderViewHost()); |
1300 } | 1171 } |
1301 | 1172 |
1302 PrerenderManager::PendingSwap::~PendingSwap() { | 1173 PrerenderManager::PendingSwap::~PendingSwap() { |
1303 timeout_cb_.Cancel(); | 1174 for (size_t i = 0; i < rvh_ids_.size(); i++) { |
1304 merge_result_cb_.Cancel(); | 1175 manager_->prerender_tracker()->RemovePrerenderPendingSwap( |
1305 for (size_t i = 0; i < rvh_ids_.size(); i++) { | 1176 rvh_ids_[i], swap_successful_); |
1306 prerender_tracker_->RemovePrerenderPendingSwap(rvh_ids_[i], false); | 1177 } |
1307 } | |
1308 } | 1178 } |
1309 | 1179 |
1310 const base::Closure& PrerenderManager::PendingSwap::GetTimeoutCallback() { | 1180 void PrerenderManager::PendingSwap::BeginSwap() { |
1311 return timeout_cb_.callback(); | 1181 SessionStorageNamespace* target_namespace = |
1312 } | 1182 target_contents_->GetController().GetDefaultSessionStorageNamespace(); |
| 1183 SessionStorageNamespace* prerender_namespace = |
| 1184 prerender_data_->contents()->GetSessionStorageNamespace(); |
1313 | 1185 |
1314 void PrerenderManager::PendingSwap::SwapSuccessful() { | 1186 prerender_namespace->Merge( |
1315 for (size_t i = 0; i < rvh_ids_.size(); i++) { | 1187 true, prerender_data_->contents()->child_id(), |
1316 prerender_tracker_->RemovePrerenderPendingSwap(rvh_ids_[i], true); | 1188 target_namespace, |
1317 } | 1189 base::Bind(&PrerenderManager::PendingSwap::OnMergeCompleted, |
1318 rvh_ids_.clear(); | 1190 weak_factory_.GetWeakPtr())); |
1319 } | |
1320 | 1191 |
1321 const SessionStorageNamespace::MergeResultCallback& | 1192 merge_timeout_.Start( |
1322 PrerenderManager::PendingSwap::GetMergeResultCallback() { | 1193 FROM_HERE, |
1323 return merge_result_cb_.callback(); | 1194 base::TimeDelta::FromMilliseconds( |
| 1195 kSessionStorageNamespaceMergeTimeoutMs), |
| 1196 this, &PrerenderManager::PendingSwap::OnMergeTimeout); |
1324 } | 1197 } |
1325 | 1198 |
1326 void PrerenderManager::PendingSwap::ProvisionalChangeToMainFrameUrl( | 1199 void PrerenderManager::PendingSwap::ProvisionalChangeToMainFrameUrl( |
1327 const GURL& url, | 1200 const GURL& url, |
1328 content::RenderViewHost* render_view_host) { | 1201 content::RenderViewHost* render_view_host) { |
1329 // We must only cancel the pending swap if the |url| navigated to is not | 1202 // We must only cancel the pending swap if the |url| navigated to is not |
1330 // the URL being attempted to be swapped in. That's because in the normal | 1203 // the URL being attempted to be swapped in. That's because in the normal |
1331 // flow, a ProvisionalChangeToMainFrameUrl will happen for the URL attempted | 1204 // flow, a ProvisionalChangeToMainFrameUrl will happen for the URL attempted |
1332 // to be swapped in immediately after the pending swap has issued its merge. | 1205 // to be swapped in immediately after the pending swap has issued its merge. |
1333 if (url != url_) | 1206 if (url != url_) |
1334 prerender_data_->ClearPendingSwap(); | 1207 prerender_data_->ClearPendingSwap(); |
1335 } | 1208 } |
1336 | 1209 |
1337 void PrerenderManager::PendingSwap::DidCommitProvisionalLoadForFrame( | 1210 void PrerenderManager::PendingSwap::DidCommitProvisionalLoadForFrame( |
1338 int64 frame_id, | 1211 int64 frame_id, |
1339 const string16& frame_unique_name, | 1212 const string16& frame_unique_name, |
1340 bool is_main_frame, | 1213 bool is_main_frame, |
1341 const GURL& validated_url, | 1214 const GURL& validated_url, |
1342 content::PageTransition transition_type, | 1215 content::PageTransition transition_type, |
1343 content::RenderViewHost* render_view_host){ | 1216 content::RenderViewHost* render_view_host){ |
1344 if (!is_main_frame) | 1217 if (!is_main_frame) |
1345 return; | 1218 return; |
1346 if (validated_url != url_) | 1219 prerender_data_->ClearPendingSwap(); |
1347 prerender_data_->ClearPendingSwap(); | |
1348 } | 1220 } |
1349 | 1221 |
1350 void PrerenderManager::PendingSwap::RenderViewCreated( | 1222 void PrerenderManager::PendingSwap::RenderViewCreated( |
1351 content::RenderViewHost* render_view_host) { | 1223 content::RenderViewHost* render_view_host) { |
| 1224 // Record the RVH id in the tracker to install throttles on MAIN_FRAME |
| 1225 // requests from that route. |
1352 int child_id = render_view_host->GetProcess()->GetID(); | 1226 int child_id = render_view_host->GetProcess()->GetID(); |
1353 int route_id = render_view_host->GetRoutingID(); | 1227 int route_id = render_view_host->GetRoutingID(); |
1354 PrerenderTracker::ChildRouteIdPair child_route_id_pair(child_id, route_id); | 1228 PrerenderTracker::ChildRouteIdPair child_route_id_pair(child_id, route_id); |
1355 rvh_ids_.push_back(child_route_id_pair); | 1229 rvh_ids_.push_back(child_route_id_pair); |
1356 prerender_tracker_->AddPrerenderPendingSwap(child_route_id_pair, url_); | 1230 manager_->prerender_tracker()->AddPrerenderPendingSwap( |
| 1231 child_route_id_pair, url_); |
1357 } | 1232 } |
1358 | 1233 |
1359 void PrerenderManager::PendingSwap::DidFailProvisionalLoad( | 1234 void PrerenderManager::PendingSwap::DidFailProvisionalLoad( |
1360 int64 frame_id, | 1235 int64 frame_id, |
1361 const string16& frame_unique_name, | 1236 const string16& frame_unique_name, |
1362 bool is_main_frame, | 1237 bool is_main_frame, |
1363 const GURL& validated_url, | 1238 const GURL& validated_url, |
1364 int error_code, | 1239 int error_code, |
1365 const string16& error_description, | 1240 const string16& error_description, |
1366 content::RenderViewHost* render_view_host) { | 1241 content::RenderViewHost* render_view_host) { |
| 1242 if (!is_main_frame) |
| 1243 return; |
1367 prerender_data_->ClearPendingSwap(); | 1244 prerender_data_->ClearPendingSwap(); |
1368 } | 1245 } |
1369 | 1246 |
1370 void PrerenderManager::PendingSwap::WebContentsDestroyed( | 1247 void PrerenderManager::PendingSwap::WebContentsDestroyed( |
1371 content::WebContents* web_contents) { | 1248 content::WebContents* web_contents) { |
1372 prerender_data_->ClearPendingSwap(); | 1249 prerender_data_->ClearPendingSwap(); |
1373 } | 1250 } |
1374 | 1251 |
1375 base::TimeDelta PrerenderManager::PendingSwap::GetElapsedTime() { | 1252 void PrerenderManager::PendingSwap::RecordEvent(PrerenderEvent event) const { |
1376 return base::TimeTicks::Now() - start_time_; | 1253 manager_->RecordEvent(prerender_data_->contents(), event); |
| 1254 } |
| 1255 |
| 1256 void PrerenderManager::PendingSwap::OnMergeCompleted( |
| 1257 SessionStorageNamespace::MergeResult result) { |
| 1258 UMA_HISTOGRAM_TIMES("Prerender.SessionStorageNamespaceMergeTime", |
| 1259 base::TimeTicks::Now() - start_time_); |
| 1260 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_MERGE_DONE); |
| 1261 |
| 1262 // Log the exact merge result in a histogram. |
| 1263 switch (result) { |
| 1264 case SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND: |
| 1265 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_FOUND); |
| 1266 break; |
| 1267 case SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_ALIAS: |
| 1268 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_ALIAS); |
| 1269 break; |
| 1270 case SessionStorageNamespace::MERGE_RESULT_NOT_LOGGING: |
| 1271 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_LOGGING); |
| 1272 break; |
| 1273 case SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS: |
| 1274 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NO_TRANSACTIONS); |
| 1275 break; |
| 1276 case SessionStorageNamespace::MERGE_RESULT_TOO_MANY_TRANSACTIONS: |
| 1277 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_TOO_MANY_TRANSACTIONS); |
| 1278 break; |
| 1279 case SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE: |
| 1280 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_MERGEABLE); |
| 1281 break; |
| 1282 case SessionStorageNamespace::MERGE_RESULT_MERGEABLE: |
| 1283 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_MERGEABLE); |
| 1284 break; |
| 1285 default: |
| 1286 NOTREACHED(); |
| 1287 } |
| 1288 |
| 1289 if (result != SessionStorageNamespace::MERGE_RESULT_MERGEABLE && |
| 1290 result != SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS) { |
| 1291 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_MERGE_FAILED); |
| 1292 prerender_data_->ClearPendingSwap(); |
| 1293 return; |
| 1294 } |
| 1295 |
| 1296 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_SWAPPING_IN); |
| 1297 // Note that SwapInternal, on success, will delete |prerender_data_| and |
| 1298 // |this|. Pass in a new GURL object rather than a reference to |url_|. |
| 1299 // |
| 1300 // TODO(davidben): See about deleting PrerenderData asynchronously so this |
| 1301 // behavior is more reasonable. |
| 1302 WebContents* new_web_contents = |
| 1303 manager_->SwapInternal(GURL(url_), target_contents_, prerender_data_); |
| 1304 if (!new_web_contents) { |
| 1305 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_SWAPIN_FAILED); |
| 1306 prerender_data_->ClearPendingSwap(); |
| 1307 } |
| 1308 } |
| 1309 |
| 1310 void PrerenderManager::PendingSwap::OnMergeTimeout() { |
| 1311 RecordEvent(PRERENDER_EVENT_MERGE_RESULT_TIMED_OUT); |
| 1312 prerender_data_->ClearPendingSwap(); |
1377 } | 1313 } |
1378 | 1314 |
1379 void PrerenderManager::SetPrerenderContentsFactory( | 1315 void PrerenderManager::SetPrerenderContentsFactory( |
1380 PrerenderContents::Factory* prerender_contents_factory) { | 1316 PrerenderContents::Factory* prerender_contents_factory) { |
1381 DCHECK(CalledOnValidThread()); | 1317 DCHECK(CalledOnValidThread()); |
1382 prerender_contents_factory_.reset(prerender_contents_factory); | 1318 prerender_contents_factory_.reset(prerender_contents_factory); |
1383 } | 1319 } |
1384 | 1320 |
1385 | 1321 |
1386 void PrerenderManager::StartPendingPrerenders( | 1322 void PrerenderManager::StartPendingPrerenders( |
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1944 void PrerenderManager::RecordEvent(PrerenderContents* contents, | 1880 void PrerenderManager::RecordEvent(PrerenderContents* contents, |
1945 PrerenderEvent event) const { | 1881 PrerenderEvent event) const { |
1946 if (!contents) | 1882 if (!contents) |
1947 histograms_->RecordEvent(ORIGIN_NONE, kNoExperiment, event); | 1883 histograms_->RecordEvent(ORIGIN_NONE, kNoExperiment, event); |
1948 else | 1884 else |
1949 histograms_->RecordEvent(contents->origin(), contents->experiment_id(), | 1885 histograms_->RecordEvent(contents->origin(), contents->experiment_id(), |
1950 event); | 1886 event); |
1951 } | 1887 } |
1952 | 1888 |
1953 } // namespace prerender | 1889 } // namespace prerender |
OLD | NEW |