Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: components/page_load_metrics/browser/page_load_metrics_web_contents_observer.cc

Issue 1312213010: PageLoadMetrics renderer and browser implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix rebase conflict Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/page_load_metrics/browser/page_load_metrics_web_contents_ob server.h"
6
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "components/page_load_metrics/common/page_load_metrics_messages.h"
10 #include "components/page_load_metrics/common/page_load_timing.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/navigation_details.h"
13 #include "content/public/browser/navigation_handle.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/browser/web_contents_observer.h"
17 #include "content/public/browser/web_contents_user_data.h"
18 #include "ipc/ipc_message.h"
19 #include "ipc/ipc_message_macros.h"
20
21 DEFINE_WEB_CONTENTS_USER_DATA_KEY(
22 page_load_metrics::MetricsWebContentsObserver);
23
24 namespace page_load_metrics {
25
26 namespace {
27
28 bool IsValidPageLoadTiming(const PageLoadTiming& timing) {
29 if (timing.IsEmpty())
30 return false;
31
32 // If we have a non-empty timing, it should always have a navigation start.
33 if (timing.navigation_start.is_null())
34 return false;
35
36 // If we have a dom content loaded event, we should have a response start.
37 if (!timing.dom_content_loaded_event_start.is_zero()) {
38 if (timing.response_start.is_zero() ||
39 !(timing.response_start < timing.dom_content_loaded_event_start)) {
Bryan McQuade 2015/09/09 16:26:25 technically we could have response_start and dom_c
Charlie Harrison 2015/09/09 17:32:03 Done.
40 return false;
41 }
42 }
43
44 // If we have a load event, we should have both a response start and a DCL.
45 if (!timing.load_event_start.is_zero()) {
46 if (timing.response_start.is_zero() ||
47 timing.dom_content_loaded_event_start.is_zero() ||
48 !(timing.dom_content_loaded_event_start < timing.load_event_start)) {
Bryan McQuade 2015/09/09 16:26:25 same
Charlie Harrison 2015/09/09 17:32:03 Done.
49 return false;
50 }
51 }
52
53 return true;
54 }
55
56 } // namespace
57 MetricsWebContentsObserver::MetricsWebContentsObserver(
58 content::WebContents* web_contents)
59 : content::WebContentsObserver(web_contents) {}
60
61 // As a tab helper, this object is tied to a single WebContent
62 // for its entire lifetime.
63 MetricsWebContentsObserver::~MetricsWebContentsObserver() {
64 RecordTimingHistograms();
65 }
66
67 bool MetricsWebContentsObserver::OnMessageReceived(
68 const IPC::Message& message,
69 content::RenderFrameHost* render_frame_host) {
70 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
71 return HandleMessageReceived(message, render_frame_host);
72 }
73
74 bool MetricsWebContentsObserver::HandleMessageReceived(
75 const IPC::Message& message,
76 content::RenderFrameHost* render_frame_host) {
77 bool handled = true;
78 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message,
79 render_frame_host)
80 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated)
81 IPC_MESSAGE_UNHANDLED(handled = false)
82 IPC_END_MESSAGE_MAP()
83 return handled;
84 }
85
86 void MetricsWebContentsObserver::DidCommitNavigation(
87 content::NavigationHandle* navigation_handle) {
88 if (navigation_handle->IsInMainFrame() && !navigation_handle->IsSamePage())
89 RecordTimingHistograms();
90 if (IsRelevantNavigation(navigation_handle)) {
91 current_timing_.reset(new PageLoadTiming());
92 }
93 }
94
95 // This will occur when the process for the main RenderFrameHost exits.
96 // This will happen with a normal exit or a crash.
97 void MetricsWebContentsObserver::RenderProcessGone(
98 base::TerminationStatus status) {
99 RecordTimingHistograms();
100 }
101
102 #define PAGE_LOAD_HISTOGRAM(name, sample) \
103 UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \
104 base::TimeDelta::FromMilliseconds(10), \
105 base::TimeDelta::FromMinutes(10), 100);
106
107 void MetricsWebContentsObserver::OnTimingUpdated(
108 content::RenderFrameHost* render_frame_host,
109 const PageLoadTiming& timing) {
110 if (!current_timing_)
111 return;
112
113 // We may receive notifications from frames that have been navigated away
114 // from. We simply ignore them.
115 if (!IsCurrentMainFrame(render_frame_host))
116 return;
117
118 // See comment in IsRelevantNavigation about
119 // browser/renderer url disagreement (newtab).
120 if (!GetLastCommittedURL().SchemeIsHTTPOrHTTPS())
121 return;
122
123 // Throw away IPCs that are not relevant to the current navigation.
124 if (!current_timing_->navigation_start.is_null() &&
125 timing.navigation_start != current_timing_->navigation_start) {
126 // TODO(csharrison) uma log a counter here
127 return;
128 }
129
130 if (current_timing_->IsEmpty())
131 current_host_ = render_frame_host;
132 else
Bryan McQuade 2015/09/09 16:26:25 reading the style guide, i see that when there's a
Charlie Harrison 2015/09/09 17:32:03 Actually it only says to do this if one of the cla
133 DCHECK(render_frame_host == current_host_);
134 *current_timing_ = timing;
135 }
136
137 void MetricsWebContentsObserver::RecordTimingHistograms() {
138 if (!current_timing_ || !IsValidPageLoadTiming(*current_timing_))
139 return;
140
141 if (!current_timing_->dom_content_loaded_event_start.is_zero()) {
142 PAGE_LOAD_HISTOGRAM("PageLoad.Timing.DOMContentLoadedEventFired",
143 current_timing_->dom_content_loaded_event_start);
144 }
145
146 if (!current_timing_->load_event_start.is_zero()) {
147 PAGE_LOAD_HISTOGRAM("PageLoad.Timing.LoadEventFired",
148 current_timing_->load_event_start);
149 }
150
151 if (!current_timing_->first_layout.is_zero()) {
152 PAGE_LOAD_HISTOGRAM("PageLoad.Timing.FirstLayout",
153 current_timing_->first_layout);
154 }
155 current_timing_.reset();
156 }
157
158 bool MetricsWebContentsObserver::IsRelevantNavigation(
159 content::NavigationHandle* navigation_handle) {
160 // The url we see from the renderer side is not always the same as what
161 // we see from the browser side (e.g. chrome://newtab). We wan't to be
162 // sure here that we aren't logging UMA for internal pages
163 const GURL& browser_url = GetLastCommittedURL();
164 return navigation_handle->IsInMainFrame() &&
165 !navigation_handle->IsSamePage() &&
166 navigation_handle->HasCommittedDocument() &&
167 navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() &&
168 browser_url.SchemeIsHTTPOrHTTPS();
169 }
170
171 const GURL& MetricsWebContentsObserver::GetLastCommittedURL() {
172 return web_contents()->GetLastCommittedURL();
173 }
174
175 bool MetricsWebContentsObserver::IsCurrentMainFrame(
176 content::RenderFrameHost* render_frame_host) {
177 return render_frame_host == web_contents()->GetMainFrame();
178 }
179
180 } // namespace page_load_metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698