Commit fffe1325 authored by Bryan McQuade's avatar Bryan McQuade Committed by Commit Bot

Report additional page load metrics on Android.

This adds support for reporting 3 new page load metrics
(largest contentful paint, first input delay, and
cumulative layout shift) to embedders on Android.

Change-Id: I3e49c4ca8cddbc6471d215cb8fc17a6a2ebcc5a5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1785882Reviewed-by: default avatarPeter Conn <peconn@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Reviewed-by: default avatarBenoit L <lizeb@chromium.org>
Commit-Queue: Bryan McQuade <bmcquade@chromium.org>
Cr-Commit-Position: refs/heads/master@{#695751}
parent aa2ad75d
...@@ -904,8 +904,9 @@ public class CustomTabsConnection { ...@@ -904,8 +904,9 @@ public class CustomTabsConnection {
if (referrer == null) return ParallelRequestStatus.FAILURE_INVALID_REFERRER; if (referrer == null) return ParallelRequestStatus.FAILURE_INVALID_REFERRER;
if (policy < 0 || policy > ReferrerPolicy.LAST) policy = ReferrerPolicy.DEFAULT; if (policy < 0 || policy > ReferrerPolicy.LAST) policy = ReferrerPolicy.DEFAULT;
if (url.toString().equals("") || !isValid(url)) if (url.toString().equals("") || !isValid(url)) {
return ParallelRequestStatus.FAILURE_INVALID_URL; return ParallelRequestStatus.FAILURE_INVALID_URL;
}
if (!canDoParallelRequest(session, referrer)) { if (!canDoParallelRequest(session, referrer)) {
return ParallelRequestStatus.FAILURE_INVALID_REFERRER_FOR_SESSION; return ParallelRequestStatus.FAILURE_INVALID_REFERRER_FOR_SESSION;
} }
...@@ -1141,20 +1142,16 @@ public class CustomTabsConnection { ...@@ -1141,20 +1142,16 @@ public class CustomTabsConnection {
} }
/** /**
* Notifies the application of a page load metric for a single metric. * Creates a Bundle with a value for navigation start and the specified page load metric.
*
* TODD(lizeb): Move this to a proper method in {@link CustomTabsCallback} once one is
* available.
* *
* @param session Session identifier.
* @param metricName Name of the page load metric. * @param metricName Name of the page load metric.
* @param navigationStartTick Absolute navigation start time, as TimeTicks taken from native. * @param navigationStartTick Absolute navigation start time, as TimeTicks taken from native.
* @param offsetMs Offset in ms from navigationStart for the page load metric. * @param offsetMs Offset in ms from navigationStart for the page load metric.
* *
* @return Whether the metric has been dispatched to the client. * @return A Bundle containing navigation start and the page load metric.
*/ */
boolean notifySinglePageLoadMetric(CustomTabsSessionToken session, String metricName, Bundle createBundleWithNavigationStartAndPageLoadMetric(
long navigationStartTick, long offsetMs) { String metricName, long navigationStartTick, long offsetMs) {
if (!mNativeTickOffsetUsComputed) { if (!mNativeTickOffsetUsComputed) {
// Compute offset from time ticks to uptimeMillis. // Compute offset from time ticks to uptimeMillis.
mNativeTickOffsetUsComputed = true; mNativeTickOffsetUsComputed = true;
...@@ -1170,8 +1167,24 @@ public class CustomTabsConnection { ...@@ -1170,8 +1167,24 @@ public class CustomTabsConnection {
// SystemClock.uptimeMillis() value. // SystemClock.uptimeMillis() value.
args.putLong(PageLoadMetrics.NAVIGATION_START, args.putLong(PageLoadMetrics.NAVIGATION_START,
(navigationStartTick - mNativeTickOffsetUs) / 1000); (navigationStartTick - mNativeTickOffsetUs) / 1000);
return args;
}
return notifyPageLoadMetrics(session, args); /**
* Notifies the application of a page load metric for a single metric.
*
* @param session Session identifier.
* @param metricName Name of the page load metric.
* @param navigationStartTick Absolute navigation start time, as TimeTicks taken from native.
* @param offsetMs Offset in ms from navigationStart for the page load metric.
*
* @return Whether the metric has been dispatched to the client.
*/
boolean notifySinglePageLoadMetric(CustomTabsSessionToken session, String metricName,
long navigationStartTick, long offsetMs) {
return notifyPageLoadMetrics(session,
createBundleWithNavigationStartAndPageLoadMetric(
metricName, navigationStartTick, offsetMs));
} }
/** /**
......
...@@ -52,6 +52,19 @@ public class PageLoadMetricsObserver implements PageLoadMetrics.Observer { ...@@ -52,6 +52,19 @@ public class PageLoadMetricsObserver implements PageLoadMetrics.Observer {
navigationStartTick, firstContentfulPaintMs); navigationStartTick, firstContentfulPaintMs);
} }
@Override
public void onLargestContentfulPaint(WebContents webContents, long navigationId,
long navigationStartTick, long largestContentfulPaintMs,
long largestContentfulPaintSize) {
if (webContents != mTab.getWebContents()) return;
Bundle args = mConnection.createBundleWithNavigationStartAndPageLoadMetric(
PageLoadMetrics.LARGEST_CONTENTFUL_PAINT, navigationStartTick,
largestContentfulPaintMs);
args.putLong(PageLoadMetrics.LARGEST_CONTENTFUL_PAINT_SIZE, largestContentfulPaintSize);
mConnection.notifyPageLoadMetrics(mSession, args);
}
@Override @Override
public void onLoadEventStart(WebContents webContents, long navigationId, public void onLoadEventStart(WebContents webContents, long navigationId,
long navigationStartTick, long loadEventStartMs) { long navigationStartTick, long loadEventStartMs) {
...@@ -77,4 +90,26 @@ public class PageLoadMetricsObserver implements PageLoadMetrics.Observer { ...@@ -77,4 +90,26 @@ public class PageLoadMetricsObserver implements PageLoadMetrics.Observer {
args.putLong(PageLoadMetrics.SEND_END, sendEndMs); args.putLong(PageLoadMetrics.SEND_END, sendEndMs);
mConnection.notifyPageLoadMetrics(mSession, args); mConnection.notifyPageLoadMetrics(mSession, args);
} }
@Override
public void onFirstInputDelay(
WebContents webContents, long navigationId, long firstInputDelayMs) {
if (webContents != mTab.getWebContents()) return;
Bundle args = new Bundle();
args.putLong(PageLoadMetrics.FIRST_INPUT_DELAY, firstInputDelayMs);
mConnection.notifyPageLoadMetrics(mSession, args);
}
@Override
public void onLayoutShiftScore(WebContents webContents, long navigationId,
float layoutShiftScoreBeforeInputOrScroll, float layoutShiftScoreOverall) {
if (webContents != mTab.getWebContents()) return;
Bundle args = new Bundle();
args.putFloat(PageLoadMetrics.LAYOUT_SHIFT_SCORE, layoutShiftScoreOverall);
args.putFloat(PageLoadMetrics.LAYOUT_SHIFT_SCORE_BEFORE_INPUT_OR_SCROLL,
layoutShiftScoreBeforeInputOrScroll);
mConnection.notifyPageLoadMetrics(mSession, args);
}
} }
...@@ -17,8 +17,14 @@ import org.chromium.content_public.browser.WebContents; ...@@ -17,8 +17,14 @@ import org.chromium.content_public.browser.WebContents;
*/ */
public class PageLoadMetrics { public class PageLoadMetrics {
public static final String FIRST_CONTENTFUL_PAINT = "firstContentfulPaint"; public static final String FIRST_CONTENTFUL_PAINT = "firstContentfulPaint";
public static final String LARGEST_CONTENTFUL_PAINT = "largestContentfulPaint";
public static final String LARGEST_CONTENTFUL_PAINT_SIZE = "largestContentfulPaintSize";
public static final String NAVIGATION_START = "navigationStart"; public static final String NAVIGATION_START = "navigationStart";
public static final String LOAD_EVENT_START = "loadEventStart"; public static final String LOAD_EVENT_START = "loadEventStart";
public static final String FIRST_INPUT_DELAY = "firstInputDelay";
public static final String LAYOUT_SHIFT_SCORE = "layoutShiftScore";
public static final String LAYOUT_SHIFT_SCORE_BEFORE_INPUT_OR_SCROLL =
"layoutShiftScoreBeforeInputOrScroll";
public static final String DOMAIN_LOOKUP_START = "domainLookupStart"; public static final String DOMAIN_LOOKUP_START = "domainLookupStart";
public static final String DOMAIN_LOOKUP_END = "domainLookupEnd"; public static final String DOMAIN_LOOKUP_END = "domainLookupEnd";
public static final String CONNECT_START = "connectStart"; public static final String CONNECT_START = "connectStart";
...@@ -70,6 +76,19 @@ public class PageLoadMetrics { ...@@ -70,6 +76,19 @@ public class PageLoadMetrics {
default void onFirstContentfulPaint(WebContents webContents, long navigationId, default void onFirstContentfulPaint(WebContents webContents, long navigationId,
long navigationStartTick, long firstContentfulPaintMs) {} long navigationStartTick, long firstContentfulPaintMs) {}
/**
* Called when the largest contentful paint page load metric is available.
*
* @param webContents the WebContents this metrics is related to.
* @param navigationId the unique id of a navigation this metrics is related to.
* @param navigationStartTick Absolute navigation start time, as TimeTicks.
* @param largestContentfulPaintMs Time to largest contentful paint from navigation start.
* @param largestContentfulPaintSize Size of largest contentful paint, in CSS pixels.
*/
default void onLargestContentfulPaint(WebContents webContents, long navigationId,
long navigationStartTick, long largestContentfulPaintMs,
long largestContentfulPaintSize) {}
/** /**
* Called when the first meaningful paint page load metric is available. See * Called when the first meaningful paint page load metric is available. See
* FirstMeaningfulPaintDetector.cpp * FirstMeaningfulPaintDetector.cpp
...@@ -82,6 +101,16 @@ public class PageLoadMetrics { ...@@ -82,6 +101,16 @@ public class PageLoadMetrics {
default void onFirstMeaningfulPaint(WebContents webContents, long navigationId, default void onFirstMeaningfulPaint(WebContents webContents, long navigationId,
long navigationStartTick, long firstMeaningfulPaintMs) {} long navigationStartTick, long firstMeaningfulPaintMs) {}
/**
* Called when the first input delay page load metric is available.
*
* @param webContents the WebContents this metrics is related to.
* @param navigationId the unique id of a navigation this metrics is related to.
* @param firstInputDelayMs First input delay.
*/
default void onFirstInputDelay(
WebContents webContents, long navigationId, long firstInputDelayMs) {}
/** /**
* Called when the load event start metric is available. * Called when the load event start metric is available.
* *
...@@ -105,6 +134,19 @@ public class PageLoadMetrics { ...@@ -105,6 +134,19 @@ public class PageLoadMetrics {
default void onLoadedMainResource(WebContents webContents, long navigationId, default void onLoadedMainResource(WebContents webContents, long navigationId,
long dnsStartMs, long dnsEndMs, long connectStartMs, long connectEndMs, long dnsStartMs, long dnsEndMs, long connectStartMs, long connectEndMs,
long requestStartMs, long sendStartMs, long sendEndMs) {} long requestStartMs, long sendStartMs, long sendEndMs) {}
/**
* Called when the layout shift score is available.
*
* @param webContents the WebContents this metrics is related to.
* @param navigationId the unique id of a navigation this metrics is related to.
* @param layoutShiftScoreBeforeInputOrScroll the cumulative layout shift score, before user
* input or scroll.
* @param layoutShiftScoreOverall the cumulative layout shift score over the lifetime of the
* web page.
*/
default void onLayoutShiftScore(WebContents webContents, long navigationId,
float layoutShiftScoreBeforeInputOrScroll, float layoutShiftScoreOverall) {}
} }
private static ObserverList<Observer> sObservers; private static ObserverList<Observer> sObservers;
...@@ -154,6 +196,18 @@ public class PageLoadMetrics { ...@@ -154,6 +196,18 @@ public class PageLoadMetrics {
} }
} }
@CalledByNative
static void onLargestContentfulPaint(WebContents webContents, long navigationId,
long navigationStartTick, long largestContentfulPaintMs,
long largestContentfulPaintSize) {
ThreadUtils.assertOnUiThread();
if (sObservers == null) return;
for (Observer observer : sObservers) {
observer.onLargestContentfulPaint(webContents, navigationId, navigationStartTick,
largestContentfulPaintMs, largestContentfulPaintSize);
}
}
@CalledByNative @CalledByNative
static void onFirstMeaningfulPaint(WebContents webContents, long navigationId, static void onFirstMeaningfulPaint(WebContents webContents, long navigationId,
long navigationStartTick, long firstMeaningfulPaintMs) { long navigationStartTick, long firstMeaningfulPaintMs) {
...@@ -165,6 +219,16 @@ public class PageLoadMetrics { ...@@ -165,6 +219,16 @@ public class PageLoadMetrics {
} }
} }
@CalledByNative
static void onFirstInputDelay(
WebContents webContents, long navigationId, long firstInputDelayMs) {
ThreadUtils.assertOnUiThread();
if (sObservers == null) return;
for (Observer observer : sObservers) {
observer.onFirstInputDelay(webContents, navigationId, firstInputDelayMs);
}
}
@CalledByNative @CalledByNative
static void onLoadEventStart(WebContents webContents, long navigationId, static void onLoadEventStart(WebContents webContents, long navigationId,
long navigationStartTick, long loadEventStartMs) { long navigationStartTick, long loadEventStartMs) {
...@@ -188,5 +252,16 @@ public class PageLoadMetrics { ...@@ -188,5 +252,16 @@ public class PageLoadMetrics {
} }
} }
@CalledByNative
static void onLayoutShiftScore(WebContents webContents, long navigationId,
float layoutShiftScoreBeforeInputOrScroll, float layoutShiftScoreOverall) {
ThreadUtils.assertOnUiThread();
if (sObservers == null) return;
for (Observer observer : sObservers) {
observer.onLayoutShiftScore(webContents, navigationId,
layoutShiftScoreBeforeInputOrScroll, layoutShiftScoreOverall);
}
}
private PageLoadMetrics() {} private PageLoadMetrics() {}
} }
...@@ -2703,8 +2703,10 @@ public class CustomTabActivityTest { ...@@ -2703,8 +2703,10 @@ public class CustomTabActivityTest {
private void checkPageLoadMetrics(boolean allowMetrics) private void checkPageLoadMetrics(boolean allowMetrics)
throws InterruptedException, TimeoutException { throws InterruptedException, TimeoutException {
final AtomicReference<Long> firstContentfulPaintMs = new AtomicReference<>(-1L); final AtomicReference<Long> firstContentfulPaintMs = new AtomicReference<>(-1L);
final AtomicReference<Long> largestContentfulPaintMs = new AtomicReference<>(-1L);
final AtomicReference<Long> activityStartTimeMs = new AtomicReference<>(-1L); final AtomicReference<Long> activityStartTimeMs = new AtomicReference<>(-1L);
final AtomicReference<Long> loadEventStartMs = new AtomicReference<>(-1L); final AtomicReference<Long> loadEventStartMs = new AtomicReference<>(-1L);
final AtomicReference<Float> layoutShiftScore = new AtomicReference<>(-1f);
final AtomicReference<Boolean> sawNetworkQualityEstimates = new AtomicReference<>(false); final AtomicReference<Boolean> sawNetworkQualityEstimates = new AtomicReference<>(false);
CustomTabsCallback cb = new CustomTabsCallback() { CustomTabsCallback cb = new CustomTabsCallback() {
...@@ -2721,6 +2723,12 @@ public class CustomTabActivityTest { ...@@ -2721,6 +2723,12 @@ public class CustomTabActivityTest {
sawNetworkQualityEstimates.set(true); sawNetworkQualityEstimates.set(true);
} }
float layoutShiftScoreValue =
args.getFloat(PageLoadMetrics.LAYOUT_SHIFT_SCORE, -1f);
if (layoutShiftScoreValue >= 0f) {
layoutShiftScore.set(layoutShiftScoreValue);
}
long navigationStart = args.getLong(PageLoadMetrics.NAVIGATION_START, -1); long navigationStart = args.getLong(PageLoadMetrics.NAVIGATION_START, -1);
if (navigationStart == -1) { if (navigationStart == -1) {
// Untested metric callback. // Untested metric callback.
...@@ -2737,6 +2745,13 @@ public class CustomTabActivityTest { ...@@ -2737,6 +2745,13 @@ public class CustomTabActivityTest {
firstContentfulPaintMs.set(firstContentfulPaint); firstContentfulPaintMs.set(firstContentfulPaint);
} }
long largestContentfulPaint =
args.getLong(PageLoadMetrics.LARGEST_CONTENTFUL_PAINT, -1);
if (largestContentfulPaint > 0) {
Assert.assertTrue(largestContentfulPaint <= (current - navigationStart));
largestContentfulPaintMs.set(largestContentfulPaint);
}
long loadEventStart = args.getLong(PageLoadMetrics.LOAD_EVENT_START, -1); long loadEventStart = args.getLong(PageLoadMetrics.LOAD_EVENT_START, -1);
if (loadEventStart > 0) { if (loadEventStart > 0) {
Assert.assertTrue(loadEventStart <= (current - navigationStart)); Assert.assertTrue(loadEventStart <= (current - navigationStart));
...@@ -2772,6 +2787,25 @@ public class CustomTabActivityTest { ...@@ -2772,6 +2787,25 @@ public class CustomTabActivityTest {
// Expected. // Expected.
} }
assertEquals(-1L, (long) firstContentfulPaintMs.get()); assertEquals(-1L, (long) firstContentfulPaintMs.get());
try {
CriteriaHelper.pollInstrumentationThread(() -> largestContentfulPaintMs.get() > 0);
} catch (AssertionError e) {
// Expected.
}
assertEquals(-1L, (long) largestContentfulPaintMs.get());
}
// Navigate to a new page, as metrics like LCP are only reported at the end of the page load
// lifetime.
TestThreadUtils.runOnUiThreadBlocking(() -> {
final CustomTabActivity activity = mCustomTabActivityTestRule.getActivity();
activity.getComponent().resolveNavigationController().navigate("about:blank");
});
if (allowMetrics) {
CriteriaHelper.pollInstrumentationThread(() -> largestContentfulPaintMs.get() > 0);
CriteriaHelper.pollInstrumentationThread(() -> layoutShiftScore.get() != -1f);
} }
} }
......
...@@ -40,6 +40,39 @@ AndroidPageLoadMetricsObserver::OnStart( ...@@ -40,6 +40,39 @@ AndroidPageLoadMetricsObserver::OnStart(
return CONTINUE_OBSERVING; return CONTINUE_OBSERVING;
} }
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
AndroidPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
const page_load_metrics::mojom::PageLoadTiming& timing) {
// FlushMetricsOnAppEnterBackground is invoked on Android in cases where the
// app is about to be backgrounded, as part of the Activity.onPause()
// flow. After this method is invoked, Chrome may be killed without further
// notification, so we record final metrics collected up to this point.
ReportBufferedMetrics(timing);
// We continue observing after being backgrounded, in case we are foregrounded
// again without being killed. In those cases we may still report non-buffered
// metrics such as FCP after being re-foregrounded.
return CONTINUE_OBSERVING;
}
AndroidPageLoadMetricsObserver::ObservePolicy
AndroidPageLoadMetricsObserver::OnHidden(
const page_load_metrics::mojom::PageLoadTiming& timing) {
ReportBufferedMetrics(timing);
return CONTINUE_OBSERVING;
}
void AndroidPageLoadMetricsObserver::OnDidFinishSubFrameNavigation(
content::NavigationHandle* navigation_handle) {
largest_contentful_paint_handler_.OnDidFinishSubFrameNavigation(
navigation_handle, GetDelegate());
}
void AndroidPageLoadMetricsObserver::OnComplete(
const page_load_metrics::mojom::PageLoadTiming& timing) {
ReportBufferedMetrics(timing);
}
void AndroidPageLoadMetricsObserver::OnFirstContentfulPaintInPage( void AndroidPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
const page_load_metrics::mojom::PageLoadTiming& timing) { const page_load_metrics::mojom::PageLoadTiming& timing) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
...@@ -50,6 +83,14 @@ void AndroidPageLoadMetricsObserver::OnFirstContentfulPaintInPage( ...@@ -50,6 +83,14 @@ void AndroidPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
first_contentful_paint_ms); first_contentful_paint_ms);
} }
void AndroidPageLoadMetricsObserver::OnFirstInputInPage(
const page_load_metrics::mojom::PageLoadTiming& timing) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
int64_t first_input_delay_ms =
timing.interactive_timing->first_input_delay->InMilliseconds();
ReportFirstInputDelay(first_input_delay_ms);
}
void AndroidPageLoadMetricsObserver::OnFirstMeaningfulPaintInMainFrameDocument( void AndroidPageLoadMetricsObserver::OnFirstMeaningfulPaintInMainFrameDocument(
const page_load_metrics::mojom::PageLoadTiming& timing) { const page_load_metrics::mojom::PageLoadTiming& timing) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
...@@ -103,6 +144,13 @@ void AndroidPageLoadMetricsObserver::OnLoadedResource( ...@@ -103,6 +144,13 @@ void AndroidPageLoadMetricsObserver::OnLoadedResource(
} }
} }
void AndroidPageLoadMetricsObserver::OnTimingUpdate(
content::RenderFrameHost* subframe_rfh,
const page_load_metrics::mojom::PageLoadTiming& timing) {
largest_contentful_paint_handler_.RecordTiming(timing.paint_timing,
subframe_rfh);
}
void AndroidPageLoadMetricsObserver::ReportNewNavigation() { void AndroidPageLoadMetricsObserver::ReportNewNavigation() {
DCHECK_GE(navigation_id_, 0); DCHECK_GE(navigation_id_, 0);
base::android::ScopedJavaLocalRef<jobject> java_web_contents = base::android::ScopedJavaLocalRef<jobject> java_web_contents =
...@@ -112,6 +160,41 @@ void AndroidPageLoadMetricsObserver::ReportNewNavigation() { ...@@ -112,6 +160,41 @@ void AndroidPageLoadMetricsObserver::ReportNewNavigation() {
static_cast<jlong>(navigation_id_)); static_cast<jlong>(navigation_id_));
} }
void AndroidPageLoadMetricsObserver::ReportBufferedMetrics(
const page_load_metrics::mojom::PageLoadTiming& timing) {
// This method may be invoked multiple times. Make sure that if we already
// reported, we do not report again.
if (reported_buffered_metrics_)
return;
reported_buffered_metrics_ = true;
// Buffered metrics aren't available until after the navigation commits.
if (!GetDelegate().DidCommit())
return;
base::android::ScopedJavaLocalRef<jobject> java_web_contents =
GetDelegate().GetWebContents()->GetJavaWebContents();
JNIEnv* env = base::android::AttachCurrentThread();
int64_t navigation_start_tick =
(GetDelegate().GetNavigationStart() - base::TimeTicks()).InMicroseconds();
const page_load_metrics::ContentfulPaintTimingInfo& largest_contentful_paint =
largest_contentful_paint_handler_.MergeMainFrameAndSubframes();
if (!largest_contentful_paint.IsEmpty()) {
Java_PageLoadMetrics_onLargestContentfulPaint(
env, java_web_contents, static_cast<jlong>(navigation_id_),
static_cast<jlong>(navigation_start_tick),
static_cast<jlong>(largest_contentful_paint.Time()->InMilliseconds()),
static_cast<jlong>(largest_contentful_paint.Size()));
}
Java_PageLoadMetrics_onLayoutShiftScore(
env, java_web_contents, static_cast<jlong>(navigation_id_),
static_cast<jfloat>(GetDelegate()
.GetMainFrameRenderData()
.layout_shift_score_before_input_or_scroll),
static_cast<jfloat>(
GetDelegate().GetPageRenderData().layout_shift_score));
}
void AndroidPageLoadMetricsObserver::ReportNetworkQualityEstimate( void AndroidPageLoadMetricsObserver::ReportNetworkQualityEstimate(
net::EffectiveConnectionType connection_type, net::EffectiveConnectionType connection_type,
int64_t http_rtt_ms, int64_t http_rtt_ms,
...@@ -179,3 +262,13 @@ void AndroidPageLoadMetricsObserver::ReportLoadedMainResource( ...@@ -179,3 +262,13 @@ void AndroidPageLoadMetricsObserver::ReportLoadedMainResource(
static_cast<jlong>(request_start_ms), static_cast<jlong>(send_start_ms), static_cast<jlong>(request_start_ms), static_cast<jlong>(send_start_ms),
static_cast<jlong>(send_end_ms)); static_cast<jlong>(send_end_ms));
} }
void AndroidPageLoadMetricsObserver::ReportFirstInputDelay(
int64_t first_input_delay_ms) {
base::android::ScopedJavaLocalRef<jobject> java_web_contents =
GetDelegate().GetWebContents()->GetJavaWebContents();
JNIEnv* env = base::android::AttachCurrentThread();
Java_PageLoadMetrics_onFirstInputDelay(
env, java_web_contents, static_cast<jlong>(navigation_id_),
static_cast<jlong>(first_input_delay_ms));
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <jni.h> #include <jni.h>
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
namespace network { namespace network {
...@@ -23,17 +24,33 @@ class AndroidPageLoadMetricsObserver ...@@ -23,17 +24,33 @@ class AndroidPageLoadMetricsObserver
AndroidPageLoadMetricsObserver(); AndroidPageLoadMetricsObserver();
// page_load_metrics::PageLoadMetricsObserver: // page_load_metrics::PageLoadMetricsObserver:
// PageLoadMetricsObserver lifecycle callbacks
ObservePolicy OnStart(content::NavigationHandle* navigation_handle, ObservePolicy OnStart(content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url, const GURL& currently_committed_url,
bool started_in_foreground) override; bool started_in_foreground) override;
ObservePolicy FlushMetricsOnAppEnterBackground(
const page_load_metrics::mojom::PageLoadTiming& timing) override;
ObservePolicy OnHidden(
const page_load_metrics::mojom::PageLoadTiming& timing) override;
void OnDidFinishSubFrameNavigation(
content::NavigationHandle* navigation_handle) override;
void OnComplete(
const page_load_metrics::mojom::PageLoadTiming& timing) override;
// PageLoadMetricsObserver event callbacks
void OnFirstContentfulPaintInPage( void OnFirstContentfulPaintInPage(
const page_load_metrics::mojom::PageLoadTiming& timing) override; const page_load_metrics::mojom::PageLoadTiming& timing) override;
void OnFirstInputInPage(
const page_load_metrics::mojom::PageLoadTiming& timing) override;
void OnFirstMeaningfulPaintInMainFrameDocument( void OnFirstMeaningfulPaintInMainFrameDocument(
const page_load_metrics::mojom::PageLoadTiming& timing) override; const page_load_metrics::mojom::PageLoadTiming& timing) override;
void OnLoadEventStart( void OnLoadEventStart(
const page_load_metrics::mojom::PageLoadTiming& timing) override; const page_load_metrics::mojom::PageLoadTiming& timing) override;
void OnLoadedResource(const page_load_metrics::ExtraRequestCompleteInfo& void OnLoadedResource(const page_load_metrics::ExtraRequestCompleteInfo&
extra_request_complete_info) override; extra_request_complete_info) override;
void OnTimingUpdate(
content::RenderFrameHost* subframe_rfh,
const page_load_metrics::mojom::PageLoadTiming& timing) override;
protected: protected:
AndroidPageLoadMetricsObserver( AndroidPageLoadMetricsObserver(
...@@ -42,6 +59,9 @@ class AndroidPageLoadMetricsObserver ...@@ -42,6 +59,9 @@ class AndroidPageLoadMetricsObserver
virtual void ReportNewNavigation(); virtual void ReportNewNavigation();
virtual void ReportBufferedMetrics(
const page_load_metrics::mojom::PageLoadTiming& timing);
virtual void ReportNetworkQualityEstimate( virtual void ReportNetworkQualityEstimate(
net::EffectiveConnectionType connection_type, net::EffectiveConnectionType connection_type,
int64_t http_rtt_ms, int64_t http_rtt_ms,
...@@ -64,12 +84,18 @@ class AndroidPageLoadMetricsObserver ...@@ -64,12 +84,18 @@ class AndroidPageLoadMetricsObserver
int64_t send_start_ms, int64_t send_start_ms,
int64_t send_end_ms); int64_t send_end_ms);
virtual void ReportFirstInputDelay(int64_t first_input_delay_ms);
private: private:
bool did_dispatch_on_main_resource_ = false; bool did_dispatch_on_main_resource_ = false;
bool reported_buffered_metrics_ = false;
int64_t navigation_id_ = -1; int64_t navigation_id_ = -1;
network::NetworkQualityTracker* network_quality_tracker_ = nullptr; network::NetworkQualityTracker* network_quality_tracker_ = nullptr;
page_load_metrics::LargestContentfulPaintHandler
largest_contentful_paint_handler_;
DISALLOW_COPY_AND_ASSIGN(AndroidPageLoadMetricsObserver); DISALLOW_COPY_AND_ASSIGN(AndroidPageLoadMetricsObserver);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment