blob: 1aaf3f59b226ba0dec087c109d60ae258ac3c0c6 [file] [log] [blame]
// Copyright 2017 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_UPDATE_DISPATCHER_H_
#define CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_UPDATE_DISPATCHER_H_
#include <map>
#include <memory>
#include "base/macros.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h"
namespace content {
class NavigationHandle;
class RenderFrameHost;
} // namespace content
namespace page_load_metrics {
class PageLoadMetricsEmbedderInterface;
namespace internal {
// Used to track the status of PageLoadTimings received from the render process.
//
// If you add elements to this enum, make sure you update the enum value in
// histograms.xml. Only add elements to the end to prevent inconsistencies
// between versions.
enum PageLoadTimingStatus {
// The PageLoadTiming is valid (all data within the PageLoadTiming is
// consistent with expectations).
VALID,
// All remaining status codes are for invalid PageLoadTimings.
// The PageLoadTiming was empty.
INVALID_EMPTY_TIMING,
// The PageLoadTiming had a null navigation_start.
INVALID_NULL_NAVIGATION_START,
// Script load or execution durations in the PageLoadTiming were too long.
INVALID_SCRIPT_LOAD_LONGER_THAN_PARSE,
INVALID_SCRIPT_EXEC_LONGER_THAN_PARSE,
INVALID_SCRIPT_LOAD_DOC_WRITE_LONGER_THAN_SCRIPT_LOAD,
INVALID_SCRIPT_EXEC_DOC_WRITE_LONGER_THAN_SCRIPT_EXEC,
// The order of two events in the PageLoadTiming was invalid. Either the first
// wasn't present when the second was present, or the second was reported as
// happening before the first.
INVALID_ORDER_RESPONSE_START_PARSE_START,
INVALID_ORDER_PARSE_START_PARSE_STOP,
INVALID_ORDER_PARSE_STOP_DOM_CONTENT_LOADED,
INVALID_ORDER_DOM_CONTENT_LOADED_LOAD,
INVALID_ORDER_PARSE_START_FIRST_LAYOUT,
INVALID_ORDER_FIRST_LAYOUT_FIRST_PAINT,
// Deprecated but not removing because it would affect histogram enumeration.
INVALID_ORDER_FIRST_PAINT_FIRST_TEXT_PAINT,
INVALID_ORDER_FIRST_PAINT_FIRST_IMAGE_PAINT,
INVALID_ORDER_FIRST_PAINT_FIRST_CONTENTFUL_PAINT,
INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT,
INVALID_ORDER_FIRST_MEANINGFUL_PAINT_PAGE_INTERACTIVE,
// We received a first input delay without a first input timestamp.
INVALID_NULL_FIRST_INPUT_TIMESTAMP,
// We received a first input timestamp without a first input delay.
INVALID_NULL_FIRST_INPUT_DELAY,
// We received a longest input delay without a longest input timestamp.
INVALID_NULL_LONGEST_INPUT_TIMESTAMP,
// We received a longest input timestamp without a longest input delay.
INVALID_NULL_LONGEST_INPUT_DELAY,
// Longest input delay cannot happen before first input delay.
INVALID_LONGEST_INPUT_TIMESTAMP_LESS_THAN_FIRST_INPUT_TIMESTAMP,
// Longest input delay cannot be less than first input delay.
INVALID_LONGEST_INPUT_DELAY_LESS_THAN_FIRST_INPUT_DELAY,
// New values should be added before this final entry.
LAST_PAGE_LOAD_TIMING_STATUS
};
extern const char kPageLoadTimingStatus[];
extern const char kHistogramOutOfOrderTiming[];
extern const char kHistogramOutOfOrderTimingBuffered[];
} // namespace internal
// PageLoadMetricsUpdateDispatcher manages updates to page load metrics data,
// and dispatches them to the Client. PageLoadMetricsUpdateDispatcher may delay
// dispatching metrics updates to the Client in cases where metrics state hasn't
// stabilized.
class PageLoadMetricsUpdateDispatcher {
public:
// The Client class is updated when metrics managed by the dispatcher have
// changed. Typically it owns the dispatcher.
class Client {
public:
virtual ~Client() {}
virtual void OnTimingChanged() = 0;
virtual void OnSubFrameTimingChanged(
content::RenderFrameHost* rfh,
const mojom::PageLoadTiming& timing) = 0;
virtual void OnMainFrameMetadataChanged() = 0;
virtual void OnSubframeMetadataChanged() = 0;
virtual void UpdateFeaturesUsage(
content::RenderFrameHost* rfh,
const mojom::PageLoadFeatures& new_features) = 0;
virtual void UpdateResourceDataUse(
int frame_tree_node_id,
const std::vector<mojom::ResourceDataUpdatePtr>& resources) = 0;
};
// The |client| instance must outlive this object.
PageLoadMetricsUpdateDispatcher(
Client* client,
content::NavigationHandle* navigation_handle,
PageLoadMetricsEmbedderInterface* embedder_interface);
~PageLoadMetricsUpdateDispatcher();
void UpdateMetrics(content::RenderFrameHost* render_frame_host,
mojom::PageLoadTimingPtr new_timing,
mojom::PageLoadMetadataPtr new_metadata,
mojom::PageLoadFeaturesPtr new_features,
const std::vector<mojom::ResourceDataUpdatePtr>& resources,
mojom::PageRenderDataPtr render_data);
// This method is only intended to be called for PageLoadFeatures being
// recorded directly from the browser process. Features coming from the
// renderer process should use the main flow into |UpdateMetrics|.
void UpdateFeatures(content::RenderFrameHost* render_frame_host,
const mojom::PageLoadFeatures& new_features);
void DidFinishSubFrameNavigation(
content::NavigationHandle* navigation_handle);
void ShutDown();
const mojom::PageLoadTiming& timing() const {
return *(current_merged_page_timing_.get());
}
const mojom::PageLoadMetadata& main_frame_metadata() const {
return *(main_frame_metadata_.get());
}
const mojom::PageLoadMetadata& subframe_metadata() const {
return *(subframe_metadata_.get());
}
const mojom::PageRenderData& main_frame_render_data() const {
return *(main_frame_render_data_.get());
}
private:
using FrameTreeNodeId = int;
void UpdateMainFrameTiming(mojom::PageLoadTimingPtr new_timing);
void UpdateSubFrameTiming(content::RenderFrameHost* render_frame_host,
mojom::PageLoadTimingPtr new_timing);
void UpdateMainFrameMetadata(mojom::PageLoadMetadataPtr new_metadata);
void UpdateSubFrameMetadata(mojom::PageLoadMetadataPtr subframe_metadata);
void UpdateMainFrameRenderData(mojom::PageRenderDataPtr render_data);
void MaybeDispatchTimingUpdates(bool did_merge_new_timing_value);
void DispatchTimingUpdates();
// The client is guaranteed to outlive this object.
Client* const client_;
std::unique_ptr<base::OneShotTimer> timer_;
// Time the navigation for this page load was initiated.
const base::TimeTicks navigation_start_;
// PageLoadTiming for the currently tracked page. The fields in |paint_timing|
// are merged across all frames in the document. All other fields are from the
// main frame document. |current_merged_page_timing_| contains the most recent
// valid page load timing data, while pending_merged_page_timing_ contains
// pending updates received since |current_merged_page_timing_| was last
// dispatched to the client. pending_merged_page_timing_ will be copied to
// |current_merged_page_timing_| once it is valid, at the time the
// Client::OnTimingChanged callback is invoked.
mojom::PageLoadTimingPtr current_merged_page_timing_;
mojom::PageLoadTimingPtr pending_merged_page_timing_;
mojom::PageLoadMetadataPtr main_frame_metadata_;
mojom::PageLoadMetadataPtr subframe_metadata_;
mojom::PageRenderDataPtr main_frame_render_data_;
// Navigation start offsets for the most recently committed document in each
// frame.
std::map<FrameTreeNodeId, base::TimeDelta> subframe_navigation_start_offset_;
DISALLOW_COPY_AND_ASSIGN(PageLoadMetricsUpdateDispatcher);
};
} // namespace page_load_metrics
#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_UPDATE_DISPATCHER_H_