| // Copyright 2014 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_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h" |
| |
| #include <cmath> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/feature_list.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/metrics/sparse_histogram.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/trace_event/trace_event.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h" |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h" |
| #include "components/data_reduction_proxy/core/browser/data_usage_store.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h" |
| #include "components/data_reduction_proxy/proto/data_store.pb.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/prefs/scoped_user_pref_update.h" |
| #include "net/base/mime_util.h" |
| |
| namespace data_reduction_proxy { |
| |
| namespace { |
| |
| #define CONCAT(a, b) a##b |
| // CONCAT1 provides extra level of indirection so that __LINE__ macro expands. |
| #define CONCAT1(a, b) CONCAT(a, b) |
| #define UNIQUE_VARNAME CONCAT1(var_, __LINE__) |
| // We need to use a macro instead of a method because UMA_HISTOGRAM_COUNTS_1M |
| // requires its first argument to be an inline string and not a variable. |
| #define RECORD_INT64PREF_TO_HISTOGRAM(pref, uma) \ |
| int64_t UNIQUE_VARNAME = GetInt64(pref); \ |
| if (UNIQUE_VARNAME > 0) { \ |
| UMA_HISTOGRAM_COUNTS_1M(uma, UNIQUE_VARNAME >> 10); \ |
| } |
| |
| const double kSecondsPerWeek = |
| base::Time::kMicrosecondsPerWeek / base::Time::kMicrosecondsPerSecond; |
| |
| // Returns the value at |index| of |list_value| as an int64_t. |
| int64_t GetInt64PrefValue(const base::ListValue& list_value, size_t index) { |
| int64_t val = 0; |
| std::string pref_value; |
| bool rv = list_value.GetString(index, &pref_value); |
| DCHECK(rv); |
| if (rv) { |
| rv = base::StringToInt64(pref_value, &val); |
| DCHECK(rv); |
| } |
| return val; |
| } |
| |
| // Ensure list has exactly |length| elements, either by truncating at the |
| // front, or appending "0"'s to the back. |
| void MaintainContentLengthPrefsWindow(base::ListValue* list, size_t length) { |
| // Remove data for old days from the front. |
| while (list->GetSize() > length) |
| list->Remove(0, nullptr); |
| // Newly added lists are empty. Add entries to back to fill the window, |
| // each initialized to zero. |
| while (list->GetSize() < length) |
| list->AppendString(base::NumberToString(0)); |
| DCHECK_EQ(length, list->GetSize()); |
| } |
| |
| // Increments an int64_t, stored as a string, in a ListPref at the specified |
| // index. The value must already exist and be a string representation of a |
| // number. |
| void AddInt64ToListPref(size_t index, |
| int64_t length, |
| base::ListValue* list_update) { |
| int64_t value = GetInt64PrefValue(*list_update, index) + length; |
| list_update->Set(index, |
| std::make_unique<base::Value>(base::NumberToString(value))); |
| } |
| |
| // DailyContentLengthUpdate maintains a data saving pref. The pref is a list |
| // of |kNumDaysInHistory| elements of daily total content lengths for the past |
| // |kNumDaysInHistory| days. |
| void RecordDailyContentLengthHistograms( |
| int64_t original_length, |
| int64_t received_length, |
| int64_t original_length_with_data_reduction_enabled, |
| int64_t received_length_with_data_reduction_enabled, |
| int64_t original_length_via_data_reduction_proxy, |
| int64_t received_length_via_data_reduction_proxy, |
| int64_t https_length_with_data_reduction_enabled, |
| int64_t short_bypass_length_with_data_reduction_enabled, |
| int64_t long_bypass_length_with_data_reduction_enabled, |
| int64_t unknown_length_with_data_reduction_enabled) { |
| // Report daily UMA only for days having received content. |
| if (original_length <= 0 || received_length <= 0) |
| return; |
| |
| // Record metrics in KB. |
| UMA_HISTOGRAM_COUNTS_1M("Net.DailyOriginalContentLength", |
| original_length >> 10); |
| UMA_HISTOGRAM_COUNTS_1M("Net.DailyContentLength", received_length >> 10); |
| |
| int percent = 0; |
| // UMA percentage cannot be negative. |
| if (original_length > received_length) { |
| percent = (100 * (original_length - received_length)) / original_length; |
| } |
| UMA_HISTOGRAM_PERCENTAGE("Net.DailyContentSavingPercent", percent); |
| |
| if (original_length_with_data_reduction_enabled <= 0 || |
| received_length_with_data_reduction_enabled <= 0) { |
| return; |
| } |
| |
| UMA_HISTOGRAM_COUNTS_1M( |
| "Net.DailyOriginalContentLength_DataReductionProxyEnabled", |
| original_length_with_data_reduction_enabled >> 10); |
| UMA_HISTOGRAM_COUNTS_1M("Net.DailyContentLength_DataReductionProxyEnabled", |
| received_length_with_data_reduction_enabled >> 10); |
| |
| int percent_data_reduction_proxy_enabled = 0; |
| // UMA percentage cannot be negative. |
| if (original_length_with_data_reduction_enabled > |
| received_length_with_data_reduction_enabled) { |
| percent_data_reduction_proxy_enabled = |
| 100 * (original_length_with_data_reduction_enabled - |
| received_length_with_data_reduction_enabled) / |
| original_length_with_data_reduction_enabled; |
| } |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentSavingPercent_DataReductionProxyEnabled", |
| percent_data_reduction_proxy_enabled); |
| |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentPercent_DataReductionProxyEnabled", |
| (100 * received_length_with_data_reduction_enabled) / received_length); |
| |
| DCHECK_GE(https_length_with_data_reduction_enabled, 0); |
| UMA_HISTOGRAM_COUNTS_1M( |
| "Net.DailyContentLength_DataReductionProxyEnabled_Https", |
| https_length_with_data_reduction_enabled >> 10); |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentPercent_DataReductionProxyEnabled_Https", |
| (100 * https_length_with_data_reduction_enabled) / received_length); |
| |
| DCHECK_GE(short_bypass_length_with_data_reduction_enabled, 0); |
| UMA_HISTOGRAM_COUNTS_1M( |
| "Net.DailyContentLength_DataReductionProxyEnabled_ShortBypass", |
| short_bypass_length_with_data_reduction_enabled >> 10); |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentPercent_DataReductionProxyEnabled_ShortBypass", |
| ((100 * short_bypass_length_with_data_reduction_enabled) / |
| received_length)); |
| |
| DCHECK_GE(long_bypass_length_with_data_reduction_enabled, 0); |
| UMA_HISTOGRAM_COUNTS_1M( |
| "Net.DailyContentLength_DataReductionProxyEnabled_LongBypass", |
| long_bypass_length_with_data_reduction_enabled >> 10); |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentPercent_DataReductionProxyEnabled_LongBypass", |
| ((100 * long_bypass_length_with_data_reduction_enabled) / |
| received_length)); |
| |
| DCHECK_GE(unknown_length_with_data_reduction_enabled, 0); |
| UMA_HISTOGRAM_COUNTS_1M( |
| "Net.DailyContentLength_DataReductionProxyEnabled_UnknownBypass", |
| unknown_length_with_data_reduction_enabled >> 10); |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentPercent_DataReductionProxyEnabled_Unknown", |
| ((100 * unknown_length_with_data_reduction_enabled) / |
| received_length)); |
| |
| DCHECK_GE(original_length_via_data_reduction_proxy, 0); |
| UMA_HISTOGRAM_COUNTS_1M( |
| "Net.DailyOriginalContentLength_ViaDataReductionProxy", |
| original_length_via_data_reduction_proxy >> 10); |
| DCHECK_GE(received_length_via_data_reduction_proxy, 0); |
| UMA_HISTOGRAM_COUNTS_1M("Net.DailyContentLength_ViaDataReductionProxy", |
| received_length_via_data_reduction_proxy >> 10); |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentPercent_ViaDataReductionProxy", |
| (100 * received_length_via_data_reduction_proxy) / received_length); |
| |
| if (original_length_via_data_reduction_proxy <= 0) |
| return; |
| int percent_savings_via_data_reduction_proxy = 0; |
| if (original_length_via_data_reduction_proxy > |
| received_length_via_data_reduction_proxy) { |
| percent_savings_via_data_reduction_proxy = |
| 100 * (original_length_via_data_reduction_proxy - |
| received_length_via_data_reduction_proxy) / |
| original_length_via_data_reduction_proxy; |
| } |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentSavingPercent_ViaDataReductionProxy", |
| percent_savings_via_data_reduction_proxy); |
| } |
| |
| void RecordSavingsClearedMetric(DataReductionProxySavingsClearedReason reason) { |
| DCHECK_GT(DataReductionProxySavingsClearedReason::REASON_COUNT, reason); |
| UMA_HISTOGRAM_ENUMERATION( |
| "DataReductionProxy.SavingsCleared.Reason", reason, |
| DataReductionProxySavingsClearedReason::REASON_COUNT); |
| } |
| |
| // Returns the week number for the current time. The epoch time is treated as |
| // week=0. |
| int32_t GetCurrentWeekNumber(const base::Time& now) { |
| double now_in_seconds = now.ToDoubleT(); |
| return now_in_seconds / kSecondsPerWeek; |
| } |
| |
| // Adds |value| to the item at |key| in the preference dictionary found at |
| // |pref|. If |key| is not found it will be inserted. |
| void AddToDictionaryPref(PrefService* pref_service, |
| const std::string& pref, |
| int key, |
| int value) { |
| DictionaryPrefUpdate pref_update(pref_service, pref); |
| base::DictionaryValue* pref_dict = pref_update.Get(); |
| const std::string key_str = base::NumberToString(key); |
| base::Value* dict_value = pref_dict->FindKey(key_str); |
| if (dict_value) |
| value += dict_value->GetInt(); |
| pref_dict->SetKey(key_str, base::Value(value)); |
| } |
| |
| // Moves the dictionary stored in preference |pref_src| to |pref_dst|, and |
| // clears the preference |pref_src|. |
| void MoveAndClearDictionaryPrefs(PrefService* pref_service, |
| const std::string& pref_dst, |
| const std::string& pref_src) { |
| DictionaryPrefUpdate pref_update_dst(pref_service, pref_dst); |
| base::DictionaryValue* pref_dict_dst = pref_update_dst.Get(); |
| DictionaryPrefUpdate pref_update_src(pref_service, pref_src); |
| base::DictionaryValue* pref_dict_src = pref_update_src.Get(); |
| pref_dict_dst->Clear(); |
| pref_dict_dst->Swap(pref_dict_src); |
| DCHECK(pref_dict_src->empty()); |
| } |
| |
| void MaybeInitWeeklyAggregateDataUsePrefs(const base::Time& now, |
| PrefService* pref_service) { |
| int saved_week = pref_service->GetInteger(prefs::kThisWeekNumber); |
| int current_week = GetCurrentWeekNumber(now); |
| |
| if (saved_week == current_week) |
| return; |
| |
| pref_service->SetInteger(prefs::kThisWeekNumber, current_week); |
| if (current_week == saved_week + 1) { |
| // The next week has just started. Move the data use aggregate prefs for |
| // this week to last week, and clear the prefs for this week. |
| MoveAndClearDictionaryPrefs(pref_service, |
| prefs::kLastWeekServicesDownstreamBackgroundKB, |
| prefs::kThisWeekServicesDownstreamBackgroundKB); |
| MoveAndClearDictionaryPrefs(pref_service, |
| prefs::kLastWeekServicesDownstreamForegroundKB, |
| prefs::kThisWeekServicesDownstreamForegroundKB); |
| MoveAndClearDictionaryPrefs( |
| pref_service, prefs::kLastWeekUserTrafficContentTypeDownstreamKB, |
| prefs::kThisWeekUserTrafficContentTypeDownstreamKB); |
| } else { |
| // Current week is too different than the last time data use aggregate prefs |
| // were updated. This may happen if Chrome was opened after a long time, or |
| // due to system clock being changed backward or forward. Clear all prefs in |
| // this case. |
| pref_service->ClearPref(prefs::kLastWeekServicesDownstreamBackgroundKB); |
| pref_service->ClearPref(prefs::kLastWeekServicesDownstreamForegroundKB); |
| pref_service->ClearPref(prefs::kLastWeekUserTrafficContentTypeDownstreamKB); |
| pref_service->ClearPref(prefs::kThisWeekServicesDownstreamBackgroundKB); |
| pref_service->ClearPref(prefs::kThisWeekServicesDownstreamForegroundKB); |
| pref_service->ClearPref(prefs::kThisWeekUserTrafficContentTypeDownstreamKB); |
| } |
| } |
| |
| // Records the key-value pairs in the dictionary in a sparse histogram. |
| void RecordDictionaryToHistogram(const std::string& histogram_name, |
| const base::DictionaryValue* dictionary) { |
| base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( |
| histogram_name, base::HistogramBase::kUmaTargetedHistogramFlag); |
| for (const auto& entry : *dictionary) { |
| int key; |
| int value = entry.second->GetInt(); |
| if (value > 0 && base::StringToInt(entry.first, &key)) { |
| histogram->AddCount(key, value); |
| } |
| } |
| } |
| |
| } // namespace |
| |
| class DataReductionProxyCompressionStats::DailyContentLengthUpdate { |
| public: |
| DailyContentLengthUpdate( |
| DataReductionProxyCompressionStats* compression_stats, |
| const char* pref_path) |
| : update_(nullptr), |
| compression_stats_(compression_stats), |
| pref_path_(pref_path) {} |
| |
| void UpdateForDateChange(int days_since_last_update) { |
| if (days_since_last_update) { |
| MaybeInitialize(); |
| MaintainContentLengthPrefForDateChange(days_since_last_update); |
| } |
| } |
| |
| // Update the lengths for the current day. |
| void Add(int64_t content_length) { |
| if (content_length != 0) { |
| MaybeInitialize(); |
| AddInt64ToListPref(kNumDaysInHistory - 1, content_length, update_); |
| } |
| } |
| |
| int64_t GetListPrefValue(size_t index) { |
| MaybeInitialize(); |
| return GetInt64PrefValue(*update_, index); |
| } |
| |
| private: |
| void MaybeInitialize() { |
| if (update_) |
| return; |
| |
| update_ = compression_stats_->GetList(pref_path_); |
| // New empty lists may have been created. Maintain the invariant that |
| // there should be exactly |kNumDaysInHistory| days in the histories. |
| MaintainContentLengthPrefsWindow(update_, kNumDaysInHistory); |
| } |
| |
| // Update the list for date change and ensure the list has exactly |length| |
| // elements. The last entry in the list will be for the current day after |
| // the update. |
| void MaintainContentLengthPrefForDateChange(int days_since_last_update) { |
| if (days_since_last_update == -1) { |
| // The system may go backwards in time by up to a day for legitimate |
| // reasons, such as with changes to the time zone. In such cases, we |
| // keep adding to the current day. |
| // Note: we accept the fact that some reported data is shifted to |
| // the adjacent day if users travel back and forth across time zones. |
| days_since_last_update = 0; |
| } else if (days_since_last_update < -1) { |
| // Erase all entries if the system went backwards in time by more than |
| // a day. |
| update_->Clear(); |
| |
| days_since_last_update = kNumDaysInHistory; |
| } |
| DCHECK_GE(days_since_last_update, 0); |
| |
| // Add entries for days since last update event. This will make the |
| // lists longer than kNumDaysInHistory. The additional items will be cut off |
| // from the head of the lists by |MaintainContentLengthPrefsWindow|, below. |
| for (int i = 0; |
| i < days_since_last_update && i < static_cast<int>(kNumDaysInHistory); |
| ++i) { |
| update_->AppendString(base::NumberToString(0)); |
| } |
| |
| // Entries for new days may have been appended. Maintain the invariant that |
| // there should be exactly |kNumDaysInHistory| days in the histories. |
| MaintainContentLengthPrefsWindow(update_, kNumDaysInHistory); |
| } |
| |
| // Non-owned. Lazily initialized, set to nullptr until initialized. |
| base::ListValue* update_; |
| // Non-owned pointer. |
| DataReductionProxyCompressionStats* compression_stats_; |
| // The path of the content length pref for |this|. |
| const char* pref_path_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DailyContentLengthUpdate); |
| }; |
| |
| // DailyDataSavingUpdate maintains a pair of data saving prefs, original_update_ |
| // and received_update_. pref_original is a list of |kNumDaysInHistory| elements |
| // of daily total original content lengths for the past |kNumDaysInHistory| |
| // days. pref_received is the corresponding list of the daily total received |
| // content lengths. |
| class DataReductionProxyCompressionStats::DailyDataSavingUpdate { |
| public: |
| DailyDataSavingUpdate(DataReductionProxyCompressionStats* compression_stats, |
| const char* original_pref_path, |
| const char* received_pref_path) |
| : original_(compression_stats, original_pref_path), |
| received_(compression_stats, received_pref_path) {} |
| |
| void UpdateForDateChange(int days_since_last_update) { |
| original_.UpdateForDateChange(days_since_last_update); |
| received_.UpdateForDateChange(days_since_last_update); |
| } |
| |
| // Update the lengths for the current day. |
| void Add(int64_t original_content_length, int64_t received_content_length) { |
| original_.Add(original_content_length); |
| received_.Add(received_content_length); |
| } |
| |
| int64_t GetOriginalListPrefValue(size_t index) { |
| return original_.GetListPrefValue(index); |
| } |
| int64_t GetReceivedListPrefValue(size_t index) { |
| return received_.GetListPrefValue(index); |
| } |
| |
| private: |
| DailyContentLengthUpdate original_; |
| DailyContentLengthUpdate received_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DailyDataSavingUpdate); |
| }; |
| |
| DataReductionProxyCompressionStats::DataReductionProxyCompressionStats( |
| DataReductionProxyService* service, |
| PrefService* prefs, |
| const base::TimeDelta& delay) |
| : service_(service), |
| pref_service_(prefs), |
| delay_(delay), |
| data_usage_map_is_dirty_(false), |
| current_data_usage_load_status_(NOT_LOADED), |
| weak_factory_(this) { |
| DCHECK(service); |
| DCHECK(prefs); |
| DCHECK_GE(delay.InMilliseconds(), 0); |
| Init(); |
| } |
| |
| DataReductionProxyCompressionStats::~DataReductionProxyCompressionStats() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| if (current_data_usage_load_status_ == LOADED) |
| PersistDataUsage(); |
| |
| WritePrefs(); |
| } |
| |
| void DataReductionProxyCompressionStats::Init() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| data_usage_reporting_enabled_.Init( |
| prefs::kDataUsageReportingEnabled, pref_service_, |
| base::Bind( |
| &DataReductionProxyCompressionStats::OnDataUsageReportingPrefChanged, |
| weak_factory_.GetWeakPtr())); |
| |
| if (data_usage_reporting_enabled_.GetValue()) { |
| current_data_usage_load_status_ = LOADING; |
| service_->LoadCurrentDataUsageBucket(base::Bind( |
| &DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| InitializeWeeklyAggregateDataUse(base::Time::Now()); |
| |
| if (delay_.is_zero()) |
| return; |
| |
| // Init all int64_t prefs. |
| InitInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate); |
| InitInt64Pref(prefs::kHttpReceivedContentLength); |
| InitInt64Pref(prefs::kHttpOriginalContentLength); |
| |
| InitInt64Pref(prefs::kDailyHttpOriginalContentLengthApplication); |
| InitInt64Pref(prefs::kDailyHttpOriginalContentLengthVideo); |
| InitInt64Pref(prefs::kDailyHttpOriginalContentLengthUnknown); |
| InitInt64Pref(prefs::kDailyHttpReceivedContentLengthApplication); |
| InitInt64Pref(prefs::kDailyHttpReceivedContentLengthVideo); |
| InitInt64Pref(prefs::kDailyHttpReceivedContentLengthUnknown); |
| |
| InitInt64Pref( |
| prefs::kDailyOriginalContentLengthViaDataReductionProxyApplication); |
| InitInt64Pref(prefs::kDailyOriginalContentLengthViaDataReductionProxyVideo); |
| InitInt64Pref(prefs::kDailyOriginalContentLengthViaDataReductionProxyUnknown); |
| InitInt64Pref(prefs::kDailyContentLengthViaDataReductionProxyApplication); |
| InitInt64Pref(prefs::kDailyContentLengthViaDataReductionProxyVideo); |
| InitInt64Pref(prefs::kDailyContentLengthViaDataReductionProxyUnknown); |
| |
| InitInt64Pref( |
| prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledApplication); |
| InitInt64Pref( |
| prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabledVideo); |
| InitInt64Pref( |
| prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabledUnknown); |
| InitInt64Pref( |
| prefs::kDailyContentLengthWithDataReductionProxyEnabledApplication); |
| InitInt64Pref(prefs::kDailyContentLengthWithDataReductionProxyEnabledVideo); |
| InitInt64Pref(prefs::kDailyContentLengthWithDataReductionProxyEnabledUnknown); |
| |
| // Init all list prefs. |
| InitListPref(prefs::kDailyContentLengthHttpsWithDataReductionProxyEnabled); |
| InitListPref( |
| prefs::kDailyContentLengthLongBypassWithDataReductionProxyEnabled); |
| InitListPref( |
| prefs::kDailyContentLengthShortBypassWithDataReductionProxyEnabled); |
| InitListPref(prefs::kDailyContentLengthUnknownWithDataReductionProxyEnabled); |
| InitListPref(prefs::kDailyContentLengthViaDataReductionProxy); |
| InitListPref(prefs::kDailyContentLengthWithDataReductionProxyEnabled); |
| InitListPref(prefs::kDailyHttpOriginalContentLength); |
| InitListPref(prefs::kDailyHttpReceivedContentLength); |
| InitListPref(prefs::kDailyOriginalContentLengthViaDataReductionProxy); |
| InitListPref(prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabled); |
| } |
| |
| void DataReductionProxyCompressionStats::RecordDataUseWithMimeType( |
| int64_t data_used, |
| int64_t original_size, |
| bool data_saver_enabled, |
| DataReductionProxyRequestType request_type, |
| const std::string& mime_type, |
| bool is_user_traffic, |
| data_use_measurement::DataUseUserData::DataUseContentType content_type, |
| int32_t service_hash_code) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| TRACE_EVENT0("loader", |
| "DataReductionProxyCompressionStats::RecordDataUseWithMimeType") |
| |
| IncreaseInt64Pref(data_reduction_proxy::prefs::kHttpReceivedContentLength, |
| data_used); |
| IncreaseInt64Pref(data_reduction_proxy::prefs::kHttpOriginalContentLength, |
| original_size); |
| |
| RecordRequestSizePrefs(data_used, original_size, data_saver_enabled, |
| request_type, mime_type, base::Time::Now()); |
| RecordWeeklyAggregateDataUse( |
| base::Time::Now(), std::round(static_cast<double>(data_used) / 1024), |
| is_user_traffic, content_type, service_hash_code); |
| } |
| |
| void DataReductionProxyCompressionStats::InitInt64Pref(const char* pref) { |
| int64_t pref_value = pref_service_->GetInt64(pref); |
| pref_map_[pref] = pref_value; |
| } |
| |
| void DataReductionProxyCompressionStats::InitListPref(const char* pref) { |
| std::unique_ptr<base::ListValue> pref_value = |
| std::unique_ptr<base::ListValue>( |
| pref_service_->GetList(pref)->DeepCopy()); |
| list_pref_map_[pref] = std::move(pref_value); |
| } |
| |
| int64_t DataReductionProxyCompressionStats::GetInt64(const char* pref_path) { |
| if (delay_.is_zero()) |
| return pref_service_->GetInt64(pref_path); |
| |
| auto iter = pref_map_.find(pref_path); |
| return iter->second; |
| } |
| |
| void DataReductionProxyCompressionStats::SetInt64(const char* pref_path, |
| int64_t pref_value) { |
| if (delay_.is_zero()) { |
| pref_service_->SetInt64(pref_path, pref_value); |
| return; |
| } |
| |
| DelayedWritePrefs(); |
| pref_map_[pref_path] = pref_value; |
| } |
| |
| void DataReductionProxyCompressionStats::IncreaseInt64Pref( |
| const char* pref_path, |
| int64_t delta) { |
| SetInt64(pref_path, GetInt64(pref_path) + delta); |
| } |
| |
| base::ListValue* DataReductionProxyCompressionStats::GetList( |
| const char* pref_path) { |
| if (delay_.is_zero()) |
| return ListPrefUpdate(pref_service_, pref_path).Get(); |
| |
| DelayedWritePrefs(); |
| auto it = list_pref_map_.find(pref_path); |
| if (it == list_pref_map_.end()) |
| return nullptr; |
| return it->second.get(); |
| } |
| |
| void DataReductionProxyCompressionStats::WritePrefs() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| if (delay_.is_zero()) |
| return; |
| |
| for (auto iter = pref_map_.begin(); iter != pref_map_.end(); ++iter) { |
| pref_service_->SetInt64(iter->first, iter->second); |
| } |
| |
| for (auto iter = list_pref_map_.begin(); iter != list_pref_map_.end(); |
| ++iter) { |
| TransferList(*(iter->second.get()), |
| ListPrefUpdate(pref_service_, iter->first).Get()); |
| } |
| } |
| |
| int64_t DataReductionProxyCompressionStats::GetLastUpdateTime() { |
| int64_t last_update_internal = |
| GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate); |
| base::Time last_update = base::Time::FromInternalValue(last_update_internal); |
| return static_cast<int64_t>(last_update.ToJsTime()); |
| } |
| |
| void DataReductionProxyCompressionStats::ResetStatistics() { |
| base::ListValue* original_update = |
| GetList(prefs::kDailyHttpOriginalContentLength); |
| base::ListValue* received_update = |
| GetList(prefs::kDailyHttpReceivedContentLength); |
| original_update->Clear(); |
| received_update->Clear(); |
| for (size_t i = 0; i < kNumDaysInHistory; ++i) { |
| original_update->AppendString(base::NumberToString(0)); |
| received_update->AppendString(base::NumberToString(0)); |
| } |
| } |
| |
| int64_t DataReductionProxyCompressionStats::GetHttpReceivedContentLength() { |
| return GetInt64(prefs::kHttpReceivedContentLength); |
| } |
| |
| int64_t DataReductionProxyCompressionStats::GetHttpOriginalContentLength() { |
| return GetInt64(prefs::kHttpOriginalContentLength); |
| } |
| |
| ContentLengthList DataReductionProxyCompressionStats::GetDailyContentLengths( |
| const char* pref_name) { |
| ContentLengthList content_lengths; |
| const base::ListValue* list_value = GetList(pref_name); |
| if (list_value->GetSize() == kNumDaysInHistory) { |
| for (size_t i = 0; i < kNumDaysInHistory; ++i) |
| content_lengths.push_back(GetInt64PrefValue(*list_value, i)); |
| } |
| return content_lengths; |
| } |
| |
| void DataReductionProxyCompressionStats::GetContentLengths( |
| unsigned int days, |
| int64_t* original_content_length, |
| int64_t* received_content_length, |
| int64_t* last_update_time) { |
| DCHECK_LE(days, kNumDaysInHistory); |
| |
| const base::ListValue* original_list = |
| GetList(prefs::kDailyHttpOriginalContentLength); |
| const base::ListValue* received_list = |
| GetList(prefs::kDailyHttpReceivedContentLength); |
| |
| if (original_list->GetSize() != kNumDaysInHistory || |
| received_list->GetSize() != kNumDaysInHistory) { |
| *original_content_length = 0L; |
| *received_content_length = 0L; |
| *last_update_time = 0L; |
| return; |
| } |
| |
| int64_t orig = 0L; |
| int64_t recv = 0L; |
| // Include days from the end of the list going backwards. |
| for (size_t i = kNumDaysInHistory - days; |
| i < kNumDaysInHistory; ++i) { |
| orig += GetInt64PrefValue(*original_list, i); |
| recv += GetInt64PrefValue(*received_list, i); |
| } |
| *original_content_length = orig; |
| *received_content_length = recv; |
| *last_update_time = GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate); |
| } |
| |
| void DataReductionProxyCompressionStats::GetHistoricalDataUsage( |
| const HistoricalDataUsageCallback& get_data_usage_callback) { |
| GetHistoricalDataUsageImpl(get_data_usage_callback, base::Time::Now()); |
| } |
| |
| void DataReductionProxyCompressionStats::DeleteBrowsingHistory( |
| const base::Time& start, |
| const base::Time& end) { |
| DCHECK_NE(LOADING, current_data_usage_load_status_); |
| |
| if (!data_usage_map_last_updated_.is_null() && |
| DataUsageStore::BucketOverlapsInterval(data_usage_map_last_updated_, |
| start, end)) { |
| data_usage_map_.clear(); |
| data_usage_map_last_updated_ = base::Time(); |
| data_usage_map_is_dirty_ = false; |
| } |
| |
| service_->DeleteBrowsingHistory(start, end); |
| |
| RecordSavingsClearedMetric(DataReductionProxySavingsClearedReason:: |
| USER_ACTION_DELETE_BROWSING_HISTORY); |
| } |
| |
| void DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded( |
| std::unique_ptr<DataUsageBucket> data_usage) { |
| // Exit early if the pref was turned off before loading from storage |
| // completed. |
| if (!data_usage_reporting_enabled_.GetValue()) { |
| DCHECK_EQ(NOT_LOADED, current_data_usage_load_status_); |
| DCHECK(data_usage_map_.empty()); |
| current_data_usage_load_status_ = NOT_LOADED; |
| return; |
| } else { |
| DCHECK_EQ(LOADING, current_data_usage_load_status_); |
| } |
| |
| DCHECK(data_usage_map_last_updated_.is_null()); |
| DCHECK(data_usage_map_.empty()); |
| |
| // We currently do not break down by connection type. However, we use a schema |
| // that makes it easy to transition to a connection based breakdown without |
| // requiring a data migration. |
| DCHECK(data_usage->connection_usage_size() == 0 || |
| data_usage->connection_usage_size() == 1); |
| for (const auto& connection_usage : data_usage->connection_usage()) { |
| for (const auto& site_usage : connection_usage.site_usage()) { |
| data_usage_map_[site_usage.hostname()] = |
| std::make_unique<PerSiteDataUsage>(site_usage); |
| } |
| } |
| |
| data_usage_map_last_updated_ = |
| base::Time::FromInternalValue(data_usage->last_updated_timestamp()); |
| // Record if there was a read error. |
| if (data_usage->had_read_error()) { |
| RecordSavingsClearedMetric( |
| DataReductionProxySavingsClearedReason::PREFS_PARSE_ERROR); |
| } |
| |
| current_data_usage_load_status_ = LOADED; |
| } |
| |
| void DataReductionProxyCompressionStats::SetDataUsageReportingEnabled( |
| bool enabled) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| if (data_usage_reporting_enabled_.GetValue() != enabled) { |
| data_usage_reporting_enabled_.SetValue(enabled); |
| OnDataUsageReportingPrefChanged(); |
| } |
| } |
| |
| void DataReductionProxyCompressionStats::ClearDataSavingStatistics( |
| DataReductionProxySavingsClearedReason reason) { |
| DeleteHistoricalDataUsage(); |
| |
| pref_service_->ClearPref(prefs::kDailyHttpContentLengthLastUpdateDate); |
| pref_service_->ClearPref(prefs::kHttpReceivedContentLength); |
| pref_service_->ClearPref(prefs::kHttpOriginalContentLength); |
| |
| pref_service_->ClearPref(prefs::kDailyHttpOriginalContentLengthApplication); |
| pref_service_->ClearPref(prefs::kDailyHttpOriginalContentLengthVideo); |
| pref_service_->ClearPref(prefs::kDailyHttpOriginalContentLengthUnknown); |
| pref_service_->ClearPref(prefs::kDailyHttpReceivedContentLengthApplication); |
| pref_service_->ClearPref(prefs::kDailyHttpReceivedContentLengthVideo); |
| pref_service_->ClearPref(prefs::kDailyHttpReceivedContentLengthUnknown); |
| |
| pref_service_->ClearPref( |
| prefs::kDailyOriginalContentLengthViaDataReductionProxyApplication); |
| pref_service_->ClearPref( |
| prefs::kDailyOriginalContentLengthViaDataReductionProxyVideo); |
| pref_service_->ClearPref( |
| prefs::kDailyOriginalContentLengthViaDataReductionProxyUnknown); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthViaDataReductionProxyApplication); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthViaDataReductionProxyVideo); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthViaDataReductionProxyUnknown); |
| |
| pref_service_->ClearPref( |
| prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledApplication); |
| pref_service_->ClearPref( |
| prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabledVideo); |
| pref_service_->ClearPref( |
| prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabledUnknown); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthWithDataReductionProxyEnabledApplication); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthWithDataReductionProxyEnabledVideo); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthWithDataReductionProxyEnabledUnknown); |
| |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthHttpsWithDataReductionProxyEnabled); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthLongBypassWithDataReductionProxyEnabled); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthShortBypassWithDataReductionProxyEnabled); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthUnknownWithDataReductionProxyEnabled); |
| pref_service_->ClearPref(prefs::kDailyContentLengthViaDataReductionProxy); |
| pref_service_->ClearPref( |
| prefs::kDailyContentLengthWithDataReductionProxyEnabled); |
| pref_service_->ClearPref(prefs::kDailyHttpOriginalContentLength); |
| pref_service_->ClearPref(prefs::kDailyHttpReceivedContentLength); |
| pref_service_->ClearPref( |
| prefs::kDailyOriginalContentLengthViaDataReductionProxy); |
| pref_service_->ClearPref( |
| prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabled); |
| |
| for (auto iter = list_pref_map_.begin(); iter != list_pref_map_.end(); |
| ++iter) { |
| iter->second->Clear(); |
| } |
| |
| RecordSavingsClearedMetric(reason); |
| } |
| |
| void DataReductionProxyCompressionStats::DelayedWritePrefs() { |
| if (pref_writer_timer_.IsRunning()) |
| return; |
| |
| pref_writer_timer_.Start(FROM_HERE, delay_, this, |
| &DataReductionProxyCompressionStats::WritePrefs); |
| } |
| |
| void DataReductionProxyCompressionStats::TransferList( |
| const base::ListValue& from_list, |
| base::ListValue* to_list) { |
| to_list->Clear(); |
| from_list.CreateDeepCopy()->Swap(to_list); |
| } |
| |
| void DataReductionProxyCompressionStats::RecordRequestSizePrefs( |
| int64_t data_used, |
| int64_t original_size, |
| bool with_data_saver_enabled, |
| DataReductionProxyRequestType request_type, |
| const std::string& mime_type, |
| const base::Time& now) { |
| // TODO(bengr): Remove this check once the underlying cause of |
| // http://crbug.com/287821 is fixed. For now, only continue if the current |
| // year is reported as being between 1972 and 2970. |
| base::TimeDelta time_since_unix_epoch = now - base::Time::UnixEpoch(); |
| const int kMinDaysSinceUnixEpoch = 365 * 2; // 2 years. |
| const int kMaxDaysSinceUnixEpoch = 365 * 1000; // 1000 years. |
| if (time_since_unix_epoch.InDays() < kMinDaysSinceUnixEpoch || |
| time_since_unix_epoch.InDays() > kMaxDaysSinceUnixEpoch) { |
| return; |
| } |
| |
| // Determine how many days it has been since the last update. |
| int64_t then_internal = GetInt64( |
| data_reduction_proxy::prefs::kDailyHttpContentLengthLastUpdateDate); |
| |
| // Local midnight could have been shifted due to time zone change. |
| // If time is null then don't care if midnight will be wrong shifted due to |
| // time zone change because it's still too much time ago. |
| base::Time then_midnight = base::Time::FromInternalValue(then_internal); |
| if (!then_midnight.is_null()) { |
| then_midnight = then_midnight.LocalMidnight(); |
| } |
| base::Time midnight = now.LocalMidnight(); |
| |
| DailyDataSavingUpdate total( |
| this, data_reduction_proxy::prefs::kDailyHttpOriginalContentLength, |
| data_reduction_proxy::prefs::kDailyHttpReceivedContentLength); |
| DailyDataSavingUpdate proxy_enabled( |
| this, data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabled, |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabled); |
| DailyDataSavingUpdate via_proxy( |
| this, data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxy, |
| data_reduction_proxy::prefs::kDailyContentLengthViaDataReductionProxy); |
| DailyContentLengthUpdate https( |
| this, data_reduction_proxy::prefs:: |
| kDailyContentLengthHttpsWithDataReductionProxyEnabled); |
| DailyContentLengthUpdate short_bypass( |
| this, data_reduction_proxy::prefs:: |
| kDailyContentLengthShortBypassWithDataReductionProxyEnabled); |
| DailyContentLengthUpdate long_bypass( |
| this, data_reduction_proxy::prefs:: |
| kDailyContentLengthLongBypassWithDataReductionProxyEnabled); |
| DailyContentLengthUpdate unknown( |
| this, data_reduction_proxy::prefs:: |
| kDailyContentLengthUnknownWithDataReductionProxyEnabled); |
| |
| int days_since_last_update = (midnight - then_midnight).InDays(); |
| if (days_since_last_update) { |
| // Record the last update time in microseconds in UTC. |
| SetInt64(data_reduction_proxy::prefs::kDailyHttpContentLengthLastUpdateDate, |
| midnight.ToInternalValue()); |
| |
| // A new day. Report the previous day's data if exists. We'll lose usage |
| // data if the last time Chrome was run was more than a day ago. |
| // Here, we prefer collecting less data but the collected data is |
| // associated with an accurate date. |
| if (days_since_last_update == 1) { |
| RecordDailyContentLengthHistograms( |
| total.GetOriginalListPrefValue(kNumDaysInHistory - 1), |
| total.GetReceivedListPrefValue(kNumDaysInHistory - 1), |
| proxy_enabled.GetOriginalListPrefValue(kNumDaysInHistory - 1), |
| proxy_enabled.GetReceivedListPrefValue(kNumDaysInHistory - 1), |
| via_proxy.GetOriginalListPrefValue(kNumDaysInHistory - 1), |
| via_proxy.GetReceivedListPrefValue(kNumDaysInHistory - 1), |
| https.GetListPrefValue(kNumDaysInHistory - 1), |
| short_bypass.GetListPrefValue(kNumDaysInHistory - 1), |
| long_bypass.GetListPrefValue(kNumDaysInHistory - 1), |
| unknown.GetListPrefValue(kNumDaysInHistory - 1)); |
| |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyHttpOriginalContentLengthApplication, |
| "Net.DailyOriginalContentLength_Application"); |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyHttpReceivedContentLengthApplication, |
| "Net.DailyReceivedContentLength_Application"); |
| |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthVideo, |
| "Net.DailyOriginalContentLength_Video"); |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthVideo, |
| "Net.DailyContentLength_Video"); |
| |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthUnknown, |
| "Net.DailyOriginalContentLength_UnknownMime"); |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthUnknown, |
| "Net.DailyContentLength_UnknownMime"); |
| |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledApplication, |
| "Net.DailyOriginalContentLength_DataReductionProxyEnabled_" |
| "Application"); |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledApplication, |
| "Net.DailyContentLength_DataReductionProxyEnabled_Application"); |
| |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledVideo, |
| "Net.DailyOriginalContentLength_DataReductionProxyEnabled_Video"); |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledVideo, |
| "Net.DailyContentLength_DataReductionProxyEnabled_Video"); |
| int64_t original_length_with_data_reduction_enabled_video = GetInt64( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledVideo); |
| if (original_length_with_data_reduction_enabled_video > 0) { |
| int64_t received_length_with_data_reduction_enabled_video = |
| GetInt64(data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledVideo); |
| int percent_data_reduction_proxy_enabled_video = 0; |
| // UMA percentage cannot be negative. |
| // The DataReductionProxy server will only serve optimized video content |
| // if the optimized content is smaller than the original content. |
| // TODO(ryansturm): Track daily data inflation percents here and |
| // elsewhere. http://crbug.com/595818 |
| if (original_length_with_data_reduction_enabled_video > |
| received_length_with_data_reduction_enabled_video) { |
| percent_data_reduction_proxy_enabled_video = |
| 100 * (original_length_with_data_reduction_enabled_video - |
| received_length_with_data_reduction_enabled_video) / |
| original_length_with_data_reduction_enabled_video; |
| } |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentSavingPercent_DataReductionProxyEnabled_Video", |
| percent_data_reduction_proxy_enabled_video); |
| } |
| |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledUnknown, |
| "Net.DailyOriginalContentLength_DataReductionProxyEnabled_" |
| "UnknownMime"); |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledUnknown, |
| "Net.DailyContentLength_DataReductionProxyEnabled_UnknownMime") |
| |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyApplication, |
| "Net.DailyOriginalContentLength_ViaDataReductionProxy_Application"); |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyApplication, |
| "Net.DailyContentLength_ViaDataReductionProxy_Application"); |
| |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyVideo, |
| "Net.DailyOriginalContentLength_ViaDataReductionProxy_Video"); |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyVideo, |
| "Net.DailyContentLength_ViaDataReductionProxy_Video"); |
| int64_t original_length_via_data_reduction_proxy_video = |
| GetInt64(data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyVideo); |
| if (original_length_via_data_reduction_proxy_video > 0) { |
| int64_t received_length_via_data_reduction_proxy_video = |
| GetInt64(data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyVideo); |
| int percent_via_data_reduction_proxy_video = 0; |
| // UMA percentage cannot be negative. |
| // The DataReductionProxy server will only serve optimized video content |
| // if the optimized content is smaller than the original content. |
| // TODO(ryansturm): Track daily data inflation percents here and |
| // elsewhere. http://crbug.com/595818 |
| if (original_length_via_data_reduction_proxy_video > |
| received_length_via_data_reduction_proxy_video) { |
| percent_via_data_reduction_proxy_video = |
| 100 * (original_length_via_data_reduction_proxy_video - |
| received_length_via_data_reduction_proxy_video) / |
| original_length_via_data_reduction_proxy_video; |
| } |
| UMA_HISTOGRAM_PERCENTAGE( |
| "Net.DailyContentSavingPercent_ViaDataReductionProxy_Video", |
| percent_via_data_reduction_proxy_video); |
| } |
| |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyUnknown, |
| "Net.DailyOriginalContentLength_ViaDataReductionProxy_UnknownMime"); |
| RECORD_INT64PREF_TO_HISTOGRAM( |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyUnknown, |
| "Net.DailyContentLength_ViaDataReductionProxy_UnknownMime"); |
| } |
| |
| if (days_since_last_update < -1) { |
| RecordSavingsClearedMetric( |
| DataReductionProxySavingsClearedReason::SYSTEM_CLOCK_MOVED_BACK); |
| } |
| |
| // The system may go backwards in time by up to a day for legitimate |
| // reasons, such as with changes to the time zone. In such cases, we |
| // keep adding to the current day which is why we check for |
| // |days_since_last_update != -1|. |
| // Note: we accept the fact that some reported data is shifted to |
| // the adjacent day if users travel back and forth across time zones. |
| if (days_since_last_update && (days_since_last_update != -1)) { |
| if (days_since_last_update < -1) { |
| pref_service_->SetInt64( |
| prefs::kDataReductionProxySavingsClearedNegativeSystemClock, |
| now.ToInternalValue()); |
| } |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyHttpOriginalContentLengthApplication, |
| 0); |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyHttpReceivedContentLengthApplication, |
| 0); |
| |
| SetInt64( |
| data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthVideo, 0); |
| SetInt64( |
| data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthVideo, 0); |
| |
| SetInt64( |
| data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthUnknown, |
| 0); |
| SetInt64( |
| data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthUnknown, |
| 0); |
| |
| SetInt64( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledApplication, |
| 0); |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledApplication, |
| 0); |
| |
| SetInt64( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledVideo, |
| 0); |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledVideo, |
| 0); |
| |
| SetInt64( |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledUnknown, |
| 0); |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledUnknown, |
| 0); |
| |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyApplication, |
| 0); |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyApplication, |
| 0); |
| |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyVideo, |
| 0); |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyVideo, |
| 0); |
| |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyUnknown, |
| 0); |
| SetInt64(data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyUnknown, |
| 0); |
| } |
| } |
| |
| total.UpdateForDateChange(days_since_last_update); |
| proxy_enabled.UpdateForDateChange(days_since_last_update); |
| via_proxy.UpdateForDateChange(days_since_last_update); |
| https.UpdateForDateChange(days_since_last_update); |
| short_bypass.UpdateForDateChange(days_since_last_update); |
| long_bypass.UpdateForDateChange(days_since_last_update); |
| unknown.UpdateForDateChange(days_since_last_update); |
| |
| total.Add(original_size, data_used); |
| if (with_data_saver_enabled) { |
| proxy_enabled.Add(original_size, data_used); |
| // Ignore data source cases, if exist, when |
| // "with_data_saver_enabled == false" |
| switch (request_type) { |
| case VIA_DATA_REDUCTION_PROXY: |
| via_proxy.Add(original_size, data_used); |
| break; |
| case HTTPS: |
| https.Add(data_used); |
| break; |
| case SHORT_BYPASS: |
| short_bypass.Add(data_used); |
| break; |
| case LONG_BYPASS: |
| long_bypass.Add(data_used); |
| break; |
| case UPDATE: |
| case DIRECT_HTTP: |
| // Don't record any request level prefs. If this is an update, this data |
| // was already recorded at the URLRequest level. Updates are generally |
| // page load level optimizations and don't correspond to request types. |
| return; |
| case UNKNOWN_TYPE: |
| unknown.Add(data_used); |
| break; |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| bool via_data_reduction_proxy = request_type == VIA_DATA_REDUCTION_PROXY; |
| bool is_application = net::MatchesMimeType("application/*", mime_type); |
| bool is_video = net::MatchesMimeType("video/*", mime_type); |
| bool is_mime_type_empty = mime_type.empty(); |
| if (is_application) { |
| IncrementDailyUmaPrefs( |
| original_size, data_used, |
| data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthApplication, |
| data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthApplication, |
| with_data_saver_enabled, |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledApplication, |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledApplication, |
| via_data_reduction_proxy, |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyApplication, |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyApplication); |
| } else if (is_video) { |
| IncrementDailyUmaPrefs( |
| original_size, data_used, |
| data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthVideo, |
| data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthVideo, |
| with_data_saver_enabled, |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledVideo, |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledVideo, |
| via_data_reduction_proxy, |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyVideo, |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyVideo); |
| } else if (is_mime_type_empty) { |
| IncrementDailyUmaPrefs( |
| original_size, data_used, |
| data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthUnknown, |
| data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthUnknown, |
| with_data_saver_enabled, |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthWithDataReductionProxyEnabledUnknown, |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthWithDataReductionProxyEnabledUnknown, |
| via_data_reduction_proxy, |
| data_reduction_proxy::prefs:: |
| kDailyOriginalContentLengthViaDataReductionProxyUnknown, |
| data_reduction_proxy::prefs:: |
| kDailyContentLengthViaDataReductionProxyUnknown); |
| } |
| } |
| |
| void DataReductionProxyCompressionStats::IncrementDailyUmaPrefs( |
| int64_t original_size, |
| int64_t received_size, |
| const char* original_size_pref, |
| const char* received_size_pref, |
| bool data_reduction_proxy_enabled, |
| const char* original_size_with_proxy_enabled_pref, |
| const char* recevied_size_with_proxy_enabled_pref, |
| bool via_data_reduction_proxy, |
| const char* original_size_via_proxy_pref, |
| const char* received_size_via_proxy_pref) { |
| IncreaseInt64Pref(original_size_pref, original_size); |
| IncreaseInt64Pref(received_size_pref, received_size); |
| |
| if (data_reduction_proxy_enabled) { |
| IncreaseInt64Pref(original_size_with_proxy_enabled_pref, original_size); |
| IncreaseInt64Pref(recevied_size_with_proxy_enabled_pref, received_size); |
| } |
| |
| if (via_data_reduction_proxy) { |
| IncreaseInt64Pref(original_size_via_proxy_pref, original_size); |
| IncreaseInt64Pref(received_size_via_proxy_pref, received_size); |
| } |
| } |
| |
| void DataReductionProxyCompressionStats::RecordDataUseByHost( |
| const std::string& data_usage_host, |
| int64_t data_used, |
| int64_t original_size, |
| const base::Time time) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| if (current_data_usage_load_status_ != LOADED) |
| return; |
| |
| DCHECK(data_usage_reporting_enabled_.GetValue()); |
| |
| if (!DataUsageStore::AreInSameInterval(data_usage_map_last_updated_, time)) { |
| PersistDataUsage(); |
| data_usage_map_.clear(); |
| data_usage_map_last_updated_ = base::Time(); |
| } |
| |
| std::string normalized_host = NormalizeHostname(data_usage_host); |
| auto j = data_usage_map_.insert( |
| std::make_pair(normalized_host, std::make_unique<PerSiteDataUsage>())); |
| PerSiteDataUsage* per_site_usage = j.first->second.get(); |
| per_site_usage->set_hostname(normalized_host); |
| per_site_usage->set_original_size(per_site_usage->original_size() + |
| original_size); |
| per_site_usage->set_data_used(per_site_usage->data_used() + data_used); |
| |
| data_usage_map_last_updated_ = time; |
| data_usage_map_is_dirty_ = true; |
| } |
| |
| void DataReductionProxyCompressionStats::PersistDataUsage() { |
| DCHECK(current_data_usage_load_status_ == LOADED); |
| |
| if (data_usage_map_is_dirty_) { |
| std::unique_ptr<DataUsageBucket> data_usage_bucket(new DataUsageBucket()); |
| data_usage_bucket->set_last_updated_timestamp( |
| data_usage_map_last_updated_.ToInternalValue()); |
| PerConnectionDataUsage* connection_usage = |
| data_usage_bucket->add_connection_usage(); |
| for (auto i = data_usage_map_.begin(); i != data_usage_map_.end(); ++i) { |
| PerSiteDataUsage* per_site_usage = connection_usage->add_site_usage(); |
| per_site_usage->CopyFrom(*(i->second.get())); |
| } |
| service_->StoreCurrentDataUsageBucket(std::move(data_usage_bucket)); |
| } |
| |
| data_usage_map_is_dirty_ = false; |
| } |
| |
| void DataReductionProxyCompressionStats::DeleteHistoricalDataUsage() { |
| // This method does not support being called in |LOADING| status since this |
| // means that the in-memory data usage will get populated when data usage |
| // loads, which will undo the clear below. This method is called when users |
| // click on the "Clear Data" button, or when user deletes the extension. In |
| // both cases, enough time has passed since startup to load current data |
| // usage. Technically, this could occur, and will have the effect of not |
| // clearing data from the current bucket. |
| // TODO(kundaji): Use cancellable tasks and remove this DCHECK. |
| DCHECK(current_data_usage_load_status_ != LOADING); |
| |
| data_usage_map_.clear(); |
| data_usage_map_last_updated_ = base::Time(); |
| data_usage_map_is_dirty_ = false; |
| |
| service_->DeleteHistoricalDataUsage(); |
| } |
| |
| void DataReductionProxyCompressionStats::GetHistoricalDataUsageImpl( |
| const HistoricalDataUsageCallback& get_data_usage_callback, |
| const base::Time& now) { |
| #if !defined(OS_ANDROID) |
| if (current_data_usage_load_status_ != LOADED) { |
| // If current data usage has not yet loaded, we return an empty array. The |
| // extension can retry after a slight delay. |
| // This use case is unlikely to occur in practice since current data usage |
| // should have sufficient time to load before user tries to view data usage. |
| get_data_usage_callback.Run( |
| std::make_unique<std::vector<DataUsageBucket>>()); |
| return; |
| } |
| #endif |
| |
| if (current_data_usage_load_status_ == LOADED) |
| PersistDataUsage(); |
| |
| if (!data_usage_map_last_updated_.is_null() && |
| !DataUsageStore::AreInSameInterval(data_usage_map_last_updated_, now)) { |
| data_usage_map_.clear(); |
| data_usage_map_last_updated_ = base::Time(); |
| |
| // Force the last bucket to be for the current interval. |
| std::unique_ptr<DataUsageBucket> data_usage_bucket(new DataUsageBucket()); |
| data_usage_bucket->set_last_updated_timestamp(now.ToInternalValue()); |
| service_->StoreCurrentDataUsageBucket(std::move(data_usage_bucket)); |
| } |
| |
| service_->LoadHistoricalDataUsage(get_data_usage_callback); |
| } |
| |
| void DataReductionProxyCompressionStats::OnDataUsageReportingPrefChanged() { |
| if (data_usage_reporting_enabled_.GetValue()) { |
| if (current_data_usage_load_status_ == NOT_LOADED) { |
| current_data_usage_load_status_ = LOADING; |
| service_->LoadCurrentDataUsageBucket(base::Bind( |
| &DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded, |
| weak_factory_.GetWeakPtr())); |
| } |
| } else { |
| // Don't delete the historical data on Android, but clear the map. |
| #if defined(OS_ANDROID) |
| if (current_data_usage_load_status_ == LOADED) |
| PersistDataUsage(); |
| |
| data_usage_map_.clear(); |
| data_usage_map_last_updated_ = base::Time(); |
| data_usage_map_is_dirty_ = false; |
| #else |
| DeleteHistoricalDataUsage(); |
| #endif |
| current_data_usage_load_status_ = NOT_LOADED; |
| } |
| } |
| |
| void DataReductionProxyCompressionStats::InitializeWeeklyAggregateDataUse( |
| const base::Time& now) { |
| #if defined(OS_ANDROID) && defined(ARCH_CPU_X86) |
| // TODO(rajendrant): Enable aggregate metrics recording in x86 Android. |
| // http://crbug.com/865373 |
| return; |
| #endif |
| |
| MaybeInitWeeklyAggregateDataUsePrefs(now, pref_service_); |
| // Record the histograms that will show up in the user feedback. |
| RecordDictionaryToHistogram( |
| "DataReductionProxy.ThisWeekAggregateKB.Services.Downstream.Background", |
| pref_service_->GetDictionary( |
| prefs::kThisWeekServicesDownstreamBackgroundKB)); |
| RecordDictionaryToHistogram( |
| "DataReductionProxy.ThisWeekAggregateKB.Services.Downstream.Foreground", |
| pref_service_->GetDictionary( |
| prefs::kThisWeekServicesDownstreamForegroundKB)); |
| RecordDictionaryToHistogram( |
| "DataReductionProxy.ThisWeekAggregateKB.UserTraffic.Downstream." |
| "ContentType", |
| pref_service_->GetDictionary( |
| prefs::kThisWeekUserTrafficContentTypeDownstreamKB)); |
| RecordDictionaryToHistogram( |
| "DataReductionProxy.LastWeekAggregateKB.Services.Downstream.Background", |
| pref_service_->GetDictionary( |
| prefs::kLastWeekServicesDownstreamBackgroundKB)); |
| RecordDictionaryToHistogram( |
| "DataReductionProxy.LastWeekAggregateKB.Services.Downstream.Foreground", |
| pref_service_->GetDictionary( |
| prefs::kLastWeekServicesDownstreamForegroundKB)); |
| RecordDictionaryToHistogram( |
| "DataReductionProxy.LastWeekAggregateKB.UserTraffic.Downstream." |
| "ContentType", |
| pref_service_->GetDictionary( |
| prefs::kLastWeekUserTrafficContentTypeDownstreamKB)); |
| } |
| |
| void DataReductionProxyCompressionStats::RecordWeeklyAggregateDataUse( |
| const base::Time& now, |
| int32_t data_used_kb, |
| bool is_user_request, |
| data_use_measurement::DataUseUserData::DataUseContentType content_type, |
| int32_t service_hash_code) { |
| #if defined(OS_ANDROID) && defined(ARCH_CPU_X86) |
| // TODO(rajendrant): Enable aggregate metrics recording in x86 Android. |
| // http://crbug.com/865373 |
| return; |
| #endif |
| // Update the prefs if this is a new week. This can happen when chrome is open |
| // for weeks without being closed. |
| MaybeInitWeeklyAggregateDataUsePrefs(now, pref_service_); |
| if (is_user_request) { |
| AddToDictionaryPref(pref_service_, |
| prefs::kThisWeekUserTrafficContentTypeDownstreamKB, |
| content_type, data_used_kb); |
| } else { |
| bool is_app_foreground = true; |
| if (is_app_foreground) { |
| AddToDictionaryPref(pref_service_, |
| prefs::kThisWeekServicesDownstreamForegroundKB, |
| service_hash_code, data_used_kb); |
| } else { |
| AddToDictionaryPref(pref_service_, |
| prefs::kThisWeekServicesDownstreamBackgroundKB, |
| service_hash_code, data_used_kb); |
| } |
| } |
| } |
| |
| // static |
| std::string DataReductionProxyCompressionStats::NormalizeHostname( |
| const std::string& host) { |
| size_t pos = host.find("://"); |
| if (pos != std::string::npos) |
| return host.substr(pos + 3); |
| |
| return host; |
| } |
| |
| } // namespace data_reduction_proxy |