File: report_request_queue_generator.cc

package info (click to toggle)
chromium 139.0.7258.138-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,120,676 kB
  • sloc: cpp: 35,100,869; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (200 lines) | stat: -rw-r--r-- 7,773 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/enterprise/browser/reporting/report_request_queue_generator.h"

#include <utility>
#include <vector>

#include "base/barrier_callback.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/metrics/histogram_functions.h"
#include "components/enterprise/browser/reporting/report_type.h"

namespace enterprise_reporting {

using IndexedProfileReport =
    std::pair<int,
              std::unique_ptr<enterprise_management::ChromeUserProfileInfo>>;

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;

IndexedProfileReport ToIndexedReportPair(
    int index,
    std::unique_ptr<enterprise_management::ChromeUserProfileInfo>
        profile_report) {
  return std::pair(index, std::move(profile_report));
}

}  // namespace

ReportRequestQueueGenerator::ReportRequestQueueGenerator(
    ReportingDelegateFactory* delegate_factory)
    : maximum_report_size_(kMaximumReportSize),
      profile_report_generator_(delegate_factory) {
#if BUILDFLAG(IS_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;
}

void ReportRequestQueueGenerator::Generate(
    std::unique_ptr<ReportRequest> basic_request,
    base::OnceCallback<void(ReportRequestQueue)> callback) {
  if (!basic_request) {
    OnAllProfileReportsGenerated(std::move(basic_request), std::move(callback),
                                 std::vector<IndexedProfileReport>());
    return;
  }

  size_t basic_request_size =
      basic_request->GetDeviceReportRequest().ByteSizeLong();
  base::UmaHistogramMemoryKB(kBasicRequestSizeMetricsName,
                             basic_request_size / 1024);

  if (basic_request_size > maximum_report_size_) {
    OnAllProfileReportsGenerated(std::move(basic_request), std::move(callback),
                                 std::vector<IndexedProfileReport>());
    return;
  }

  int profile_infos_size = basic_request->GetDeviceReportRequest()
                               .browser_report()
                               .chrome_user_profile_infos_size();
  const auto* basic_request_ptr = basic_request.get();
  auto barrier_callback = base::BarrierCallback<IndexedProfileReport>(
      profile_infos_size,
      base::BindOnce(&ReportRequestQueueGenerator::OnAllProfileReportsGenerated,
                     weak_factory_.GetWeakPtr(), std::move(basic_request),
                     std::move(callback)));

  for (int index = 0; index < profile_infos_size; index++) {
    GenerateProfileReportWithIndex(index, basic_request_ptr, barrier_callback);
  }
}

void ReportRequestQueueGenerator::GenerateProfileReportWithIndex(
    int profile_index,
    const ReportRequest* basic_request,
    base::OnceCallback<void(IndexedProfileReport)> callback) {
  DCHECK_LT(profile_index, basic_request->GetDeviceReportRequest()
                               .browser_report()
                               .chrome_user_profile_infos_size());

  auto basic_profile = basic_request->GetDeviceReportRequest()
                           .browser_report()
                           .chrome_user_profile_infos(profile_index);
  profile_report_generator_.MaybeGenerate(
      base::FilePath::FromUTF8Unsafe(basic_profile.id()), ReportType::kFull,
      base::BindOnce(ToIndexedReportPair, profile_index)
          .Then(std::move(callback)));
}

void ReportRequestQueueGenerator::OnAllProfileReportsGenerated(
    std::unique_ptr<ReportRequest> basic_request,
    base::OnceCallback<void(ReportRequestQueue)> callback,
    std::vector<IndexedProfileReport> indexed_reports) {
  ReportRequestQueue requests;

  size_t basic_request_size =
      basic_request->GetDeviceReportRequest().ByteSizeLong();
  if (basic_request_size <= maximum_report_size_) {
    requests.push(basic_request->Clone());
  }

  for (auto& indexed_report : indexed_reports) {
    auto profile_index = std::get<int>(indexed_report);
    auto profile_report = std::move(
        std::get<std::unique_ptr<enterprise_management::ChromeUserProfileInfo>>(
            indexed_report));

    // Skip if Profile is not loaded and there is no full report.
    if (!profile_report) {
      continue;
    }

    auto basic_profile = basic_request->GetDeviceReportRequest()
                             .browser_report()
                             .chrome_user_profile_infos(profile_index);
    // 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()->GetDeviceReportRequest().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()
          ->GetDeviceReportRequest()
          .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()->GetDeviceReportRequest().ByteSizeLong() / 1024);
      requests.push(basic_request->Clone());
      requests.back()
          ->GetDeviceReportRequest()
          .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);
    }
  }

  base::UmaHistogramExactLinear(kRequestCountMetricsName, requests.size(),
                                kRequestCountMetricMaxValue);

  if (!requests.empty()) {
    base::UmaHistogramMemoryKB(
        kRequestSizeMetricsName,
        requests.back()->GetDeviceReportRequest().ByteSizeLong() / 1024);
  }

  std::move(callback).Run(std::move(requests));
}

}  // namespace enterprise_reporting