summaryrefslogtreecommitdiff
path: root/chromium/components/data_use_measurement
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/data_use_measurement')
-rw-r--r--chromium/components/data_use_measurement/core/BUILD.gn10
-rw-r--r--chromium/components/data_use_measurement/core/DEPS1
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement.cc156
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement.h72
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc47
-rw-r--r--chromium/components/data_use_measurement/core/data_use_pref_names.h30
-rw-r--r--chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc130
-rw-r--r--chromium/components/data_use_measurement/core/data_use_tracker_prefs.h70
-rw-r--r--chromium/components/data_use_measurement/core/data_use_tracker_prefs_unittest.cc173
9 files changed, 606 insertions, 83 deletions
diff --git a/chromium/components/data_use_measurement/core/BUILD.gn b/chromium/components/data_use_measurement/core/BUILD.gn
index 29dd799f1de..775b77a2752 100644
--- a/chromium/components/data_use_measurement/core/BUILD.gn
+++ b/chromium/components/data_use_measurement/core/BUILD.gn
@@ -19,24 +19,32 @@ static_library("ascriber") {
"data_use.h",
"data_use_measurement.cc",
"data_use_measurement.h",
+ "data_use_pref_names.h",
+ "data_use_tracker_prefs.cc",
+ "data_use_tracker_prefs.h",
]
deps = [
":core",
"//base",
"//components/metrics",
+ "//components/prefs",
"//net",
"//services/network/public/cpp:cpp",
]
}
source_set("unit_tests") {
- sources = [ "data_use_measurement_unittest.cc" ]
+ sources = [
+ "data_use_measurement_unittest.cc",
+ "data_use_tracker_prefs_unittest.cc",
+ ]
testonly = true
deps = [
":ascriber",
":core",
"//base/test:test_support",
"//components/metrics:metrics",
+ "//components/prefs:test_support",
"//net:test_support",
"//services/network:test_support",
"//testing/gtest",
diff --git a/chromium/components/data_use_measurement/core/DEPS b/chromium/components/data_use_measurement/core/DEPS
index 9592232ea5d..c620476d474 100644
--- a/chromium/components/data_use_measurement/core/DEPS
+++ b/chromium/components/data_use_measurement/core/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+net",
"+components/metrics",
+ "+components/prefs",
"+services/network/public/cpp",
"+services/network/test",
]
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement.cc b/chromium/components/data_use_measurement/core/data_use_measurement.cc
index b570ead3738..51708b685e6 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement.cc
+++ b/chromium/components/data_use_measurement/core/data_use_measurement.cc
@@ -12,6 +12,8 @@
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/stringprintf.h"
+#include "base/time/clock.h"
+#include "base/time/default_clock.h"
#include "build/build_config.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
@@ -25,6 +27,20 @@ namespace data_use_measurement {
namespace {
+#if defined(OS_ANDROID)
+bool IsInForeground(base::android::ApplicationState state) {
+ switch (state) {
+ case base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES:
+ return true;
+ case base::android::APPLICATION_STATE_UNKNOWN:
+ case base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES:
+ case base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES:
+ case base::android::APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES:
+ return false;
+ }
+}
+#endif
+
// Records the occurrence of |sample| in |name| histogram. Conventional UMA
// histograms are not used because the |name| is not static.
void RecordUMAHistogramCount(const std::string& name, int64_t sample) {
@@ -41,24 +57,13 @@ void RecordUMAHistogramCount(const std::string& name, int64_t sample) {
} // namespace
DataUseMeasurement::DataUseMeasurement(
+ PrefService* pref_service,
network::NetworkConnectionTracker* network_connection_tracker)
- :
-#if defined(OS_ANDROID)
- app_state_(base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES),
- app_listener_(base::android::ApplicationStatusListener::New(
- base::BindRepeating(&DataUseMeasurement::OnApplicationStateChange,
- base::Unretained(this)))),
- rx_bytes_os_(0),
- tx_bytes_os_(0),
- no_reads_since_background_(false),
-#endif
- network_connection_tracker_(network_connection_tracker),
- connection_type_(network::mojom::ConnectionType::CONNECTION_UNKNOWN) {
+ : network_connection_tracker_(network_connection_tracker),
+ data_use_tracker_prefs_(base::DefaultClock::GetInstance(), pref_service) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(network_connection_tracker_);
- network_connection_tracker_->AddLeakyNetworkConnectionObserver(this);
-
#if defined(OS_ANDROID)
int64_t bytes = 0;
// Query Android traffic stats.
@@ -68,10 +73,29 @@ DataUseMeasurement::DataUseMeasurement(
if (net::android::traffic_stats::GetCurrentUidTxBytes(&bytes))
tx_bytes_os_ = bytes;
#endif
+
+ network_connection_tracker_->AddLeakyNetworkConnectionObserver(this);
+
+ network_connection_tracker_->GetConnectionType(
+ &connection_type_,
+ base::BindOnce(&DataUseMeasurement::OnConnectionChanged,
+ weak_ptr_factory_.GetWeakPtr()));
+
+#if defined(OS_ANDROID)
+ app_state_ = base::android::ApplicationStatusListener::GetState();
+
+ app_listener_ = base::android::ApplicationStatusListener::New(
+ base::BindRepeating(&DataUseMeasurement::OnApplicationStateChange,
+ base::Unretained(this)));
+#endif
}
DataUseMeasurement::~DataUseMeasurement() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+#if defined(OS_ANDROID)
+ if (app_listener_)
+ app_listener_.reset();
+#endif
network_connection_tracker_->RemoveNetworkConnectionObserver(this);
DCHECK(!services_data_use_observer_list_.might_have_observers());
}
@@ -84,6 +108,13 @@ void DataUseMeasurement::RecordDownstreamUserTrafficSizeMetric(
CurrentAppState(), IsCurrentNetworkCellular()),
bytes);
RecordTabStateHistogram(DOWNSTREAM, CurrentAppState(), is_tab_visible, bytes);
+ bytes_transferred_since_last_traffic_stats_query_ += bytes;
+ MaybeRecordNetworkBytesOS(/*force_record_metrics=*/false);
+
+ data_use_tracker_prefs_.ReportNetworkServiceDataUse(
+ IsCurrentNetworkCellular(),
+ CurrentAppState() == DataUseUserData::FOREGROUND,
+ /*is_user_traffic=*/true, bytes);
}
#if defined(OS_ANDROID)
@@ -95,17 +126,18 @@ void DataUseMeasurement::OnApplicationStateChangeForTesting(
DataUseUserData::AppState DataUseMeasurement::CurrentAppState() const {
#if defined(OS_ANDROID)
- if (app_state_ != base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES)
- return DataUseUserData::BACKGROUND;
+ return IsInForeground(app_state_) ? DataUseUserData::FOREGROUND
+ : DataUseUserData::BACKGROUND;
#endif
// If the OS is not Android, all the requests are considered Foreground.
return DataUseUserData::FOREGROUND;
}
+// static
std::string DataUseMeasurement::GetHistogramNameWithConnectionType(
const char* prefix,
TrafficDirection dir,
- DataUseUserData::AppState app_state) const {
+ DataUseUserData::AppState app_state) {
return base::StringPrintf(
"%s.%s.%s", prefix, dir == UPSTREAM ? "Upstream" : "Downstream",
app_state == DataUseUserData::UNKNOWN
@@ -114,11 +146,12 @@ std::string DataUseMeasurement::GetHistogramNameWithConnectionType(
: "Background"));
}
+// static
std::string DataUseMeasurement::GetHistogramName(
const char* prefix,
TrafficDirection dir,
DataUseUserData::AppState app_state,
- bool is_connection_cellular) const {
+ bool is_connection_cellular) {
return base::StringPrintf(
"%s.%s.%s.%s", prefix, dir == UPSTREAM ? "Upstream" : "Downstream",
app_state == DataUseUserData::UNKNOWN
@@ -132,24 +165,24 @@ std::string DataUseMeasurement::GetHistogramName(
void DataUseMeasurement::OnApplicationStateChange(
base::android::ApplicationState application_state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (app_state_ == application_state)
+ return;
+ MaybeRecordNetworkBytesOS(/*force_record_metrics=*/true);
app_state_ = application_state;
- if (app_state_ != base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
- last_app_background_time_ = base::TimeTicks::Now();
- no_reads_since_background_ = true;
- MaybeRecordNetworkBytesOS();
- } else {
- last_app_background_time_ = base::TimeTicks();
- }
}
+#endif
-void DataUseMeasurement::MaybeRecordNetworkBytesOS() {
+void DataUseMeasurement::MaybeRecordNetworkBytesOS(bool force_record_metrics) {
+#if defined(OS_ANDROID)
// Minimum number of bytes that should be reported by the network delegate
// before Android's TrafficStats API is queried (if Chrome is not in
// background). This reduces the overhead of repeatedly calling the API.
static const int64_t kMinDelegateBytes = 25000;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (bytes_transferred_since_last_traffic_stats_query_ < kMinDelegateBytes &&
+ if (!force_record_metrics &&
+ bytes_transferred_since_last_traffic_stats_query_ < kMinDelegateBytes &&
CurrentAppState() == DataUseUserData::FOREGROUND) {
return;
}
@@ -162,9 +195,16 @@ void DataUseMeasurement::MaybeRecordNetworkBytesOS() {
if (rx_bytes_os_ != 0) {
DCHECK_GE(bytes, rx_bytes_os_);
if (bytes > rx_bytes_os_) {
+ int64_t incremental_bytes = bytes - rx_bytes_os_;
// Do not record samples with value 0.
- UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesReceived.OS",
- bytes - rx_bytes_os_);
+ UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesReceived.OS", incremental_bytes);
+ if (IsInForeground(app_state_)) {
+ UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesReceived.OS.Foreground",
+ incremental_bytes);
+ } else {
+ UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesReceived.OS.Background",
+ incremental_bytes);
+ }
}
}
rx_bytes_os_ = bytes;
@@ -174,29 +214,49 @@ void DataUseMeasurement::MaybeRecordNetworkBytesOS() {
if (tx_bytes_os_ != 0) {
DCHECK_GE(bytes, tx_bytes_os_);
if (bytes > tx_bytes_os_) {
+ int64_t incremental_bytes = bytes - tx_bytes_os_;
// Do not record samples with value 0.
- UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesSent.OS", bytes - tx_bytes_os_);
+ UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesSent.OS", incremental_bytes);
+ if (IsInForeground(app_state_)) {
+ UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesSent.OS.Foreground",
+ incremental_bytes);
+ } else {
+ UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesSent.OS.Background",
+ incremental_bytes);
+ }
}
}
tx_bytes_os_ = bytes;
}
-}
#endif
+}
void DataUseMeasurement::ReportDataUsageServices(
int32_t traffic_annotation_hash,
TrafficDirection dir,
DataUseUserData::AppState app_state,
- int64_t message_size_bytes) const {
- if (message_size_bytes > 0) {
- // Conventional UMA histograms are not used because name is not static.
- base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
- GetHistogramNameWithConnectionType("DataUse.AllServicesKB", dir,
- app_state),
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->AddKiB(traffic_annotation_hash,
- base::saturated_cast<int>(message_size_bytes));
- }
+ int64_t message_size_bytes) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (message_size_bytes <= 0)
+ return;
+
+ // Conventional UMA histograms are not used because name is not static.
+ base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+ GetHistogramNameWithConnectionType("DataUse.AllServicesKB", dir,
+ app_state),
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ // AddKiB method takes value in bytes.
+ histogram->AddKiB(traffic_annotation_hash,
+ base::saturated_cast<int>(message_size_bytes));
+
+ bytes_transferred_since_last_traffic_stats_query_ += message_size_bytes;
+ MaybeRecordNetworkBytesOS(/*force_record_metrics=*/false);
+
+ data_use_tracker_prefs_.ReportNetworkServiceDataUse(
+ IsCurrentNetworkCellular(),
+ CurrentAppState() == DataUseUserData::FOREGROUND,
+ /*is_user_traffic=*/false, message_size_bytes);
}
void DataUseMeasurement::RecordTabStateHistogram(
@@ -204,6 +264,8 @@ void DataUseMeasurement::RecordTabStateHistogram(
DataUseUserData::AppState app_state,
bool is_tab_visible,
int64_t bytes) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
if (app_state == DataUseUserData::UNKNOWN)
return;
@@ -284,17 +346,29 @@ bool DataUseMeasurement::IsCurrentNetworkCellular() const {
void DataUseMeasurement::OnConnectionChanged(
network::mojom::ConnectionType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (connection_type_ != network::mojom::ConnectionType::CONNECTION_UNKNOWN)
+ MaybeRecordNetworkBytesOS(/*force_record_metrics=*/true);
+
connection_type_ = type;
}
void DataUseMeasurement::AddServicesDataUseObserver(
ServicesDataUseObserver* observer) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
services_data_use_observer_list_.AddObserver(observer);
}
void DataUseMeasurement::RemoveServicesDataUseObserver(
ServicesDataUseObserver* observer) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
services_data_use_observer_list_.RemoveObserver(observer);
}
+// static
+void DataUseMeasurement::RegisterDataUseComponentLocalStatePrefs(
+ PrefRegistrySimple* registry) {
+ DataUseTrackerPrefs::RegisterDataUseTrackerLocalStatePrefs(registry);
+}
+
} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement.h b/chromium/components/data_use_measurement/core/data_use_measurement.h
index 5b331b2d438..6b5d3e84193 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement.h
+++ b/chromium/components/data_use_measurement/core/data_use_measurement.h
@@ -12,10 +12,12 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "components/data_use_measurement/core/data_use_tracker_prefs.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "services/network/public/cpp/network_connection_tracker.h"
@@ -23,6 +25,8 @@
#include "base/android/application_status_listener.h"
#endif
+class PrefService;
+
namespace data_use_measurement {
// Records the data use of user traffic and various services in UMA histograms.
@@ -53,7 +57,10 @@ class DataUseMeasurement
static bool IsMetricsServiceRequest(
int32_t network_traffic_annotation_hash_id);
+ // |pref_service| can be used for accessing local state prefs. Can be null.
+ // |network_connection_tracker| is guaranteed to be non-null.
DataUseMeasurement(
+ PrefService* pref_service,
network::NetworkConnectionTracker* network_connection_tracker);
~DataUseMeasurement() override;
@@ -88,39 +95,35 @@ class DataUseMeasurement
void ReportDataUsageServices(int32_t traffic_annotation_hash,
TrafficDirection dir,
DataUseUserData::AppState app_state,
- int64_t message_size_bytes) const;
+ int64_t message_size_bytes);
// Returns if the current network connection type is cellular.
bool IsCurrentNetworkCellular() const;
-#if defined(OS_ANDROID)
- // Records the count of bytes received and sent by Chrome on the network as
- // reported by the operating system.
- void MaybeRecordNetworkBytesOS();
-
- // Number of bytes received and sent by Chromium as reported by the network
- // delegate since the operating system was last queried for traffic
- // statistics.
- int64_t bytes_transferred_since_last_traffic_stats_query_ = 0;
-#endif
+ static void RegisterDataUseComponentLocalStatePrefs(
+ PrefRegistrySimple* registry);
base::ObserverList<ServicesDataUseObserver>::Unchecked
services_data_use_observer_list_;
- SEQUENCE_CHECKER(sequence_checker_);
-
private:
friend class DataUseMeasurementTest;
+ // Records the count of bytes received and sent by Chrome on the network as
+ // reported by the operating system. If |force_record_metrics| is true, the
+ // data use metrics are always recorded. If |force_record_metrics| is false,
+ // data use may be recorded only if it's expected to be high.
+ void MaybeRecordNetworkBytesOS(bool force_record_metrics);
+
// Makes the full name of the histogram. It is made from |prefix| and suffix
// which is made based on network and application status. suffix is a string
// representing whether the data use was on the send ("Upstream") or receive
// ("Downstream") path, and whether the app was in the "Foreground" or
// "Background".
- std::string GetHistogramNameWithConnectionType(
+ static std::string GetHistogramNameWithConnectionType(
const char* prefix,
TrafficDirection dir,
- DataUseUserData::AppState app_state) const;
+ DataUseUserData::AppState app_state);
// Makes the full name of the histogram. It is made from |prefix| and suffix
// which is made based on network and application status. suffix is a string
@@ -130,10 +133,10 @@ class DataUseMeasurement
// example, "Prefix.Upstream.Foreground.Cellular" is a possible output.
// |app_state| indicates the app state which can be foreground, background, or
// unknown.
- std::string GetHistogramName(const char* prefix,
- TrafficDirection dir,
- DataUseUserData::AppState app_state,
- bool is_connection_cellular) const;
+ static std::string GetHistogramName(const char* prefix,
+ TrafficDirection dir,
+ DataUseUserData::AppState app_state,
+ bool is_connection_cellular);
#if defined(OS_ANDROID)
// Called whenever the application transitions from foreground to background
@@ -156,32 +159,39 @@ class DataUseMeasurement
#if defined(OS_ANDROID)
// Application listener store the last known state of the application in this
// field.
- base::android::ApplicationState app_state_;
+ base::android::ApplicationState app_state_ =
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES;
// ApplicationStatusListener used to monitor whether the application is in the
// foreground or in the background. It is owned by DataUseMeasurement.
std::unique_ptr<base::android::ApplicationStatusListener> app_listener_;
+#endif
// Number of bytes received and sent by Chromium as reported by the operating
// system when it was last queried for traffic statistics. Set to 0 if the
// operating system was never queried.
- int64_t rx_bytes_os_;
- int64_t tx_bytes_os_;
-
- // The time at which Chromium app state changed to background. Can be null if
- // app is not in background.
- base::TimeTicks last_app_background_time_;
-
- // True if app is in background and first network read has not yet happened.
- bool no_reads_since_background_;
-#endif
+ int64_t rx_bytes_os_ = 0;
+ int64_t tx_bytes_os_ = 0;
// Watches for network connection changes. Global singleton object and
// outlives |this|
network::NetworkConnectionTracker* network_connection_tracker_;
// The current connection type.
- network::mojom::ConnectionType connection_type_;
+ network::mojom::ConnectionType connection_type_ =
+ network::mojom::ConnectionType::CONNECTION_UNKNOWN;
+
+ // Number of bytes received and sent by Chromium as reported by the network
+ // delegate since the operating system was last queried for traffic
+ // statistics.
+ int64_t bytes_transferred_since_last_traffic_stats_query_ = 0;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // Records the data usage in prefs.
+ DataUseTrackerPrefs data_use_tracker_prefs_;
+
+ base::WeakPtrFactory<DataUseMeasurement> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DataUseMeasurement);
};
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc b/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
index 26d3a990c7a..f310daf9a66 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
+++ b/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
@@ -11,6 +11,9 @@
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "build/build_config.h"
+#include "components/data_use_measurement/core/data_use_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
#include "net/base/network_change_notifier.h"
#include "services/network/test/test_network_connection_tracker.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,10 +24,11 @@
namespace data_use_measurement {
-class DataUseMeasurementTest : public testing::Test {
+class DataUseMeasurementTest {
public:
- DataUseMeasurementTest()
+ explicit DataUseMeasurementTest(TestingPrefServiceSimple* test_prefs_)
: data_use_measurement_(
+ test_prefs_,
network::TestNetworkConnectionTracker::GetInstance()) {
// During the test it is expected to not have cellular connection.
DCHECK(!net::NetworkChangeNotifier::IsConnectionCellular(
@@ -59,22 +63,45 @@ class DataUseMeasurementTest : public testing::Test {
// foreground or the OS is not Android.
// TODO(amohammadkhan): Add tests for Cellular/non-cellular connection types
// when support for testing is provided in its class.
-TEST_F(DataUseMeasurementTest, UserNotUserTest) {
+TEST(DataUseMeasurementTest, UserNotUserTest) {
+ TestingPrefServiceSimple test_prefs;
+
+ test_prefs.registry()->RegisterDictionaryPref(prefs::kDataUsedUserForeground);
+ test_prefs.registry()->RegisterDictionaryPref(prefs::kDataUsedUserBackground);
+ test_prefs.registry()->RegisterDictionaryPref(
+ prefs::kDataUsedServicesForeground);
+ test_prefs.registry()->RegisterDictionaryPref(
+ prefs::kDataUsedServicesBackground);
+
+ DataUseMeasurementTest data_use_measurement_test(&test_prefs);
#if defined(OS_ANDROID)
- data_use_measurement()->OnApplicationStateChangeForTesting(
- base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+ data_use_measurement_test.data_use_measurement()
+ ->OnApplicationStateChangeForTesting(
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
#endif
- TestForAUserRequest("Foreground.");
+ data_use_measurement_test.TestForAUserRequest("Foreground.");
}
#if defined(OS_ANDROID)
// This test function tests recording of data use information in UMA histogram
// when packet is originated from user or services when the app is in the
// background and OS is Android.
-TEST_F(DataUseMeasurementTest, ApplicationStateTest) {
- data_use_measurement()->OnApplicationStateChangeForTesting(
- base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
- TestForAUserRequest("Background.");
+TEST(DataUseMeasurementTest, ApplicationStateTest) {
+ TestingPrefServiceSimple test_prefs;
+
+ test_prefs.registry()->RegisterDictionaryPref(prefs::kDataUsedUserForeground);
+ test_prefs.registry()->RegisterDictionaryPref(prefs::kDataUsedUserBackground);
+ test_prefs.registry()->RegisterDictionaryPref(
+ prefs::kDataUsedServicesForeground);
+ test_prefs.registry()->RegisterDictionaryPref(
+ prefs::kDataUsedServicesBackground);
+
+ DataUseMeasurementTest data_use_measurement_test(&test_prefs);
+
+ data_use_measurement_test.data_use_measurement()
+ ->OnApplicationStateChangeForTesting(
+ base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
+ data_use_measurement_test.TestForAUserRequest("Background.");
}
#endif
diff --git a/chromium/components/data_use_measurement/core/data_use_pref_names.h b/chromium/components/data_use_measurement/core/data_use_pref_names.h
new file mode 100644
index 00000000000..5135a402e03
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_pref_names.h
@@ -0,0 +1,30 @@
+// Copyright 2020 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 COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_PREF_NAMES_H_
+#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_PREF_NAMES_H_
+
+#include <memory>
+
+#include "base/macros.h"
+
+namespace data_use_measurement {
+
+namespace prefs {
+// Dictionary prefs for measuring cellular data used. |key| is
+// the date of data usage (stored as string using exploded format). |value|
+// stores the data used for that date as a double in kilobytes.
+const char kDataUsedUserForeground[] =
+ "data_use_measurement.data_used.user.foreground";
+const char kDataUsedUserBackground[] =
+ "data_use_measurement.data_used.user.background";
+const char kDataUsedServicesForeground[] =
+ "data_use_measurement.data_used.services.foreground";
+const char kDataUsedServicesBackground[] =
+ "data_use_measurement.data_used.services.background";
+} // namespace prefs
+
+} // namespace data_use_measurement
+
+#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_PREF_NAMES_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc b/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc
new file mode 100644
index 00000000000..5eb549068ca
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc
@@ -0,0 +1,130 @@
+// Copyright 2020 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 "components/data_use_measurement/core/data_use_tracker_prefs.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/time/clock.h"
+#include "build/build_config.h"
+#include "components/data_use_measurement/core/data_use_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/scoped_user_pref_update.h"
+
+namespace data_use_measurement {
+
+DataUseTrackerPrefs::DataUseTrackerPrefs(const base::Clock* time_clock,
+ PrefService* pref_service)
+ : time_clock_(time_clock), pref_service_(pref_service) {
+ DCHECK(time_clock_);
+
+ RemoveExpiredEntriesForPref(prefs::kDataUsedUserForeground);
+ RemoveExpiredEntriesForPref(prefs::kDataUsedUserBackground);
+ RemoveExpiredEntriesForPref(prefs::kDataUsedServicesForeground);
+ RemoveExpiredEntriesForPref(prefs::kDataUsedServicesBackground);
+}
+
+void DataUseTrackerPrefs::ReportNetworkServiceDataUse(
+ bool is_metered_connection,
+ bool is_app_foreground,
+ bool is_user_traffic,
+ int64_t sent_or_recv_bytes) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!is_metered_connection)
+ return;
+
+ if (sent_or_recv_bytes <= 0)
+ return;
+
+ if (is_user_traffic && is_app_foreground) {
+ UpdateUsagePref(prefs::kDataUsedUserForeground, sent_or_recv_bytes);
+ } else if (is_user_traffic && !is_app_foreground) {
+ UpdateUsagePref(prefs::kDataUsedUserBackground, sent_or_recv_bytes);
+ } else if (!is_user_traffic && is_app_foreground) {
+ UpdateUsagePref(prefs::kDataUsedServicesForeground, sent_or_recv_bytes);
+ } else {
+ UpdateUsagePref(prefs::kDataUsedServicesBackground, sent_or_recv_bytes);
+ }
+}
+
+base::Time DataUseTrackerPrefs::GetCurrentMeasurementDate() const {
+ return time_clock_->Now().LocalMidnight();
+}
+
+void DataUseTrackerPrefs::RemoveExpiredEntriesForPref(
+ const std::string& pref_name) {
+ if (!pref_service_)
+ return;
+
+ const base::DictionaryValue* user_pref_dict =
+ pref_service_->GetDictionary(pref_name);
+ const base::Time current_date = GetCurrentMeasurementDate();
+ const base::Time last_date = current_date - base::TimeDelta::FromDays(60);
+
+ base::DictionaryValue user_pref_new_dict;
+ for (const auto& it : user_pref_dict->DictItems()) {
+ base::Time key_date;
+ if (base::Time::FromUTCString(it.first.c_str(), &key_date) &&
+ key_date > last_date) {
+ user_pref_new_dict.Set(it.first, it.second.CreateDeepCopy());
+ }
+ }
+ pref_service_->Set(pref_name, user_pref_new_dict);
+}
+
+std::string DataUseTrackerPrefs::GetCurrentMeasurementDateAsString() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ base::Time::Exploded today_exploded;
+ GetCurrentMeasurementDate().LocalExplode(&today_exploded);
+ std::string date =
+ base::StringPrintf("%04d-%02d-%02d", today_exploded.year,
+ today_exploded.month, today_exploded.day_of_month);
+ return date;
+}
+
+void DataUseTrackerPrefs::UpdateUsagePref(const std::string& pref_name,
+ int64_t message_size_bytes) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!pref_service_)
+ return;
+
+ DictionaryPrefUpdate pref_updater(pref_service_, pref_name);
+ double todays_traffic = 0;
+ std::string todays_key = GetCurrentMeasurementDateAsString();
+
+ const base::DictionaryValue* user_pref_dict =
+ pref_service_->GetDictionary(pref_name);
+ user_pref_dict->GetDouble(todays_key, &todays_traffic);
+ pref_updater->SetDouble(
+ todays_key,
+ todays_traffic + (static_cast<double>(message_size_bytes) / 1024.0));
+}
+
+// static
+void DataUseTrackerPrefs::RegisterDataUseTrackerLocalStatePrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterDictionaryPref(prefs::kDataUsedUserForeground,
+ PrefRegistry::LOSSY_PREF);
+ registry->RegisterDictionaryPref(prefs::kDataUsedUserBackground,
+ PrefRegistry::LOSSY_PREF);
+ registry->RegisterDictionaryPref(prefs::kDataUsedServicesForeground,
+ PrefRegistry::LOSSY_PREF);
+ registry->RegisterDictionaryPref(prefs::kDataUsedServicesBackground,
+ PrefRegistry::LOSSY_PREF);
+}
+
+} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_tracker_prefs.h b/chromium/components/data_use_measurement/core/data_use_tracker_prefs.h
new file mode 100644
index 00000000000..96cc18d9ac9
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_tracker_prefs.h
@@ -0,0 +1,70 @@
+// Copyright 2020 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 COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_TRACKER_PREFS_H_
+#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_TRACKER_PREFS_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/sequence_checker.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace data_use_measurement {
+
+// DataUseTrackerPrefs keeps track of the data used over last 60 days. The data
+// used is recorded separately based on whether the data use was initiated by a
+// Chrome service or a user-initiated request.
+class DataUseTrackerPrefs {
+ public:
+ // |pref_service| may be null in tests.
+ DataUseTrackerPrefs(const base::Clock* time_clock, PrefService* pref_service);
+
+ // Move-only class.
+ DataUseTrackerPrefs(const DataUseTrackerPrefs&) = delete;
+ DataUseTrackerPrefs& operator=(const DataUseTrackerPrefs&) = delete;
+
+ // Report data used by a service or a user-initiated request.
+ // |is_metered_connection| should be true if data consumption happened on a
+ // metered connection. |is_app_foreground| should be true if data was used
+ // when Chrome app was in foregorund. |is_user_traffic| should be true if data
+ // was used by a user-initiated request. |sent_or_recv_bytes| should be set to
+ // the data consumed (in bytes).
+ void ReportNetworkServiceDataUse(bool is_metered_connection,
+ bool is_app_foreground,
+ bool is_user_traffic,
+ int64_t sent_or_recv_bytes);
+
+ // Register local state prefs.
+ static void RegisterDataUseTrackerLocalStatePrefs(
+ PrefRegistrySimple* registry);
+
+ private:
+ // Returns the current date for measurement.
+ base::Time GetCurrentMeasurementDate() const;
+
+ // Removes entries from the given |pref_name| if they are too old.
+ void RemoveExpiredEntriesForPref(const std::string& pref_name);
+
+ // Returns the current date as a string with a proper formatting.
+ std::string GetCurrentMeasurementDateAsString() const;
+
+ // Updates provided |pref_name| for a current date with the given message
+ // size.
+ void UpdateUsagePref(const std::string& pref_name,
+ int64_t message_size_bytes);
+
+ const base::Clock* time_clock_;
+ PrefService* pref_service_ = nullptr;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+};
+
+} // namespace data_use_measurement
+
+#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_TRACKER_PREFS_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_tracker_prefs_unittest.cc b/chromium/components/data_use_measurement/core/data_use_tracker_prefs_unittest.cc
new file mode 100644
index 00000000000..1e0c7e3aae1
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_tracker_prefs_unittest.cc
@@ -0,0 +1,173 @@
+// Copyright 2020 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 "components/data_use_measurement/core/data_use_tracker_prefs.h"
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/simple_test_clock.h"
+#include "components/data_use_measurement/core/data_use_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace data_use_measurement {
+
+void RegisterPrefs(TestingPrefServiceSimple* test_prefs) {
+ test_prefs->registry()->RegisterDictionaryPref(
+ prefs::kDataUsedUserForeground);
+ test_prefs->registry()->RegisterDictionaryPref(
+ prefs::kDataUsedUserBackground);
+ test_prefs->registry()->RegisterDictionaryPref(
+ prefs::kDataUsedServicesForeground);
+ test_prefs->registry()->RegisterDictionaryPref(
+ prefs::kDataUsedServicesBackground);
+}
+
+class DataUseTrackerPrefsTest {
+ public:
+ DataUseTrackerPrefsTest(base::SimpleTestClock* clock,
+ TestingPrefServiceSimple* test_prefs)
+ : data_use_tracker_prefs_(clock, test_prefs) {
+ // Register the prefs before accessing them.
+ }
+
+ DataUseTrackerPrefsTest(const DataUseTrackerPrefsTest&) = delete;
+ DataUseTrackerPrefsTest& operator=(const DataUseTrackerPrefsTest&) = delete;
+
+ DataUseTrackerPrefs* data_use_tracker_prefs() {
+ return &data_use_tracker_prefs_;
+ }
+
+ private:
+ DataUseTrackerPrefs data_use_tracker_prefs_;
+};
+
+// Verifies that the prefs are stored correctly: The date is used as the key
+// in the pref and the expired keys are removed.
+TEST(DataUseTrackerPrefsTest, PrefsOnMeteredConnection) {
+ base::SimpleTestClock clock;
+ clock.SetNow(base::Time::Now());
+ TestingPrefServiceSimple test_prefs;
+ RegisterPrefs(&test_prefs);
+
+ // Report 2 data uses for the same day.
+ DataUseTrackerPrefsTest tracker_prefs_test_1(&clock, &test_prefs);
+ tracker_prefs_test_1.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
+ true, true, true, 10);
+ EXPECT_EQ(1u,
+ test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->size());
+ tracker_prefs_test_1.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
+ true, true, true, 10);
+ EXPECT_EQ(1u,
+ test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->size());
+
+ // Verify other prefs are not set.
+ EXPECT_TRUE(
+ test_prefs.GetDictionary(prefs::kDataUsedUserBackground)->empty());
+ EXPECT_TRUE(
+ test_prefs.GetDictionary(prefs::kDataUsedServicesForeground)->empty());
+ EXPECT_TRUE(
+ test_prefs.GetDictionary(prefs::kDataUsedServicesBackground)->empty());
+
+ // Move clock forward 10 days. New data use reported must go in a separate
+ // entry in the dictionary pref.
+ clock.Advance(base::TimeDelta::FromDays(10));
+ DataUseTrackerPrefsTest tracker_prefs_test_2(&clock, &test_prefs);
+ EXPECT_EQ(1u,
+ test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->size());
+ tracker_prefs_test_2.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
+ true, true, true, 10);
+ EXPECT_EQ(2u,
+ test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->size());
+
+ // Move clock forward 55 days. This should clean up the first entry since they
+ // are now 65 days older (i.e., more than 60 days old). New data use reported
+ // must go in a separate entry in the dictionary pref.
+ clock.Advance(base::TimeDelta::FromDays(55));
+ DataUseTrackerPrefsTest tracker_prefs_test_3(&clock, &test_prefs);
+ EXPECT_EQ(1u,
+ test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->size());
+ tracker_prefs_test_2.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
+ true, true, true, 10);
+ EXPECT_EQ(2u,
+ test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->size());
+}
+
+// Verifies that the prefs are not updated on unmetered connections.
+TEST(DataUseTrackerPrefsTest, PrefsOnUnmeteredConnection) {
+ base::SimpleTestClock clock;
+ clock.SetNow(base::Time::Now());
+ TestingPrefServiceSimple test_prefs;
+ RegisterPrefs(&test_prefs);
+
+ // Report 2 data uses for the same day.
+ DataUseTrackerPrefsTest tracker_prefs_test_1(&clock, &test_prefs);
+ tracker_prefs_test_1.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
+ /*is_metered_connection=*/false, true, true, 10);
+ tracker_prefs_test_1.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
+ /*is_metered_connection=*/false, true, true, 10);
+
+ // Verify prefs are not set.
+ EXPECT_TRUE(
+ test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->empty());
+ EXPECT_TRUE(
+ test_prefs.GetDictionary(prefs::kDataUsedUserBackground)->empty());
+ EXPECT_TRUE(
+ test_prefs.GetDictionary(prefs::kDataUsedServicesForeground)->empty());
+ EXPECT_TRUE(
+ test_prefs.GetDictionary(prefs::kDataUsedServicesBackground)->empty());
+}
+
+TEST(DataUseTrackerPrefsTest, TestBasicUserForeground) {
+ base::SimpleTestClock clock;
+ clock.SetNow(base::Time::Now());
+ TestingPrefServiceSimple test_prefs;
+ RegisterPrefs(&test_prefs);
+
+ // Report 2 data uses for the same day.
+ DataUseTrackerPrefsTest tracker_prefs_test(&clock, &test_prefs);
+
+ const struct {
+ bool foreground;
+ bool user_initiated;
+ std::string pref_expected_as_non_empty;
+ } tests[] = {
+ {false, false, prefs::kDataUsedServicesBackground},
+ {false, true, prefs::kDataUsedUserBackground},
+ {true, false, prefs::kDataUsedServicesForeground},
+ {true, true, prefs::kDataUsedUserForeground},
+ };
+
+ for (const auto& test : tests) {
+ test_prefs.ClearPref(prefs::kDataUsedServicesBackground);
+ test_prefs.ClearPref(prefs::kDataUsedUserBackground);
+ test_prefs.ClearPref(prefs::kDataUsedServicesForeground);
+ test_prefs.ClearPref(prefs::kDataUsedServicesForeground);
+
+ tracker_prefs_test.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
+ true, test.foreground, test.user_initiated, 10);
+ // Verify that the expected pref has an entry.
+ EXPECT_FALSE(
+ test_prefs.GetDictionary(test.pref_expected_as_non_empty)->empty());
+
+ // Verify other prefs are not set.
+ EXPECT_TRUE(
+ test.pref_expected_as_non_empty == prefs::kDataUsedUserForeground ||
+ test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->empty());
+ EXPECT_TRUE(
+ test.pref_expected_as_non_empty == prefs::kDataUsedUserBackground ||
+ test_prefs.GetDictionary(prefs::kDataUsedUserBackground)->empty());
+ EXPECT_TRUE(
+ test.pref_expected_as_non_empty == prefs::kDataUsedServicesForeground ||
+ test_prefs.GetDictionary(prefs::kDataUsedServicesForeground)->empty());
+ EXPECT_TRUE(
+ test.pref_expected_as_non_empty == prefs::kDataUsedServicesBackground ||
+ test_prefs.GetDictionary(prefs::kDataUsedServicesBackground)->empty());
+ }
+}
+
+} // namespace data_use_measurement