| 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 <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 "POST", | 77 "POST", |
| 78 "TRACE", | 78 "TRACE", |
| 79 }; | 79 }; |
| 80 | 80 |
| 81 // Length of prerender history, for display in chrome://net-internals | 81 // Length of prerender history, for display in chrome://net-internals |
| 82 const int kHistoryLength = 100; | 82 const int kHistoryLength = 100; |
| 83 | 83 |
| 84 // Indicates whether a Prerender has been cancelled such that we need | 84 // Indicates whether a Prerender has been cancelled such that we need |
| 85 // a dummy replacement for the purpose of recording the correct PPLT for | 85 // a dummy replacement for the purpose of recording the correct PPLT for |
| 86 // the Match Complete case. | 86 // the Match Complete case. |
| 87 // Traditionally, "Match" means that a prerendered page was actually visited & |
| 88 // the prerender was used. Our goal is to have "Match" cases line up in the |
| 89 // control group & the experiment group, so that we can make meaningful |
| 90 // comparisons of improvements. However, in the control group, since we don't |
| 91 // actually perform prerenders, many of the cancellation reasons cannot be |
| 92 // detected. Therefore, in the Prerender group, when we cancel for one of these |
| 93 // reasons, we keep track of a dummy Prerender representing what we would |
| 94 // have in the control group. If that dummy prerender in the prerender group |
| 95 // would then be swapped in (but isn't actually b/c it's a dummy), we record |
| 96 // this as a MatchComplete. This allows us to compare MatchComplete's |
| 97 // across Prerender & Control group which ideally should be lining up. |
| 98 // This ensures that there is no bias in terms of the page load times |
| 99 // of the pages forming the difference between the two sets. |
| 87 | 100 |
| 88 bool NeedMatchCompleteDummyForFinalStatus(FinalStatus final_status) { | 101 bool NeedMatchCompleteDummyForFinalStatus(FinalStatus final_status) { |
| 89 return final_status != FINAL_STATUS_USED && | 102 return final_status != FINAL_STATUS_USED && |
| 90 final_status != FINAL_STATUS_TIMED_OUT && | 103 final_status != FINAL_STATUS_TIMED_OUT && |
| 91 final_status != FINAL_STATUS_EVICTED && | 104 final_status != FINAL_STATUS_EVICTED && |
| 92 final_status != FINAL_STATUS_MANAGER_SHUTDOWN && | 105 final_status != FINAL_STATUS_MANAGER_SHUTDOWN && |
| 93 final_status != FINAL_STATUS_APP_TERMINATING && | 106 final_status != FINAL_STATUS_APP_TERMINATING && |
| 94 final_status != FINAL_STATUS_RENDERER_CRASHED && | 107 final_status != FINAL_STATUS_RENDERER_CRASHED && |
| 95 final_status != FINAL_STATUS_WINDOW_OPENER && | 108 final_status != FINAL_STATUS_WINDOW_OPENER && |
| 96 final_status != FINAL_STATUS_FRAGMENT_MISMATCH && | 109 final_status != FINAL_STATUS_FRAGMENT_MISMATCH && |
| 97 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED && | 110 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED && |
| 98 final_status != FINAL_STATUS_CANCELLED && | 111 final_status != FINAL_STATUS_CANCELLED && |
| 99 final_status != FINAL_STATUS_MATCH_COMPLETE_DUMMY; | 112 final_status != FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH && |
| 113 final_status != FINAL_STATUS_DEVTOOLS_ATTACHED && |
| 114 final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING; |
| 100 } | 115 } |
| 101 | 116 |
| 102 } // namespace | 117 } // namespace |
| 103 | 118 |
| 104 class PrerenderManager::OnCloseTabContentsDeleter | 119 class PrerenderManager::OnCloseTabContentsDeleter |
| 105 : public content::WebContentsDelegate, | 120 : public content::WebContentsDelegate, |
| 106 public base::SupportsWeakPtr< | 121 public base::SupportsWeakPtr< |
| 107 PrerenderManager::OnCloseTabContentsDeleter> { | 122 PrerenderManager::OnCloseTabContentsDeleter> { |
| 108 public: | 123 public: |
| 109 OnCloseTabContentsDeleter(PrerenderManager* manager, | 124 OnCloseTabContentsDeleter(PrerenderManager* manager, |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 if (!prerender_contents || !prerender_contents->Init()) | 445 if (!prerender_contents || !prerender_contents->Init()) |
| 431 return false; | 446 return false; |
| 432 | 447 |
| 433 histograms_->RecordPrerenderStarted(origin); | 448 histograms_->RecordPrerenderStarted(origin); |
| 434 | 449 |
| 435 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? | 450 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? |
| 436 PrerenderContentsData data(prerender_contents, GetCurrentTime()); | 451 PrerenderContentsData data(prerender_contents, GetCurrentTime()); |
| 437 | 452 |
| 438 prerender_list_.push_back(data); | 453 prerender_list_.push_back(data); |
| 439 | 454 |
| 440 if (IsControlGroup()) { | 455 if (!IsControlGroup()) { |
| 441 data.contents_->set_final_status(FINAL_STATUS_CONTROL_GROUP); | |
| 442 } else { | |
| 443 last_prerender_start_time_ = GetCurrentTimeTicks(); | 456 last_prerender_start_time_ = GetCurrentTimeTicks(); |
| 444 data.contents_->StartPrerendering(source_render_view_host, | 457 data.contents_->StartPrerendering(source_render_view_host, |
| 445 session_storage_namespace); | 458 session_storage_namespace); |
| 446 } | 459 } |
| 447 while (prerender_list_.size() > config_.max_elements) { | 460 while (prerender_list_.size() > config_.max_elements) { |
| 448 data = prerender_list_.front(); | 461 data = prerender_list_.front(); |
| 449 prerender_list_.pop_front(); | 462 prerender_list_.pop_front(); |
| 450 data.contents_->Destroy(FINAL_STATUS_EVICTED); | 463 data.contents_->Destroy(FINAL_STATUS_EVICTED); |
| 451 } | 464 } |
| 452 StartSchedulingPeriodicCleanups(); | 465 StartSchedulingPeriodicCleanups(); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 } | 540 } |
| 528 } | 541 } |
| 529 // Entry not found. | 542 // Entry not found. |
| 530 return NULL; | 543 return NULL; |
| 531 } | 544 } |
| 532 | 545 |
| 533 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) { | 546 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) { |
| 534 return GetEntryButNotSpecifiedWC(url, NULL); | 547 return GetEntryButNotSpecifiedWC(url, NULL); |
| 535 } | 548 } |
| 536 | 549 |
| 550 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed( |
| 551 PrerenderContents* prerender_contents, |
| 552 FinalStatus final_status) { |
| 553 prerender_contents->set_match_complete_status( |
| 554 PrerenderContents::MATCH_COMPLETE_REPLACED); |
| 555 histograms_->RecordFinalStatus(prerender_contents->origin(), |
| 556 prerender_contents->experiment_id(), |
| 557 PrerenderContents::MATCH_COMPLETE_REPLACEMENT, |
| 558 FINAL_STATUS_WOULD_HAVE_BEEN_USED); |
| 559 prerender_contents->Destroy(final_status); |
| 560 } |
| 561 |
| 537 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, | 562 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, |
| 538 const GURL& url, | 563 const GURL& url, |
| 539 const GURL& opener_url) { | 564 const GURL& opener_url) { |
| 540 DCHECK(CalledOnValidThread()); | 565 DCHECK(CalledOnValidThread()); |
| 541 RecordNavigation(url); | 566 RecordNavigation(url); |
| 542 | 567 |
| 543 scoped_ptr<PrerenderContents> prerender_contents( | 568 scoped_ptr<PrerenderContents> prerender_contents( |
| 544 GetEntryButNotSpecifiedWC(url, web_contents)); | 569 GetEntryButNotSpecifiedWC(url, web_contents)); |
| 545 if (prerender_contents.get() == NULL) | 570 if (prerender_contents.get() == NULL) |
| 546 return false; | 571 return false; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 562 if (url_matches && url.ref() != matching_url.ref()) { | 587 if (url_matches && url.ref() != matching_url.ref()) { |
| 563 prerender_contents.release()->Destroy(FINAL_STATUS_FRAGMENT_MISMATCH); | 588 prerender_contents.release()->Destroy(FINAL_STATUS_FRAGMENT_MISMATCH); |
| 564 return false; | 589 return false; |
| 565 } | 590 } |
| 566 | 591 |
| 567 // If we are just in the control group (which can be detected by noticing | 592 // If we are just in the control group (which can be detected by noticing |
| 568 // that prerendering hasn't even started yet), record that |web_contents| now | 593 // that prerendering hasn't even started yet), record that |web_contents| now |
| 569 // would be showing a prerendered contents, but otherwise, don't do anything. | 594 // would be showing a prerendered contents, but otherwise, don't do anything. |
| 570 if (!prerender_contents->prerendering_has_started()) { | 595 if (!prerender_contents->prerendering_has_started()) { |
| 571 MarkWebContentsAsWouldBePrerendered(web_contents); | 596 MarkWebContentsAsWouldBePrerendered(web_contents); |
| 597 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); |
| 572 return false; | 598 return false; |
| 573 } | 599 } |
| 574 | 600 |
| 575 // Don't use prerendered pages if debugger is attached to the tab. | 601 // Don't use prerendered pages if debugger is attached to the tab. |
| 576 // See http://crbug.com/98541 | 602 // See http://crbug.com/98541 |
| 577 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) { | 603 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) { |
| 578 prerender_contents.release()->Destroy(FINAL_STATUS_DEVTOOLS_ATTACHED); | 604 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(), |
| 605 FINAL_STATUS_DEVTOOLS_ATTACHED); |
| 579 return false; | 606 return false; |
| 580 } | 607 } |
| 581 | 608 |
| 582 // If the prerendered page is in the middle of a cross-site navigation, | 609 // If the prerendered page is in the middle of a cross-site navigation, |
| 583 // don't swap it in because there isn't a good way to merge histories. | 610 // don't swap it in because there isn't a good way to merge histories. |
| 584 if (prerender_contents->IsCrossSiteNavigationPending()) { | 611 if (prerender_contents->IsCrossSiteNavigationPending()) { |
| 585 prerender_contents.release()->Destroy( | 612 DestroyAndMarkMatchCompleteAsUsed( |
| 613 prerender_contents.release(), |
| 586 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING); | 614 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING); |
| 587 return false; | 615 return false; |
| 588 } | 616 } |
| 589 | 617 |
| 590 // If the session storage namespaces don't match, cancel the prerender. | 618 // If the session storage namespaces don't match, cancel the prerender. |
| 591 RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost(); | 619 RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost(); |
| 592 RenderViewHost* new_render_view_host = | 620 RenderViewHost* new_render_view_host = |
| 593 prerender_contents->prerender_contents()->web_contents()-> | 621 prerender_contents->prerender_contents()->web_contents()-> |
| 594 GetRenderViewHost(); | 622 GetRenderViewHost(); |
| 595 DCHECK(old_render_view_host); | 623 DCHECK(old_render_view_host); |
| 596 DCHECK(new_render_view_host); | 624 DCHECK(new_render_view_host); |
| 597 if (old_render_view_host->session_storage_namespace() != | 625 if (old_render_view_host->session_storage_namespace() != |
| 598 new_render_view_host->session_storage_namespace()) { | 626 new_render_view_host->session_storage_namespace()) { |
| 599 prerender_contents.release()->Destroy( | 627 DestroyAndMarkMatchCompleteAsUsed( |
| 628 prerender_contents.release(), |
| 600 FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH); | 629 FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH); |
| 601 return false; | 630 return false; |
| 602 } | 631 } |
| 603 | 632 |
| 604 // If we don't want to use prerenders at all, we are done. | 633 // If we don't want to use prerenders at all, we are done. |
| 605 // For bookkeeping purposes, we need to mark this TabContents to | 634 // For bookkeeping purposes, we need to mark this TabContents to |
| 606 // reflect that it would have been prerendered. | 635 // reflect that it would have been prerendered. |
| 607 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) { | 636 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) { |
| 608 MarkWebContentsAsWouldBePrerendered(web_contents); | 637 MarkWebContentsAsWouldBePrerendered(web_contents); |
| 609 prerender_contents.release()->Destroy(FINAL_STATUS_NO_USE_GROUP); | 638 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); |
| 610 return false; | 639 return false; |
| 611 } | 640 } |
| 612 | 641 |
| 613 int child_id, route_id; | 642 int child_id, route_id; |
| 614 CHECK(prerender_contents->GetChildId(&child_id)); | 643 CHECK(prerender_contents->GetChildId(&child_id)); |
| 615 CHECK(prerender_contents->GetRouteId(&route_id)); | 644 CHECK(prerender_contents->GetRouteId(&route_id)); |
| 616 | 645 |
| 617 // Try to set the prerendered page as used, so any subsequent attempts to | 646 // Try to set the prerendered page as used, so any subsequent attempts to |
| 618 // cancel on other threads will fail. If this fails because the prerender | 647 // cancel on other threads will fail. If this fails because the prerender |
| 619 // was already cancelled, possibly on another thread, fail. | 648 // was already cancelled, possibly on another thread, fail. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 it != prerender_list_.end(); | 727 it != prerender_list_.end(); |
| 699 ++it) { | 728 ++it) { |
| 700 if (it->contents_ == entry) { | 729 if (it->contents_ == entry) { |
| 701 bool swapped_in_dummy_replacement = false; | 730 bool swapped_in_dummy_replacement = false; |
| 702 | 731 |
| 703 // If this PrerenderContents is being deleted due to a cancellation, | 732 // If this PrerenderContents is being deleted due to a cancellation, |
| 704 // we need to create a dummy replacement for PPLT accounting purposes | 733 // we need to create a dummy replacement for PPLT accounting purposes |
| 705 // for the Match Complete group. | 734 // for the Match Complete group. |
| 706 // This is the case if the cancellation is for any reason that would not | 735 // This is the case if the cancellation is for any reason that would not |
| 707 // occur in the control group case. | 736 // occur in the control group case. |
| 708 if (NeedMatchCompleteDummyForFinalStatus(final_status)) { | 737 if (entry->match_complete_status() == |
| 738 PrerenderContents::MATCH_COMPLETE_DEFAULT && |
| 739 NeedMatchCompleteDummyForFinalStatus(final_status)) { |
| 709 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. | 740 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. |
| 710 // However, what if new conditions are added and | 741 // However, what if new conditions are added and |
| 711 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure | 742 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure |
| 712 // what's the best thing to do here. For now, I will just check whether | 743 // what's the best thing to do here. For now, I will just check whether |
| 713 // we are actually prerendering. | 744 // we are actually prerendering. |
| 714 if (ActuallyPrerendering()) { | 745 if (ActuallyPrerendering()) { |
| 746 entry->set_match_complete_status( |
| 747 PrerenderContents::MATCH_COMPLETE_REPLACED); |
| 715 PrerenderContents* dummy_replacement_prerender_contents = | 748 PrerenderContents* dummy_replacement_prerender_contents = |
| 716 CreatePrerenderContents( | 749 CreatePrerenderContents( |
| 717 entry->prerender_url(), | 750 entry->prerender_url(), |
| 718 entry->referrer(), | 751 entry->referrer(), |
| 719 entry->origin(), | 752 entry->origin(), |
| 720 entry->experiment_id()); | 753 entry->experiment_id()); |
| 721 if (dummy_replacement_prerender_contents && | 754 if (dummy_replacement_prerender_contents && |
| 722 dummy_replacement_prerender_contents->Init()) { | 755 dummy_replacement_prerender_contents->Init()) { |
| 723 dummy_replacement_prerender_contents-> | 756 dummy_replacement_prerender_contents-> |
| 724 AddAliasURLsFromOtherPrerenderContents(entry); | 757 AddAliasURLsFromOtherPrerenderContents(entry); |
| 758 dummy_replacement_prerender_contents->set_match_complete_status( |
| 759 PrerenderContents::MATCH_COMPLETE_REPLACEMENT); |
| 725 it->contents_ = dummy_replacement_prerender_contents; | 760 it->contents_ = dummy_replacement_prerender_contents; |
| 726 it->contents_->set_final_status(FINAL_STATUS_MATCH_COMPLETE_DUMMY); | |
| 727 swapped_in_dummy_replacement = true; | 761 swapped_in_dummy_replacement = true; |
| 728 } | 762 } |
| 729 } | 763 } |
| 730 } | 764 } |
| 731 if (!swapped_in_dummy_replacement) | 765 if (!swapped_in_dummy_replacement) |
| 732 prerender_list_.erase(it); | 766 prerender_list_.erase(it); |
| 733 break; | 767 break; |
| 734 } | 768 } |
| 735 } | 769 } |
| 736 AddToHistory(entry); | 770 AddToHistory(entry); |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1092 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { | 1126 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { |
| 1093 DeleteOldTabContents(); | 1127 DeleteOldTabContents(); |
| 1094 while (!prerender_list_.empty()) { | 1128 while (!prerender_list_.empty()) { |
| 1095 PrerenderContentsData data = prerender_list_.front(); | 1129 PrerenderContentsData data = prerender_list_.front(); |
| 1096 prerender_list_.pop_front(); | 1130 prerender_list_.pop_front(); |
| 1097 data.contents_->Destroy(final_status); | 1131 data.contents_->Destroy(final_status); |
| 1098 } | 1132 } |
| 1099 DeletePendingDeleteEntries(); | 1133 DeletePendingDeleteEntries(); |
| 1100 } | 1134 } |
| 1101 | 1135 |
| 1136 void PrerenderManager::RecordFinalStatusWithMatchCompleteStatus( |
| 1137 Origin origin, |
| 1138 uint8 experiment_id, |
| 1139 PrerenderContents::MatchCompleteStatus mc_status, |
| 1140 FinalStatus final_status) const { |
| 1141 histograms_->RecordFinalStatus(origin, |
| 1142 experiment_id, |
| 1143 mc_status, |
| 1144 final_status); |
| 1145 } |
| 1146 |
| 1102 void PrerenderManager::RecordFinalStatus(Origin origin, | 1147 void PrerenderManager::RecordFinalStatus(Origin origin, |
| 1103 uint8 experiment_id, | 1148 uint8 experiment_id, |
| 1104 FinalStatus final_status) const { | 1149 FinalStatus final_status) const { |
| 1105 histograms_->RecordFinalStatus(origin, experiment_id, final_status); | 1150 RecordFinalStatusWithMatchCompleteStatus( |
| 1151 origin, experiment_id, |
| 1152 PrerenderContents::MATCH_COMPLETE_DEFAULT, |
| 1153 final_status); |
| 1106 } | 1154 } |
| 1107 | 1155 |
| 1156 |
| 1108 PrerenderManager* FindPrerenderManagerUsingRenderProcessId( | 1157 PrerenderManager* FindPrerenderManagerUsingRenderProcessId( |
| 1109 int render_process_id) { | 1158 int render_process_id) { |
| 1110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1111 content::RenderProcessHost* render_process_host = | 1160 content::RenderProcessHost* render_process_host = |
| 1112 content::RenderProcessHost::FromID(render_process_id); | 1161 content::RenderProcessHost::FromID(render_process_id); |
| 1113 // Each render process is guaranteed to only hold RenderViews owned by the | 1162 // Each render process is guaranteed to only hold RenderViews owned by the |
| 1114 // same BrowserContext. This is enforced by | 1163 // same BrowserContext. This is enforced by |
| 1115 // RenderProcessHost::GetExistingProcessHost. | 1164 // RenderProcessHost::GetExistingProcessHost. |
| 1116 if (!render_process_host || !render_process_host->GetBrowserContext()) | 1165 if (!render_process_host || !render_process_host->GetBrowserContext()) |
| 1117 return NULL; | 1166 return NULL; |
| 1118 Profile* profile = Profile::FromBrowserContext( | 1167 Profile* profile = Profile::FromBrowserContext( |
| 1119 render_process_host->GetBrowserContext()); | 1168 render_process_host->GetBrowserContext()); |
| 1120 if (!profile) | 1169 if (!profile) |
| 1121 return NULL; | 1170 return NULL; |
| 1122 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); | 1171 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); |
| 1123 } | 1172 } |
| 1124 | 1173 |
| 1125 } // namespace prerender | 1174 } // namespace prerender |
| OLD | NEW |