blob: d28c39991ea9ae3ff41eccd8e63086b2ff19c717 [file] [log] [blame]
// Copyright 2016 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.
#include <list>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <unordered_set>
#include <utility>
#include "base/feature_list.h"
#include "base/hash/hash.h"
#include "base/macros.h"
#include "base/supports_user_data.h"
#include "base/time/time.h"
#include "chrome/browser/data_use_measurement/chrome_data_use_recorder.h"
#include "components/data_use_measurement/core/data_use_ascriber.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/global_routing_id.h"
#include "url/gurl.h"
namespace content {
class RenderFrameHost;
namespace data_use_measurement {
// Disables data use ascriber if data saver is disabled.
extern const base::Feature kDisableAscriberIfDataSaverDisabled;
class URLRequestClassifier;
// Browser implementation of DataUseAscriber. Maintains a list of
// DataUseRecorder instances, one for each source of data, such as a page
// load.
// A page includes all resources loaded in response to a main page navigation.
// The scope of a page load ends either when the tab is closed or a new page
// load is initiated by clicking on a link, entering a new URL, window location
// change, etc.
// For URLRequests initiated outside the context of a page load, such as
// Service Workers, Chrome Services, etc, a new instance of DataUseRecorder
// will be created for each URLRequest.
// Each page load will be associated with an instance of DataUseRecorder.
// Each URLRequest initiated in the context of a page load will be mapped to
// the DataUseRecorder instance for page load.
// This class lives entirely on the IO thread. It maintains a copy of frame and
// navigation information on the IO thread.
class ChromeDataUseAscriber : public DataUseAscriber {
~ChromeDataUseAscriber() override;
// DataUseAscriber implementation:
ChromeDataUseRecorder* GetOrCreateDataUseRecorder(
net::URLRequest* request) override;
ChromeDataUseRecorder* GetDataUseRecorder(
const net::URLRequest& request) override;
void OnBeforeUrlRequest(net::URLRequest* request) override;
void OnUrlRequestCompleted(net::URLRequest* request, bool started) override;
void OnUrlRequestDestroyed(net::URLRequest* request) override;
std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate(
std::unique_ptr<net::NetworkDelegate> wrapped_network_delegate) override;
std::unique_ptr<URLRequestClassifier> CreateURLRequestClassifier()
const override;
// Called when a render frame host is created. When the render frame is a main
// frame, |main_render_process_id| and |main_render_frame_id| should be -1.
void RenderFrameCreated(int render_process_id,
int render_frame_id,
int main_render_process_id,
int main_render_frame_id);
// Called when a render frame host is deleted. When the render frame is a main
// frame, |main_render_process_id| and |main_render_frame_id| should be -1.
void RenderFrameDeleted(int render_process_id,
int render_frame_id,
int main_render_process_id,
int main_render_frame_id);
// Called when a main frame navigation is ready to be committed in a
// renderer.
void ReadyToCommitMainFrameNavigation(
content::GlobalRequestID global_request_id,
int render_process_id,
int render_frame_id);
// Called when the main frame navigation is committed in the renderer.
void DidFinishMainFrameNavigation(int render_process_id,
int render_frame_id,
const GURL& gurl,
bool is_same_document_navigation,
uint32_t page_transition,
base::TimeTicks time);
// Called every time the WebContents changes visibility.
void WasShownOrHidden(int main_render_process_id,
int main_render_frame_id,
bool visible);
// Called whenever one of the render frames of a WebContents is swapped.
void RenderFrameHostChanged(int old_render_process_id,
int old_render_frame_id,
int new_render_process_id,
int new_render_frame_id);
// Called when the load is finished.
void DidFinishLoad(int render_process_id,
int render_frame_id,
const GURL& validated_url);
friend class ChromeDataUseAscriberTest;
void OnUrlRequestCompletedOrDestroyed(net::URLRequest* request);
// Entry in the |data_use_recorders_| list which owns all instances of
// DataUseRecorder. std::list is used so that iterators remain valid until the
// lifetime of the container, and will not be invalidated when container is
// modified.
typedef std::list<ChromeDataUseRecorder> DataUseRecorderList;
typedef DataUseRecorderList::iterator DataUseRecorderEntry;
class DataUseRecorderEntryAsUserData : public base::SupportsUserData::Data {
explicit DataUseRecorderEntryAsUserData(DataUseRecorderEntry entry);
~DataUseRecorderEntryAsUserData() override;
DataUseRecorderEntry recorder_entry() { return entry_; }
static const void* const kDataUseAscriberUserDataKey;
DataUseRecorderEntry entry_;
// Contains the details of a main render frame.
struct MainRenderFrameEntry {
explicit MainRenderFrameEntry(
ChromeDataUseAscriber::DataUseRecorderEntry data_use_recorder);
// DataUseRecorderEntry in |data_use_recorders_| that the main frame
// ascribes data use to.
DataUseRecorderEntry data_use_recorder;
// Global requestid of the pending navigation in the main frame, if any.
// This is needed to support navigations that transfer from one mainframe to
// another.
content::GlobalRequestID pending_navigation_global_request_id;
// Visibility of the main frame, whether it is currently shown to the user.
// This is updated on WasShownOrHidden(), and passed down to DataUseRecorder
// when created. Visibility is used to record data use brokend by tab state
// histograms.
bool is_visible;
DataUseRecorderEntry GetDataUseRecorderEntry(const net::URLRequest* request);
// Validate and cleanup the URL requests that point to |entry|.
void ValidateAndCleanUp(DataUseRecorderEntry entry);
DataUseRecorderEntry GetOrCreateDataUseRecorderEntry(
net::URLRequest* request);
void NotifyPageLoadCommit(DataUseRecorderEntry entry);
void NotifyDidFinishLoad(DataUseRecorderEntry entry);
void NotifyPageLoadConcluded(DataUseRecorderEntry entry);
DataUseRecorderEntry CreateNewDataUseRecorder(
net::URLRequest* request,
DataUse::TrafficType traffic_type);
bool IsRecorderInPendingNavigationMap(net::URLRequest* request);
bool IsRecorderInRenderFrameMap(net::URLRequest* request);
void AscribeRecorderWithRequest(net::URLRequest* request,
DataUseRecorderEntry entry);
void DisableAscriber() override;
// Returns true if data use ascriber is disabled.
bool IsDisabled() const;
// Owner for all instances of DataUseRecorder. An instance is kept in this
// list if any entity (render frame hosts, URLRequests, pending navigations)
// that ascribe data use to the instance exists, and deleted when all
// ascribing entities go away.
DataUseRecorderList data_use_recorders_;
// Map from RenderFrameHost to the MainRenderFrameEntry which contains all
// details of the main frame. New entry is added on main render frame creation
// and removed on its deletion.
std::map<content::GlobalFrameRoutingId, MainRenderFrameEntry>
// Maps subframe IDs to the mainframe ID, so the mainframe lifetime can have
// ownership over the lifetime of entries in |data_use_recorders_|. Mainframes
// are mapped to themselves.
std::map<content::GlobalFrameRoutingId, content::GlobalFrameRoutingId>
// Map from pending navigations to the DataUseRecorderEntry in
// |data_use_recorders_| that the navigation ascribes data use to.
std::map<content::GlobalRequestID, DataUseRecorderEntry>
// True if the data use ascriber should be disabled. The ascriber is disabled
// by default.
bool disable_ascriber_ = true;
// Set of requests that are currently in-flight.
std::unordered_set<const net::URLRequest*> requests_;
} // namespace data_use_measurement