Commit d17049f1 authored by Robert Ogden's avatar Robert Ogden Committed by Commit Bot

Plumb prefetch results in IsolatedPrerender Metrics Collector

Also transitions the origin prober over to using the new probe result
enum so that it can be passed to the metrics collector.

ScopedRefPtr:
The metrics collector uses a scoped ref ptr to manage its lifetime.
For mainframe prefetching, the TabHelper has the only refptr to the
collector. But during NSP, the refptr is shared to every subresource
manager that is created.
If the next navigation does not go to a prefetched page, all subresource
managers are destroyed, as well as the TabHelper's CurrentPageLoad class
which destroys the metrics collector. Since there would not be any
cache reuse to record in the metrics, it can be safely destroyed then.
If the next navigation goes to a prefetched page, then all refptrs to
the metrics collector will be destroyed, except for the one in the
subresource manager associated with that page. This allows the
subresource manager to record cache reuse directly, without relying on
the TabHelper to make some lifetime guarantee about the metrics
collector.
Furthermore, this pattern keeps the cache reuse logic out of the
TabHelper when it is already isolated to the subresource manager.

Bug: 1136174
Change-Id: I4e0e52acb8f99a1490f67d98b44329f997e40720
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2463544
Commit-Queue: Robert Ogden <robertogden@chromium.org>
Reviewed-by: default avatarRyan Sturm <ryansturm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#818670}
parent 34c3cc61
......@@ -143,7 +143,9 @@ class TLSProber {
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream,
const base::Optional<net::SSLInfo>& ssl_info) {
std::move(callback_).Run(result == net::OK);
std::move(callback_).Run(
result == net::OK ? IsolatedPrerenderProbeResult::kTLSProbeSuccess
: IsolatedPrerenderProbeResult::kTLSProbeFailure);
delete this;
}
......@@ -156,7 +158,7 @@ class TLSProber {
}
void HandleFailure() {
std::move(callback_).Run(false);
std::move(callback_).Run(IsolatedPrerenderProbeResult::kTLSProbeFailure);
delete this;
}
......@@ -177,7 +179,9 @@ void HTTPProbeHelper(
std::unique_ptr<AvailabilityProber> prober,
IsolatedPrerenderOriginProber::OnProbeResultCallback callback,
bool success) {
std::move(callback).Run(success);
std::move(callback).Run(success
? IsolatedPrerenderProbeResult::kTLSProbeSuccess
: IsolatedPrerenderProbeResult::kTLSProbeFailure);
}
class CanaryCheckDelegate : public AvailabilityProber::Delegate {
......@@ -323,7 +327,7 @@ void IsolatedPrerenderOriginProber::OnTLSCanaryCheckComplete(bool success) {
StartCanaryCheck(dns_canary_check_->AsWeakPtr());
}
bool IsolatedPrerenderOriginProber::ShouldProbeOrigins() {
bool IsolatedPrerenderOriginProber::ShouldProbeOrigins() const {
if (!IsolatedPrerenderProbingEnabled()) {
return false;
}
......@@ -442,7 +446,7 @@ void IsolatedPrerenderOriginProber::HTTPProbe(const GURL& url,
// Transfer ownership of the prober to the callback so that the class instance
// is automatically destroyed when the probe is complete.
OnProbeResultCallback owning_callback =
auto owning_callback =
base::BindOnce(&HTTPProbeHelper, std::move(prober), std::move(callback));
prober_ptr->SetOnCompleteCallback(base::BindOnce(std::move(owning_callback)));
......@@ -460,12 +464,12 @@ void IsolatedPrerenderOriginProber::OnDNSResolved(
// A TLS connection needs the resolved addresses, so it also fails here.
if (!successful) {
std::move(callback).Run(false);
std::move(callback).Run(IsolatedPrerenderProbeResult::kDNSProbeFailure);
return;
}
if (!also_do_tls_connect) {
std::move(callback).Run(true);
std::move(callback).Run(IsolatedPrerenderProbeResult::kDNSProbeSuccess);
return;
}
......
......@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_probe_result.h"
#include "net/base/address_list.h"
#include "url/gurl.h"
......@@ -30,7 +31,7 @@ class IsolatedPrerenderOriginProber {
~IsolatedPrerenderOriginProber();
// Returns true if a probe needs to be done before using prefetched resources.
bool ShouldProbeOrigins();
bool ShouldProbeOrigins() const;
// Sets the probe url override delegate for testing.
void SetProbeURLOverrideDelegateOverrideForTesting(
......@@ -43,9 +44,10 @@ class IsolatedPrerenderOriginProber {
// Tells whether a DNS canary check is active. Used for testing.
bool IsDNSCanaryCheckActiveForTesting() const;
// Starts a probe to |url| and calls |callback| with a bool to indicate
// success (when true) or failure (when false).
using OnProbeResultCallback = base::OnceCallback<void(bool)>;
// Starts a probe to |url| and calls |callback| with an
// |IsolatedPrerenderProbeResult| to indicate success.
using OnProbeResultCallback =
base::OnceCallback<void(IsolatedPrerenderProbeResult)>;
void Probe(const GURL& url, OnProbeResultCallback callback);
private:
......
......@@ -85,6 +85,10 @@ enum class IsolatedPrerenderPrefetchStatus {
kPrefetchUsedNoProbeNSPNotStarted = 22,
kPrefetchUsedProbeSuccessNSPNotStarted = 23,
kPrefetchNotUsedProbeFailedNSPNotStarted = 24,
// A subresource which was not fetched because it was throttled by an
// experimental control for the max number of subresources per prerender.
kSubresourceThrottled = 25,
};
#endif // CHROME_BROWSER_PRERENDER_ISOLATED_ISOLATED_PRERENDER_PREFETCH_STATUS_H_
......@@ -20,6 +20,7 @@
#include "content/public/common/content_constants.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
#include "third_party/blink/public/common/client_hints/client_hints.h"
namespace {
......@@ -27,24 +28,6 @@ namespace {
const char kAllowedUAClientHint[] = "sec-ch-ua";
const char kAllowedUAMobileClientHint[] = "sec-ch-ua-mobile";
void RecordSubresourceMetricsDuringPrerender(
const network::URLLoaderCompletionStatus& status,
base::Optional<int> http_response_code) {
base::UmaHistogramSparse("IsolatedPrerender.Prefetch.Subresources.NetError",
std::abs(status.error_code));
if (http_response_code) {
base::UmaHistogramSparse("IsolatedPrerender.Prefetch.Subresources.RespCode",
*http_response_code);
}
}
void RecordSubresourceMetricsAfterClick(
const network::URLLoaderCompletionStatus& status,
base::Optional<int> http_response_code) {
UMA_HISTOGRAM_BOOLEAN("IsolatedPrerender.AfterClick.Subresources.UsedCache",
status.exists_in_cache);
}
// Little helper class for
// |CheckRedirectsBeforeRunningResourceSuccessfulCallback| since size_t can't be
// ref counted.
......@@ -183,8 +166,8 @@ void IsolatedPrerenderProxyingURLLoaderFactory::InProgressRequest::
void IsolatedPrerenderProxyingURLLoaderFactory::InProgressRequest::
OnReceiveResponse(network::mojom::URLResponseHeadPtr head) {
if (head && head->headers) {
http_response_code_ = head->headers->response_code();
if (head) {
head_ = head->Clone();
}
target_client_->OnReceiveResponse(std::move(head));
}
......@@ -228,7 +211,8 @@ void IsolatedPrerenderProxyingURLLoaderFactory::InProgressRequest::
void IsolatedPrerenderProxyingURLLoaderFactory::InProgressRequest::OnComplete(
const network::URLLoaderCompletionStatus& status) {
if (on_complete_metrics_callback_) {
std::move(on_complete_metrics_callback_).Run(status, http_response_code_);
std::move(on_complete_metrics_callback_)
.Run(redirect_chain_[0], head_->Clone(), status);
}
MaybeReportResourceLoadSuccess(status);
target_client_->OnComplete(status);
......@@ -247,15 +231,19 @@ void IsolatedPrerenderProxyingURLLoaderFactory::InProgressRequest::
return;
}
if (!http_response_code_) {
if (!head_) {
return;
}
if (!head_->headers) {
return;
}
if (*http_response_code_ >= 300) {
if (head_->headers->response_code() >= net::HTTP_MULTIPLE_CHOICES) {
return;
}
if (*http_response_code_ < 200) {
if (head_->headers->response_code() < net::HTTP_OK) {
return;
}
......@@ -319,6 +307,7 @@ void IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::
IsolatedPrerenderProxyingURLLoaderFactory::
IsolatedPrerenderProxyingURLLoaderFactory(
ResourceMetricsObserver* metrics_observer,
int frame_tree_node_id,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
......@@ -326,9 +315,12 @@ IsolatedPrerenderProxyingURLLoaderFactory::
mojo::PendingRemote<network::mojom::URLLoaderFactory> isolated_factory,
DisconnectCallback on_disconnect,
ResourceLoadSuccessfulCallback on_resource_load_successful)
: frame_tree_node_id_(frame_tree_node_id),
: metrics_observer_(metrics_observer),
frame_tree_node_id_(frame_tree_node_id),
on_resource_load_successful_(std::move(on_resource_load_successful)),
on_disconnect_(std::move(on_disconnect)) {
DCHECK(metrics_observer_);
network_process_factory_.Bind(std::move(network_process_factory));
network_process_factory_.set_disconnect_handler(base::BindOnce(
&IsolatedPrerenderProxyingURLLoaderFactory::OnNetworkProcessFactoryError,
......@@ -381,6 +373,7 @@ void IsolatedPrerenderProxyingURLLoaderFactory::CreateLoaderAndStart(
// Check if this prerender has exceeded its max number of subresources.
request_count_++;
if (request_count_ > IsolatedPrerenderMaxSubresourcesPerPrerender()) {
metrics_observer_->OnResourceThrottled(request.url);
std::unique_ptr<AbortRequest> request = std::make_unique<AbortRequest>(
std::move(loader_receiver), std::move(client));
// The request will manage its own lifecycle based on the mojo pipes.
......@@ -410,7 +403,9 @@ void IsolatedPrerenderProxyingURLLoaderFactory::CreateLoaderAndStart(
std::move(loader_receiver), routing_id, request_id, options, request,
std::move(client), traffic_annotation);
in_progress_request->SetOnCompleteRecordMetricsCallback(
base::BindOnce(&RecordSubresourceMetricsAfterClick));
base::BindOnce(&IsolatedPrerenderProxyingURLLoaderFactory::
RecordSubresourceMetricsAfterClick,
base::Unretained(this)));
requests_.insert(std::move(in_progress_request));
} else {
// Resource was not cached during the NSP, so load it normally.
......@@ -433,7 +428,7 @@ void IsolatedPrerenderProxyingURLLoaderFactory::OnEligibilityResult(
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
const GURL& url,
bool eligible,
base::Optional<IsolatedPrerenderPrefetchStatus> not_used) {
base::Optional<IsolatedPrerenderPrefetchStatus> status) {
DCHECK_EQ(request.url, url);
DCHECK(!previously_cached_subresources_.has_value());
DCHECK(request.cors_exempt_headers.HasHeader(
......@@ -470,6 +465,10 @@ void IsolatedPrerenderProxyingURLLoaderFactory::OnEligibilityResult(
// not, it must still be put on the wire to avoid privacy attacks but should
// not be cached or change any cookies.
if (!eligible) {
if (status) {
metrics_observer_->OnResourceNotEligible(url, *status);
}
isolated_request.load_flags |= net::LOAD_DISABLE_CACHE;
isolated_request.credentials_mode = network::mojom::CredentialsMode::kOmit;
......@@ -482,10 +481,37 @@ void IsolatedPrerenderProxyingURLLoaderFactory::OnEligibilityResult(
std::move(loader_receiver), routing_id, request_id, options,
isolated_request, std::move(client), traffic_annotation);
in_progress_request->SetOnCompleteRecordMetricsCallback(
base::BindOnce(&RecordSubresourceMetricsDuringPrerender));
base::BindOnce(&IsolatedPrerenderProxyingURLLoaderFactory::
RecordSubresourceMetricsDuringPrerender,
base::Unretained(this)));
requests_.insert(std::move(in_progress_request));
}
void IsolatedPrerenderProxyingURLLoaderFactory::
RecordSubresourceMetricsDuringPrerender(
const GURL& url,
network::mojom::URLResponseHeadPtr head,
const network::URLLoaderCompletionStatus& status) {
base::UmaHistogramSparse("IsolatedPrerender.Prefetch.Subresources.NetError",
std::abs(status.error_code));
if (head && head->headers) {
base::UmaHistogramSparse("IsolatedPrerender.Prefetch.Subresources.RespCode",
head->headers->response_code());
}
metrics_observer_->OnResourceFetchComplete(url, std::move(head), status);
}
void IsolatedPrerenderProxyingURLLoaderFactory::
RecordSubresourceMetricsAfterClick(
const GURL& url,
network::mojom::URLResponseHeadPtr head,
const network::URLLoaderCompletionStatus& status) {
UMA_HISTOGRAM_BOOLEAN("IsolatedPrerender.AfterClick.Subresources.UsedCache",
status.exists_in_cache);
metrics_observer_->OnResourceUsedFromCache(url);
}
void IsolatedPrerenderProxyingURLLoaderFactory::Clone(
mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver) {
proxy_receivers_.Add(this, std::move(loader_receiver));
......
......@@ -35,6 +35,27 @@ class Profile;
class IsolatedPrerenderProxyingURLLoaderFactory
: public network::mojom::URLLoaderFactory {
public:
class ResourceMetricsObserver {
public:
// Called when the resource finishes, either in failure or success.
virtual void OnResourceFetchComplete(
const GURL& url,
network::mojom::URLResponseHeadPtr head,
const network::URLLoaderCompletionStatus& status) = 0;
// Called when a subresource load exceeds the experimental maximum and the
// load is aborted before going to the network.
virtual void OnResourceThrottled(const GURL& url) = 0;
// Called when a subresource is not eligible to be prefetched.
virtual void OnResourceNotEligible(
const GURL& url,
IsolatedPrerenderPrefetchStatus status) = 0;
// Called when a previously prefetched subresource is loaded from the cache.
virtual void OnResourceUsedFromCache(const GURL& url) = 0;
};
using DisconnectCallback =
base::OnceCallback<void(IsolatedPrerenderProxyingURLLoaderFactory*)>;
......@@ -42,6 +63,7 @@ class IsolatedPrerenderProxyingURLLoaderFactory
base::RepeatingCallback<void(const GURL& url)>;
IsolatedPrerenderProxyingURLLoaderFactory(
ResourceMetricsObserver* metrics_observer,
int frame_tree_node_id,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
......@@ -91,8 +113,9 @@ class IsolatedPrerenderProxyingURLLoaderFactory
// Sets a callback that will be run during |OnComplete| to record metrics.
using OnCompleteRecordMetricsCallback = base::OnceCallback<void(
const network::URLLoaderCompletionStatus& status,
base::Optional<int> http_response_code)>;
const GURL& url,
network::mojom::URLResponseHeadPtr head,
const network::URLLoaderCompletionStatus& status)>;
void SetOnCompleteRecordMetricsCallback(
OnCompleteRecordMetricsCallback callback);
......@@ -139,8 +162,8 @@ class IsolatedPrerenderProxyingURLLoaderFactory
// This should be run on destruction of |this|.
base::OnceClosure destruction_callback_;
// Records the HTTP response code in |OnReceiveResponse|.
base::Optional<int> http_response_code_;
// Holds onto the response head for reporting to the metrics callback.
network::mojom::URLResponseHeadPtr head_;
// All urls loaded by |this| in order of redirects. The first element is the
// requested url and the last element is the final loaded url. Always has
......@@ -210,7 +233,17 @@ class IsolatedPrerenderProxyingURLLoaderFactory
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
const GURL& url,
bool eligible,
base::Optional<IsolatedPrerenderPrefetchStatus> not_used);
base::Optional<IsolatedPrerenderPrefetchStatus> status);
void RecordSubresourceMetricsDuringPrerender(
const GURL& url,
network::mojom::URLResponseHeadPtr head,
const network::URLLoaderCompletionStatus& status);
void RecordSubresourceMetricsAfterClick(
const GURL& url,
network::mojom::URLResponseHeadPtr head,
const network::URLLoaderCompletionStatus& status);
// Returns true when this factory was created during a NoStatePrefetch.
// Internally, this means |NotifyPageNavigatedToAfterSRP| has not been called.
......@@ -222,6 +255,8 @@ class IsolatedPrerenderProxyingURLLoaderFactory
void RemoveRequest(InProgressRequest* request);
void MaybeDestroySelf();
// Must outlive |this|.
ResourceMetricsObserver* metrics_observer_;
// For getting the web contents.
const int frame_tree_node_id_;
......
......@@ -5,7 +5,7 @@
#include "chrome/browser/prerender/isolated/isolated_prerender_subresource_manager.h"
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_proxying_url_loader_factory.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_prefetch_metrics_collector.h"
#include "chrome/browser/prerender/isolated/prefetched_mainframe_response_container.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_frame_host.h"
......@@ -134,7 +134,7 @@ bool IsolatedPrerenderSubresourceManager::MaybeProxyURLLoaderFactory(
frame->GetIsolationInfoForSubresources());
auto proxy = std::make_unique<IsolatedPrerenderProxyingURLLoaderFactory>(
frame->GetFrameTreeNodeId(), std::move(proxied_receiver),
this, frame->GetFrameTreeNodeId(), std::move(proxied_receiver),
std::move(network_process_factory_remote),
std::move(isolated_factory_remote),
base::BindOnce(
......@@ -168,3 +168,47 @@ void IsolatedPrerenderSubresourceManager::RemoveProxiedURLLoaderFactory(
DCHECK(it != proxied_loader_factories_.end());
proxied_loader_factories_.erase(it);
}
void IsolatedPrerenderSubresourceManager::SetPrefetchMetricsCollector(
scoped_refptr<IsolatedPrerenderPrefetchMetricsCollector> collector) {
metrics_collector_ = collector;
}
void IsolatedPrerenderSubresourceManager::OnResourceFetchComplete(
const GURL& url,
network::mojom::URLResponseHeadPtr head,
const network::URLLoaderCompletionStatus& status) {
if (!metrics_collector_)
return;
metrics_collector_->OnSubresourcePrefetched(
/*mainframe_url=*/url_,
/*subresource_url=*/url, std::move(head), status);
}
void IsolatedPrerenderSubresourceManager::OnResourceNotEligible(
const GURL& url,
IsolatedPrerenderPrefetchStatus status) {
if (!metrics_collector_)
return;
metrics_collector_->OnSubresourceNotEligible(
/*mainframe_url=*/url_,
/*subresource_url=*/url, status);
}
void IsolatedPrerenderSubresourceManager::OnResourceThrottled(const GURL& url) {
if (!metrics_collector_)
return;
metrics_collector_->OnSubresourceNotEligible(
/*mainframe_url=*/url_,
/*subresource_url=*/url,
IsolatedPrerenderPrefetchStatus::kSubresourceThrottled);
}
void IsolatedPrerenderSubresourceManager::OnResourceUsedFromCache(
const GURL& url) {
if (!metrics_collector_)
return;
metrics_collector_->OnCachedSubresourceUsed(/*mainframe_url=*/url_,
/*subresource_url=*/url);
}
......@@ -13,6 +13,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_proxying_url_loader_factory.h"
#include "components/prerender/browser/prerender_handle.h"
#include "content/public/browser/content_browser_client.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
......@@ -32,11 +33,14 @@ class PrerenderHandle;
}
class PrefetchedMainframeResponseContainer;
class IsolatedPrerenderPrefetchMetricsCollector;
class IsolatedPrerenderProxyingURLLoaderFactory;
// This class manages the isolated prerender of a page and its subresources.
class IsolatedPrerenderSubresourceManager
: public prerender::PrerenderHandle::Observer {
: public prerender::PrerenderHandle::Observer,
public IsolatedPrerenderProxyingURLLoaderFactory::
ResourceMetricsObserver {
public:
// A callback to create new URL Loader Factories for subresources.
using CreateIsolatedLoaderFactoryRepeatingCallback =
......@@ -61,6 +65,10 @@ class IsolatedPrerenderSubresourceManager
return successfully_loaded_subresources_;
}
// Sets the prefetch metrics collector to report subresource fetches to.
void SetPrefetchMetricsCollector(
scoped_refptr<IsolatedPrerenderPrefetchMetricsCollector> collector);
// Takes ownership of |mainframe_response_|.
std::unique_ptr<PrefetchedMainframeResponseContainer> TakeMainframeResponse();
......@@ -96,6 +104,16 @@ class IsolatedPrerenderSubresourceManager
void OnPrerenderNetworkBytesChanged(
prerender::PrerenderHandle* handle) override {}
// IsolatedPrerenderProxyingURLLoaderFactory::ResourceMetricsObserver:
void OnResourceFetchComplete(
const GURL& url,
network::mojom::URLResponseHeadPtr head,
const network::URLLoaderCompletionStatus& status) override;
void OnResourceNotEligible(const GURL& url,
IsolatedPrerenderPrefetchStatus status) override;
void OnResourceThrottled(const GURL& url) override;
void OnResourceUsedFromCache(const GURL& url) override;
IsolatedPrerenderSubresourceManager(
const IsolatedPrerenderSubresourceManager&) = delete;
IsolatedPrerenderSubresourceManager& operator=(
......@@ -139,6 +157,10 @@ class IsolatedPrerenderSubresourceManager
// The mainframe response headers and body.
std::unique_ptr<PrefetchedMainframeResponseContainer> mainframe_response_;
// Collects metrics from the implementation of
// |IsolatedPrerenderProxyingURLLoaderFactory::ResourceMetricsObserver|.
scoped_refptr<IsolatedPrerenderPrefetchMetricsCollector> metrics_collector_;
// State for managing the NoStatePrerender when it is running. If
// |nsp_handle_| is set, then |on_nsp_done_callback_| is also set and vise
// versa.
......
......@@ -21,6 +21,7 @@
#include "chrome/browser/prerender/isolated/isolated_prerender_features.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_network_context_client.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_params.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_prefetch_metrics_collector.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_proxy_configurator.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_service.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_service_factory.h"
......@@ -348,6 +349,16 @@ void IsolatedPrerenderTabHelper::NotifyPrefetchProbeLatency(
page_->probe_latency_ = probe_latency;
}
void IsolatedPrerenderTabHelper::ReportProbeResult(
const GURL& url,
IsolatedPrerenderProbeResult result) {
if (!page_->prefetch_metrics_collector_) {
return;
}
page_->prefetch_metrics_collector_->OnMainframeNavigationProbeResult(url,
result);
}
void IsolatedPrerenderTabHelper::OnPrefetchStatusUpdate(
const GURL& url,
IsolatedPrerenderPrefetchStatus usage) {
......@@ -381,6 +392,7 @@ IsolatedPrerenderTabHelper::MaybeUpdatePrefetchStatusWithNSPContext(
case IsolatedPrerenderPrefetchStatus::kPrefetchFailedNotHTML:
case IsolatedPrerenderPrefetchStatus::kPrefetchSuccessful:
case IsolatedPrerenderPrefetchStatus::kNavigatedToLinkNotOnSRP:
case IsolatedPrerenderPrefetchStatus::kSubresourceThrottled:
return status;
// These statuses we are going to update to, and this is the only place that
// they are set so they are not expected to be passed in.
......@@ -554,6 +566,8 @@ void IsolatedPrerenderTabHelper::DidFinishNavigation(
std::make_unique<CurrentPageLoad>(navigation_handle);
if (page_->srp_metrics_->predicted_urls_count_ > 0) {
page_->prefetch_metrics_collector_->OnMainframeNavigatedTo(url);
// If the previous page load was a Google SRP, the AfterSRPMetrics class
// needs to be created now from the SRP's |page_| and then set on the new
// one when we set it at the end of this method.
......@@ -790,6 +804,13 @@ void IsolatedPrerenderTabHelper::OnPrefetchComplete(
base::UmaHistogramSparse("IsolatedPrerender.Prefetch.Mainframe.NetError",
std::abs(loader->NetError()));
if (loader->CompletionStatus()) {
page_->prefetch_metrics_collector_->OnMainframeResourcePrefetched(
url, page_->original_prediction_ordering_.find(url)->second,
loader->ResponseInfo() ? loader->ResponseInfo()->Clone() : nullptr,
loader->CompletionStatus().value());
}
if (loader->NetError() != net::OK) {
OnPrefetchStatusUpdate(
url, IsolatedPrerenderPrefetchStatus::kPrefetchFailedNetError);
......@@ -805,6 +826,7 @@ void IsolatedPrerenderTabHelper::OnPrefetchComplete(
DCHECK(!head->proxy_server.is_direct());
HandlePrefetchResponse(url, isolation_info, std::move(head),
std::move(body));
}
......@@ -938,6 +960,8 @@ void IsolatedPrerenderTabHelper::DoNoStatePrefetch() {
service->OnAboutToNoStatePrefetch(url, CopyPrefetchResponseForNSP(url));
DCHECK_EQ(manager, service->GetSubresourceManagerForURL(url));
manager->SetPrefetchMetricsCollector(page_->prefetch_metrics_collector_);
manager->SetCreateIsolatedLoaderFactoryCallback(base::BindRepeating(
&IsolatedPrerenderTabHelper::CreateNewURLLoaderFactory,
weak_factory_.GetWeakPtr()));
......@@ -1065,6 +1089,13 @@ void IsolatedPrerenderTabHelper::OnPredictionUpdated(
return;
}
if (!page_->prefetch_metrics_collector_) {
page_->prefetch_metrics_collector_ =
base::MakeRefCounted<IsolatedPrerenderPrefetchMetricsCollector>(
page_->navigation_start_,
web_contents()->GetMainFrame()->GetPageUkmSourceId());
}
// It's very likely we'll prefetch something at this point, so inform PLM to
// start tracking metrics.
InformPLMOfLikelyPrefetching(web_contents());
......@@ -1189,6 +1220,10 @@ void IsolatedPrerenderTabHelper::OnGotEligibilityResult(
if (!eligible) {
if (status) {
OnPrefetchStatusUpdate(url, status.value());
DCHECK(page_->prefetch_metrics_collector_);
page_->prefetch_metrics_collector_->OnMainframeResourceNotEligible(
url, page_->original_prediction_ordering_.find(url)->second, *status);
}
return;
}
......
......@@ -19,6 +19,7 @@
#include "base/time/time.h"
#include "chrome/browser/navigation_predictor/navigation_predictor_keyed_service.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_prefetch_status.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_probe_result.h"
#include "chrome/browser/prerender/isolated/prefetched_mainframe_response_container.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/web_contents_observer.h"
......@@ -27,11 +28,13 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/isolation_info.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
#include "url/gurl.h"
class IsolatedPrerenderPageLoadMetricsObserver;
class IsolatedPrerenderPrefetchMetricsCollector;
class IsolatedPrerenderSubresourceManager;
class Profile;
......@@ -193,6 +196,10 @@ class IsolatedPrerenderTabHelper
// Called by the URLLoaderInterceptor to update |page_.probe_latency_|.
void NotifyPrefetchProbeLatency(base::TimeDelta probe_latency);
// Called by the URLLoaderInterceptor to report the outcome of an origin
// probe.
void ReportProbeResult(const GURL& url, IsolatedPrerenderProbeResult result);
// When a previously prefetched page is navigated to, any cookies set on that
// page load should be copied over to the normal profile. While this copy is
// in progress, this method returns true to indicate to the navigation loader
......@@ -253,6 +260,12 @@ class IsolatedPrerenderTabHelper
// Only set for pages after a Google SRP.
std::unique_ptr<AfterSRPMetrics> after_srp_metrics_;
// Collects metrics on all prefetching. This is a scoped refptr so that it
// can also be shared with subresource managers until all pointers to it are
// destroyed, at which time it logs UKM.
scoped_refptr<IsolatedPrerenderPrefetchMetricsCollector>
prefetch_metrics_collector_;
// The status of each prefetch.
std::map<GURL, IsolatedPrerenderPrefetchStatus> prefetch_status_by_url_;
......
......@@ -50,6 +50,22 @@ void ReportProbeLatency(int frame_tree_node_id, base::TimeDelta probe_latency) {
tab_helper->NotifyPrefetchProbeLatency(probe_latency);
}
void ReportProbeResult(int frame_tree_node_id,
const GURL& url,
IsolatedPrerenderProbeResult result) {
content::WebContents* web_contents =
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
if (!web_contents)
return;
IsolatedPrerenderTabHelper* tab_helper =
IsolatedPrerenderTabHelper::FromWebContents(web_contents);
if (!tab_helper)
return;
tab_helper->ReportProbeResult(url, result);
}
void RecordCookieWaitTime(base::TimeDelta wait_time) {
UMA_HISTOGRAM_CUSTOM_TIMES(
"IsolatedPrerender.AfterClick.Mainframe.CookieWaitTime", wait_time,
......@@ -228,12 +244,13 @@ void IsolatedPrerenderURLLoaderInterceptor::DoNotInterceptNavigation() {
void IsolatedPrerenderURLLoaderInterceptor::OnProbeComplete(
base::OnceClosure on_success_callback,
bool success) {
IsolatedPrerenderProbeResult result) {
DCHECK(probe_start_time_.has_value());
ReportProbeLatency(frame_tree_node_id_,
base::TimeTicks::Now() - probe_start_time_.value());
ReportProbeResult(frame_tree_node_id_, url_, result);
if (success) {
if (IsolatedPrerenderProbeResultIsSuccess(result)) {
std::move(on_success_callback).Run();
return;
}
......
......@@ -15,6 +15,7 @@
#include "base/time/time.h"
#include "chrome/browser/availability/availability_prober.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_prefetch_status.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_probe_result.h"
#include "content/public/browser/url_loader_request_interceptor.h"
#include "services/network/public/cpp/resource_request.h"
#include "url/gurl.h"
......@@ -60,8 +61,9 @@ class IsolatedPrerenderURLLoaderInterceptor
bool MaybeInterceptNoStatePrefetchNavigation(
const network::ResourceRequest& tentative_resource_request);
// Called when the probe finishes with |success|.
void OnProbeComplete(base::OnceClosure on_success_callback, bool success);
// Called when the probe finishes with |result|.
void OnProbeComplete(base::OnceClosure on_success_callback,
IsolatedPrerenderProbeResult result);
// Notifies the Tab Helper about the usage of a prefetched resource.
void NotifyPrefetchStatusUpdate(IsolatedPrerenderPrefetchStatus usage) const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment