blob: a64a55bd8dc263e70d3204858f5074d0c208ee48 [file] [log] [blame]
// Copyright 2018 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 "chrome/browser/data_use_measurement/chrome_data_use_measurement.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "components/metrics/data_use_tracker.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/network_service_instance.h"
using content::BrowserThread;
namespace data_use_measurement {
namespace {
// Global instance to be used when network service is enabled, this will never
// be deleted. When network service is disabled, this should always be null.
ChromeDataUseMeasurement* g_chrome_data_use_measurement = nullptr;
DataUseUserData::DataUseContentType GetContentType(const std::string& mime_type,
bool is_main_frame_resource,
bool is_app_background,
bool is_tab_visible) {
if (mime_type == "text/html")
return is_main_frame_resource ? DataUseUserData::MAIN_FRAME_HTML
: DataUseUserData::NON_MAIN_FRAME_HTML;
if (mime_type == "text/css")
return DataUseUserData::CSS;
if (base::StartsWith(mime_type, "image/", base::CompareCase::SENSITIVE))
return DataUseUserData::IMAGE;
if (base::EndsWith(mime_type, "javascript", base::CompareCase::SENSITIVE) ||
base::EndsWith(mime_type, "ecmascript", base::CompareCase::SENSITIVE)) {
return DataUseUserData::JAVASCRIPT;
}
if (mime_type.find("font") != std::string::npos)
return DataUseUserData::FONT;
if (base::StartsWith(mime_type, "audio/", base::CompareCase::SENSITIVE))
return is_app_background
? DataUseUserData::AUDIO_APPBACKGROUND
: (!is_tab_visible ? DataUseUserData::AUDIO_TABBACKGROUND
: DataUseUserData::AUDIO);
if (base::StartsWith(mime_type, "video/", base::CompareCase::SENSITIVE))
return is_app_background
? DataUseUserData::VIDEO_APPBACKGROUND
: (!is_tab_visible ? DataUseUserData::VIDEO_TABBACKGROUND
: DataUseUserData::VIDEO);
return DataUseUserData::OTHER;
}
} // namespace
// static
void ChromeDataUseMeasurement::CreateInstance(PrefService* local_state) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
!BrowserThread::IsThreadInitialized(BrowserThread::UI));
DCHECK(!g_chrome_data_use_measurement);
g_chrome_data_use_measurement = new ChromeDataUseMeasurement(
content::GetNetworkConnectionTracker(), local_state);
}
// static
ChromeDataUseMeasurement* ChromeDataUseMeasurement::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
!BrowserThread::IsThreadInitialized(BrowserThread::UI));
return g_chrome_data_use_measurement;
}
// static
void ChromeDataUseMeasurement::DeleteInstance() {
if (g_chrome_data_use_measurement) {
delete g_chrome_data_use_measurement;
g_chrome_data_use_measurement = nullptr;
}
}
ChromeDataUseMeasurement::ChromeDataUseMeasurement(
network::NetworkConnectionTracker* network_connection_tracker,
PrefService* local_state)
: DataUseMeasurement(local_state, network_connection_tracker),
local_state_(local_state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void ChromeDataUseMeasurement::ReportNetworkServiceDataUse(
int32_t network_traffic_annotation_id_hash,
int64_t recv_bytes,
int64_t sent_bytes) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Negative byte numbers is not a critical problem (i.e., should have no
// security implications) but is not expected. TODO(rajendrant): remove these
// DCHECKs or consider using uint in Mojo instead.
DCHECK_GE(recv_bytes, 0);
DCHECK_GE(sent_bytes, 0);
bool is_user_request =
DataUseMeasurement::IsUserRequest(network_traffic_annotation_id_hash);
bool is_metrics_service_request =
IsMetricsServiceRequest(network_traffic_annotation_id_hash);
UpdateMetricsUsagePrefs(recv_bytes, IsCurrentNetworkCellular(),
is_metrics_service_request);
UpdateMetricsUsagePrefs(sent_bytes, IsCurrentNetworkCellular(),
is_metrics_service_request);
if (!is_user_request) {
ReportDataUsageServices(network_traffic_annotation_id_hash, UPSTREAM,
CurrentAppState(), sent_bytes);
ReportDataUsageServices(network_traffic_annotation_id_hash, DOWNSTREAM,
CurrentAppState(), recv_bytes);
}
if (!is_user_request || DataUseMeasurement::IsUserDownloadsRequest(
network_traffic_annotation_id_hash)) {
for (auto& observer : services_data_use_observer_list_)
observer.OnServicesDataUse(network_traffic_annotation_id_hash, recv_bytes,
sent_bytes);
}
base::UmaHistogramCustomCounts("DataUse.BytesReceived2.Delegate", recv_bytes,
50, 10 * 1000 * 1000, 50);
UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesSent.Delegate", sent_bytes);
}
void ChromeDataUseMeasurement::ReportUserTrafficDataUse(bool is_tab_visible,
int64_t recv_bytes) {
RecordDownstreamUserTrafficSizeMetric(is_tab_visible, recv_bytes);
}
void ChromeDataUseMeasurement::RecordContentTypeMetric(
const std::string& mime_type,
bool is_main_frame_resource,
bool is_tab_visible,
int64_t recv_bytes) {
DataUseUserData::DataUseContentType content_type = GetContentType(
mime_type, is_main_frame_resource,
CurrentAppState() == DataUseUserData::BACKGROUND, is_tab_visible);
UMA_HISTOGRAM_SCALED_ENUMERATION("DataUse.ContentType.UserTrafficKB",
content_type, recv_bytes, 1024);
}
void ChromeDataUseMeasurement::UpdateMetricsUsagePrefs(
int64_t total_bytes,
bool is_cellular,
bool is_metrics_service_usage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(local_state_);
metrics::DataUseTracker::UpdateMetricsUsagePrefs(
base::saturated_cast<int>(total_bytes), is_cellular,
is_metrics_service_usage, local_state_);
}
// static
void ChromeDataUseMeasurement::RegisterPrefs(PrefRegistrySimple* registry) {
DataUseMeasurement::RegisterDataUseComponentLocalStatePrefs(registry);
}
} // namespace data_use_measurement