Chromium Code Reviews| Index: chrome/browser/android/data_usage/external_data_use_observer.cc |
| diff --git a/chrome/browser/android/data_usage/external_data_use_observer.cc b/chrome/browser/android/data_usage/external_data_use_observer.cc |
| index 55774278b8b6fc688fa719175cc956bec917d4cd..3c3b1bcc961d15993436cd60e779da7bc7b2c4e4 100644 |
| --- a/chrome/browser/android/data_usage/external_data_use_observer.cc |
| +++ b/chrome/browser/android/data_usage/external_data_use_observer.cc |
| @@ -11,6 +11,7 @@ |
| #include "base/containers/hash_tables.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/metrics/field_trial.h" |
| +#include "base/metrics/histogram_macros.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "chrome/browser/android/data_usage/data_use_tab_model.h" |
| #include "components/data_usage/core/data_use.h" |
| @@ -25,10 +26,53 @@ using base::android::ToJavaArrayOfStrings; |
| namespace { |
| +// Result of data usage report submission. |
| +enum DataUsageReportSubmissionResult { |
| + // Submission of data use report to the external observer was successful. |
| + DATAUSAGE_REPORT_SUBMISSION_SUCCESSFUL = 0, |
| + // Submission of data use report to the external observer returned error. |
| + DATAUSAGE_REPORT_SUBMISSION_FAILED = 1, |
| + // Submission of data use report to the external observer timed out. |
| + DATAUSAGE_REPORT_SUBMISSION_TIMED_OUT = 2, |
| + // Data use report was lost before an attempt was made to submit it. |
| + DATAUSAGE_REPORT_SUBMISSION_LOST = 3, |
| + DATAUSAGE_REPORT_SUBMISSION_BOUNDARY = 4 |
| +}; |
| + |
| +// Record the result of data use report submission. |bytes| is the sum of send |
| +// and received bytes in the report. |
| +void RecordDataUsageReportSubmission(DataUsageReportSubmissionResult result, |
| + int64_t bytes) { |
| + UMA_HISTOGRAM_ENUMERATION("DataUsage.ReportSubmissionResult", result, |
| + DATAUSAGE_REPORT_SUBMISSION_BOUNDARY); |
| + switch (result) { |
| + case DATAUSAGE_REPORT_SUBMISSION_SUCCESSFUL: |
| + UMA_HISTOGRAM_COUNTS("DataUsage.ReportSubmission.Successful.Bytes", |
| + bytes); |
|
sclittle
2015/12/02 19:07:54
Histogram samples are casted to int32_t when they'
tbansal1
2015/12/03 03:19:45
Good point. Done.
|
| + break; |
| + case DATAUSAGE_REPORT_SUBMISSION_FAILED: |
| + UMA_HISTOGRAM_COUNTS("DataUsage.ReportSubmission.Failed.Bytes", bytes); |
| + break; |
| + case DATAUSAGE_REPORT_SUBMISSION_TIMED_OUT: |
| + UMA_HISTOGRAM_COUNTS("DataUsage.ReportSubmission.TimedOut.Bytes", bytes); |
| + break; |
| + case DATAUSAGE_REPORT_SUBMISSION_LOST: |
| + UMA_HISTOGRAM_COUNTS("DataUsage.ReportSubmission.Lost.Bytes", bytes); |
| + break; |
| + default: |
| + NOTIMPLEMENTED(); |
| + break; |
| + } |
| +} |
| + |
| // Default duration after which matching rules are periodically fetched. May be |
| // overridden by the field trial. |
| const int kDefaultFetchMatchingRulesDurationSeconds = 60 * 15; // 15 minutes. |
| +// Default duration after which a pending data use report is considered timed |
| +// out. May be overridden by the field trial. |
| +const int kDefaultDataUseReportSubmitTimeoutSeconds = 60 * 2; // 2 minutes. |
|
sclittle
2015/12/02 19:07:54
nit: Since you're controlling this with a field tr
tbansal1
2015/12/03 03:19:45
Done.
|
| + |
| // Default value of the minimum number of bytes that should be buffered before |
| // a data use report is submitted. May be overridden by the field trial. |
| const int64_t kDefaultDataUseReportMinBytes = 100 * 1024; // 100 KB. |
| @@ -36,7 +80,7 @@ const int64_t kDefaultDataUseReportMinBytes = 100 * 1024; // 100 KB. |
| // Populates various parameters from the values specified in the field trial. |
| int32_t GetFetchMatchingRulesDurationSeconds() { |
| int32_t duration_seconds = -1; |
| - std::string variation_value = variations::GetVariationParamValue( |
| + const std::string variation_value = variations::GetVariationParamValue( |
| chrome::android::ExternalDataUseObserver:: |
| kExternalDataUseObserverFieldTrial, |
| "fetch_matching_rules_duration_seconds"); |
| @@ -49,9 +93,24 @@ int32_t GetFetchMatchingRulesDurationSeconds() { |
| } |
| // Populates various parameters from the values specified in the field trial. |
| +int32_t GetDataReportSubmitTimeoutSeconds() { |
| + int32_t duration_seconds = -1; |
| + const std::string variation_value = variations::GetVariationParamValue( |
| + chrome::android::ExternalDataUseObserver:: |
| + kExternalDataUseObserverFieldTrial, |
| + "data_report_submit_timeout_seconds"); |
| + if (!variation_value.empty() && |
| + base::StringToInt(variation_value, &duration_seconds)) { |
| + DCHECK_LE(0, duration_seconds); |
| + return duration_seconds; |
| + } |
| + return kDefaultDataUseReportSubmitTimeoutSeconds; |
| +} |
| + |
| +// Populates various parameters from the values specified in the field trial. |
| int64_t GetMinBytes() { |
| int64_t min_bytes = -1; |
| - std::string variation_value = variations::GetVariationParamValue( |
| + const std::string variation_value = variations::GetVariationParamValue( |
| chrome::android::ExternalDataUseObserver:: |
| kExternalDataUseObserverFieldTrial, |
| "data_use_report_min_bytes"); |
| @@ -82,7 +141,8 @@ ExternalDataUseObserver::ExternalDataUseObserver( |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
| : data_use_aggregator_(data_use_aggregator), |
| matching_rules_fetch_pending_(false), |
| - submit_data_report_pending_(false), |
| + last_data_report_submitted_(base::TimeTicks()), |
| + pending_report_bytes_(0), |
| registered_as_observer_(false), |
| io_task_runner_(io_task_runner), |
| ui_task_runner_(ui_task_runner), |
| @@ -92,11 +152,14 @@ ExternalDataUseObserver::ExternalDataUseObserver( |
| fetch_matching_rules_duration_( |
| base::TimeDelta::FromSeconds(GetFetchMatchingRulesDurationSeconds())), |
| data_use_report_min_bytes_(GetMinBytes()), |
| + data_report_submit_timeout_( |
| + base::TimeDelta::FromSeconds(GetDataReportSubmitTimeoutSeconds())), |
| io_weak_factory_(this), |
| ui_weak_factory_(this) { |
| DCHECK(data_use_aggregator_); |
| DCHECK(io_task_runner_); |
| DCHECK(ui_task_runner_); |
| + DCHECK(last_data_report_submitted_.is_null()); |
| ui_task_runner_->PostTask( |
| FROM_HERE, |
| @@ -204,11 +267,18 @@ base::WeakPtr<ExternalDataUseObserver> ExternalDataUseObserver::GetUIWeakPtr() { |
| void ExternalDataUseObserver::OnReportDataUseDoneOnIOThread(bool success) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - DCHECK(submit_data_report_pending_); |
| + DCHECK(!last_data_report_submitted_.is_null()); |
| - // TODO(tbansal): If not successful, record UMA. |
| + if (success) { |
| + RecordDataUsageReportSubmission(DATAUSAGE_REPORT_SUBMISSION_SUCCESSFUL, |
| + pending_report_bytes_); |
| + } else { |
| + RecordDataUsageReportSubmission(DATAUSAGE_REPORT_SUBMISSION_FAILED, |
| + pending_report_bytes_); |
| + } |
| - submit_data_report_pending_ = false; |
| + last_data_report_submitted_ = base::TimeTicks(); |
| + pending_report_bytes_ = 0; |
| SubmitBufferedDataUseReport(); |
| } |
| @@ -268,7 +338,8 @@ void ExternalDataUseObserver::BufferDataUseReport( |
| if (it == buffered_data_reports_.end()) { |
| // Limit the buffer size. |
| if (buffered_data_reports_.size() == kMaxBufferSize) { |
| - // TODO(tbansal): Add UMA to track impact of lost reports. |
| + RecordDataUsageReportSubmission(DATAUSAGE_REPORT_SUBMISSION_LOST, |
| + data_use.rx_bytes + data_use.tx_bytes); |
| return; |
| } |
| buffered_data_reports_.insert(std::make_pair(data_use_report_key, report)); |
| @@ -285,29 +356,49 @@ void ExternalDataUseObserver::BufferDataUseReport( |
| } |
| total_bytes_buffered_ += (data_use.rx_bytes + data_use.tx_bytes); |
| + DCHECK_LT(0U, buffered_data_reports_.size()); |
| DCHECK_LE(buffered_data_reports_.size(), kMaxBufferSize); |
| } |
| void ExternalDataUseObserver::SubmitBufferedDataUseReport() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - if (submit_data_report_pending_ || buffered_data_reports_.empty()) |
| + const base::TimeTicks ticks_now = base::TimeTicks::Now(); |
| + |
| + // Return if a data use report has been pending for less than |
| + // |data_report_submit_timeout_| duration. |
| + if (!last_data_report_submitted_.is_null() && |
| + ticks_now - last_data_report_submitted_ < data_report_submit_timeout_) { |
| + return; |
| + } |
| + |
| + if (buffered_data_reports_.empty()) |
| return; |
| if (total_bytes_buffered_ < data_use_report_min_bytes_) |
| return; |
| + if (!last_data_report_submitted_.is_null()) { |
| + RecordDataUsageReportSubmission(DATAUSAGE_REPORT_SUBMISSION_TIMED_OUT, |
| + pending_report_bytes_); |
| + pending_report_bytes_ = 0; |
| + last_data_report_submitted_ = base::TimeTicks(); |
| + } |
| + |
| // Send one data use report. |
| DataUseReports::iterator it = buffered_data_reports_.begin(); |
| DataUseReportKey key = it->first; |
| DataUseReport report = it->second; |
| + DCHECK_EQ(0, pending_report_bytes_); |
| + DCHECK(last_data_report_submitted_.is_null()); |
| + pending_report_bytes_ = report.bytes_downloaded + report.bytes_uploaded; |
| + last_data_report_submitted_ = ticks_now; |
| + |
| // Remove the entry from the map. |
| buffered_data_reports_.erase(it); |
| total_bytes_buffered_ -= (report.bytes_downloaded + report.bytes_uploaded); |
| - submit_data_report_pending_ = true; |
| - |
| ui_task_runner_->PostTask( |
| FROM_HERE, base::Bind(&ExternalDataUseObserver::ReportDataUseOnUIThread, |
| GetIOWeakPtr(), key, report)); |