blob: cf8947018ae0c8a6be67d4cf22e903a492723b6b [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/enterprise/reporting/report_request_queue_generator.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/metrics/histogram_functions.h"
#include "chrome/browser/enterprise/reporting/profile_report_generator_desktop.h"
namespace enterprise_reporting {
namespace {
const size_t kMaximumReportSize =
5000000; // The report size limitation is 5mb.
constexpr char kRequestCountMetricsName[] =
"Enterprise.CloudReportingRequestCount";
constexpr char kRequestSizeMetricsName[] =
"Enterprise.CloudReportingRequestSize";
constexpr char kBasicRequestSizeMetricsName[] =
"Enterprise.CloudReportingBasicRequestSize";
// Because server only stores 20 profiles for each report and when report is
// separated into requests, there is at least one profile per request. It means
// server will truncate the report when there are more than 20 requests. Actions
// are needed if there are many reports exceed this limitation.
const int kRequestCountMetricMaxValue = 21;
} // namespace
ReportRequestQueueGenerator::ReportRequestQueueGenerator()
: maximum_report_size_(kMaximumReportSize),
profile_report_generator_(
std::make_unique<ProfileReportGeneratorDesktop>()) {
#if defined(OS_CHROMEOS)
// For Chrome OS, policy information needn't be uploaded to DM server.
profile_report_generator_.set_policies_enabled(false);
#endif
}
ReportRequestQueueGenerator::~ReportRequestQueueGenerator() = default;
size_t ReportRequestQueueGenerator::GetMaximumReportSizeForTesting() const {
return maximum_report_size_;
}
void ReportRequestQueueGenerator::SetMaximumReportSizeForTesting(
size_t maximum_report_size) {
maximum_report_size_ = maximum_report_size;
}
ReportRequestQueueGenerator::ReportRequests
ReportRequestQueueGenerator::Generate(const ReportRequest& basic_request) {
ReportRequests requests;
size_t basic_request_size = basic_request.ByteSizeLong();
base::UmaHistogramMemoryKB(kBasicRequestSizeMetricsName,
basic_request_size / 1024);
if (basic_request_size <= maximum_report_size_) {
requests.push(std::make_unique<ReportRequest>(basic_request));
int profile_infos_size =
basic_request.browser_report().chrome_user_profile_infos_size();
for (int index = 0; index < profile_infos_size; index++) {
GenerateProfileReportWithIndex(basic_request, index, &requests);
}
base::UmaHistogramMemoryKB(kRequestSizeMetricsName,
requests.back()->ByteSizeLong() / 1024);
}
base::UmaHistogramExactLinear(kRequestCountMetricsName, requests.size(),
kRequestCountMetricMaxValue);
return requests;
}
void ReportRequestQueueGenerator::GenerateProfileReportWithIndex(
const ReportRequest& basic_request,
int profile_index,
ReportRequests* requests) {
DCHECK_LT(profile_index,
basic_request.browser_report().chrome_user_profile_infos_size());
size_t basic_request_size = basic_request.ByteSizeLong();
auto basic_profile =
basic_request.browser_report().chrome_user_profile_infos(profile_index);
auto profile_report = profile_report_generator_.MaybeGenerate(
base::FilePath::FromUTF8Unsafe(basic_profile.id()), basic_profile.name());
// Return if Profile is not loaded and there is no full report.
if (!profile_report)
return;
// Use size diff to calculate estimated request size after full profile report
// is added. There are still few bytes difference but close enough.
size_t profile_report_incremental_size =
profile_report->ByteSizeLong() - basic_profile.ByteSizeLong();
size_t current_request_size = requests->back()->ByteSizeLong();
if (current_request_size + profile_report_incremental_size <=
maximum_report_size_) {
// The new full Profile report can be appended into the current request.
requests->back()
->mutable_browser_report()
->mutable_chrome_user_profile_infos(profile_index)
->Swap(profile_report.get());
} else if (basic_request_size + profile_report_incremental_size <=
maximum_report_size_) {
// The new full Profile report is too big to be appended into the current
// request, move it to the next request if possible. Record metrics for the
// current request's size.
base::UmaHistogramMemoryKB(kRequestSizeMetricsName,
requests->back()->ByteSizeLong() / 1024);
requests->push(std::make_unique<ReportRequest>(basic_request));
requests->back()
->mutable_browser_report()
->mutable_chrome_user_profile_infos(profile_index)
->Swap(profile_report.get());
} else {
// The new full Profile report is too big to be uploaded, skip this
// Profile report. But we still add the report size into metrics so
// that we could understand the situation better.
base::UmaHistogramMemoryKB(
kRequestSizeMetricsName,
(basic_request_size + profile_report_incremental_size) / 1024);
}
}
} // namespace enterprise_reporting