| // Copyright 2015 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_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_OBSERVER_H_ |
| #define CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_OBSERVER_H_ |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "base/optional.h" |
| #include "chrome/common/page_load_metrics/page_load_timing.h" |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h" |
| #include "content/public/browser/navigation_handle.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "third_party/WebKit/public/platform/WebInputEvent.h" |
| #include "url/gurl.h" |
| |
| namespace page_load_metrics { |
| |
| // This enum represents how a page load ends. If the action occurs before the |
| // page load finishes (or reaches some point like first paint), then we consider |
| // the load to be aborted. |
| enum PageEndReason { |
| // Page lifetime has not yet ended (page is still active). |
| END_NONE, |
| |
| // The page was reloaded, possibly by the user. |
| END_RELOAD, |
| |
| // The page was navigated away from, via a back or forward navigation. |
| END_FORWARD_BACK, |
| |
| // The navigation is replaced with a navigation with the qualifier |
| // ui::PAGE_TRANSITION_CLIENT_REDIRECT, which is caused by Javascript, or the |
| // meta refresh tag. |
| END_CLIENT_REDIRECT, |
| |
| // If the page load is replaced by a new navigation. This includes link |
| // clicks, typing in the omnibox (not a reload), and form submissions. |
| END_NEW_NAVIGATION, |
| |
| // The page load was stopped (e.g. the user presses the stop X button). |
| END_STOP, |
| |
| // Page load ended due to closing the tab or browser. |
| END_CLOSE, |
| |
| // The provisional load for this page load failed before committing. |
| END_PROVISIONAL_LOAD_FAILED, |
| |
| // The render process hosting the page terminated unexpectedly. |
| END_RENDER_PROCESS_GONE, |
| |
| // We don't know why the page load ended. This is the value we assign to a |
| // terminated provisional load if the only signal we get is the load finished |
| // without committing, either without error or with net::ERR_ABORTED. |
| END_OTHER |
| }; |
| |
| // Information related to failed provisional loads. |
| struct FailedProvisionalLoadInfo { |
| FailedProvisionalLoadInfo(base::TimeDelta interval, net::Error error); |
| ~FailedProvisionalLoadInfo(); |
| |
| base::TimeDelta time_to_failed_provisional_load; |
| net::Error error; |
| }; |
| |
| // Information related to whether an associated action, such as a navigation or |
| // an abort, was initiated by a user. Clicking a link or tapping on a UI |
| // element are examples of user initiation actions. |
| struct UserInitiatedInfo { |
| static UserInitiatedInfo NotUserInitiated() { |
| return UserInitiatedInfo(false, false, false); |
| } |
| |
| static UserInitiatedInfo BrowserInitiated() { |
| return UserInitiatedInfo(true, false, false); |
| } |
| |
| static UserInitiatedInfo RenderInitiated(bool user_gesture, |
| bool user_input_event) { |
| return UserInitiatedInfo(false, user_gesture, user_input_event); |
| } |
| |
| // Whether the associated action was initiated from the browser process, as |
| // opposed to from the render process. We generally assume that all actions |
| // initiated from the browser process are user initiated. |
| bool browser_initiated; |
| |
| // Whether the associated action was initiated by a user, according to user |
| // gesture tracking in content and Blink, as reported by NavigationHandle. |
| bool user_gesture; |
| |
| // Whether the associated action was initiated by a user, based on our |
| // heuristic-driven implementation that tests to see if there was an input |
| // event that happened shortly before the given action. |
| bool user_input_event; |
| |
| private: |
| UserInitiatedInfo(bool browser_initiated, |
| bool user_gesture, |
| bool user_input_event) |
| : browser_initiated(browser_initiated), |
| user_gesture(user_gesture), |
| user_input_event(user_input_event) {} |
| }; |
| |
| struct PageLoadExtraInfo { |
| PageLoadExtraInfo( |
| base::TimeTicks navigation_start, |
| const base::Optional<base::TimeDelta>& first_background_time, |
| const base::Optional<base::TimeDelta>& first_foreground_time, |
| bool started_in_foreground, |
| UserInitiatedInfo user_initiated_info, |
| const GURL& url, |
| const GURL& start_url, |
| bool did_commit, |
| PageEndReason page_end_reason, |
| UserInitiatedInfo page_end_user_initiated_info, |
| const base::Optional<base::TimeDelta>& page_end_time, |
| const PageLoadMetadata& main_frame_metadata, |
| const PageLoadMetadata& child_frame_metadata); |
| |
| // Simplified version of the constructor, intended for use in tests. |
| static PageLoadExtraInfo CreateForTesting(const GURL& url, |
| bool started_in_foreground); |
| |
| PageLoadExtraInfo(const PageLoadExtraInfo& other); |
| |
| ~PageLoadExtraInfo(); |
| |
| // The time the navigation was initiated. |
| const base::TimeTicks navigation_start; |
| |
| // The first time that the page was backgrounded since the navigation started. |
| const base::Optional<base::TimeDelta> first_background_time; |
| |
| // The first time that the page was foregrounded since the navigation started. |
| const base::Optional<base::TimeDelta> first_foreground_time; |
| |
| // True if the page load started in the foreground. |
| const bool started_in_foreground; |
| |
| // Whether the page load was initiated by a user. |
| const UserInitiatedInfo user_initiated_info; |
| |
| // Most recent URL for this page. Can be updated at navigation start, upon |
| // redirection, and at commit time. |
| const GURL url; |
| |
| // The URL that started the navigation, before redirects. |
| const GURL start_url; |
| |
| // Whether the navigation for this page load committed. |
| const bool did_commit; |
| |
| // The reason the page load ended. If the page is still active, |
| // |page_end_reason| will be |END_NONE|. |page_end_time| contains the duration |
| // of time until the cause of the page end reason was encountered. |
| const PageEndReason page_end_reason; |
| |
| // Whether the end reason for this page load was user initiated. For example, |
| // if |
| // this page load was ended due to a new navigation, this field tracks whether |
| // that new navigation was user-initiated. This field is only useful if this |
| // page load's end reason is a value other than END_NONE. Note that this |
| // value is currently experimental, and is subject to change. In particular, |
| // this field is not currently set for some end reasons, such as stop and |
| // close, since we don't yet have sufficient instrumentation to know if a stop |
| // or close was caused by a user action. |
| // |
| // TODO(csharrison): If more metadata for end reasons is needed we should |
| // provide a |
| // better abstraction. Note that this is an approximation. |
| UserInitiatedInfo page_end_user_initiated_info; |
| |
| // Total lifetime of the page from the user standoint, starting at navigation |
| // start. The page lifetime ends when the first of the following events |
| // happen: |
| // * the load of the main resource fails |
| // * the page load is stopped |
| // * the tab hosting the page is closed |
| // * the render process hosting the page goes away |
| // * a new navigation which later commits is initiated in the same tab |
| // This field will not be set if the page is still active and hasn't yet |
| // finished. |
| const base::Optional<base::TimeDelta> page_end_time; |
| |
| // Extra information supplied to the page load metrics system from the |
| // renderer for the main frame. |
| const PageLoadMetadata main_frame_metadata; |
| |
| // PageLoadMetadata for child frames of the current page load. |
| const PageLoadMetadata child_frame_metadata; |
| }; |
| |
| // Container for various information about a request within a page load. |
| struct ExtraRequestInfo { |
| ExtraRequestInfo(bool was_cached, |
| int64_t raw_body_bytes, |
| int64_t original_network_content_length, |
| std::unique_ptr<data_reduction_proxy::DataReductionProxyData> |
| data_reduction_proxy_data); |
| |
| ~ExtraRequestInfo(); |
| |
| // True if the resource was loaded from cache. |
| const bool was_cached; |
| |
| // The number of body (not header) prefilter bytes. |
| const int64_t raw_body_bytes; |
| |
| // The number of body (not header) bytes that the data reduction proxy saw |
| // before it compressed the requests. |
| const int64_t original_network_content_length; |
| |
| // Data related to data saver. |
| const std::unique_ptr<data_reduction_proxy::DataReductionProxyData> |
| data_reduction_proxy_data; |
| }; |
| |
| // Interface for PageLoadMetrics observers. All instances of this class are |
| // owned by the PageLoadTracker tracking a page load. |
| class PageLoadMetricsObserver { |
| public: |
| // ObservePolicy is used as a return value on some PageLoadMetricsObserver |
| // callbacks to indicate whether the observer would like to continue observing |
| // metric callbacks. Observers that wish to continue observing metric |
| // callbacks should return CONTINUE_OBSERVING; observers that wish to stop |
| // observing callbacks should return STOP_OBSERVING. Observers that return |
| // STOP_OBSERVING may be deleted. |
| enum ObservePolicy { |
| CONTINUE_OBSERVING, |
| STOP_OBSERVING, |
| }; |
| |
| virtual ~PageLoadMetricsObserver() {} |
| |
| // The page load started, with the given navigation handle. |
| // currently_committed_url contains the URL of the committed page load at the |
| // time the navigation for navigation_handle was initiated, or the empty URL |
| // if there was no committed page load at the time the navigation was |
| // initiated. |
| virtual ObservePolicy OnStart(content::NavigationHandle* navigation_handle, |
| const GURL& currently_committed_url, |
| bool started_in_foreground); |
| |
| // OnRedirect is triggered when a page load redirects to another URL. |
| // The navigation handle holds relevant data for the navigation, but will |
| // be destroyed soon after this call. Don't hold a reference to it. This can |
| // be called multiple times. |
| virtual ObservePolicy OnRedirect( |
| content::NavigationHandle* navigation_handle); |
| |
| // OnCommit is triggered when a page load commits, i.e. when we receive the |
| // first data for the request. The navigation handle holds relevant data for |
| // the navigation, but will be destroyed soon after this call. Don't hold a |
| // reference to it. |
| // Observers that return STOP_OBSERVING will not receive any additional |
| // callbacks, and will be deleted after invocation of this method returns. |
| virtual ObservePolicy OnCommit(content::NavigationHandle* navigation_handle); |
| |
| // OnHidden is triggered when a page leaves the foreground. It does not fire |
| // when a foreground page is permanently closed; for that, listen to |
| // OnComplete instead. |
| virtual ObservePolicy OnHidden(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info); |
| |
| // OnShown is triggered when a page is brought to the foreground. It does not |
| // fire when the page first loads; for that, listen for OnStart instead. |
| virtual ObservePolicy OnShown(); |
| |
| // Called before OnCommit. The observer should return whether it wishes to |
| // observe navigations whose main resource has MIME type |mine_type|. The |
| // default is to observe HTML and XHTML only. Note that PageLoadTrackers only |
| // track XHTML, HTML, and MHTML (related/multipart). |
| virtual ObservePolicy ShouldObserveMimeType( |
| const std::string& mime_type) const; |
| |
| // The callbacks below are only invoked after a navigation commits, for |
| // tracked page loads. Page loads that don't meet the criteria for being |
| // tracked at the time a navigation commits will not receive any of the |
| // callbacks below. |
| |
| // OnTimingUpdate is triggered when an updated PageLoadTiming is |
| // available. This method may be called multiple times over the course of the |
| // page load. This method is currently only intended for use in testing. Most |
| // implementers should implement one of the On* callbacks, such as |
| // OnFirstContentfulPaint or OnDomContentLoadedEventStart. Please email |
| // loading-dev@chromium.org if you intend to override this method. |
| virtual void OnTimingUpdate(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| // OnUserInput is triggered when a new user input is passed in to |
| // web_contents. Contains a TimeDelta from navigation start. |
| virtual void OnUserInput(const blink::WebInputEvent& event) {} |
| |
| // The following methods are invoked at most once, when the timing for the |
| // associated event first becomes available. |
| virtual void OnDomContentLoadedEventStart( |
| const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| virtual void OnLoadEventStart(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| virtual void OnFirstLayout(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| virtual void OnFirstPaint(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| virtual void OnFirstTextPaint(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| virtual void OnFirstImagePaint(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| virtual void OnFirstContentfulPaint(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| virtual void OnFirstMeaningfulPaint(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| virtual void OnParseStart(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| virtual void OnParseStop(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| |
| // Invoked when there is a change in either the main_frame_metadata or the |
| // child_frame_metadata's loading behavior_flags. |
| virtual void OnLoadingBehaviorObserved( |
| const page_load_metrics::PageLoadExtraInfo& extra_info) {} |
| |
| // Invoked when a media element starts playing. |
| virtual void MediaStartedPlaying( |
| const content::WebContentsObserver::MediaPlayerInfo& video_type, |
| bool is_in_main_frame) {} |
| |
| // Invoked on navigations where a navigation delay was added by the |
| // DelayNavigationThrottle. This is a temporary method that will be removed |
| // once the experiment is complete. |
| virtual void OnNavigationDelayComplete(base::TimeDelta scheduled_delay, |
| base::TimeDelta actual_delay) {} |
| |
| // Invoked when the UMA metrics subsystem is persisting metrics as the |
| // application goes into the background, on platforms where the browser |
| // process may be killed after backgrounding (Android). Implementers should |
| // persist any metrics that have been buffered in memory in this callback, as |
| // the application may be killed at any time after this method is invoked |
| // without further notification. Note that this may be called both for |
| // provisional loads as well as committed loads. Implementations that only |
| // want to track committed loads should check whether extra_info.committed_url |
| // is empty to determine if the load had committed. If the implementation |
| // returns CONTINUE_OBSERVING, this method may be called multiple times per |
| // observer, once for each time that the application enters the backround. |
| // |
| // The default implementation does nothing, and returns CONTINUE_OBSERVING. |
| virtual ObservePolicy FlushMetricsOnAppEnterBackground( |
| const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info); |
| |
| // One of OnComplete or OnFailedProvisionalLoad is invoked for tracked page |
| // loads, immediately before the observer is deleted. These callbacks will not |
| // be invoked for page loads that did not meet the criteria for being tracked |
| // at the time the navigation completed. The PageLoadTiming struct contains |
| // timing data and the PageLoadExtraInfo struct contains other useful data |
| // collected over the course of the page load. Most observers should not need |
| // to implement these callbacks, and should implement the On* timing callbacks |
| // instead. |
| |
| // OnComplete is invoked for tracked page loads that committed, immediately |
| // before the observer is deleted. Observers that implement OnComplete may |
| // also want to implement FlushMetricsOnAppEnterBackground, to avoid loss of |
| // data if the application is killed while in the background (this happens |
| // frequently on Android). |
| virtual void OnComplete(const PageLoadTiming& timing, |
| const PageLoadExtraInfo& extra_info) {} |
| |
| // OnFailedProvisionalLoad is invoked for tracked page loads that did not |
| // commit, immediately before the observer is deleted. |
| virtual void OnFailedProvisionalLoad( |
| const FailedProvisionalLoadInfo& failed_provisional_load_info, |
| const PageLoadExtraInfo& extra_info) {} |
| |
| // Called whenever a request is loaded for this page load. |
| virtual void OnLoadedResource(const ExtraRequestInfo& extra_request_info) {} |
| }; |
| |
| } // namespace page_load_metrics |
| |
| #endif // CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_OBSERVER_H_ |