blob: e980aa92963549b267595fec2d6b145e34dc2e8d [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_PREDICTORS_LOADING_DATA_COLLECTOR_H_
#define CHROME_BROWSER_PREDICTORS_LOADING_DATA_COLLECTOR_H_
#include <map>
#include <memory>
#include <string>
#include "base/containers/flat_set.h"
#include "base/memory/weak_ptr.h"
#include "base/types/id_type.h"
#include "chrome/browser/predictors/loading_predictor_config.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/fetch_api.mojom-forward.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-forward.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
class NavigationHandle;
} // namespace content
namespace predictors {
class LoadingStatsCollector;
struct OptimizationGuidePrediction;
class ResourcePrefetchPredictor;
using NavigationId = base::IdType64<content::NavigationHandle>;
// Data collected for origin-based prediction, for a single origin during a
// page load (see PageRequestSummary).
struct OriginRequestSummary {
OriginRequestSummary();
OriginRequestSummary(const OriginRequestSummary& other);
~OriginRequestSummary();
url::Origin origin;
bool always_access_network = false;
bool accessed_network = false;
int first_occurrence = 0;
};
// Stores the data learned from a single navigation.
struct PageRequestSummary {
PageRequestSummary(ukm::SourceId ukm_source_id,
const GURL& main_frame_url,
base::TimeTicks creation_time);
PageRequestSummary(const PageRequestSummary& other);
~PageRequestSummary();
void UpdateOrAddResource(
const blink::mojom::ResourceLoadInfo& resource_load_info);
void AddPreconnectAttempt(const GURL& preconnect_url);
void AddPrefetchAttempt(const GURL& prefetch_url);
ukm::SourceId ukm_source_id;
GURL main_frame_url;
GURL initial_url;
base::TimeTicks navigation_started;
base::TimeTicks navigation_committed;
base::TimeTicks first_contentful_paint;
// Map of origin -> OriginRequestSummary. Only one instance of each origin
// is kept per navigation, but the summary is updated several times.
std::map<url::Origin, OriginRequestSummary> origins;
// Set of origins for which preconnects were initiated.
base::flat_set<url::Origin> preconnect_origins;
// Set of seen resource URLs.
base::flat_set<GURL> subresource_urls;
// Set of resource URLs for which prefetches were initiated.
base::flat_set<GURL> prefetch_urls;
// The time for which the first resource prefetch was initiated for the
// navigation.
absl::optional<base::TimeTicks> first_prefetch_initiated;
private:
void UpdateOrAddToOrigins(
const url::Origin& origin,
const blink::mojom::CommonNetworkInfoPtr& network_info);
};
// Records navigation events as reported by various observers to the database
// and stats collection classes. All the non-static methods of this class need
// to be called on the UI thread.
class LoadingDataCollector {
public:
explicit LoadingDataCollector(
predictors::ResourcePrefetchPredictor* predictor,
predictors::LoadingStatsCollector* stats_collector,
const LoadingPredictorConfig& config);
virtual ~LoadingDataCollector();
// |LoadingPredictorTabHelper| calls the below functions to inform the
// collector of navigation and resource load events.
virtual void RecordStartNavigation(NavigationId navigation_id,
ukm::SourceId ukm_source_id,
const GURL& main_frame_url,
base::TimeTicks creation_time);
virtual void RecordFinishNavigation(NavigationId navigation_id,
const GURL& old_main_frame_url,
const GURL& new_main_frame_url,
bool is_error_page);
virtual void RecordResourceLoadComplete(
NavigationId navigation_id,
const blink::mojom::ResourceLoadInfo& resource_load_info);
// Called when a preconnect is initiated for the navigation.
virtual void RecordPreconnectInitiated(NavigationId navigation_id,
const GURL& preconnect_url);
// Called when a prefetch is initiated for the navigation.
virtual void RecordPrefetchInitiated(NavigationId navigation_id,
const GURL& prefetch_url);
// Called when the main frame of a page completes loading. We treat this point
// as the "completion" of the navigation. The resources requested by the page
// up to this point are the only ones considered.
virtual void RecordMainFrameLoadComplete(
NavigationId navigation_id,
const absl::optional<OptimizationGuidePrediction>&
optimization_guide_prediction);
// Called after the main frame's first contentful paint.
virtual void RecordFirstContentfulPaint(
NavigationId navigation_id,
base::TimeTicks first_contentful_paint);
private:
using NavigationMap =
std::map<NavigationId, std::unique_ptr<PageRequestSummary>>;
friend class LoadingDataCollectorTest;
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest, HandledResourceTypes);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest, ShouldRecordMainFrameLoad);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest,
ShouldRecordSubresourceLoadAfterFCP);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest,
ShouldRecordSubresourceLoad);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest, SimpleNavigation);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest, SimpleRedirect);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest,
RecordStartNavigationMissing);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest, RecordFailedNavigation);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest, ManyNavigations);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest,
RecordResourceLoadComplete);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest,
RecordPreconnectInitiatedNoInflightNavigation);
FRIEND_TEST_ALL_PREFIXES(LoadingDataCollectorTest,
RecordPrefetchInitiatedNoInflightNavigation);
static void SetAllowPortInUrlsForTesting(bool state);
bool ShouldRecordResourceLoad(
const blink::mojom::ResourceLoadInfo& resource_load_info) const;
// Returns true if the resource has a supported type.
static bool IsHandledResourceType(
network::mojom::RequestDestination destination,
const std::string& mime_type);
// Cleanup inflight_navigations_ and call a cleanup for stats_collector_.
void CleanupAbandonedNavigations(NavigationId navigation_id);
ResourcePrefetchPredictor* const predictor_;
LoadingStatsCollector* const stats_collector_;
const LoadingPredictorConfig config_;
NavigationMap inflight_navigations_;
};
} // namespace predictors
#endif // CHROME_BROWSER_PREDICTORS_LOADING_DATA_COLLECTOR_H_