File: private_aggregation_pending_contributions.h

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; 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 (284 lines) | stat: -rw-r--r-- 12,386 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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_PRIVATE_AGGREGATION_PRIVATE_AGGREGATION_PENDING_CONTRIBUTIONS_H_
#define CONTENT_BROWSER_PRIVATE_AGGREGATION_PRIVATE_AGGREGATION_PENDING_CONTRIBUTIONS_H_

#include <stddef.h>
#include <stdint.h>

#include <map>
#include <optional>
#include <set>
#include <string_view>
#include <variant>
#include <vector>

#include "base/numerics/safe_conversions.h"
#include "content/browser/private_aggregation/private_aggregation_budgeter.h"
#include "content/common/content_export.h"
#include "third_party/abseil-cpp/absl/numeric/int128.h"
#include "third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom.h"
#include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom.h"

namespace content {

// Holds the pending histogram contributions for a particular aggregatable
// report through the Private Aggregation layer -- i.e. from the
// PrivateAggregationHost until just before the final budgeting round. This
// class also stores contributions that are conditional on error events,
// triggering or dropping those contributions based on whether the event
// occurred, as well as contribution merging and truncation.
//
// This class is only usable/constructible when the
// `kPrivateAggregationApiErrorReporting` feature is enabled. However, see
// `PrivateAggregationPendingContributions::Wrapper` for a class that holds
// either this type or a bare vector of contributions based on the state of that
// feature.
class CONTENT_EXPORT PrivateAggregationPendingContributions {
 public:
  // Contributions can be merged if they have matching keys.
  struct ContributionMergeKey {
    explicit ContributionMergeKey(
        const blink::mojom::AggregatableReportHistogramContribution&
            contribution)
        : bucket(contribution.bucket),
          filtering_id(contribution.filtering_id.value_or(0)) {}

    explicit ContributionMergeKey(
        const blink::mojom::AggregatableReportHistogramContributionPtr&
            contribution)
        : ContributionMergeKey(*contribution) {}

    auto operator<=>(const ContributionMergeKey& a) const = default;

    absl::uint128 bucket;
    uint64_t filtering_id;
  };

  class Wrapper;

  using BudgeterResult = PrivateAggregationBudgeter::ResultForContribution;
  using PendingReportLimitResult =
      PrivateAggregationBudgeter::PendingReportLimitResult;

  // Indicates the reason for the PrivateAggregationHost mojo pipe closing.
  // TODO(crbug.com/381788013): Consider moving this enum to
  // `PrivateAggregationHost` once the feature is fully launched and the
  // circular dependency is avoided.
  enum TimeoutOrDisconnect {
    // The timeout was reached.
    kTimeout,

    // The pipe was disconnected by the caller API (e.g. due to the script
    // completing).
    kDisconnect
  };

  // Mirrors `PrivateAggregationHost::NullReportBehavior` to avoid a circular
  // dependency.
  // TODO(crbug.com/381788013): Merge these enums once the feature is fully
  // launched and the circular dependency is avoided.
  enum class NullReportBehavior {
    kSendNullReport,
    kDontSendReport,
  };

  // These values are persisted to logs. Entries should not be renumbered and
  // numeric values should never be reused.
  //
  // LINT.IfChange(TruncationResult)
  enum class TruncationResult {
    kNoTruncation = 0,
    kTruncationDueToUnconditionalContributions = 1,
    kTruncationNotDueToUnconditionalContributions = 2,
    kMaxValue = kTruncationNotDueToUnconditionalContributions,
  };
  // LINT.ThenChange(//tools/metrics/histograms/metadata/privacy/enums.xml:PrivacySandboxPrivateAggregationTruncationResult)

  // The elements of `histogram_suffixes` must outlive this object.
  PrivateAggregationPendingContributions(
      base::StrictNumeric<size_t> max_num_contributions,
      std::vector<std::string_view> histogram_suffixes);

  PrivateAggregationPendingContributions(
      PrivateAggregationPendingContributions&& other);
  PrivateAggregationPendingContributions& operator=(
      PrivateAggregationPendingContributions&& other);

  ~PrivateAggregationPendingContributions();

  const std::vector<blink::mojom::AggregatableReportHistogramContribution>&
  unconditional_contributions() const {
    return unconditional_contributions_;
  }

  bool are_contributions_finalized() const {
    return are_contributions_finalized_;
  }

  // Returns false if this object has any unconditional or conditional
  // contributions.
  bool IsEmpty() const;

  const std::map<
      blink::mojom::PrivateAggregationErrorEvent,
      std::vector<blink::mojom::AggregatableReportHistogramContribution>>&
  GetConditionalContributionsForTesting() const;

  // Tracks contributions not conditional on any error event (i.e. passed via
  // `ContributeToHistogram()`). Drops contributions with value 0.
  void AddUnconditionalContributions(
      std::vector<blink::mojom::AggregatableReportHistogramContribution>
          contributions);

  // Tracks contributions conditional on an error event (i.e. passed via
  // `ContributeToHistogramOnEvent()`). Drops contributions with value 0.
  void AddConditionalContributions(
      blink::mojom::PrivateAggregationErrorEvent error_event,
      std::vector<blink::mojom::AggregatableReportHistogramContribution>
          contributions);

  // Should be called exactly once per object when no further contributions can
  // be made. `finalization_cause` should indicate whether the mojo pipe
  // disconnected or timed out.
  void MarkContributionsFinalized(TimeoutOrDisconnect finalization_cause);

  // Applies the results of the test budget call, i.e. filtering out
  // unconditional contributions that were denied in that call and possibly
  // triggering conditional contributions, and then compiles (and returns) a
  // final list of unmerged contributions. This consists of any conditional
  // contributions for error events that were triggered followed by any
  // unconditional contributions. 'Truncates' the resulting list by assuming all
  // contributions would be approved by the budgeter and removing any
  // contributions that would not fit into the report *after merging is
  // performed*. In other words, this 'truncation' determines the first n
  // `ContributionMergeKey`s in this list, where n is `max_contributions_` and
  // removes any contributions with other `ContributionMergeKey`s. Note that
  // `test_budgeter_results` must a length equal to the number of unconditional
  // contributions before the call. Can only be called after
  // `MarkContributionsFinalized()`.
  const std::vector<blink::mojom::AggregatableReportHistogramContribution>&
  CompileFinalUnmergedContributions(
      std::vector<BudgeterResult> test_budgeter_results,
      PendingReportLimitResult pending_report_limit_result,
      NullReportBehavior null_report_behavior);

  // Applies the results of the final budget call to the result of
  // `CompileFinalUnmergedContributions()`, i.e. filtering out any contributions
  // denied by the budgeter, and then merges (approved) contributions where
  // possible (i.e. have the same `ContributionMergeKey`). Given the
  // 'truncation' performed earlier, no further truncation is needed to ensure
  // the overall length fits in limits. Consumes this object and returns the
  // final vector of merged (and truncated) contributions. Can only be called
  // after `CompileFinalUnmergedContributions()`.
  std::vector<blink::mojom::AggregatableReportHistogramContribution>
  TakeFinalContributions(std::vector<BudgeterResult> final_budgeter_results) &&;

 private:
  // Adds `contributions` to the end of the `final_unmerged_contributions_`
  // vector, adding each associated `ContributionMergeKey` to
  // `accepted_merge_keys`. However, if a contribution would cause
  // `accepted_merge_keys.size()` to grow beyond `max_contributions_`, the
  // contribution is instead dropped and its `ContributionMergeKey` is added to
  // `truncated_merge_keys`. The contributions are processed in the order given.
  void AddToFinalUnmergedContributions(
      std::vector<blink::mojom::AggregatableReportHistogramContribution>
          contributions,
      std::set<ContributionMergeKey>& accepted_merge_keys,
      std::set<ContributionMergeKey>& truncated_merge_keys);

  void ApplyTestBudgeterResults(
      std::vector<BudgeterResult> results,
      PendingReportLimitResult pending_report_limit_result,
      NullReportBehavior null_report_behavior);
  void ApplyFinalBudgeterResults(std::vector<BudgeterResult> results);

  void RecordNumberOfContributionMergeKeysHistogram(
      size_t num_merge_keys_sent_or_truncated) const;
  void RecordNumberOfFinalUnmergedContributionsHistogram(
      size_t num_final_unmerged_contributions) const;
  void RecordTruncationHistogram(
      size_t num_truncations_due_to_unconditional_contributions,
      size_t total_truncations) const;

  bool are_contributions_finalized_ = false;

  // Contributions passed to `ContributeToHistogram()` for the associated mojo
  // receiver. Only very loose truncation (to limit worst-case memory usage) and
  // dropping zero-value contributions has occurred. No contribution merging has
  // been occurred. This is consumed in `CompileFinalUnmergedContributions()`.
  std::vector<blink::mojom::AggregatableReportHistogramContribution>
      unconditional_contributions_;

  // Same considerations as `unconditional_contributions_`, but for
  // contributions passed to `ContributeToHistogramOnEvent()`.
  std::map<blink::mojom::PrivateAggregationErrorEvent,
           std::vector<blink::mojom::AggregatableReportHistogramContribution>>
      conditional_contributions_;

  // For each error event, whether the error has been triggered or not. No entry
  // for an error event if it hasn't yet been determined.
  std::map<blink::mojom::PrivateAggregationErrorEvent, bool>
      was_error_triggered_;

  // Only populated when `CompileFinalUnmergedContributions()` is called. The
  // return value of that call is a const reference to this object.
  std::vector<blink::mojom::AggregatableReportHistogramContribution>
      final_unmerged_contributions_;

  size_t max_contributions_;

  std::vector<std::string_view> histogram_suffixes_;
};

// This is a simple union class that holds contributions in the appropriate
// type given the state of the `kPrivateAggregationApiErrorReporting` feature.
//
// When the feature is disabled, this class is a wrapper around a vector of
// contributions (accessed via `GetContributionsVector()`), with contribution
// merging and truncation occurring before construction.
//
// When the feature is enabled, this class is a wrapper around
// `PrivateAggregationPendingContributions`, which also stores contributions
// that are conditional on error events, triggering or dropping those
// contributions based on whether the event occurred, as well as contribution
// merging and truncation.
//
// TODO(crbug.com/381788013): Remove this wrapper (replacing with a bare
// `PrivateAggregationPendingContributions`) after the feature is fully
// launched and the flag can be removed.
class CONTENT_EXPORT PrivateAggregationPendingContributions::Wrapper {
 public:
  // Usable iff `PrivateAggregationPendingContributions` is enabled.
  explicit Wrapper(
      PrivateAggregationPendingContributions pending_contributions);

  // Usable iff `PrivateAggregationPendingContributions` is disabled.
  explicit Wrapper(
      std::vector<blink::mojom::AggregatableReportHistogramContribution>
          contributions_vector);

  Wrapper(Wrapper&& other);
  Wrapper& operator=(Wrapper&& other);

  ~Wrapper();

  // Usable iff `PrivateAggregationPendingContributions` is enabled.
  PrivateAggregationPendingContributions& GetPendingContributions();

  // Usable iff `PrivateAggregationPendingContributions` is disabled.
  std::vector<blink::mojom::AggregatableReportHistogramContribution>&
  GetContributionsVector();

 private:
  std::variant<
      PrivateAggregationPendingContributions,
      std::vector<blink::mojom::AggregatableReportHistogramContribution>>
      contributions_;
};

}  // namespace content

#endif  // CONTENT_BROWSER_PRIVATE_AGGREGATION_PRIVATE_AGGREGATION_PENDING_CONTRIBUTIONS_H_