1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_METRIC_BUILDER_H_
6 #define THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_METRIC_BUILDER_H_
7 
8 #include <cstdint>
9 #include <vector>
10 
11 #include "services/metrics/public/cpp/ukm_recorder.h"
12 #include "services/metrics/public/cpp/ukm_source_id.h"
13 #include "third_party/blink/public/common/common_export.h"
14 #include "third_party/blink/public/common/privacy_budget/identifiable_sample.h"
15 #include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
16 #include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
17 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-forward.h"
18 
19 namespace blink {
20 
21 // IdentifiabilityMetricBuilder builds an identifiability metric encoded into a
22 // UkmEntry.
23 //
24 // This UkmEntry can be recorded via a UkmRecorder.
25 //
26 // # Encoding
27 //
28 // All identifiability metrics are represented using the tuple
29 //
30 //     < identifiable_surface_type, input, output >.
31 //
32 // A typical URL-Keyed-Metrics (UKM) entry looks like the following:
33 //
34 //     struct UkmEntry {
35 //       int64 source_id;
36 //       uint64 event_hash;
37 //       map<uint64,int64> metrics;
38 //     };
39 //
40 // (From //services/metrics/public/mojom/ukm_interface.mojom)
41 //
42 // This class encodes the former into the latter.
43 //
44 // The |source_id| is one that is known to UKM. Follow UKM guidelines for how to
45 // generate or determine the |source_id| corresponding to a document or URL.
46 //
47 // The |event_hash| is a digest of the UKM event name via
48 // |base::HashMetricName()|. For identifiability metrics, this is always
49 // UINT64_C(287024497009309687) which corresponds to 'Identifiability'.
50 //
51 // Metrics for *regular* UKM consist of a mapping from a metric ID to a metric
52 // value. The metric ID is a digest of the metric name as determined by
53 // base::IdentifiabilityDigestOfBytes(), similar to how an |event_hash| is
54 // derived from the event name.
55 //
56 // However, for identifiability metrics, the method for generating metric IDs
57 // is:
58 //
59 //     metrics_hash = (input << 8) | identifiable_surface_type;
60 //
61 // The |identifiable_surface_type| is an enumeration identifying the input
62 // identifier defined in |IdentifiableSurface::Type|.
63 //
64 // We lose the 8 MSBs of |input|. Retaining the lower bits allow us to use small
65 // (i.e. under 56-bits) numbers as-is without losing information.
66 //
67 // The |IdentifiableSurface| class encapsulates this translation.
68 //
69 // The |metrics| field in |UkmEntry| thus contains a mapping from the resulting
70 // |metric_hash| to the output of the identifiable surface encoded into 64-bits.
71 //
72 // To generate a 64-bit hash of a random binary blob, use
73 // |blink::IdentifiabilityDigestOfBytes()|. For numbers with fewer than 56
74 // significant bits, you can use the number itself as the input hash.
75 //
76 // As mentioned in |identifiability_metrics.h|, this function is **not** a
77 // cryptographic hash function. While it is expected to have a reasonable
78 // distribution for a uniform input, it should be assumed that finding
79 // collisions is trivial.
80 //
81 // E.g.:
82 //
83 // 1. A simple web exposed API that's represented using a |WebFeature|
84 //    constant. Values are defined in
85 //    blink/public/mojom/web_feature/web_feature.mojom.
86 //
87 //        identifiable_surface = IdentifiableSurface::FromTypeAndToken(
88 //            IdentifiableSurface::Type::kWebFeature,
89 //            blink::mojom::WebFeature::kDeviceOrientationSecureOrigin);
90 //        output = IdentifiabilityDigestOfBytes(result_as_binary_blob);
91 //
92 // 2. A surface that takes a non-trivial input represented as a binary blob:
93 //
94 //        identifiable_surface = IdentifiableSurface::FromTypeAndToken(
95 //            IdentifiableSurface::Type::kFancySurface,
96 //            IdentifiabilityDigestOfBytes(input_as_binary_blob));
97 //        output = IdentifiabilityDigestOfBytes(result_as_binary_blob);
98 class BLINK_COMMON_EXPORT IdentifiabilityMetricBuilder {
99  public:
100   // Construct a metrics builder for the given |source_id|. The source must be
101   // known to UKM.
102   explicit IdentifiabilityMetricBuilder(ukm::SourceIdObj source_id);
103 
104   // This has the same effect as the previous constructor but takes the
105   // deprecated ukm::SourceId for convenience. Doing so allows callsites to use
106   // methods like Document::GetUkmSourceId() without an extra conversion. In
107   // addition, when Document::GetUkmSourceId() migrates to returning a
108   // ukm::SourceIdObj, callsites won't need to change.
IdentifiabilityMetricBuilder(ukm::SourceId source_id)109   explicit IdentifiabilityMetricBuilder(ukm::SourceId source_id)
110       : IdentifiabilityMetricBuilder(ukm::SourceIdObj::FromInt64(source_id)) {}
111 
112   ~IdentifiabilityMetricBuilder();
113 
114   // Set the metric using a previously constructed |IdentifiableSurface|.
115   IdentifiabilityMetricBuilder& Set(IdentifiableSurface surface,
116                                     IdentifiableToken sample);
117 
118   // Convenience method for recording the result of invoking a simple API
119   // surface with a |UseCounter|.
SetWebfeature(mojom::WebFeature feature,IdentifiableToken sample)120   IdentifiabilityMetricBuilder& SetWebfeature(mojom::WebFeature feature,
121                                               IdentifiableToken sample) {
122     return Set(IdentifiableSurface::FromTypeAndToken(
123                    IdentifiableSurface::Type::kWebFeature, feature),
124                sample);
125   }
126 
127   // Record collected metrics to `recorder`.
128   void Record(ukm::UkmRecorder* recorder);
129 
130  private:
131   std::vector<IdentifiableSample> metrics_;
132   const ukm::SourceIdObj source_id_;
133 };
134 
135 }  // namespace blink
136 
137 #endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_METRIC_BUILDER_H_
138