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 |