blob: 90d9b4b0c7863f5bdafe9ef9069ca5d890c26817 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_NAVIGATION_PREDICTOR_NAVIGATION_PREDICTOR_H_
#define CHROME_BROWSER_NAVIGATION_PREDICTOR_NAVIGATION_PREDICTOR_H_
#include <string>
#include <unordered_map>
#include <vector>
#include "base/macros.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "content/public/browser/visibility.h"
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "third_party/blink/public/mojom/loader/navigation_predictor.mojom.h"
#include "url/origin.h"
#ifdef OS_ANDROID
#include "base/android/application_status_listener.h"
#endif // OS_ANDROID
namespace content {
class BrowserContext;
class RenderFrameHost;
}
class SiteEngagementService;
class TemplateURLService;
// This class gathers metrics of anchor elements from both renderer process
// and browser process. Then it uses these metrics to make predictions on what
// are the most likely anchor elements that the user will click.
class NavigationPredictor : public blink::mojom::AnchorElementMetricsHost,
public content::WebContentsObserver {
public:
// |render_frame_host| is the host associated with the render frame. It is
// used to retrieve metrics at the browser side.
explicit NavigationPredictor(content::RenderFrameHost* render_frame_host);
~NavigationPredictor() override;
// Create and bind NavigationPredictor.
static void Create(mojo::InterfaceRequest<AnchorElementMetricsHost> request,
content::RenderFrameHost* render_frame_host);
// Enum describing the possible set of actions that navigation predictor may
// take. This enum should remain synchronized with enum
// NavigationPredictorActionTaken in enums.xml. Order of enum values should
// not be changed since the values are recorded in UMA.
enum class Action {
kUnknown = 0,
kNone = 1,
kPreresolve = 2,
kPreconnect = 3,
kPrefetch = 4,
kPreconnectOnVisibilityChange = 5,
kPreconnectOnAppForeground = 6,
kMaxValue = kPreconnectOnAppForeground,
};
// Enum describing the accuracy of actions taken by the navigation predictor.
// This enum should remain synchronized with enum
// NavigationPredictorAccuracyActionTaken in enums.xml. Order of enum values
// should not be changed since the values are recorded in UMA.
enum class ActionAccuracy {
// No action was taken, but an anchor element was clicked.
kNoActionTakenClickHappened = 0,
// Navigation predictor prefetched a URL, and an anchor element was clicked
// which pointed to the same URL as prefetched URL.
kPrefetchActionClickToSameURL = 1,
// Navigation predictor prefetched a URL, and an anchor element was clicked
// whose URL had the same origin as the prefetched URL.
kPrefetchActionClickToSameOrigin = 2,
// Navigation predictor prefetched a URL, and an anchor element was clicked
// whose URL had a different origin than the prefetched URL.
kPrefetchActionClickToDifferentOrigin = 3,
// Navigation predictor preconnected to an origin, and an anchor element was
// clicked whose URL had the same origin as the preconnected origin.
kPreconnectActionClickToSameOrigin = 4,
// Navigation predictor preconnected to an origin, and an anchor element was
// clicked whose URL had a different origin than the preconnected origin.
kPreconnectActionClickToDifferentOrigin = 5,
kMaxValue = kPreconnectActionClickToDifferentOrigin,
};
protected:
// Origin that we decided to preconnect to.
base::Optional<url::Origin> preconnect_origin_;
// URL that we decided to prefetch.
base::Optional<GURL> prefetch_url_;
private:
// Struct holding navigation score, rank and other info of the anchor element.
// Used for look up when an anchor element is clicked.
struct NavigationScore;
// blink::mojom::AnchorElementMetricsHost:
void ReportAnchorElementMetricsOnClick(
blink::mojom::AnchorElementMetricsPtr metrics) override;
void ReportAnchorElementMetricsOnLoad(
std::vector<blink::mojom::AnchorElementMetricsPtr> metrics) override;
// Returns true if the anchor element metric from the renderer process is
// valid.
bool IsValidMetricFromRenderer(
const blink::mojom::AnchorElementMetrics& metric) const;
// Returns site engagement service, which can be used to get site engagement
// score. Return value is guaranteed to be non-null.
SiteEngagementService* GetEngagementService() const;
// Returns template URL service. Guaranteed to be non-null.
TemplateURLService* GetTemplateURLService() const;
// Merge anchor element metrics that have the same target url (href).
void MergeMetricsSameTargetUrl(
std::vector<blink::mojom::AnchorElementMetricsPtr>* metrics) const;
// Computes and stores document level metrics, including |number_of_anchors_|,
// |document_engagement_score_|, etc.
void ComputeDocumentMetricsOnLoad(
const std::vector<blink::mojom::AnchorElementMetricsPtr>& metrics);
// Given metrics of an anchor element from both renderer and browser process,
// returns navigation score. Virtual for testing purposes.
virtual double CalculateAnchorNavigationScore(
const blink::mojom::AnchorElementMetrics& metrics,
double document_engagement_score,
double target_engagement_score,
int area_rank,
int number_of_anchors) const;
// Given a vector of navigation scores sorted in descending order, decide what
// action to take, or decide not to do anything. Example actions including
// preresolve, preload, prerendering, etc.
void MaybeTakeActionOnLoad(
const url::Origin& document_origin,
const std::vector<std::unique_ptr<NavigationScore>>&
sorted_navigation_scores);
base::Optional<GURL> GetUrlToPrefetch(
const url::Origin& document_origin,
const std::vector<std::unique_ptr<NavigationScore>>&
sorted_navigation_scores) const;
base::Optional<url::Origin> GetOriginToPreconnect(
const url::Origin& document_origin,
const std::vector<std::unique_ptr<NavigationScore>>&
sorted_navigation_scores) const;
// Record anchor element metrics on page load.
void RecordMetricsOnLoad(
const blink::mojom::AnchorElementMetrics& metric) const;
// Record timing information when an anchor element is clicked.
void RecordTimingOnClick();
// Records the accuracy of the action taken by the navigator predictor based
// on the action taken as well as the URL that was navigated to.
// |target_url| is the URL navigated to by the user.
void RecordActionAccuracyOnClick(const GURL& target_url) const;
// content::WebContentsObserver:
void OnVisibilityChanged(content::Visibility visibility) override;
#ifdef OS_ANDROID
// Called when application state changes. e.g., application is brought to the
// background or the foreground.
void OnApplicationStateChange(
base::android::ApplicationState application_state);
#endif // OS_ANDROID
// Called when tab or app visibility change. Takes a pre* action.
// |log_action| should be set to the reason why this method was called.
void TakeActionNowOnTabOrAppVisibilityChange(Action log_action);
// MaybePreconnectNow preconnects to an origin server if it's allowed.
void MaybePreconnectNow(Action log_action);
// Used to get keyed services.
content::BrowserContext* const browser_context_;
// Maps from target url (href) to navigation score.
std::unordered_map<std::string, std::unique_ptr<NavigationScore>>
navigation_scores_map_;
// Total number of anchors that: href has the same host as the document,
// contains image, inside an iframe, href incremented by 1 from document url.
int number_of_anchors_same_host_ = 0;
int number_of_anchors_contains_image_ = 0;
int number_of_anchors_in_iframe_ = 0;
int number_of_anchors_url_incremented_ = 0;
// Scaling factors used to compute navigation scores.
const int ratio_area_scale_;
const int is_in_iframe_scale_;
const int is_same_host_scale_;
const int contains_image_scale_;
const int is_url_incremented_scale_;
const int source_engagement_score_scale_;
const int target_engagement_score_scale_;
const int area_rank_scale_;
// Sum of all scales. Used to normalize the final computed weight.
const int sum_scales_;
// True if device is a low end device.
const bool is_low_end_device_;
// Minimum score that a URL should have for it to be prefetched. Note
// that scores of origins are computed differently from scores of URLs, so
// they are not comparable.
const int prefetch_url_score_threshold_;
// Minimum preconnect score that the origin should have for preconnect. Note
// that scores of origins are computed differently from scores of URLs, so
// they are not comparable.
const int preconnect_origin_score_threshold_;
// True if |this| is allowed to preconnect to same origin hosts.
const bool same_origin_preconnecting_allowed_;
// Timing of document loaded and last click.
base::TimeTicks document_loaded_timing_;
base::TimeTicks last_click_timing_;
// True if the source webpage (i.e., the page on which we are trying to
// predict the next navigation) is a page from user's default search engine.
bool source_is_default_search_engine_page_ = false;
// Current visibility state of the web contents.
content::Visibility current_visibility_;
#ifdef OS_ANDROID
// Used to listen to the changes in the application state changes. e.g., when
// the application is brought to the background or the foreground.
std::unique_ptr<base::android::ApplicationStatusListener>
application_status_listener_;
base::android::ApplicationState application_state_;
#endif // OS_ANDROID
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(NavigationPredictor);
};
#endif // CHROME_BROWSER_NAVIGATION_PREDICTOR_NAVIGATION_PREDICTOR_H_