| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 #ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_METRICS_WEB_CONTENTS_OBSERVER_H_ | 5 #ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_METRICS_WEB_CONTENTS_OBSERVER_H_ |
| 6 #define CHROME_BROWSER_PAGE_LOAD_METRICS_METRICS_WEB_CONTENTS_OBSERVER_H_ | 6 #define CHROME_BROWSER_PAGE_LOAD_METRICS_METRICS_WEB_CONTENTS_OBSERVER_H_ |
| 7 | 7 |
| 8 #include <map> | 8 #include <map> |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/time/time.h" | 13 #include "base/time/time.h" |
| 14 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" | 14 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" |
| 15 #include "chrome/common/page_load_metrics/page_load_timing.h" | 15 #include "chrome/common/page_load_metrics/page_load_timing.h" |
| 16 #include "content/public/browser/render_widget_host.h" | 16 #include "content/public/browser/render_widget_host.h" |
| 17 #include "content/public/browser/web_contents.h" | 17 #include "content/public/browser/web_contents.h" |
| 18 #include "content/public/browser/web_contents_observer.h" | 18 #include "content/public/browser/web_contents_observer.h" |
| 19 #include "content/public/browser/web_contents_user_data.h" | 19 #include "content/public/browser/web_contents_user_data.h" |
| 20 #include "content/public/common/resource_type.h" | 20 #include "content/public/common/resource_type.h" |
| 21 #include "net/base/net_errors.h" | |
| 22 #include "third_party/WebKit/public/web/WebInputEvent.h" | 21 #include "third_party/WebKit/public/web/WebInputEvent.h" |
| 23 | 22 |
| 24 namespace content { | 23 namespace content { |
| 25 class NavigationHandle; | 24 class NavigationHandle; |
| 26 class RenderFrameHost; | 25 class RenderFrameHost; |
| 27 } // namespace content | 26 } // namespace content |
| 28 | 27 |
| 29 namespace IPC { | 28 namespace IPC { |
| 30 class Message; | 29 class Message; |
| 31 } // namespace IPC | 30 } // namespace IPC |
| 32 | 31 |
| 33 namespace page_load_metrics { | 32 namespace page_load_metrics { |
| 34 | 33 |
| 34 class PageLoadMetricsEmbedderInterface; |
| 35 class PageLoadTracker; | 35 class PageLoadTracker; |
| 36 | 36 |
| 37 namespace internal { | |
| 38 | |
| 39 extern const char kErrorEvents[]; | |
| 40 extern const char kAbortChainSizeReload[]; | |
| 41 extern const char kAbortChainSizeForwardBack[]; | |
| 42 extern const char kAbortChainSizeNewNavigation[]; | |
| 43 extern const char kAbortChainSizeNoCommit[]; | |
| 44 extern const char kAbortChainSizeSameURL[]; | |
| 45 extern const char kPageLoadCompletedAfterAppBackground[]; | |
| 46 | |
| 47 } // namespace internal | |
| 48 | |
| 49 // These errors are internal to the page_load_metrics subsystem and do not | |
| 50 // reflect actual errors that occur during a page load. | |
| 51 // | |
| 52 // If you add elements to this enum, make sure you update the enum | |
| 53 // value in histograms.xml. Only add elements to the end to prevent | |
| 54 // inconsistencies between versions. | |
| 55 enum InternalErrorLoadEvent { | |
| 56 // A timing IPC was sent from the renderer that did not line up with previous | |
| 57 // data we've received (i.e. navigation start is different or the timing | |
| 58 // struct is somehow invalid). This error can only occur once the IPC is | |
| 59 // vetted in other ways (see other errors). | |
| 60 ERR_BAD_TIMING_IPC, | |
| 61 | |
| 62 // The following IPCs are not mutually exclusive. | |
| 63 // | |
| 64 // We received an IPC when we weren't tracking a committed load. This will | |
| 65 // often happen if we get an IPC from a bad URL scheme (that is, the renderer | |
| 66 // sent us an IPC from a navigation we don't care about). | |
| 67 ERR_IPC_WITH_NO_RELEVANT_LOAD, | |
| 68 | |
| 69 // Received a notification from a frame that has been navigated away from. | |
| 70 ERR_IPC_FROM_WRONG_FRAME, | |
| 71 | |
| 72 // We received an IPC even through the last committed url from the browser | |
| 73 // was not http/s. This can happen with the renderer sending IPCs for the | |
| 74 // new tab page. This will often come paired with | |
| 75 // ERR_IPC_WITH_NO_RELEVANT_LOAD. | |
| 76 ERR_IPC_FROM_BAD_URL_SCHEME, | |
| 77 | |
| 78 // If we track a navigation, but the renderer sends us no IPCs. This could | |
| 79 // occur if the browser filters loads less aggressively than the renderer. | |
| 80 ERR_NO_IPCS_RECEIVED, | |
| 81 | |
| 82 // Tracks frequency with which we record an abort time that occurred before | |
| 83 // navigation start. This is expected to happen in some cases (see comments in | |
| 84 // cc file for details). We use this error counter to understand how often it | |
| 85 // happens. | |
| 86 ERR_ABORT_BEFORE_NAVIGATION_START, | |
| 87 | |
| 88 // A new navigation triggers abort updates in multiple trackers in | |
| 89 // |aborted_provisional_loads_|, when usually there should only be one (the | |
| 90 // navigation that just aborted because of this one). If this happens, the | |
| 91 // latest aborted load is used to track the chain size. | |
| 92 ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS, | |
| 93 | |
| 94 // Received user input without a relevant load. This error type is deprecated, | |
| 95 // as it is valid to receive user input without a relevant load. We leave the | |
| 96 // enum value here since it's also used in histogram recording, so it's | |
| 97 // important that we not re-use this enum entry for a different value. | |
| 98 DEPRECATED_ERR_USER_INPUT_WITH_NO_RELEVANT_LOAD, | |
| 99 | |
| 100 // A TimeTicks value in the browser process has value less than | |
| 101 // navigation_start_. This could happen if navigation_start_ was computed in | |
| 102 // renderer process and the system clock has inter process time tick skew. | |
| 103 ERR_INTER_PROCESS_TIME_TICK_SKEW, | |
| 104 | |
| 105 // At the time a PageLoadTracker was destroyed, we had received neither a | |
| 106 // commit nor a failed provisional load. | |
| 107 ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD, | |
| 108 | |
| 109 // Add values before this final count. | |
| 110 ERR_LAST_ENTRY, | |
| 111 }; | |
| 112 | |
| 113 // This class serves as a functional interface to various chrome// features. | |
| 114 // Impl version is defined in chrome/browser/page_load_metrics. | |
| 115 class PageLoadMetricsEmbedderInterface { | |
| 116 public: | |
| 117 virtual ~PageLoadMetricsEmbedderInterface() {} | |
| 118 virtual bool IsPrerendering(content::WebContents* web_contents) = 0; | |
| 119 virtual bool IsNewTabPageUrl(const GURL& url) = 0; | |
| 120 virtual void RegisterObservers(PageLoadTracker* metrics) = 0; | |
| 121 }; | |
| 122 | |
| 123 // This class tracks a given page load, starting from navigation start / | |
| 124 // provisional load, until a new navigation commits or the navigation fails. | |
| 125 // MetricsWebContentsObserver manages a set of provisional PageLoadTrackers, as | |
| 126 // well as a committed PageLoadTracker. | |
| 127 class PageLoadTracker { | |
| 128 public: | |
| 129 // Caller must guarantee that the embedder_interface pointer outlives this | |
| 130 // class. The PageLoadTracker must not hold on to | |
| 131 // currently_committed_load_or_null or navigation_handle beyond the scope of | |
| 132 // the constructor. | |
| 133 PageLoadTracker(bool in_foreground, | |
| 134 PageLoadMetricsEmbedderInterface* embedder_interface, | |
| 135 const GURL& currently_committed_url, | |
| 136 content::NavigationHandle* navigation_handle, | |
| 137 int aborted_chain_size, | |
| 138 int aborted_chain_size_same_url); | |
| 139 ~PageLoadTracker(); | |
| 140 void Redirect(content::NavigationHandle* navigation_handle); | |
| 141 void Commit(content::NavigationHandle* navigation_handle); | |
| 142 void FailedProvisionalLoad(content::NavigationHandle* navigation_handle); | |
| 143 void WebContentsHidden(); | |
| 144 void WebContentsShown(); | |
| 145 | |
| 146 void OnInputEvent(const blink::WebInputEvent& event); | |
| 147 | |
| 148 // Flush any buffered metrics, as part of the metrics subsystem persisting | |
| 149 // metrics as the application goes into the background. The application may be | |
| 150 // killed at any time after this method is invoked without further | |
| 151 // notification. | |
| 152 void FlushMetricsOnAppEnterBackground(); | |
| 153 | |
| 154 void NotifyClientRedirectTo(const PageLoadTracker& destination); | |
| 155 | |
| 156 // Returns true if the timing was successfully updated. | |
| 157 bool UpdateTiming(const PageLoadTiming& timing, | |
| 158 const PageLoadMetadata& metadata); | |
| 159 | |
| 160 void OnLoadedSubresource(bool was_cached); | |
| 161 | |
| 162 // Signals that we should stop tracking metrics for the associated page load. | |
| 163 // We may stop tracking a page load if it doesn't meet the criteria for | |
| 164 // tracking metrics in DidFinishNavigation. | |
| 165 void StopTracking(); | |
| 166 | |
| 167 int aborted_chain_size() const { return aborted_chain_size_; } | |
| 168 int aborted_chain_size_same_url() const { | |
| 169 return aborted_chain_size_same_url_; | |
| 170 } | |
| 171 | |
| 172 UserAbortType abort_type() const { return abort_type_; } | |
| 173 base::TimeTicks abort_time() const { return abort_time_; } | |
| 174 | |
| 175 void AddObserver(std::unique_ptr<PageLoadMetricsObserver> observer); | |
| 176 | |
| 177 // If the user performs some abort-like action while we are tracking this page | |
| 178 // load, notify the tracker. Note that we may not classify this as an abort if | |
| 179 // we've already performed a first paint. | |
| 180 // is_certainly_browser_timestamp signifies if the timestamp passed is taken | |
| 181 // in the | |
| 182 // browser process or not. We need this to possibly clamp browser timestamp on | |
| 183 // a machine with inter process time tick skew. | |
| 184 void NotifyAbort(UserAbortType abort_type, | |
| 185 bool user_initiated, | |
| 186 base::TimeTicks timestamp, | |
| 187 bool is_certainly_browser_timestamp); | |
| 188 void UpdateAbort(UserAbortType abort_type, | |
| 189 bool user_initiated, | |
| 190 base::TimeTicks timestamp, | |
| 191 bool is_certainly_browser_timestamp); | |
| 192 | |
| 193 // This method returns true if this page load has been aborted with type of | |
| 194 // ABORT_OTHER, and the |abort_cause_time| is within a sufficiently close | |
| 195 // delta to when it was aborted. Note that only provisional loads can be | |
| 196 // aborted with ABORT_OTHER. While this heuristic is coarse, it works better | |
| 197 // and is simpler than other feasible methods. See https://goo.gl/WKRG98. | |
| 198 bool IsLikelyProvisionalAbort(base::TimeTicks abort_cause_time) const; | |
| 199 | |
| 200 bool MatchesOriginalNavigation(content::NavigationHandle* navigation_handle); | |
| 201 | |
| 202 // Only valid to call post-commit. | |
| 203 const GURL& committed_url() const { | |
| 204 DCHECK(!committed_url_.is_empty()); | |
| 205 return committed_url_; | |
| 206 } | |
| 207 | |
| 208 base::TimeTicks navigation_start() const { return navigation_start_; } | |
| 209 | |
| 210 PageLoadExtraInfo ComputePageLoadExtraInfo(); | |
| 211 | |
| 212 ui::PageTransition page_transition() const { return page_transition_; } | |
| 213 | |
| 214 private: | |
| 215 // This function converts a TimeTicks value taken in the browser process | |
| 216 // to navigation_start_ if: | |
| 217 // - base::TimeTicks is not comparable across processes because the clock | |
| 218 // is not system wide monotonic. | |
| 219 // - *event_time < navigation_start_ | |
| 220 void ClampBrowserTimestampIfInterProcessTimeTickSkew( | |
| 221 base::TimeTicks* event_time); | |
| 222 | |
| 223 void UpdateAbortInternal(UserAbortType abort_type, | |
| 224 bool user_initiated, | |
| 225 base::TimeTicks timestamp, | |
| 226 bool is_certainly_browser_timestamp); | |
| 227 | |
| 228 // If |final_navigation| is null, then this is an "unparented" abort chain, | |
| 229 // and represents a sequence of provisional aborts that never ends with a | |
| 230 // committed load. | |
| 231 void LogAbortChainHistograms(content::NavigationHandle* final_navigation); | |
| 232 | |
| 233 // Whether we stopped tracking this navigation after it was initiated. We may | |
| 234 // stop tracking a navigation if it doesn't meet the criteria for tracking | |
| 235 // metrics in DidFinishNavigation. | |
| 236 bool did_stop_tracking_; | |
| 237 | |
| 238 // Whether the application went into the background when this PageLoadTracker | |
| 239 // was active. This is a temporary boolean for UMA tracking. | |
| 240 bool app_entered_background_; | |
| 241 | |
| 242 // The navigation start in TimeTicks, not the wall time reported by Blink. | |
| 243 const base::TimeTicks navigation_start_; | |
| 244 | |
| 245 // The committed URL of this page load. | |
| 246 GURL committed_url_; | |
| 247 | |
| 248 // The start URL for this page load (before redirects). | |
| 249 GURL start_url_; | |
| 250 | |
| 251 std::unique_ptr<FailedProvisionalLoadInfo> failed_provisional_load_info_; | |
| 252 | |
| 253 // Will be ABORT_NONE if we have not aborted this load yet. Otherwise will | |
| 254 // be the first abort action the user performed. | |
| 255 UserAbortType abort_type_; | |
| 256 | |
| 257 // This boolean is only an approximation. As the aborts pipeline is updated, | |
| 258 // more abort types will have this set to true. Currently, this is only set | |
| 259 // for navigations aborting navigations. | |
| 260 bool abort_user_initiated_; | |
| 261 | |
| 262 base::TimeTicks abort_time_; | |
| 263 | |
| 264 // We record separate metrics for events that occur after a background, | |
| 265 // because metrics like layout/paint are delayed artificially | |
| 266 // when they occur in the background. | |
| 267 base::TimeTicks background_time_; | |
| 268 base::TimeTicks foreground_time_; | |
| 269 bool started_in_foreground_; | |
| 270 | |
| 271 PageLoadTiming timing_; | |
| 272 PageLoadMetadata metadata_; | |
| 273 | |
| 274 ui::PageTransition page_transition_; | |
| 275 | |
| 276 // Note: these are only approximations, based on WebContents attribution from | |
| 277 // ResourceRequestInfo objects while this is the currently committed load in | |
| 278 // the WebContents. | |
| 279 int num_cache_requests_; | |
| 280 int num_network_requests_; | |
| 281 | |
| 282 // This is derived from the user gesture bit in the renderer. For browser | |
| 283 // initiated navigations this will always be true. | |
| 284 bool user_gesture_; | |
| 285 | |
| 286 // This is a subtle member. If a provisional load A gets aborted by | |
| 287 // provisional load B, which gets aborted by C that eventually commits, then | |
| 288 // there exists an abort chain of length 2, starting at A's navigation_start. | |
| 289 // This is useful because it allows histograming abort chain lengths based on | |
| 290 // what the last load's transition type is. i.e. holding down F-5 to spam | |
| 291 // reload will produce a long chain with the RELOAD transition. | |
| 292 const int aborted_chain_size_; | |
| 293 | |
| 294 // This member counts consecutive provisional aborts that share a url. It will | |
| 295 // always be less than or equal to |aborted_chain_size_|. | |
| 296 const int aborted_chain_size_same_url_; | |
| 297 | |
| 298 // Interface to chrome features. Must outlive the class. | |
| 299 PageLoadMetricsEmbedderInterface* const embedder_interface_; | |
| 300 | |
| 301 std::vector<std::unique_ptr<PageLoadMetricsObserver>> observers_; | |
| 302 | |
| 303 DISALLOW_COPY_AND_ASSIGN(PageLoadTracker); | |
| 304 }; | |
| 305 | |
| 306 // MetricsWebContentsObserver tracks page loads and loading metrics | 37 // MetricsWebContentsObserver tracks page loads and loading metrics |
| 307 // related data based on IPC messages received from a | 38 // related data based on IPC messages received from a |
| 308 // MetricsRenderFrameObserver. | 39 // MetricsRenderFrameObserver. |
| 309 class MetricsWebContentsObserver | 40 class MetricsWebContentsObserver |
| 310 : public content::WebContentsObserver, | 41 : public content::WebContentsObserver, |
| 311 public content::WebContentsUserData<MetricsWebContentsObserver>, | 42 public content::WebContentsUserData<MetricsWebContentsObserver>, |
| 312 public content::RenderWidgetHost::InputEventObserver { | 43 public content::RenderWidgetHost::InputEventObserver { |
| 313 public: | 44 public: |
| 314 // Note that the returned metrics is owned by the web contents. | 45 // Note that the returned metrics is owned by the web contents. |
| 315 static MetricsWebContentsObserver* CreateForWebContents( | 46 static MetricsWebContentsObserver* CreateForWebContents( |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 | 145 |
| 415 // Has the MWCO observed at least one navigation? | 146 // Has the MWCO observed at least one navigation? |
| 416 bool has_navigated_; | 147 bool has_navigated_; |
| 417 | 148 |
| 418 DISALLOW_COPY_AND_ASSIGN(MetricsWebContentsObserver); | 149 DISALLOW_COPY_AND_ASSIGN(MetricsWebContentsObserver); |
| 419 }; | 150 }; |
| 420 | 151 |
| 421 } // namespace page_load_metrics | 152 } // namespace page_load_metrics |
| 422 | 153 |
| 423 #endif // CHROME_BROWSER_PAGE_LOAD_METRICS_METRICS_WEB_CONTENTS_OBSERVER_H_ | 154 #endif // CHROME_BROWSER_PAGE_LOAD_METRICS_METRICS_WEB_CONTENTS_OBSERVER_H_ |
| OLD | NEW |