| Index: chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
|
| diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
|
| index a41f0296c23da9b94cc5a08cd2084f2128059a3c..366e5d45178ef8ecafa330e5d36ed04d0f84f961 100644
|
| --- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
|
| +++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
|
| @@ -4,7 +4,10 @@
|
|
|
| #include "chrome/browser/data_use_measurement/chrome_data_use_ascriber.h"
|
|
|
| +#include <string>
|
| +
|
| #include "base/memory/ptr_util.h"
|
| +#include "chrome/browser/data_use_measurement/chrome_data_use_recorder.h"
|
| #include "components/data_use_measurement/content/content_url_request_classifier.h"
|
| #include "components/data_use_measurement/core/data_use_recorder.h"
|
| #include "components/data_use_measurement/core/data_use_user_data.h"
|
| @@ -14,6 +17,7 @@
|
| #include "content/public/browser/render_frame_host.h"
|
| #include "content/public/browser/resource_request_info.h"
|
| #include "content/public/common/browser_side_navigation_policy.h"
|
| +#include "ipc/ipc_message.h"
|
| #include "net/url_request/url_request.h"
|
|
|
| namespace data_use_measurement {
|
| @@ -39,14 +43,100 @@ ChromeDataUseAscriber::~ChromeDataUseAscriber() {
|
| DCHECK_EQ(0u, data_use_recorders_.size());
|
| }
|
|
|
| -DataUseRecorder* ChromeDataUseAscriber::GetDataUseRecorder(
|
| - net::URLRequest* request) {
|
| +ChromeDataUseRecorder* ChromeDataUseAscriber::GetDataUseRecorder(
|
| + net::URLRequest* request,
|
| + bool can_create_new) {
|
| + DataUseRecorderEntry entry = GetDataUseRecorderEntry(request, can_create_new);
|
| + return entry == data_use_recorders_.end() ? nullptr : &(*entry);
|
| +}
|
| +
|
| +ChromeDataUseAscriber::DataUseRecorderEntry
|
| +ChromeDataUseAscriber::GetDataUseRecorderEntry(net::URLRequest* request,
|
| + bool can_create_new) {
|
| DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
| - return nullptr;
|
| +
|
| + // TODO(ryansturm): Handle PlzNavigate (http://crbug/664233).
|
| + if (content::IsBrowserSideNavigationEnabled())
|
| + return data_use_recorders_.end();
|
| +
|
| + // If a DataUseRecorder has already been set as user data, then return that.
|
| + auto user_data = static_cast<DataUseRecorderEntryAsUserData*>(
|
| + request->GetUserData(DataUseRecorderEntryAsUserData::kUserDataKey));
|
| + if (user_data)
|
| + return user_data->recorder_entry();
|
| +
|
| + if (!can_create_new)
|
| + return data_use_recorders_.end();
|
| +
|
| + // If request is associated with a ChromeService, create a new
|
| + // DataUseRecorder for it. There is no reason to aggregate URLRequests
|
| + // from ChromeServices into the same DataUseRecorder instance.
|
| + DataUseUserData* service = static_cast<DataUseUserData*>(
|
| + request->GetUserData(DataUseUserData::kUserDataKey));
|
| + if (service) {
|
| + DataUseRecorderEntry entry = CreateNewDataUseRecorder(request);
|
| +
|
| + entry->data_use().set_description(
|
| + DataUseUserData::GetServiceNameAsString(service->service_name()));
|
| + return entry;
|
| + }
|
| +
|
| + int render_process_id = -1;
|
| + int render_frame_id = -1;
|
| + bool has_valid_frame = content::ResourceRequestInfo::GetRenderFrameForRequest(
|
| + request, &render_process_id, &render_frame_id);
|
| + if (has_valid_frame &&
|
| + render_frame_id != SpecialRoutingIDs::MSG_ROUTING_NONE) {
|
| + DCHECK(render_process_id >= 0 || render_frame_id >= 0);
|
| +
|
| + // Browser tests may not set up DataUseWebContentsObservers in which case
|
| + // this class never sees navigation and frame events so DataUseRecorders
|
| + // will never be destroyed. To avoid this, we ignore requests whose
|
| + // render frames don't have a record. However, this can also be caused by
|
| + // URLRequests racing the frame create events.
|
| + // TODO(kundaji): Add UMA.
|
| + RenderFrameHostID frame_key(render_process_id, render_frame_id);
|
| + auto frame_iter = render_frame_data_use_map_.find(frame_key);
|
| + if (frame_iter == render_frame_data_use_map_.end()) {
|
| + return data_use_recorders_.end();
|
| + }
|
| +
|
| + const content::ResourceRequestInfo* request_info =
|
| + content::ResourceRequestInfo::ForRequest(request);
|
| + content::ResourceType resource_type =
|
| + request_info ? request_info->GetResourceType()
|
| + : content::RESOURCE_TYPE_LAST_TYPE;
|
| +
|
| + if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
|
| + content::GlobalRequestID navigation_key =
|
| + request_info->GetGlobalRequestID();
|
| +
|
| + DataUseRecorderEntry new_entry = CreateNewDataUseRecorder(request);
|
| + new_entry->set_main_frame_request_id(navigation_key);
|
| + pending_navigation_data_use_map_.insert(
|
| + std::make_pair(navigation_key, new_entry));
|
| +
|
| + return new_entry;
|
| + }
|
| +
|
| + DCHECK(frame_iter != render_frame_data_use_map_.end());
|
| + auto entry = frame_iter->second;
|
| + request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey,
|
| + new DataUseRecorderEntryAsUserData(entry));
|
| + entry->AddPendingURLRequest(request);
|
| + return entry;
|
| + }
|
| +
|
| + // Create a new DataUseRecorder for all other requests.
|
| + DataUseRecorderEntry entry = CreateNewDataUseRecorder(request);
|
| + DataUse& data_use = entry->data_use();
|
| + data_use.set_url(request->url());
|
| + return entry;
|
| }
|
|
|
| void ChromeDataUseAscriber::OnBeforeUrlRequest(net::URLRequest* request) {
|
| DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
| + DataUseAscriber::OnBeforeUrlRequest(request);
|
|
|
| // TODO(kundaji): Handle PlzNavigate.
|
| if (content::IsBrowserSideNavigationEnabled())
|
| @@ -90,8 +180,8 @@ void ChromeDataUseAscriber::OnBeforeUrlRequest(net::URLRequest* request) {
|
| if (user_data)
|
| return;
|
|
|
| - DataUseRecorderEntry entry = data_use_recorders_.insert(
|
| - data_use_recorders_.end(), base::MakeUnique<DataUseRecorder>());
|
| + DataUseRecorderEntry entry = data_use_recorders_.emplace(
|
| + data_use_recorders_.end());
|
| request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey,
|
| new DataUseRecorderEntryAsUserData(entry));
|
| pending_navigation_data_use_map_.insert(
|
| @@ -99,18 +189,51 @@ void ChromeDataUseAscriber::OnBeforeUrlRequest(net::URLRequest* request) {
|
| }
|
|
|
| void ChromeDataUseAscriber::OnUrlRequestDestroyed(net::URLRequest* request) {
|
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
| +
|
| + DataUseRecorderEntry entry = GetDataUseRecorderEntry(request, true);
|
| +
|
| + if (entry == data_use_recorders_.end())
|
| + return;
|
| +
|
| + DataUseRecorder* recorder = &(*entry);
|
| +
|
| + RenderFrameHostID frame_key = entry->main_frame_id();
|
| + auto frame_iter = render_frame_data_use_map_.find(frame_key);
|
| + bool is_in_render_frame_map =
|
| + frame_iter != render_frame_data_use_map_.end() &&
|
| + frame_iter->second->HasPendingURLRequest(request);
|
| +
|
| const content::ResourceRequestInfo* request_info =
|
| content::ResourceRequestInfo::ForRequest(request);
|
| content::ResourceType resource_type = request_info
|
| ? request_info->GetResourceType()
|
| : content::RESOURCE_TYPE_LAST_TYPE;
|
| - if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
|
| - // If request was not successful, then ReadyToCommitNavigation will not be
|
| - // called. So delete the pending navigation DataUseRecorderEntry here.
|
| - if (!request->status().is_success()) {
|
| - DeletePendingNavigationEntry(request_info->GetGlobalRequestID());
|
| +
|
| + bool is_in_pending_navigation_map = false;
|
| + if (request_info && resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
|
| + auto navigation_iter = pending_navigation_data_use_map_.find(
|
| + entry->main_frame_request_id());
|
| + is_in_pending_navigation_map =
|
| + navigation_iter != pending_navigation_data_use_map_.end();
|
| +
|
| + // If request was not successful, then NavigationHandle in
|
| + // DidFinishMainFrameNavigation will not have GlobalRequestID. So we erase
|
| + // the DataUseRecorderEntry here.
|
| + if (is_in_pending_navigation_map && !request->status().is_success()) {
|
| + pending_navigation_data_use_map_.erase(navigation_iter);
|
| + is_in_pending_navigation_map = false;
|
| }
|
| }
|
| +
|
| + DataUseAscriber::OnUrlRequestDestroyed(request);
|
| + request->RemoveUserData(DataUseRecorderEntryAsUserData::kUserDataKey);
|
| +
|
| + if (recorder->IsDataUseComplete() && !is_in_render_frame_map &&
|
| + !is_in_pending_navigation_map) {
|
| + OnDataUseCompleted(entry);
|
| + data_use_recorders_.erase(entry);
|
| + }
|
| }
|
|
|
| void ChromeDataUseAscriber::RenderFrameCreated(int render_process_id,
|
| @@ -119,12 +242,30 @@ void ChromeDataUseAscriber::RenderFrameCreated(int render_process_id,
|
| int parent_render_frame_id) {
|
| DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
|
|
| - // TODO(kundaji): Point child render frames to the same DataUseRecorder as
|
| - // parent render frame.
|
| - DataUseRecorderEntry entry = data_use_recorders_.insert(
|
| - data_use_recorders_.end(), base::MakeUnique<DataUseRecorder>());
|
| - render_frame_data_use_map_.insert(std::make_pair(
|
| - RenderFrameHostID(render_process_id, render_frame_id), entry));
|
| + if (content::IsBrowserSideNavigationEnabled())
|
| + return;
|
| +
|
| + if (parent_render_process_id != -1 && parent_render_frame_id != -1) {
|
| + // Create an entry in |render_frame_data_use_map_| for this frame with
|
| + // the same DataUseRecorderEntry as its parent frame.
|
| + auto frame_iter = render_frame_data_use_map_.find(
|
| + RenderFrameHostID(parent_render_process_id, parent_render_frame_id));
|
| +
|
| + DCHECK(frame_iter != render_frame_data_use_map_.end());
|
| +
|
| + DataUseRecorderEntry entry = frame_iter->second;
|
| + render_frame_data_use_map_.insert(std::make_pair(
|
| + RenderFrameHostID(render_process_id, render_frame_id), entry));
|
| + } else {
|
| + auto frame_iter = render_frame_data_use_map_.find(
|
| + RenderFrameHostID(render_process_id, render_frame_id));
|
| + DCHECK(frame_iter == render_frame_data_use_map_.end());
|
| + DataUseRecorderEntry entry = CreateNewDataUseRecorder(nullptr);
|
| + entry->set_main_frame_id(
|
| + RenderFrameHostID(render_process_id, render_frame_id));
|
| + render_frame_data_use_map_.insert(std::make_pair(
|
| + RenderFrameHostID(render_process_id, render_frame_id), entry));
|
| + }
|
| }
|
|
|
| void ChromeDataUseAscriber::RenderFrameDeleted(int render_process_id,
|
| @@ -132,13 +273,25 @@ void ChromeDataUseAscriber::RenderFrameDeleted(int render_process_id,
|
| int parent_render_process_id,
|
| int parent_render_frame_id) {
|
| DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
| +
|
| + if (content::IsBrowserSideNavigationEnabled())
|
| + return;
|
| +
|
| RenderFrameHostID key(render_process_id, render_frame_id);
|
| auto frame_iter = render_frame_data_use_map_.find(key);
|
| +
|
| DCHECK(frame_iter != render_frame_data_use_map_.end());
|
| +
|
| DataUseRecorderEntry entry = frame_iter->second;
|
| - render_frame_data_use_map_.erase(frame_iter);
|
| + DataUseRecorder* recorder = &(*entry);
|
| +
|
| + if (parent_render_process_id == -1 && parent_render_frame_id == -1 &&
|
| + recorder->IsDataUseComplete()) {
|
| + OnDataUseCompleted(entry);
|
| + data_use_recorders_.erase(entry);
|
| + }
|
|
|
| - data_use_recorders_.erase(entry);
|
| + render_frame_data_use_map_.erase(frame_iter);
|
| }
|
|
|
| void ChromeDataUseAscriber::DidStartMainFrameNavigation(
|
| @@ -158,36 +311,106 @@ void ChromeDataUseAscriber::ReadyToCommitMainFrameNavigation(
|
| void* navigation_handle) {
|
| DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
|
|
| - // TODO(kundaji): Move the DataUseRecorderEntry from pending navigation map
|
| - // to render frame map if |is_same_page_navigation| is true. Otherwise,
|
| - // merge it with the DataUseRecorderEntry in the render frame map.
|
| - DeletePendingNavigationEntry(global_request_id);
|
| -}
|
| + // Find the DataUseRecorderEntry the frame is associated with
|
| + auto frame_it = render_frame_data_use_map_.find(
|
| + RenderFrameHostID(render_process_id, render_frame_id));
|
|
|
| -void ChromeDataUseAscriber::DidRedirectMainFrameNavigation(
|
| - GURL gurl,
|
| - int render_process_id,
|
| - int render_frame_id,
|
| - void* navigation_handle) {
|
| - DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
| -}
|
| -
|
| -void ChromeDataUseAscriber::DeletePendingNavigationEntry(
|
| - content::GlobalRequestID global_request_id) {
|
| + // Find the pending navigation entry.
|
| auto navigation_iter =
|
| pending_navigation_data_use_map_.find(global_request_id);
|
| - // Pending navigation entry will not be found if finish navigation
|
| - // raced the URLRequest.
|
| - if (navigation_iter != pending_navigation_data_use_map_.end()) {
|
| - auto entry = navigation_iter->second;
|
| - pending_navigation_data_use_map_.erase(navigation_iter);
|
| + // We might not find a navigation entry since the pending navigation may not
|
| + // have caused any HTTP or HTTPS URLRequests to be made.
|
| + if (navigation_iter == pending_navigation_data_use_map_.end()) {
|
| + // No pending navigation entry to worry about. However, the old frame entry
|
| + // must be removed from frame map, and possibly marked complete and deleted.
|
| + if (frame_it != render_frame_data_use_map_.end()) {
|
| + DataUseRecorderEntry old_frame_entry = frame_it->second;
|
| + render_frame_data_use_map_.erase(frame_it);
|
| + if (old_frame_entry->IsDataUseComplete()) {
|
| + OnDataUseCompleted(old_frame_entry);
|
| + data_use_recorders_.erase(old_frame_entry);
|
| + }
|
| +
|
| + // Add a new recorder to the render frame map to replace the deleted one.
|
| + DataUseRecorderEntry entry = data_use_recorders_.emplace(
|
| + data_use_recorders_.end());
|
| + render_frame_data_use_map_.insert(std::make_pair(
|
| + RenderFrameHostID(render_process_id, render_frame_id), entry));
|
| + }
|
| + return;
|
| + }
|
| +
|
| + DataUseRecorderEntry entry = navigation_iter->second;
|
| + pending_navigation_data_use_map_.erase(navigation_iter);
|
| + entry->set_main_frame_id(
|
| + RenderFrameHostID(render_process_id, render_frame_id));
|
| +
|
| + // If the frame has already been deleted then mark this navigation as having
|
| + // completed its data use.
|
| + if (frame_it == render_frame_data_use_map_.end()) {
|
| + if (entry->IsDataUseComplete()) {
|
| + OnDataUseCompleted(entry);
|
| + data_use_recorders_.erase(entry);
|
| + }
|
| + return;
|
| + }
|
| + DataUseRecorderEntry old_frame_entry = frame_it->second;
|
| + if (is_same_page_navigation) {
|
| + old_frame_entry->MergeFrom(&(*entry));
|
| +
|
| + for (auto request : entry->pending_url_requests()) {
|
| + request->RemoveUserData(DataUseRecorderEntryAsUserData::kUserDataKey);
|
| + request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey,
|
| + new DataUseRecorderEntryAsUserData(old_frame_entry));
|
| + old_frame_entry->AddPendingURLRequest(request);
|
| + }
|
| +
|
| + entry->RemoveAllPendingURLRequests();
|
| +
|
| data_use_recorders_.erase(entry);
|
| + } else {
|
| + // Navigation is not same page, so remove old entry from
|
| + // |render_frame_data_use_map_|, possibly marking it complete.
|
| + render_frame_data_use_map_.erase(frame_it);
|
| + if (old_frame_entry->IsDataUseComplete()) {
|
| + OnDataUseCompleted(old_frame_entry);
|
| + data_use_recorders_.erase(old_frame_entry);
|
| + }
|
| +
|
| + DataUse& data_use = entry->data_use();
|
| +
|
| + DCHECK(!data_use.url().is_valid() || data_use.url() == gurl)
|
| + << "is valid: " << data_use.url().is_valid()
|
| + << "; data_use.url(): " << data_use.url().spec()
|
| + << "; gurl: " << gurl.spec();
|
| + if (!data_use.url().is_valid()) {
|
| + data_use.set_url(gurl);
|
| + }
|
| +
|
| + render_frame_data_use_map_.insert(std::make_pair(
|
| + RenderFrameHostID(render_process_id, render_frame_id), entry));
|
| }
|
| }
|
|
|
| +void ChromeDataUseAscriber::OnDataUseCompleted(DataUseRecorderEntry entry) {
|
| + // TODO(ryansturm): Notify observers that data use is complete.
|
| +}
|
| +
|
| std::unique_ptr<URLRequestClassifier>
|
| ChromeDataUseAscriber::CreateURLRequestClassifier() const {
|
| return base::MakeUnique<ContentURLRequestClassifier>();
|
| }
|
|
|
| +ChromeDataUseAscriber::DataUseRecorderEntry
|
| +ChromeDataUseAscriber::CreateNewDataUseRecorder(net::URLRequest* request) {
|
| + DataUseRecorderEntry entry = data_use_recorders_.emplace(
|
| + data_use_recorders_.end());
|
| + if (request) {
|
| + entry->AddPendingURLRequest(request);
|
| + request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey,
|
| + new DataUseRecorderEntryAsUserData(entry));
|
| + }
|
| + return entry;
|
| +}
|
| +
|
| } // namespace data_use_measurement
|
|
|